-
Notifications
You must be signed in to change notification settings - Fork 0
/
metered_cache.go
140 lines (123 loc) · 3.79 KB
/
metered_cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// (c) 2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package utils
import (
"fmt"
"os"
"path/filepath"
"sync/atomic"
"time"
"github.com/lasthyphen/subnet-evm/metrics"
"github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
// MeteredCache wraps *fastcache.Cache and periodically pulls stats from it.
type MeteredCache struct {
*fastcache.Cache
namespace string
// stats to be surfaced
entriesCount metrics.Gauge
bytesSize metrics.Gauge
collisions metrics.Gauge
gets metrics.Gauge
sets metrics.Gauge
misses metrics.Gauge
statsTime metrics.Gauge
// count all operations to decide when to update stats
ops uint64
updateFrequency uint64
}
func dirSize(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return nil
})
return size, err
}
// NewMeteredCache returns a new MeteredCache that will update stats to the
// provided namespace once per each [updateFrequency] operations.
// Note: if [updateFrequency] is passed as 0, it will be treated as 1.
func NewMeteredCache(size int, journal string, namespace string, updateFrequency uint64) *MeteredCache {
var cache *fastcache.Cache
if journal == "" {
cache = fastcache.New(size)
} else {
dirSize, err := dirSize(journal)
log.Info("attempting to load cache from disk", "path", journal, "dirSize", common.StorageSize(dirSize), "err", err)
cache = fastcache.LoadFromFileOrNew(journal, size)
}
if updateFrequency == 0 {
updateFrequency = 1 // avoid division by zero
}
mc := &MeteredCache{
Cache: cache,
namespace: namespace,
updateFrequency: updateFrequency,
}
if namespace != "" {
// only register stats if a namespace is provided.
mc.entriesCount = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/entriesCount", namespace), nil)
mc.bytesSize = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/bytesSize", namespace), nil)
mc.collisions = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/collisions", namespace), nil)
mc.gets = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/gets", namespace), nil)
mc.sets = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/sets", namespace), nil)
mc.misses = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/misses", namespace), nil)
mc.statsTime = metrics.GetOrRegisterGauge(fmt.Sprintf("%s/statsTime", namespace), nil)
}
return mc
}
// updateStats updates metrics from fastcache
func (mc *MeteredCache) updateStatsIfNeeded() {
if mc.namespace == "" {
return
}
ops := atomic.AddUint64(&mc.ops, 1)
if ops%mc.updateFrequency != 0 {
return
}
start := time.Now()
s := fastcache.Stats{}
mc.UpdateStats(&s)
mc.entriesCount.Update(int64(s.EntriesCount))
mc.bytesSize.Update(int64(s.BytesSize))
mc.collisions.Update(int64(s.Collisions))
mc.gets.Update(int64(s.GetCalls))
mc.sets.Update(int64(s.SetCalls))
mc.misses.Update(int64(s.Misses))
mc.statsTime.Inc(int64(time.Since(start))) // cumulative metric
}
func (mc *MeteredCache) Del(k []byte) {
mc.updateStatsIfNeeded()
mc.Cache.Del(k)
}
func (mc *MeteredCache) Get(dst, k []byte) []byte {
mc.updateStatsIfNeeded()
return mc.Cache.Get(dst, k)
}
func (mc *MeteredCache) GetBig(dst, k []byte) []byte {
mc.updateStatsIfNeeded()
return mc.Cache.GetBig(dst, k)
}
func (mc *MeteredCache) Has(k []byte) bool {
mc.updateStatsIfNeeded()
return mc.Cache.Has(k)
}
func (mc *MeteredCache) HasGet(dst, k []byte) ([]byte, bool) {
mc.updateStatsIfNeeded()
return mc.Cache.HasGet(dst, k)
}
func (mc *MeteredCache) Set(k, v []byte) {
mc.updateStatsIfNeeded()
mc.Cache.Set(k, v)
}
func (mc *MeteredCache) SetBig(k, v []byte) {
mc.updateStatsIfNeeded()
mc.Cache.SetBig(k, v)
}