1package flow
2
3import (
4	"sync"
5	"time"
6)
7
8// MeterRegistry is a registry for named meters.
9type MeterRegistry struct {
10	meters sync.Map
11}
12
13// Get gets (or creates) a meter by name.
14func (r *MeterRegistry) Get(name string) *Meter {
15	if m, ok := r.meters.Load(name); ok {
16		return m.(*Meter)
17	}
18	m, _ := r.meters.LoadOrStore(name, NewMeter())
19	return m.(*Meter)
20}
21
22// FindIdle finds all meters that haven't been used since the given time.
23func (r *MeterRegistry) FindIdle(since time.Time) []string {
24	var idle []string
25	r.walkIdle(since, func(key interface{}) {
26		idle = append(idle, key.(string))
27	})
28	return idle
29}
30
31// TrimIdle trims that haven't been updated since the given time. Returns the
32// number of timers trimmed.
33func (r *MeterRegistry) TrimIdle(since time.Time) (trimmed int) {
34	// keep these as interfaces to avoid allocating when calling delete.
35	var idle []interface{}
36	r.walkIdle(since, func(key interface{}) {
37		idle = append(idle, since)
38	})
39	for _, i := range idle {
40		r.meters.Delete(i)
41	}
42	return len(idle)
43}
44
45func (r *MeterRegistry) walkIdle(since time.Time, cb func(key interface{})) {
46	// Yes, this is a global lock. However, all taking this does is pause
47	// snapshotting.
48	globalSweeper.snapshotMu.RLock()
49	defer globalSweeper.snapshotMu.RUnlock()
50
51	r.meters.Range(func(k, v interface{}) bool {
52		// So, this _is_ slightly inaccurate.
53		if v.(*Meter).snapshot.LastUpdate.Before(since) {
54			cb(k)
55		}
56		return true
57	})
58}
59
60// Remove removes the named meter from the registry.
61//
62// Note: The only reason to do this is to save a bit of memory. Unused meters
63// don't consume any CPU (after they go idle).
64func (r *MeterRegistry) Remove(name string) {
65	r.meters.Delete(name)
66}
67
68// ForEach calls the passed function for each registered meter.
69func (r *MeterRegistry) ForEach(iterFunc func(string, *Meter)) {
70	r.meters.Range(func(k, v interface{}) bool {
71		iterFunc(k.(string), v.(*Meter))
72		return true
73	})
74}
75
76// Clear removes all meters from the registry.
77func (r *MeterRegistry) Clear() {
78	r.meters.Range(func(k, v interface{}) bool {
79		r.meters.Delete(k)
80		return true
81	})
82}
83