// getCachedRangeDescriptorLocked is a helper function to retrieve the // descriptor of the range which contains the given key, if present in the // cache. It is assumed that the caller holds a read lock on rdc.rangeCacheMu. func (rdc *rangeDescriptorCache) getCachedRangeDescriptorLocked(key proto.Key, inclusive bool) ( rangeCacheKey, *proto.RangeDescriptor) { // The cache is indexed using the end-key of the range, but the // end-key is non-inclusive by default. var metaKey proto.Key if !inclusive { metaKey = keys.RangeMetaKey(key.Next()) } else { metaKey = keys.RangeMetaKey(key) } k, v, ok := rdc.rangeCache.Ceil(rangeCacheKey(metaKey)) if !ok { return nil, nil } metaEndKey := k.(rangeCacheKey) rd := v.(*proto.RangeDescriptor) // Check that key actually belongs to the range. if !rd.ContainsKey(key) { // The key is the EndKey and we're inclusive, so just return the range descriptor. if inclusive && key.Equal(rd.EndKey) { return metaEndKey, rd } return nil, nil } // The key is the StartKey, but we're inclusive and thus need to return the // previous range descriptor, but it is not in the cache yet. if inclusive && key.Equal(rd.StartKey) { return nil, nil } return metaEndKey, rd }
// ValidateRangeMetaKey validates that the given key is a valid Range Metadata // key. func ValidateRangeMetaKey(key proto.Key) error { // KeyMin is a valid key. if key.Equal(proto.KeyMin) { return nil } // Key must be at least as long as Meta1Prefix. if len(key) < len(Meta1Prefix) { return NewInvalidRangeMetaKeyError("too short", key) } prefix, body := proto.Key(key[:len(Meta1Prefix)]), proto.Key(key[len(Meta1Prefix):]) if prefix.Equal(Meta2Prefix) { if body.Less(proto.KeyMax) { return nil } return NewInvalidRangeMetaKeyError("body of meta2 range lookup is >= KeyMax", key) } if prefix.Equal(Meta1Prefix) { if proto.KeyMax.Less(body) { return NewInvalidRangeMetaKeyError("body of meta1 range lookup is > KeyMax", key) } return nil } return NewInvalidRangeMetaKeyError("not a meta key", key) }
// Get searches the kv list for 'key' and returns its // raw byte value if found. ok is true only if the key is found. func (s *SystemConfig) Get(key proto.Key) ([]byte, bool) { l := len(s.Values) index := sort.Search(l, func(i int) bool { return bytes.Compare(s.Values[i].Key, key) >= 0 }) if index == l || !key.Equal(s.Values[index].Key) { return nil, false } // TODO(marc): I'm pretty sure a Value returned by MVCCScan can // never be nil. Should check. return s.Values[index].Value.Bytes, true }
// MetaScanBounds returns the start and end keys of the range within which the // desired meta record can be found by means of an engine scan. The given key // must be a valid RangeMetaKey as defined by ValidateRangeMetaKey. func MetaScanBounds(key proto.Key) (proto.Key, proto.Key) { if key.Equal(proto.KeyMin) { // Special case KeyMin: find the first entry in meta1. return Meta1Prefix, Meta1Prefix.PrefixEnd() } if key.Equal(Meta1KeyMax) { // Special case Meta1KeyMax: this is the last key in Meta1, we don't want // to start at Next(). return key, Meta1Prefix.PrefixEnd() } // Otherwise find the first entry greater than the given key in the same meta prefix. return key.Next(), proto.Key(key[:len(Meta1Prefix)]).PrefixEnd() }
// GetIndex searches the kv list for 'key' and returns its index if found. func (s *SystemConfig) GetIndex(key proto.Key) (int, bool) { if s == nil { return 0, false } l := len(s.Values) index := sort.Search(l, func(i int) bool { return !s.Values[i].Key.Less(key) }) if index == l || !key.Equal(s.Values[index].Key) { return 0, false } return index, true }
// ObjectIDForKey returns the object ID (table or database) for 'key', // or (_, false) if not within the structured key space. func ObjectIDForKey(key proto.Key) (uint32, bool) { if key.Equal(proto.KeyMax) { return 0, false } if key.Equal(keys.TableDataPrefix) { // TODO(marc): this should eventually return SystemDatabaseID. return 0, false } remaining := bytes.TrimPrefix(key, keys.TableDataPrefix) if len(remaining) == len(key) { // TrimPrefix returns the input untouched if the prefix doesn't match. return 0, false } // Consume first encoded int. _, id64, err := encoding.DecodeUvarint(remaining) return uint32(id64), err == nil }
// ObjectIDForKey returns the object ID (table or database) for 'key', // or (_, false) if not within the structured key space. func ObjectIDForKey(key proto.Key) (uint32, bool) { if key.Equal(proto.KeyMax) { return 0, false } if key.Equal(keys.TableDataPrefix) { // TODO(marc): this should eventually return SystemDatabaseID. return 0, false } remaining := bytes.TrimPrefix(key, keys.TableDataPrefix) if len(remaining) == len(key) { // TrimPrefix returns the input untouched if the prefix doesn't match. return 0, false } // Consume first encoded int. defer func() { // Nothing to do, default return values mean "could not decode", which is // definitely the case if DecodeUvarint panics. _ = recover() }() _, id64 := encoding.DecodeUvarint(remaining) return uint32(id64), true }
// getCachedRangeDescriptorLocked is a helper function to retrieve the // descriptor of the range which contains the given key, if present in the // cache. It is assumed that the caller holds a read lock on rdc.rangeCacheMu. func (rdc *rangeDescriptorCache) getCachedRangeDescriptorLocked(key proto.Key, isReverse bool) ( rangeCacheKey, *proto.RangeDescriptor) { // The cache is indexed using the end-key of the range, but the // end-key is non-inclusive. var metaKey proto.Key if !isReverse { // If it is not reverse scan, we access the cache using key.Next(). metaKey = keys.RangeMetaKey(key.Next()) } else { // Because reverse scan request is begining at end key(exclusive),so we // access the cache using key directly. metaKey = keys.RangeMetaKey(key) } k, v, ok := rdc.rangeCache.Ceil(rangeCacheKey(metaKey)) if !ok { return nil, nil } metaEndKey := k.(rangeCacheKey) rd := v.(*proto.RangeDescriptor) // Check that key actually belongs to the range. if !rd.ContainsKey(keys.KeyAddress(key)) { // The key is the EndKey of the range in reverse scan, just return the range descriptor. if isReverse && key.Equal(rd.EndKey) { return metaEndKey, rd } return nil, nil } // The key is the StartKey of the range in reverse scan. We need to return the previous range // descriptor, but it is not in the cache yet. if isReverse && key.Equal(rd.StartKey) { return nil, nil } return metaEndKey, rd }
// MetaReverseScanBounds returns the range [start,end) within which the desired // meta record can be found by means of a reverse engine scan. The given key // must be a valid RangeMetaKey as defined by ValidateRangeMetaKey. func MetaReverseScanBounds(key proto.Key) (proto.Key, proto.Key, error) { if key.Equal(proto.KeyMin) || key.Equal(Meta1Prefix) { return nil, nil, NewInvalidRangeMetaKeyError("KeyMin and Meta1Prefix can't be used as the key of reverse scan", key) } if key.Equal(Meta2Prefix) { // Special case Meta2Prefix: this is the first key in Meta2, and the scan // interval covers all of Meta1. return Meta1Prefix, key.Next(), nil } // Otherwise find the first entry greater than the given key and find the last entry // in the same prefix. For MVCCReverseScan the endKey is exclusive, if we want to find // the range descriptor the given key specified,we need to set the key.Next() as the // MVCCReverseScan`s endKey. For example: // If we have ranges ["", "f") and ["f", "z"), then we'll have corresponding meta records // at "f" and "z". If you're looking for the meta record for key "f", then you want the // second record (exclusive in MVCCReverseScan), hence key.Next() below. return key[:len(Meta1Prefix)], key.Next(), nil }
// MetaScanBounds returns the range [start,end) within which the desired meta // record can be found by means of an engine scan. The given key must be a // valid RangeMetaKey as defined by validateRangeMetaKey. func MetaScanBounds(key proto.Key) (proto.Key, proto.Key, error) { if err := validateRangeMetaKey(key); err != nil { return nil, nil, err } if key.Equal(Meta2KeyMax) { return nil, nil, NewInvalidRangeMetaKeyError("Meta2KeyMax can't be used as the key of scan", key) } if key.Equal(proto.KeyMin) { // Special case KeyMin: find the first entry in meta1. return Meta1Prefix, Meta1Prefix.PrefixEnd(), nil } if key.Equal(Meta1KeyMax) { // Special case Meta1KeyMax: this is the last key in Meta1, we don't want // to start at Next(). return key, Meta1Prefix.PrefixEnd(), nil } // Otherwise find the first entry greater than the given key in the same meta prefix. return key.Next(), proto.Key(key[:len(Meta1Prefix)]).PrefixEnd(), nil }