diff --git a/builder.go b/builder.go index 4a6c150..e939b46 100644 --- a/builder.go +++ b/builder.go @@ -24,7 +24,7 @@ type Builder[K comparable, V any] struct { maximumSize *int maximumWeight *uint64 initialCapacity *int - statsCollector StatsCollector + statsCollector StatsRecorder ttl *time.Duration withVariableTTL bool weigher func(key K, value V) uint32 @@ -35,7 +35,7 @@ type Builder[K comparable, V any] struct { // NewBuilder creates a builder and sets the future cache capacity. func NewBuilder[K comparable, V any]() *Builder[K, V] { return &Builder[K, V]{ - statsCollector: noopStatsCollector{}, + statsCollector: noopStatsRecorder{}, logger: noopLogger{}, } } @@ -73,7 +73,7 @@ func (b *Builder[K, V]) MaximumWeight(maximumWeight uint64) *Builder[K, V] { // // NOTE: collecting statistics requires bookkeeping to be performed with each operation, // and thus imposes a performance penalty on cache operations. -func (b *Builder[K, V]) CollectStats(statsCollector StatsCollector) *Builder[K, V] { +func (b *Builder[K, V]) CollectStats(statsCollector StatsRecorder) *Builder[K, V] { b.statsCollector = statsCollector return b } diff --git a/cache.go b/cache.go index e9fa355..b8f92d7 100644 --- a/cache.go +++ b/cache.go @@ -99,7 +99,7 @@ type Cache[K comparable, V any] struct { hashmap *hashtable.Map[K, V] policy evictionPolicy[K, V] expiryPolicy expiryPolicy[K, V] - stats statsCollector + stats statsRecorder logger Logger clock *clock.Clock stripedBuffer []*lossy.Buffer[K, V] @@ -146,7 +146,7 @@ func newCache[K comparable, V any](b *Builder[K, V]) *Cache[K, V] { cache := &Cache[K, V]{ nodeManager: nodeManager, hashmap: hashmap, - stats: newStatsCollector(b.statsCollector), + stats: newStatsRecorder(b.statsCollector), logger: b.logger, stripedBuffer: stripedBuffer, doneClear: make(chan struct{}), @@ -223,7 +223,7 @@ func (c *Cache[K, V]) Get(key K) (V, bool) { func (c *Cache[K, V]) GetNode(key K) (node.Node[K, V], bool) { n, ok := c.hashmap.Get(key) if !ok || !n.IsAlive() { - c.stats.CollectMisses(1) + c.stats.RecordMisses(1) return nil, false } @@ -235,12 +235,12 @@ func (c *Cache[K, V]) GetNode(key K) (node.Node[K, V], bool) { n.Die() c.writeBuffer.Push(newExpiredTask(n)) } - c.stats.CollectMisses(1) + c.stats.RecordMisses(1) return nil, false } c.afterGet(n) - c.stats.CollectHits(1) + c.stats.RecordHits(1) return n, true } @@ -417,7 +417,7 @@ func (c *Cache[K, V]) deleteExpiredNode(n node.Node[K, V]) { if deleted != nil { n.Die() c.notifyDeletion(n.Key(), n.Value(), Expired) - c.stats.CollectEviction(n.Weight()) + c.stats.RecordEviction(n.Weight()) } } @@ -442,7 +442,7 @@ func (c *Cache[K, V]) evictNode(n node.Node[K, V]) { if deleted != nil { n.Die() c.notifyDeletion(n.Key(), n.Value(), Size) - c.stats.CollectEviction(n.Weight()) + c.stats.RecordEviction(n.Weight()) } } @@ -456,7 +456,7 @@ func (c *Cache[K, V]) addToPolicies(n node.Node[K, V]) { if deleted != nil { n.Die() } - c.stats.CollectRejectedSets(1) + c.stats.RecordRejections(1) return } diff --git a/cache_test.go b/cache_test.go index 99e6a3c..cbdfd7d 100644 --- a/cache_test.go +++ b/cache_test.go @@ -175,7 +175,7 @@ func TestCache_SetWithWeight(t *testing.T) { c.Set(uint32(goodWeight), 1) c.Set(uint32(badWeight), 1) time.Sleep(time.Second) - if rejections := statsCounter.Snapshot().RejectedSets(); rejections != 1 { + if rejections := statsCounter.Snapshot().Rejections(); rejections != 1 { t.Fatalf("Set wasn't dropped, though it should have been. Max available weight: %d, actual weight: %d", c.policy.MaxAvailableWeight(), c.weigher(uint32(badWeight), 1), diff --git a/stats.go b/stats.go index 2e1637c..8a9442a 100644 --- a/stats.go +++ b/stats.go @@ -20,94 +20,94 @@ import ( "github.com/maypok86/otter/v2/stats" ) -// StatsCollector accumulates statistics during the operation of a Cache. +// StatsRecorder accumulates statistics during the operation of a Cache. // -// If you also want to collect eviction statistics, -// then your collector should implement an EvictionStatsCollector. +// If you also want to record eviction statistics, +// then your recorder should implement an EvictionStatsRecorder. // -// If you also want to collect statistics on set rejections, -// then your collector should implement an RejectedSetsStatsCollector. +// If you also want to record statistics on rejections, +// then your recorder should implement an RejectionStatsRecorder. // -// If you also want to collect load statistics, -// then your collector should implement an LoadingStatsCollector. -type StatsCollector interface { - // CollectHits collects cache hits. This should be called when a cache request returns a cached value. - CollectHits(count int) - // CollectMisses collects cache misses. This should be called when a cache request returns a value that was not +// If you also want to record load statistics, +// then your recorder should implement an LoadStatsRecorder. +type StatsRecorder interface { + // RecordHits records cache hits. This should be called when a cache request returns a cached value. + RecordHits(count int) + // RecordMisses records cache misses. This should be called when a cache request returns a value that was not // found in the cache. - CollectMisses(count int) + RecordMisses(count int) } -// EvictionStatsCollector is a collector that collects statistics on the eviction of entries from the cache. -type EvictionStatsCollector interface { - // CollectEviction collects the eviction of an entry from the cache. This should only been called when an entry is +// EvictionStatsRecorder is a recorder that records statistics on the eviction of entries from the cache. +type EvictionStatsRecorder interface { + // RecordEviction records the eviction of an entry from the cache. This should only been called when an entry is // evicted due to the cache's eviction strategy, and not as a result of manual deletions. - CollectEviction(weight uint32) + RecordEviction(weight uint32) } -// RejectedSetsStatsCollector is a collector that collects statistics on the rejection of sets. -type RejectedSetsStatsCollector interface { - // CollectRejectedSets collects rejected sets due to too much weight of entries in them. - CollectRejectedSets(count int) +// RejectionStatsRecorder is a recorder that records statistics on the rejections. +type RejectionStatsRecorder interface { + // RecordRejections records rejections of entries. Cache rejects entries only if they have too much weight. + RecordRejections(count int) } -// LoadingStatsCollector is a collector that collects statistics on the loads of new entries. -type LoadingStatsCollector interface { - // CollectLoadSuccess collects the successful load of a new entry. This method should be called when a cache request +// LoadStatsRecorder is a recorder that records statistics on the loads of new entries. +type LoadStatsRecorder interface { + // RecordLoadSuccess records the successful load of a new entry. This method should be called when a cache request // causes an entry to be loaded and the loading completes successfully. - CollectLoadSuccess(loadTime time.Duration) - // CollectLoadFailure collects the failed load of a new entry. This method should be called when a cache request + RecordLoadSuccess(loadTime time.Duration) + // RecordLoadFailure records the failed load of a new entry. This method should be called when a cache request // causes an entry to be loaded, but the loading function returns an error. - CollectLoadFailure(loadTime time.Duration) + RecordLoadFailure(loadTime time.Duration) } -type noopStatsCollector struct{} +type noopStatsRecorder struct{} -func (np noopStatsCollector) CollectHits(count int) {} -func (np noopStatsCollector) CollectMisses(count int) {} -func (np noopStatsCollector) CollectEviction(weight uint32) {} -func (np noopStatsCollector) CollectRejectedSets(count int) {} -func (np noopStatsCollector) CollectLoadFailure(loadTime time.Duration) {} -func (np noopStatsCollector) CollectLoadSuccess(loadTime time.Duration) {} +func (np noopStatsRecorder) RecordHits(count int) {} +func (np noopStatsRecorder) RecordMisses(count int) {} +func (np noopStatsRecorder) RecordEviction(weight uint32) {} +func (np noopStatsRecorder) RecordRejections(count int) {} +func (np noopStatsRecorder) RecordLoadFailure(loadTime time.Duration) {} +func (np noopStatsRecorder) RecordLoadSuccess(loadTime time.Duration) {} -type statsCollector interface { - StatsCollector - EvictionStatsCollector - RejectedSetsStatsCollector - LoadingStatsCollector +type statsRecorder interface { + StatsRecorder + EvictionStatsRecorder + RejectionStatsRecorder + LoadStatsRecorder } -type statsCollectorComposition struct { - StatsCollector - EvictionStatsCollector - RejectedSetsStatsCollector - LoadingStatsCollector +type statsRecorderHub struct { + StatsRecorder + EvictionStatsRecorder + RejectionStatsRecorder + LoadStatsRecorder } -func newStatsCollector(collector StatsCollector) statsCollector { +func newStatsRecorder(recorder StatsRecorder) statsRecorder { // optimization - if noop, ok := collector.(noopStatsCollector); ok { + if noop, ok := recorder.(noopStatsRecorder); ok { return noop } - if c, ok := collector.(*stats.Counter); ok { + if c, ok := recorder.(*stats.Counter); ok { return c } - sc := &statsCollectorComposition{ - StatsCollector: collector, - EvictionStatsCollector: noopStatsCollector{}, - RejectedSetsStatsCollector: noopStatsCollector{}, - LoadingStatsCollector: noopStatsCollector{}, + sc := &statsRecorderHub{ + StatsRecorder: recorder, + EvictionStatsRecorder: noopStatsRecorder{}, + RejectionStatsRecorder: noopStatsRecorder{}, + LoadStatsRecorder: noopStatsRecorder{}, } - if ec, ok := collector.(EvictionStatsCollector); ok { - sc.EvictionStatsCollector = ec + if ec, ok := recorder.(EvictionStatsRecorder); ok { + sc.EvictionStatsRecorder = ec } - if rsc, ok := collector.(RejectedSetsStatsCollector); ok { - sc.RejectedSetsStatsCollector = rsc + if rsc, ok := recorder.(RejectionStatsRecorder); ok { + sc.RejectionStatsRecorder = rsc } - if lc, ok := collector.(LoadingStatsCollector); ok { - sc.LoadingStatsCollector = lc + if lc, ok := recorder.(LoadStatsRecorder); ok { + sc.LoadStatsRecorder = lc } return sc diff --git a/stats/counter.go b/stats/counter.go index 0c10109..1c53b15 100644 --- a/stats/counter.go +++ b/stats/counter.go @@ -21,7 +21,7 @@ import ( "github.com/maypok86/otter/v2/internal/xsync" ) -// Counter is a goroutine-safe otter.StatsCollector implementation for use by otter.Cache. +// Counter is a goroutine-safe otter.StatsRecorder implementation for use by otter.Cache. type Counter struct { hits *xsync.Adder misses *xsync.Adder @@ -47,11 +47,11 @@ func NewCounter() *Counter { } } -// Snapshot returns a snapshot of this collector's values. Note that this may be an inconsistent view, as it +// Snapshot returns a snapshot of this recorder's values. Note that this may be an inconsistent view, as it // may be interleaved with update operations. // // NOTE: the values of the metrics are undefined in case of overflow. If you require specific handling, we recommend -// implementing your own otter.StatsCollector. +// implementing your own otter.StatsRecorder. func (c *Counter) Snapshot() Stats { totalLoadTime := c.totalLoadTime.Value() if totalLoadTime > uint64(math.MaxInt64) { @@ -62,7 +62,7 @@ func (c *Counter) Snapshot() Stats { misses: c.misses.Value(), evictions: c.evictions.Value(), evictionWeight: c.evictionWeight.Value(), - rejectedSets: c.rejectedSets.Value(), + rejections: c.rejectedSets.Value(), loadSuccesses: c.loadSuccesses.Value(), loadFailures: c.loadFailures.Value(), //nolint:gosec // overflow is handled above @@ -70,39 +70,39 @@ func (c *Counter) Snapshot() Stats { } } -// CollectHits collects cache hits. This should be called when a cache request returns a cached value. -func (c *Counter) CollectHits(count int) { +// RecordHits records cache hits. This should be called when a cache request returns a cached value. +func (c *Counter) RecordHits(count int) { c.hits.Add(uint64(count)) } -// CollectMisses collects cache misses. This should be called when a cache request returns a value that was not +// RecordMisses records cache misses. This should be called when a cache request returns a value that was not // found in the cache. -func (c *Counter) CollectMisses(count int) { +func (c *Counter) RecordMisses(count int) { c.misses.Add(uint64(count)) } -// CollectEviction collects the eviction of an entry from the cache. This should only been called when an entry is +// RecordEviction records the eviction of an entry from the cache. This should only been called when an entry is // evicted due to the cache's eviction strategy, and not as a result of manual deletions. -func (c *Counter) CollectEviction(weight uint32) { +func (c *Counter) RecordEviction(weight uint32) { c.evictions.Add(1) c.evictionWeight.Add(uint64(weight)) } -// CollectRejectedSets collects rejected sets due to too much weight of entries in them. -func (c *Counter) CollectRejectedSets(count int) { +// RecordRejections records rejections of entries. Cache rejects entries only if they have too much weight. +func (c *Counter) RecordRejections(count int) { c.rejectedSets.Add(uint64(count)) } -// CollectLoadSuccess collects the successful load of a new entry. This method should be called when a cache request +// RecordLoadSuccess records the successful load of a new entry. This method should be called when a cache request // causes an entry to be loaded and the loading completes successfully. -func (c *Counter) CollectLoadSuccess(loadTime time.Duration) { +func (c *Counter) RecordLoadSuccess(loadTime time.Duration) { c.loadSuccesses.Add(1) c.totalLoadTime.Add(uint64(loadTime)) } -// CollectLoadFailure collects the failed load of a new entry. This method should be called when a cache request +// RecordLoadFailure records the failed load of a new entry. This method should be called when a cache request // causes an entry to be loaded, but the loading function returns an error. -func (c *Counter) CollectLoadFailure(loadTime time.Duration) { +func (c *Counter) RecordLoadFailure(loadTime time.Duration) { c.loadFailures.Add(1) c.totalLoadTime.Add(uint64(loadTime)) } diff --git a/stats/counter_test.go b/stats/counter_test.go index a05d29b..f12cf68 100644 --- a/stats/counter_test.go +++ b/stats/counter_test.go @@ -23,19 +23,19 @@ import ( func TestCounter_Basic(t *testing.T) { t.Run("enabled", func(t *testing.T) { c := NewCounter() - c.CollectHits(1) - c.CollectMisses(1) - c.CollectEviction(10) - c.CollectRejectedSets(20) - c.CollectLoadSuccess(1) - c.CollectLoadFailure(1) + c.RecordHits(1) + c.RecordMisses(1) + c.RecordEviction(10) + c.RecordRejections(20) + c.RecordLoadSuccess(1) + c.RecordLoadFailure(1) expected := Stats{ hits: 1, misses: 1, evictions: 1, evictionWeight: 10, - rejectedSets: 20, + rejections: 20, loadSuccesses: 1, loadFailures: 1, totalLoadTime: 2, @@ -69,12 +69,12 @@ func TestCounter_Concurrent(t *testing.T) { go func() { defer wg.Done() - c.CollectHits(1) - c.CollectMisses(1) - c.CollectEviction(10) - c.CollectRejectedSets(20) - c.CollectLoadSuccess(1) - c.CollectLoadFailure(1) + c.RecordHits(1) + c.RecordMisses(1) + c.RecordEviction(10) + c.RecordRejections(20) + c.RecordLoadSuccess(1) + c.RecordLoadFailure(1) }() } @@ -85,7 +85,7 @@ func TestCounter_Concurrent(t *testing.T) { misses: 50, evictions: 50, evictionWeight: 500, - rejectedSets: 1000, + rejections: 1000, loadSuccesses: 50, loadFailures: 50, totalLoadTime: 100, diff --git a/stats/stats.go b/stats/stats.go index 379d923..75053d9 100644 --- a/stats/stats.go +++ b/stats/stats.go @@ -25,7 +25,7 @@ type Stats struct { misses uint64 evictions uint64 evictionWeight uint64 - rejectedSets uint64 + rejections uint64 loadSuccesses uint64 loadFailures uint64 totalLoadTime time.Duration @@ -44,7 +44,7 @@ func (s Stats) Misses() uint64 { // Requests returns the number of times otter.Cache lookup methods were looking for a cached value. // // NOTE: the values of the metrics are undefined in case of overflow. If you require specific handling, we recommend -// implementing your own otter.StatsCollector. +// implementing your own otter.StatsRecorder. func (s Stats) Requests() uint64 { return checkedAdd(s.hits, s.misses) } @@ -71,9 +71,9 @@ func (s Stats) MissRatio() float64 { return float64(s.misses) / float64(requests) } -// RejectedSets returns the number of rejected sets. -func (s Stats) RejectedSets() uint64 { - return s.rejectedSets +// Rejections returns the number of rejections. +func (s Stats) Rejections() uint64 { + return s.rejections } // Evictions returns the number of times an entry has been evicted. This count does not include manual @@ -102,7 +102,7 @@ func (s Stats) LoadFailures() uint64 { // Loads returns the total number of times that otter.Cache lookup methods attempted to load new values. // // NOTE: the values of the metrics are undefined in case of overflow. If you require specific handling, we recommend -// implementing your own otter.StatsCollector. +// implementing your own otter.StatsRecorder. func (s Stats) Loads() uint64 { return checkedAdd(s.loadSuccesses, s.loadFailures) } diff --git a/stats/stats_test.go b/stats/stats_test.go index 9c3b587..e3909bc 100644 --- a/stats/stats_test.go +++ b/stats/stats_test.go @@ -55,8 +55,8 @@ func testStats( if s.MissRatio() != missRatio { t.Fatalf("missRatio should be %.2f, but got %.2f", missRatio, s.MissRatio()) } - if s.RejectedSets() != rejectedSets { - t.Fatalf("rejectedSets should be %d, but got %d", rejectedSets, s.RejectedSets()) + if s.Rejections() != rejectedSets { + t.Fatalf("rejections should be %d, but got %d", rejectedSets, s.Rejections()) } if s.Evictions() != evictions { t.Fatalf("evictions should be %d, but got %d", evictions, s.Evictions()) @@ -110,7 +110,7 @@ func TestStats(t *testing.T) { misses: 13, evictions: 27, evictionWeight: 54, - rejectedSets: 1, + rejections: 1, loadSuccesses: 17, loadFailures: 19, totalLoadTime: 23, @@ -138,7 +138,7 @@ func TestStats(t *testing.T) { misses: math.MaxUint64, evictions: 27, evictionWeight: 54, - rejectedSets: 1, + rejections: 1, loadSuccesses: math.MaxUint64, loadFailures: math.MaxUint64, totalLoadTime: math.MaxInt64, diff --git a/stats_test.go b/stats_test.go index 55f0b7e..c04b4db 100644 --- a/stats_test.go +++ b/stats_test.go @@ -19,19 +19,19 @@ import ( "time" ) -type testStatsCollector struct{} +type testStatsRecorder struct{} -func (np testStatsCollector) CollectHits(count int) {} -func (np testStatsCollector) CollectMisses(count int) {} -func (np testStatsCollector) CollectEviction(weight uint32) {} -func (np testStatsCollector) CollectRejectedSets(count int) {} -func (np testStatsCollector) CollectLoadFailure(loadTime time.Duration) {} -func (np testStatsCollector) CollectLoadSuccess(loadTime time.Duration) {} +func (np testStatsRecorder) RecordHits(count int) {} +func (np testStatsRecorder) RecordMisses(count int) {} +func (np testStatsRecorder) RecordEviction(weight uint32) {} +func (np testStatsRecorder) RecordRejections(count int) {} +func (np testStatsRecorder) RecordLoadFailure(loadTime time.Duration) {} +func (np testStatsRecorder) RecordLoadSuccess(loadTime time.Duration) {} -func TestStatsCollector(t *testing.T) { - sc := newStatsCollector(testStatsCollector{}) +func TestStatsRecorder(t *testing.T) { + sc := newStatsRecorder(testStatsRecorder{}) - if _, ok := sc.(*statsCollectorComposition); !ok { - t.Fatalf("not valid for stats counter. got: %T", sc) + if _, ok := sc.(*statsRecorderHub); !ok { + t.Fatalf("not valid stats recorder. got: %T", sc) } }