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  }