Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions platform/common/utils/cache/cachemetrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package cache

import (
"github.com/hyperledger/fabric-lib-go/common/metrics"
)

type CacheMetrics interface {
IncrementGet()
IncrementPut()
IncrementUpdate()
IncrementDelete()
IncrementHit()
IncrementMiss()
SetSize(n int)
SetDataSize(n int)
}

type noCacheMetrics struct{}

Check failure on line 24 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

type noCacheMetrics is unused (U1000)

Check failure on line 24 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

type noCacheMetrics is unused (unused)

func (n *noCacheMetrics) IncrementGet() {}

Check failure on line 26 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).IncrementGet is unused (U1000)

Check failure on line 26 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).IncrementGet is unused (unused)
func (n *noCacheMetrics) IncrementPut() {}

Check failure on line 27 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).IncrementPut is unused (U1000)

Check failure on line 27 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).IncrementPut is unused (unused)
func (n *noCacheMetrics) IncrementUpdate() {}

Check failure on line 28 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).IncrementUpdate is unused (U1000)

Check failure on line 28 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).IncrementUpdate is unused (unused)
func (n *noCacheMetrics) IncrementDelete() {}

Check failure on line 29 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).IncrementDelete is unused (U1000)

Check failure on line 29 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).IncrementDelete is unused (unused)
func (n *noCacheMetrics) IncrementHit() {}

Check failure on line 30 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).IncrementHit is unused (U1000)

Check failure on line 30 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).IncrementHit is unused (unused)
func (n *noCacheMetrics) IncrementMiss() {}

Check failure on line 31 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).IncrementMiss is unused (U1000)

Check failure on line 31 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).IncrementMiss is unused (unused)
func (n *noCacheMetrics) SetSize(_ int) {}

Check failure on line 32 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).SetSize is unused (U1000)

Check failure on line 32 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).SetSize is unused (unused)
func (n *noCacheMetrics) SetDataSize(_ int) {}

Check failure on line 33 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / checks

func (*noCacheMetrics).SetDataSize is unused (U1000)

Check failure on line 33 in platform/common/utils/cache/cachemetrics.go

View workflow job for this annotation

GitHub Actions / lint

func (*noCacheMetrics).SetDataSize is unused (unused)

type cacheMetrics struct {
// Total number of get operations
GetCounter metrics.Counter
// Total number of put operations
PutCounter metrics.Counter
// Total number of updates operations
UpdateCounter metrics.Counter
// Total number of delete operations
DeleteCounter metrics.Counter
// Total number of successful cache lookups (hits)
HitCounter metrics.Counter
// Total number of cache lookups that did not find a matching key (misses)
MissCounter metrics.Counter
// Number of entries in cache
Size metrics.Gauge
// Total size in bytes of actual data stored in the cache
DataSize metrics.Gauge
}

func NewCacheMetrics(cacheName string, p metrics.Provider) *cacheMetrics {
return &cacheMetrics{
GetCounter: p.NewCounter(metrics.CounterOpts{
Namespace: "Cache",
Name: cacheName + "_get_total",
Help: "Total number of get operations",
}),
PutCounter: p.NewCounter(metrics.CounterOpts{
Namespace: "Cache",
Name: cacheName + "_put_total",
Help: "Total number of put operations",
}),
UpdateCounter: p.NewCounter(metrics.CounterOpts{
Namespace: "Cache",
Name: cacheName + "_update_total",
Help: "Total number of update operations",
}),
DeleteCounter: p.NewCounter(metrics.CounterOpts{
Namespace: "Cache",
Name: cacheName + "_delete_total",
Help: "Total number of delete operations",
}),
HitCounter: p.NewCounter(metrics.CounterOpts{
Namespace: "Cache",
Name: cacheName + "_hit_total",
Help: "Total number of cache hits",
}),
MissCounter: p.NewCounter(metrics.CounterOpts{
Namespace: "Cache",
Name: cacheName + "_miss_total",
Help: "Total number of cache misses",
}),
Size: p.NewGauge(metrics.GaugeOpts{
Namespace: "Cache",
Name: cacheName + "_entry_count",
Help: "Number of entries in cache",
}),
DataSize: p.NewGauge(metrics.GaugeOpts{
Namespace: "Cache",
Name: cacheName + "_data_size_bytes",
Help: "Total size in bytes of actual data stored in the cache",
}),
}
}

