prysm-pulse/beacon-chain/cache/total_balance.go
2019-08-03 16:28:04 -04:00

110 lines
3.3 KiB
Go

package cache
import (
"errors"
"strconv"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
"k8s.io/client-go/tools/cache"
)
var (
// ErrNotTotalBalanceInfo will be returned when a cache object is not a pointer to
// a TotalBalanceByEpoch struct.
ErrNotTotalBalanceInfo = errors.New("object is not a total balance obj")
// maxTotalBalanceListSize defines the max number of total balance can cache.
maxTotalBalanceListSize = 1000
// Metrics.
totalBalanceCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
Name: "total_balance_cache_miss",
Help: "The number of total balance requests that aren't present in the cache.",
})
totalBalanceCacheHit = promauto.NewCounter(prometheus.CounterOpts{
Name: "total_balance_cache_hit",
Help: "The number of total balance requests that are present in the cache.",
})
)
// TotalBalanceByEpoch defines the total validator balance per epoch.
type TotalBalanceByEpoch struct {
Epoch uint64
TotalBalance uint64
}
// TotalBalanceCache is a struct with 1 queue for looking up total balance by epoch.
type TotalBalanceCache struct {
totalBalanceCache *cache.FIFO
lock sync.RWMutex
}
// totalBalanceKeyFn takes the epoch as the key for the total balance of a given epoch.
func totalBalanceKeyFn(obj interface{}) (string, error) {
tInfo, ok := obj.(*TotalBalanceByEpoch)
if !ok {
return "", ErrNotTotalBalanceInfo
}
return strconv.Itoa(int(tInfo.Epoch)), nil
}
// NewTotalBalanceCache creates a new total balance cache for storing/accessing total validator balance.
func NewTotalBalanceCache() *TotalBalanceCache {
return &TotalBalanceCache{
totalBalanceCache: cache.NewFIFO(totalBalanceKeyFn),
}
}
// TotalBalanceInEpoch fetches TotalBalanceByEpoch by epoch. Returns true with a
// reference to the TotalBalanceInEpoch info, if exists. Otherwise returns false, nil.
func (c *TotalBalanceCache) TotalBalanceInEpoch(epoch uint64) (uint64, error) {
if !featureconfig.FeatureConfig().EnableTotalBalanceCache {
// Return a miss result if cache is not enabled.
totalBalanceCacheMiss.Inc()
return params.BeaconConfig().FarFutureEpoch, nil
}
c.lock.RLock()
defer c.lock.RUnlock()
obj, exists, err := c.totalBalanceCache.GetByKey(strconv.Itoa(int(epoch)))
if err != nil {
return params.BeaconConfig().FarFutureEpoch, err
}
if exists {
totalBalanceCacheHit.Inc()
} else {
totalBalanceCacheMiss.Inc()
return params.BeaconConfig().FarFutureEpoch, nil
}
tInfo, ok := obj.(*TotalBalanceByEpoch)
if !ok {
return params.BeaconConfig().FarFutureEpoch, ErrNotTotalBalanceInfo
}
return tInfo.TotalBalance, nil
}
// AddTotalBalance adds TotalBalanceByEpoch object to the cache. This method also trims the least
// recently added TotalBalanceByEpoch object if the cache size has ready the max cache size limit.
func (c *TotalBalanceCache) AddTotalBalance(totalBalance *TotalBalanceByEpoch) error {
if !featureconfig.FeatureConfig().EnableTotalBalanceCache {
return nil
}
c.lock.Lock()
defer c.lock.Unlock()
if err := c.totalBalanceCache.AddIfNotPresent(totalBalance); err != nil {
return err
}
trim(c.totalBalanceCache, maxTotalBalanceListSize)
return nil
}