cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.32.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/promapi/cache.go

192lines · modecode

1package promapi
2
3import (
4 "sync"
5 "time"
6
7 "github.com/prometheus/client_golang/prometheus"
8)
9
10func newQueryCache(maxSize int, maxSinceLastRequest time.Duration) *queryCache {
11 return &queryCache{
12 requests: map[uint64]cacheRequest{},
13 entries: map[uint64]queryResult{},
14 maxSize: maxSize,
15 maxSinceLastRequest: maxSinceLastRequest,
16 hits: map[string]int{},
17 misses: map[string]int{},
18 }
19}
20
21type cacheRequest struct {
22 lastGet time.Time
23 count int
24}
25
26type queryCache struct {
27 mu sync.Mutex
28 requests map[uint64]cacheRequest
29 entries map[uint64]queryResult
30 maxSize int
31 maxSinceLastRequest time.Duration
32 hits map[string]int
33 misses map[string]int
34 evictions int
35}
36
37func (c *queryCache) get(key uint64, endpoint string) (v queryResult, ok bool) {
38 c.mu.Lock()
39 defer c.mu.Unlock()
40
41 var r cacheRequest
42 r, ok = c.requests[key]
43 if ok {
44 r.lastGet = time.Now()
45 r.count++
46 c.requests[key] = r
47 } else {
48 c.requests[key] = cacheRequest{
49 lastGet: time.Now(),
50 count: 1,
51 }
52 }
53
54 v, ok = c.entries[key]
55 if ok {
56 c.hits[endpoint]++
57 } else {
58 c.misses[endpoint]++
59 }
60
61 return v, ok
62}
63
64func (c *queryCache) set(key uint64, val queryResult, minRequests int) {
65 c.mu.Lock()
66 defer c.mu.Unlock()
67
68 if minRequests > 0 {
69 if r, ok := c.requests[key]; !ok || r.count <= minRequests {
70 return
71 }
72 }
73
74 if len(c.entries) >= c.maxSize {
75 c.purgeOne()
76 }
77
78 c.entries[key] = val
79}
80
81func (c *queryCache) purgeOne() {
82 var purgeKey uint64
83 purgeRequests := -100
84 var purgeLastGet time.Time
85 for k, r := range c.requests {
86 if r.count < purgeRequests || purgeRequests < 0 || (r.count == purgeRequests && r.lastGet.Before(purgeLastGet)) {
87 purgeKey = k
88 purgeRequests = r.count
89 purgeLastGet = r.lastGet
90 }
91 }
92 delete(c.entries, purgeKey)
93 delete(c.requests, purgeKey)
94 c.evictions++
95}
96
97func (c *queryCache) gc() {
98 c.mu.Lock()
99 defer c.mu.Unlock()
100
101 var r cacheRequest
102 var ok bool
103
104 requests := map[uint64]cacheRequest{}
105 entries := map[uint64]queryResult{}
106 now := time.Now()
107 for k, v := range c.entries {
108 r, ok = c.requests[k]
109 if !ok || (ok && now.Sub(r.lastGet) >= c.maxSinceLastRequest) {
110 c.evictions++
111 continue
112 }
113 if v.expires.IsZero() || !v.expires.Before(now) {
114 if ok {
115 requests[k] = r
116 }
117 entries[k] = v
118 } else {
119 c.evictions++
120 }
121 }
122
123 for k, r := range c.requests {
124 if _, ok = requests[k]; ok {
125 continue
126 }
127 if now.Sub(r.lastGet) < c.maxSinceLastRequest {
128 requests[k] = r
129 }
130 }
131
132 c.requests = requests
133 c.entries = entries
134}
135
136type cacheCollector struct {
137 cache *queryCache
138 entries *prometheus.Desc
139 hits *prometheus.Desc
140 misses *prometheus.Desc
141 evictions *prometheus.Desc
142}
143
144func newCacheCollector(cache *queryCache, name string) *cacheCollector {
145 return &cacheCollector{
146 cache: cache,
147 entries: prometheus.NewDesc(
148 "pint_prometheus_cache_size",
149 "Total number of entries currently stored in Prometheus query cache",
150 nil,
151 prometheus.Labels{"name": name},
152 ),
153 hits: prometheus.NewDesc(
154 "pint_prometheus_cache_hits_total",
155 "Total number of query cache hits",
156 []string{"endpoint"},
157 prometheus.Labels{"name": name},
158 ),
159 misses: prometheus.NewDesc(
160 "pint_prometheus_cache_miss_total",
161 "Total number of query cache misses",
162 []string{"endpoint"},
163 prometheus.Labels{"name": name},
164 ),
165 evictions: prometheus.NewDesc(
166 "pint_prometheus_cache_evictions_total",
167 "Total number of times an entry was evicted from query cache due to size limit or TTL",
168 nil,
169 prometheus.Labels{"name": name},
170 ),
171 }
172}
173
174func (c *cacheCollector) Describe(ch chan<- *prometheus.Desc) {
175 ch <- c.entries
176 ch <- c.hits
177 ch <- c.misses
178 ch <- c.evictions
179}
180
181func (c *cacheCollector) Collect(ch chan<- prometheus.Metric) {
182 c.cache.mu.Lock()
183 defer c.cache.mu.Unlock()
184 ch <- prometheus.MustNewConstMetric(c.entries, prometheus.GaugeValue, float64(len(c.cache.entries)))
185 for endpoint, hits := range c.cache.hits {
186 ch <- prometheus.MustNewConstMetric(c.hits, prometheus.CounterValue, float64(hits), endpoint)
187 }
188 for endpoint, misses := range c.cache.misses {
189 ch <- prometheus.MustNewConstMetric(c.misses, prometheus.CounterValue, float64(misses), endpoint)
190 }
191 ch <- prometheus.MustNewConstMetric(c.evictions, prometheus.CounterValue, float64(c.cache.evictions))
192}
193