func (c *cacheMetrics) IncrementGet() {
c.GetCounter.Add(1)
}

func (c *cacheMetrics) IncrementPut() {
c.PutCounter.Add(1)
}

func (c *cacheMetrics) IncrementUpdate() {
c.UpdateCounter.Add(1)
}

func (c *cacheMetrics) IncrementDelete() {
c.DeleteCounter.Add(1)
}

func (c *cacheMetrics) IncrementHit() {
c.HitCounter.Add(1)
}

func (c *cacheMetrics) IncrementMiss() {
c.MissCounter.Add(1)
}

func (c *cacheMetrics) SetSize(n int) {
c.Size.Set(float64(n))
}

func (c *cacheMetrics) SetDataSize(n int) {
c.DataSize.Set(float64(n))
}
9 changes: 9 additions & 0 deletions platform/common/utils/cache/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ SPDX-License-Identifier: Apache-2.0

package cache

import "sync"

// NewMapCache creates a dummy implementation of the Cache interface.
// It is backed by a map with unlimited capacity.
func NewMapCache[K comparable, V any]() *mapCache[K, V] {
Expand All @@ -15,6 +17,13 @@ func NewMapCache[K comparable, V any]() *mapCache[K, V] {
}
}

func NewSafeMapCache[K comparable, V any]() *mapCache[K, V] {
return &mapCache[K, V]{
m: map[K]V{},
l: &sync.RWMutex{},
}
}

type mapCache[K comparable, V any] struct {
m map[K]V
l rwLock
Expand Down
89 changes: 89 additions & 0 deletions platform/common/utils/cache/metricmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package cache

import "sync"

type sizeFunc[T any] func(T) int

type metricMapCache[K comparable, V any] struct {
// Reference to the original mapCache
mapCache *mapCache[K, V]
// Metrics implementation used to track cache operations
metrics CacheMetrics
// Estimation of map cache memory size
memsize int
// Estimation of key size
keySize sizeFunc[K]
// Estimation of value size
valSize sizeFunc[V]
// Lock to update the size
locksize sync.RWMutex
}

func NewMetricMapCache[K comparable, V any](keySize sizeFunc[K], valSize sizeFunc[V], metrics CacheMetrics) *metricMapCache[K, V] {
return &metricMapCache[K, V]{
mapCache: NewMapCache[K, V](),
metrics: metrics,
memsize: 0,
}
}

func NewMetricSafeMapCache[K comparable, V any, keySize sizeFunc[K], valSize sizeFunc[V]](metrics CacheMetrics) *metricMapCache[K, V] {
return &metricMapCache[K, V]{
mapCache: NewSafeMapCache[K, V](),
metrics: metrics,
}
}

func (m *metricMapCache[K, V]) updateMetricSize(entrySize int) {
m.locksize.Lock()
defer m.locksize.Unlock()
m.memsize = m.memsize + entrySize
m.metrics.SetDataSize(entrySize)
m.metrics.SetSize(m.mapCache.Len())
}

func (m *metricMapCache[K, V]) Get(key K) (V, bool) {
m.metrics.IncrementGet()
val, ok := m.mapCache.Get(key)
if ok {
m.metrics.IncrementHit()
} else {
m.metrics.IncrementMiss()
}
return val, ok
}

func (m *metricMapCache[K, V]) Put(key K, value V) {
m.mapCache.Put(key, value)
m.metrics.IncrementPut()
m.updateMetricSize(m.keySize(key) + m.valSize(value))
}

func (m *metricMapCache[K, V]) Delete(key K) {
val, ok := m.mapCache.Get(key)
m.mapCache.Delete(key)
m.metrics.IncrementDelete()
if ok {
m.updateMetricSize(-1 * (m.keySize(key) + m.valSize(val)))
}
}

func (m *metricMapCache[K, V]) Update(key K, f func(bool, V) (bool, V)) bool {
val, ok := m.mapCache.Get(key)
if ok {
m.updateMetricSize(-1 * (m.keySize(key) + m.valSize(val)))
}
ok = m.mapCache.Update(key, f)
if ok {
val, _ = m.mapCache.Get(key)
m.updateMetricSize((m.keySize(key) + m.valSize(val)))
}
m.metrics.IncrementUpdate()
return ok
}
Loading