// EvictCachedRangeMetadata will evict any cached metadata range descriptors for // the given key. It is intended that this method be called from a consumer of // RangeMetadataCache when the returned range metadata is discovered to be // stale. func (rmc *RangeMetadataCache) EvictCachedRangeMetadata(key storage.Key) { for { k, _ := rmc.getCachedRangeMetadata(key) if k != nil { rmc.rangeCacheMu.Lock() rmc.rangeCache.Del(k) rmc.rangeCacheMu.Unlock() } // Retrieve the metadata range key for the next level of metadata, and // evict that key as well. This loop ends after the meta1 range, which // returns KeyMin as its metadata key. key = storage.RangeMetaKey(key) if len(key) == 0 { break } } }
// getCachedRangeMetadata is a helper function to retrieve the metadata // range which contains the given key, if present in the cache. func (rmc *RangeMetadataCache) getCachedRangeMetadata(key storage.Key) ( rangeCacheKey, *storage.RangeDescriptor) { metaKey := storage.RangeMetaKey(key) rmc.rangeCacheMu.RLock() defer rmc.rangeCacheMu.RUnlock() k, v, ok := rmc.rangeCache.Ceil(rangeCacheKey(metaKey)) if !ok { return nil, nil } metaEndKey := k.(rangeCacheKey) rd := v.(*storage.RangeDescriptor) // Check that key actually belongs to range if !rd.ContainsKey(key) { return nil, nil } return metaEndKey, rd }
// LookupRangeMetadata retrieves the range metadata for the range containing the // given key. Because range metadata in cockroach is stored using a multi-level // lookup table, this method may be called recursively to look up higher-level // ranges. Recursive lookups are dispatched through the metadata range cache. func (db *DistDB) LookupRangeMetadata(key storage.Key) (storage.Key, *storage.RangeDescriptor, error) { metadataKey := storage.RangeMetaKey(key) if len(metadataKey) == 0 { // Metadata range is the first range, the description of which is always // gossiped. infoI, err := db.gossip.GetInfo(gossip.KeyFirstRangeMetadata) if err != nil { return nil, nil, firstRangeMissingError{err} } info := infoI.(storage.RangeDescriptor) return storage.KeyMin, &info, nil } // Look up the range containing metadataKey in the cache, which will // recursively call into db.LookupRangeMetadata if it is not cached. metadataRange, err := db.rangeCache.LookupRangeMetadata(metadataKey) if err != nil { return nil, nil, err } return db.internalRangeLookup(metadataKey, metadataRange) }
// LookupRangeMetadata attempts to locate metadata for the range containing the // given Key. This is done by querying the two-level lookup table of range // metadata which cockroach maintains. // // This method first looks up the specified key in the first level of range // metadata, which returns the location of the key within the second level of // range metadata. This second level location is then queried to retrieve // metadata for the range where the key's value resides. Range metadata // descriptors retrieved during each search are cached for subsequent lookups. // // This method returns the RangeDescriptor for the range containing the key's // data, or an error if any occurred. func (rmc *RangeMetadataCache) LookupRangeMetadata(key storage.Key) (*storage.RangeDescriptor, error) { metadataKey := storage.RangeMetaKey(key) if len(metadataKey) == 0 { // The description of the first range is gossiped, and thus does not // need to be cached. Just ask the underlying db, which will return // immediately. _, r, err := rmc.db.LookupRangeMetadata(key) return r, err } _, r := rmc.getCachedRangeMetadata(key) if r != nil { return r, nil } k, r, err := rmc.db.LookupRangeMetadata(key) if err != nil { return nil, err } rmc.rangeCacheMu.Lock() rmc.rangeCache.Add(rangeCacheKey(k), r) rmc.rangeCacheMu.Unlock() return r, nil }