Skip to content

Commit

Permalink
[Chore] Rename StatsCollector to StatsRecorder
Browse files Browse the repository at this point in the history
  • Loading branch information
maypok86 committed Sep 7, 2024
1 parent fb42aec commit f248ce7
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 120 deletions.
6 changes: 3 additions & 3 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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{},
}
}
Expand Down Expand Up @@ -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
}
Expand Down
16 changes: 8 additions & 8 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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{}),
Expand Down Expand Up @@ -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
}

Expand All @@ -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
}
Expand Down Expand Up @@ -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())
}
}

Expand All @@ -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())
}
}

Expand All @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
114 changes: 57 additions & 57 deletions stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions stats/counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand All @@ -62,47 +62,47 @@ 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
totalLoadTime: time.Duration(totalLoadTime),
}
}

// 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))
}
28 changes: 14 additions & 14 deletions stats/counter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}()
}

Expand All @@ -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,
Expand Down
Loading

0 comments on commit f248ce7

Please sign in to comment.