Пример #1
0
// PutResponse writes a response and an error associated with it to the
// cache for the specified cmdID.
func (rc *ResponseCache) PutResponse(e engine.Engine, cmdID roachpb.ClientCmdID, replyWithErr roachpb.ResponseWithError) error {
	// Do nothing if command ID is empty.
	if cmdID.IsEmpty() {
		return nil
	}

	// Write the response value to the engine.
	if rc.shouldCacheResponse(replyWithErr) {
		// Write the error into the reply before caching.
		replyWithErr.Reply.SetGoError(replyWithErr.Err)
		// Be sure to clear it when you're done!
		defer func() { replyWithErr.Reply.BatchResponse_Header.Error = nil }()

		key := keys.ResponseCacheKey(rc.rangeID, &cmdID)
		return engine.MVCCPutProto(e, nil, key, roachpb.ZeroTimestamp, nil, replyWithErr.Reply)
	}

	return nil
}
Пример #2
0
// GetResponse looks up a response matching the specified cmdID. If the
// response is found, it is returned along with its associated error.
// If the response is not found, nil is returned for both the response
// and its error. In all cases, the third return value is the error
// returned from the engine when reading the on-disk cache.
func (rc *ResponseCache) GetResponse(e engine.Engine, cmdID roachpb.ClientCmdID) (roachpb.ResponseWithError, error) {
	// Do nothing if command ID is empty.
	if cmdID.IsEmpty() {
		return roachpb.ResponseWithError{}, nil
	}

	// Pull response from the cache and read into reply if available.
	br := &roachpb.BatchResponse{}
	key := keys.ResponseCacheKey(rc.rangeID, &cmdID)
	ok, err := engine.MVCCGetProto(e, key, roachpb.ZeroTimestamp, true, nil, br)
	if err != nil {
		return roachpb.ResponseWithError{}, err
	}
	if ok {
		header := br.Header()
		defer func() { header.Error = nil }()
		return roachpb.ResponseWithError{Reply: br, Err: header.Error.GoError()}, nil
	}
	return roachpb.ResponseWithError{}, nil
}
Пример #3
0
func (rc *ResponseCache) decodeResponseCacheKey(encKey roachpb.EncodedKey) (roachpb.ClientCmdID, error) {
	ret := roachpb.ClientCmdID{}
	key, _, isValue, err := engine.MVCCDecodeKey(encKey)
	if err != nil {
		return ret, err
	}
	if isValue {
		return ret, util.Errorf("key %s is not a raw MVCC value", encKey)
	}
	if !bytes.HasPrefix(key, keys.LocalRangeIDPrefix) {
		return ret, util.Errorf("key %s does not have %s prefix", key, keys.LocalRangeIDPrefix)
	}
	// Cut the prefix and the Range ID.
	b := key[len(keys.LocalRangeIDPrefix):]
	b, _, err = encoding.DecodeUvarint(b)
	if err != nil {
		return ret, err
	}
	if !bytes.HasPrefix(b, keys.LocalResponseCacheSuffix) {
		return ret, util.Errorf("key %s does not contain the response cache suffix %s",
			key, keys.LocalResponseCacheSuffix)
	}
	// Cut the response cache suffix.
	b = b[len(keys.LocalResponseCacheSuffix):]
	// Now, decode the command ID.
	b, wt, err := encoding.DecodeUvarint(b)
	if err != nil {
		return ret, err
	}
	b, rd, err := encoding.DecodeUint64(b)
	if err != nil {
		return ret, err
	}
	if len(b) > 0 {
		return ret, util.Errorf("key %s has leftover bytes after decode: %s; indicates corrupt key",
			encKey, b)
	}
	ret.WallTime = int64(wt)
	ret.Random = int64(rd)
	return ret, nil
}