|
1 | 1 | package cache |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "sync" |
| 4 | + "strconv" |
| 5 | + "time" |
5 | 6 |
|
| 7 | + "github.com/patrickmn/go-cache" |
| 8 | + "github.com/pkg/errors" |
| 9 | + "github.com/prometheus/client_golang/prometheus" |
| 10 | + "github.com/prometheus/client_golang/prometheus/promauto" |
6 | 11 | "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" |
| 12 | + "github.com/sirupsen/logrus" |
7 | 13 | ) |
8 | 14 |
|
9 | | -type TrackedValidator struct { |
10 | | - Active bool |
11 | | - FeeRecipient primitives.ExecutionAddress |
12 | | - Index primitives.ValidatorIndex |
13 | | -} |
| 15 | +const ( |
| 16 | + defaultExpiration = 1 * time.Hour |
| 17 | + cleanupInterval = 15 * time.Minute |
| 18 | +) |
14 | 19 |
|
15 | | -type TrackedValidatorsCache struct { |
16 | | - sync.Mutex |
17 | | - trackedValidators map[primitives.ValidatorIndex]TrackedValidator |
18 | | -} |
| 20 | +type ( |
| 21 | + TrackedValidator struct { |
| 22 | + Active bool |
| 23 | + FeeRecipient primitives.ExecutionAddress |
| 24 | + Index primitives.ValidatorIndex |
| 25 | + } |
| 26 | + |
| 27 | + TrackedValidatorsCache struct { |
| 28 | + trackedValidators cache.Cache |
| 29 | + } |
| 30 | +) |
| 31 | + |
| 32 | +var ( |
| 33 | + // Metrics. |
| 34 | + trackedValidatorsCacheMiss = promauto.NewCounter(prometheus.CounterOpts{ |
| 35 | + Name: "tracked_validators_cache_miss", |
| 36 | + Help: "The number of tracked validators requests that are not present in the cache.", |
| 37 | + }) |
| 38 | + |
| 39 | + trackedValidatorsCacheTotal = promauto.NewCounter(prometheus.CounterOpts{ |
| 40 | + Name: "tracked_validators_cache_total", |
| 41 | + Help: "The total number of tracked validators requests in the cache.", |
| 42 | + }) |
19 | 43 |
|
| 44 | + trackedValidatorsCacheCount = promauto.NewGauge(prometheus.GaugeOpts{ |
| 45 | + Name: "tracked_validators_cache_count", |
| 46 | + Help: "The number of tracked validators in the cache.", |
| 47 | + }) |
| 48 | +) |
| 49 | + |
| 50 | +// NewTrackedValidatorsCache creates a new cache for tracking validators. |
20 | 51 | func NewTrackedValidatorsCache() *TrackedValidatorsCache { |
21 | 52 | return &TrackedValidatorsCache{ |
22 | | - trackedValidators: make(map[primitives.ValidatorIndex]TrackedValidator), |
| 53 | + trackedValidators: *cache.New(defaultExpiration, cleanupInterval), |
23 | 54 | } |
24 | 55 | } |
25 | 56 |
|
| 57 | +// Validator retrieves a tracked validator from the cache (if present). |
26 | 58 | func (t *TrackedValidatorsCache) Validator(index primitives.ValidatorIndex) (TrackedValidator, bool) { |
27 | | - t.Lock() |
28 | | - defer t.Unlock() |
29 | | - val, ok := t.trackedValidators[index] |
30 | | - return val, ok |
| 59 | + trackedValidatorsCacheTotal.Inc() |
| 60 | + |
| 61 | + key := toCacheKey(index) |
| 62 | + item, ok := t.trackedValidators.Get(key) |
| 63 | + if !ok { |
| 64 | + trackedValidatorsCacheMiss.Inc() |
| 65 | + return TrackedValidator{}, false |
| 66 | + } |
| 67 | + |
| 68 | + val, ok := item.(TrackedValidator) |
| 69 | + if !ok { |
| 70 | + logrus.Errorf("Failed to cast tracked validator from cache, got unexpected item type %T", item) |
| 71 | + return TrackedValidator{}, false |
| 72 | + } |
| 73 | + |
| 74 | + return val, true |
31 | 75 | } |
32 | 76 |
|
| 77 | +// Set adds a tracked validator to the cache. |
33 | 78 | func (t *TrackedValidatorsCache) Set(val TrackedValidator) { |
34 | | - t.Lock() |
35 | | - defer t.Unlock() |
36 | | - t.trackedValidators[val.Index] = val |
| 79 | + key := toCacheKey(val.Index) |
| 80 | + t.trackedValidators.Set(key, val, cache.DefaultExpiration) |
37 | 81 | } |
38 | 82 |
|
| 83 | +// Delete removes a tracked validator from the cache. |
39 | 84 | func (t *TrackedValidatorsCache) Prune() { |
40 | | - t.Lock() |
41 | | - defer t.Unlock() |
42 | | - t.trackedValidators = make(map[primitives.ValidatorIndex]TrackedValidator) |
| 85 | + t.trackedValidators.Flush() |
| 86 | + trackedValidatorsCacheCount.Set(0) |
43 | 87 | } |
44 | 88 |
|
| 89 | +// Validating returns true if there are at least one tracked validators in the cache. |
45 | 90 | func (t *TrackedValidatorsCache) Validating() bool { |
46 | | - t.Lock() |
47 | | - defer t.Unlock() |
48 | | - return len(t.trackedValidators) > 0 |
| 91 | + count := t.trackedValidators.ItemCount() |
| 92 | + trackedValidatorsCacheCount.Set(float64(count)) |
| 93 | + |
| 94 | + return count > 0 |
| 95 | +} |
| 96 | + |
| 97 | +// ItemCount returns the number of tracked validators in the cache. |
| 98 | +func (t *TrackedValidatorsCache) ItemCount() int { |
| 99 | + count := t.trackedValidators.ItemCount() |
| 100 | + trackedValidatorsCacheCount.Set(float64(count)) |
| 101 | + |
| 102 | + return count |
| 103 | +} |
| 104 | + |
| 105 | +// Indices returns a map of validator indices that are being tracked. |
| 106 | +func (t *TrackedValidatorsCache) Indices() map[primitives.ValidatorIndex]bool { |
| 107 | + items := t.trackedValidators.Items() |
| 108 | + count := len(items) |
| 109 | + trackedValidatorsCacheCount.Set(float64(count)) |
| 110 | + |
| 111 | + indices := make(map[primitives.ValidatorIndex]bool, count) |
| 112 | + |
| 113 | + for cacheKey := range items { |
| 114 | + index, err := fromCacheKey(cacheKey) |
| 115 | + if err != nil { |
| 116 | + logrus.WithError(err).Error("Failed to get validator index from cache key") |
| 117 | + continue |
| 118 | + } |
| 119 | + |
| 120 | + indices[index] = true |
| 121 | + } |
| 122 | + |
| 123 | + return indices |
| 124 | +} |
| 125 | + |
| 126 | +// toCacheKey creates a cache key from the validator index. |
| 127 | +func toCacheKey(validatorIndex primitives.ValidatorIndex) string { |
| 128 | + return strconv.FormatUint(uint64(validatorIndex), 10) |
| 129 | +} |
| 130 | + |
| 131 | +// fromCacheKey gets the validator index from the cache key. |
| 132 | +func fromCacheKey(key string) (primitives.ValidatorIndex, error) { |
| 133 | + validatorIndex, err := strconv.ParseUint(key, 10, 64) |
| 134 | + if err != nil { |
| 135 | + return 0, errors.Wrapf(err, "parse Uint: %s", key) |
| 136 | + } |
| 137 | + |
| 138 | + return primitives.ValidatorIndex(validatorIndex), nil |
49 | 139 | } |
0 commit comments