github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvclient/kvcoord/leaseholder_cache.go (about) 1 // Copyright 2015 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package kvcoord 12 13 import ( 14 "context" 15 "runtime" 16 17 "github.com/cockroachdb/cockroach/pkg/roachpb" 18 "github.com/cockroachdb/cockroach/pkg/util/cache" 19 "github.com/cockroachdb/cockroach/pkg/util/log" 20 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 21 ) 22 23 var ( 24 defaultShards = 2 * runtime.NumCPU() 25 ) 26 27 // A LeaseHolderCache is a cache of replica descriptors keyed by range ID. 28 type LeaseHolderCache struct { 29 shards []LeaseHolderCacheShard 30 } 31 32 // A LeaseHolderCacheShard is a cache of replica descriptors keyed by range ID. 33 type LeaseHolderCacheShard struct { 34 // NB: This can't be a RWMutex for lookup because UnorderedCache.Get 35 // manipulates an internal LRU list. 36 mu syncutil.Mutex 37 cache *cache.UnorderedCache 38 } 39 40 // NewLeaseHolderCache creates a new leaseHolderCache of the given size. 41 // The underlying cache internally uses a hash map, so lookups 42 // are cheap. 43 func NewLeaseHolderCache(size func() int64) *LeaseHolderCache { 44 leaseholderCache := &LeaseHolderCache{} 45 leaseholderCache.shards = make([]LeaseHolderCacheShard, defaultShards) 46 for i := range leaseholderCache.shards { 47 val := &leaseholderCache.shards[i] 48 val.cache = cache.NewUnorderedCache(cache.Config{ 49 Policy: cache.CacheLRU, 50 ShouldEvict: func(s int, key, value interface{}) bool { 51 return int64(s) > size()/int64(defaultShards) 52 }, 53 }) 54 } 55 return leaseholderCache 56 } 57 58 // Lookup returns the cached leader of the given range ID. 59 func (lc *LeaseHolderCache) Lookup( 60 ctx context.Context, rangeID roachpb.RangeID, 61 ) (roachpb.StoreID, bool) { 62 ld := &lc.shards[int(rangeID)%len(lc.shards)] 63 ld.mu.Lock() 64 defer ld.mu.Unlock() 65 if v, ok := ld.cache.Get(rangeID); ok { 66 if log.V(2) { 67 log.Infof(ctx, "r%d: lookup leaseholder: %s", rangeID, v) 68 } 69 return v.(roachpb.StoreID), true 70 } 71 if log.V(2) { 72 log.Infof(ctx, "r%d: lookup leaseholder: not found", rangeID) 73 } 74 return 0, false 75 } 76 77 // Update invalidates the cached leader for the given range ID. If an empty 78 // replica descriptor is passed, the cached leader is evicted. Otherwise, the 79 // passed-in replica descriptor is cached. 80 func (lc *LeaseHolderCache) Update( 81 ctx context.Context, rangeID roachpb.RangeID, storeID roachpb.StoreID, 82 ) { 83 ld := &lc.shards[int(rangeID)%len(lc.shards)] 84 ld.mu.Lock() 85 defer ld.mu.Unlock() 86 if storeID == 0 { 87 if log.V(2) { 88 log.Infof(ctx, "r%d: evicting leaseholder", rangeID) 89 } 90 ld.cache.Del(rangeID) 91 } else { 92 if log.V(2) { 93 log.Infof(ctx, "r%d: updating leaseholder: %d", rangeID, storeID) 94 } 95 ld.cache.Add(rangeID, storeID) 96 } 97 }