cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.40.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/cache.go

155lines · modecode

1package promapi
2
3import (
4 "sync"
5 "time"
6
7 "github.com/prometheus/client_golang/prometheus"
8)
9
10type cacheEntry struct {
11 data any
12 expiresAt time.Time
13 lastGet time.Time
14}
15
16type endpointStats struct {
17 hits int
18 misses int
19}
20
21func (e *endpointStats) hit() { e.hits++ }
22func (e *endpointStats) miss() { e.misses++ }
23
24func newQueryCache(maxStale time.Duration) *queryCache {
25 return &queryCache{
26 entries: map[uint64]*cacheEntry{},
27 stats: map[string]*endpointStats{},
28 maxStale: maxStale,
29 }
30}
31
32type queryCache struct {
33 mu sync.Mutex
34 entries map[uint64]*cacheEntry
35 stats map[string]*endpointStats
36 maxStale time.Duration
37 evictions int
38}
39
40func (c *queryCache) endpointStats(endpoint string) *endpointStats {
41 e, ok := c.stats[endpoint]
42 if ok {
43 return e
44 }
45
46 e = &endpointStats{}
47 c.stats[endpoint] = e
48 return e
49}
50
51func (c *queryCache) get(key uint64, endpoint string) (v any, ok bool) {
52 c.mu.Lock()
53 defer c.mu.Unlock()
54
55 var ce *cacheEntry
56 ce, ok = c.entries[key]
57 if !ok {
58 c.endpointStats(endpoint).miss()
59 return v, ok
60 }
61
62 ce.lastGet = time.Now()
63 c.endpointStats(endpoint).hit()
64
65 return ce.data, true
66}
67
68// Cache results if it was requested at least twice EVER - which means it's either
69// popular and requested multiple times within a loop OR this cache key survives between loops.
70func (c *queryCache) set(key uint64, val any, ttl time.Duration, endpoint string) {
71 c.mu.Lock()
72 defer c.mu.Unlock()
73
74 c.entries[key] = &cacheEntry{
75 data: val,
76 lastGet: time.Now(),
77 }
78 if ttl > 0 {
79 c.entries[key].expiresAt = time.Now().Add(ttl)
80 }
81}
82
83func (c *queryCache) gc() {
84 c.mu.Lock()
85 defer c.mu.Unlock()
86
87 entries := map[uint64]*cacheEntry{}
88
89 now := time.Now()
90 for key, ce := range c.entries {
91 if (!ce.expiresAt.IsZero() && ce.expiresAt.Before(now)) || now.Sub(ce.lastGet) >= c.maxStale {
92 c.evictions++
93 continue
94 }
95 entries[key] = ce
96 }
97 c.entries = entries
98}
99
100type cacheCollector struct {
101 cache *queryCache
102 entries *prometheus.Desc
103 hits *prometheus.Desc
104 misses *prometheus.Desc
105 evictions *prometheus.Desc
106}
107
108func newCacheCollector(cache *queryCache, name string) *cacheCollector {
109 return &cacheCollector{
110 cache: cache,
111 entries: prometheus.NewDesc(
112 "pint_prometheus_cache_size",
113 "Total number of entries currently stored in Prometheus query cache",
114 nil,
115 prometheus.Labels{"name": name},
116 ),
117 hits: prometheus.NewDesc(
118 "pint_prometheus_cache_hits_total",
119 "Total number of query cache hits",
120 []string{"endpoint"},
121 prometheus.Labels{"name": name},
122 ),
123 misses: prometheus.NewDesc(
124 "pint_prometheus_cache_miss_total",
125 "Total number of query cache misses",
126 []string{"endpoint"},
127 prometheus.Labels{"name": name},
128 ),
129 evictions: prometheus.NewDesc(
130 "pint_prometheus_cache_evictions_total",
131 "Total number of times an entry was evicted from query cache due to size limit or TTL",
132 nil,
133 prometheus.Labels{"name": name},
134 ),
135 }
136}
137
138func (c *cacheCollector) Describe(ch chan<- *prometheus.Desc) {
139 ch <- c.entries
140 ch <- c.hits
141 ch <- c.misses
142 ch <- c.evictions
143}
144
145func (c *cacheCollector) Collect(ch chan<- prometheus.Metric) {
146 c.cache.mu.Lock()
147 defer c.cache.mu.Unlock()
148 ch <- prometheus.MustNewConstMetric(c.entries, prometheus.GaugeValue, float64(len(c.cache.entries)))
149
150 for endpoint, stats := range c.cache.stats {
151 ch <- prometheus.MustNewConstMetric(c.hits, prometheus.CounterValue, float64(stats.hits), endpoint)
152 ch <- prometheus.MustNewConstMetric(c.misses, prometheus.CounterValue, float64(stats.misses), endpoint)
153 }
154 ch <- prometheus.MustNewConstMetric(c.evictions, prometheus.CounterValue, float64(c.cache.evictions))
155}
156