blob: 89312f65a2752ee50c8c4257ffa65d0e58197c43 [file] [log] [blame]
Robin Thellendfa70aaa2014-10-09 17:13:05 -07001package stats
2
3import (
4 "path"
5 "sort"
6 "sync"
7 "time"
8)
9
10// NewMap creates a new Map StatsObject with the given name and
11// returns a pointer to it.
12func NewMap(name string) *Map {
13 lock.Lock()
14 defer lock.Unlock()
15 node := findNodeLocked(name, true)
16 m := Map{name: name, value: make(map[string]mapValue)}
17 node.object = &m
18 return &m
19}
20
21// Map implements the StatsObject interface. The map keys are strings and the
22// values can be bool, int64, uint64, float64, or string.
23type Map struct {
24 mu sync.RWMutex // ACQUIRED_BEFORE(stats.lock)
25 name string
26 value map[string]mapValue // GUARDED_BY(mu)
27}
28
29type mapValue struct {
30 lastUpdate time.Time
31 value interface{}
32}
33
34// Set sets the values of the given keys. There must be exactly one value for
35// each key.
36func (m *Map) Set(kvpairs []KeyValue) {
37 now := time.Now()
38 m.mu.Lock()
39 defer m.mu.Unlock()
40 for _, kv := range kvpairs {
41 var v interface{}
42 switch value := kv.Value.(type) {
43 case bool:
44 v = bool(value)
45 case int:
46 v = int64(value)
47 case int8:
48 v = int64(value)
49 case int16:
50 v = int64(value)
51 case int32:
52 v = int64(value)
53 case int64:
54 v = int64(value)
55 case uint:
56 v = uint64(value)
57 case uint8:
58 v = uint64(value)
59 case uint16:
60 v = uint64(value)
61 case uint32:
62 v = uint64(value)
63 case uint64:
64 v = uint64(value)
65 case float32:
66 v = float64(value)
67 case float64:
68 v = float64(value)
69 case string:
70 v = string(value)
71 default:
72 panic("attempt to use an unsupported type as value")
73 }
74 m.value[kv.Key] = mapValue{now, v}
75 }
76 m.insertMissingNodes()
77}
78
79// Delete deletes the given keys from the map object.
80func (m *Map) Delete(keys []string) {
81 // The lock order is important.
82 m.mu.Lock()
83 defer m.mu.Unlock()
84 lock.Lock()
85 defer lock.Unlock()
86 n := findNodeLocked(m.name, false)
87 for _, k := range keys {
88 delete(m.value, k)
89 if n != nil {
90 delete(n.children, k)
91 }
92 }
93}
94
95// Keys returns a sorted list of all the keys in the map.
96func (m *Map) Keys() []string {
97 m.mu.RLock()
98 defer m.mu.RUnlock()
99 keys := []string{}
100 for k, _ := range m.value {
101 keys = append(keys, k)
102 }
103 sort.Strings(keys)
104 return keys
105}
106
107// LastUpdate always returns a zero-value Time for a Map.
108func (m *Map) LastUpdate() time.Time {
109 return time.Time{}
110}
111
112// Value always returns nil for a Map.
113func (m *Map) Value() interface{} {
114 return nil
115}
116
117// insertMissingNodes inserts all the missing nodes.
118func (m *Map) insertMissingNodes() {
119 missing := []string{}
120 lock.RLock()
121 for key, _ := range m.value {
122 oName := path.Join(m.name, key)
123 if n := findNodeLocked(oName, false); n == nil {
124 missing = append(missing, key)
125 }
126 }
127 lock.RUnlock()
128 if len(missing) == 0 {
129 return
130 }
131
132 lock.Lock()
133 for _, key := range missing {
134 oName := path.Join(m.name, key)
135 if n := findNodeLocked(oName, true); n.object == nil {
136 n.object = &mapValueWrapper{m, key}
137 }
138 }
139 lock.Unlock()
140}
141
142type mapValueWrapper struct {
143 m *Map
144 key string
145}
146
147// LastUpdate returns the time at which the parent map object was last updated.
148func (w *mapValueWrapper) LastUpdate() time.Time {
149 w.m.mu.RLock()
150 defer w.m.mu.RUnlock()
151 if v, ok := w.m.value[w.key]; ok {
152 return v.lastUpdate
153 }
154 return time.Time{}
155}
156
157// Value returns the current value for the map key.
158func (w *mapValueWrapper) Value() interface{} {
159 w.m.mu.RLock()
160 defer w.m.mu.RUnlock()
161 if v, ok := w.m.value[w.key]; ok {
162 return v.value
163 }
164 return nil
165}