@@ -99,9 +99,9 @@ func (v *Float) Set(value float64) {
99
99
100
100
// Map is a string-to-Var map variable that satisfies the Var interface.
101
101
type Map struct {
102
- mu sync.RWMutex
103
- m map [ string ] Var
104
- keys []string // sorted
102
+ m sync.Map // map[string]Var
103
+ keysMu sync. RWMutex
104
+ keys []string // sorted
105
105
}
106
106
107
107
// KeyValue represents a single entry in a Map.
@@ -111,12 +111,10 @@ type KeyValue struct {
111
111
}
112
112
113
113
func (v * Map ) String () string {
114
- v .mu .RLock ()
115
- defer v .mu .RUnlock ()
116
114
var b bytes.Buffer
117
115
fmt .Fprintf (& b , "{" )
118
116
first := true
119
- v .doLocked (func (kv KeyValue ) {
117
+ v .Do (func (kv KeyValue ) {
120
118
if ! first {
121
119
fmt .Fprintf (& b , ", " )
122
120
}
@@ -127,79 +125,60 @@ func (v *Map) String() string {
127
125
return b .String ()
128
126
}
129
127
130
- func (v * Map ) Init () * Map {
131
- v .m = make (map [string ]Var )
132
- return v
133
- }
128
+ func (v * Map ) Init () * Map { return v }
134
129
135
130
// updateKeys updates the sorted list of keys in v.keys.
136
- // must be called with v.mu held.
137
- func (v * Map ) updateKeys () {
138
- if len (v .m ) == len (v .keys ) {
139
- // No new key.
140
- return
141
- }
142
- v .keys = v .keys [:0 ]
143
- for k := range v .m {
144
- v .keys = append (v .keys , k )
145
- }
131
+ func (v * Map ) addKey (key string ) {
132
+ v .keysMu .Lock ()
133
+ defer v .keysMu .Unlock ()
134
+ v .keys = append (v .keys , key )
146
135
sort .Strings (v .keys )
147
136
}
148
137
149
138
func (v * Map ) Get (key string ) Var {
150
- v . mu . RLock ( )
151
- defer v . mu . RUnlock ( )
152
- return v . m [ key ]
139
+ i , _ := v . m . Load ( key )
140
+ av , _ := i .( Var )
141
+ return av
153
142
}
154
143
155
144
func (v * Map ) Set (key string , av Var ) {
156
- v .mu .Lock ()
157
- defer v .mu .Unlock ()
158
- v .m [key ] = av
159
- v .updateKeys ()
145
+ if _ , dup := v .m .LoadOrStore (key , av ); dup {
146
+ v .m .Store (key , av )
147
+ } else {
148
+ v .addKey (key )
149
+ }
160
150
}
161
151
152
+ // Add adds delta to the *Int value stored under the given map key.
162
153
func (v * Map ) Add (key string , delta int64 ) {
163
- v .mu .RLock ()
164
- av , ok := v .m [key ]
165
- v .mu .RUnlock ()
154
+ i , ok := v .m .Load (key )
166
155
if ! ok {
167
- // check again under the write lock
168
- v .mu .Lock ()
169
- av , ok = v .m [key ]
170
- if ! ok {
171
- av = new (Int )
172
- v .m [key ] = av
173
- v .updateKeys ()
156
+ var dup bool
157
+ i , dup = v .m .LoadOrStore (key , new (Int ))
158
+ if ! dup {
159
+ v .addKey (key )
174
160
}
175
- v .mu .Unlock ()
176
161
}
177
162
178
163
// Add to Int; ignore otherwise.
179
- if iv , ok := av .(* Int ); ok {
164
+ if iv , ok := i .(* Int ); ok {
180
165
iv .Add (delta )
181
166
}
182
167
}
183
168
184
169
// AddFloat adds delta to the *Float value stored under the given map key.
185
170
func (v * Map ) AddFloat (key string , delta float64 ) {
186
- v .mu .RLock ()
187
- av , ok := v .m [key ]
188
- v .mu .RUnlock ()
171
+ i , ok := v .m .Load (key )
189
172
if ! ok {
190
- // check again under the write lock
191
- v .mu .Lock ()
192
- av , ok = v .m [key ]
193
- if ! ok {
194
- av = new (Float )
195
- v .m [key ] = av
196
- v .updateKeys ()
173
+ var dup bool
174
+ i , dup = v .m .LoadOrStore (key , new (Float ))
175
+ if ! dup {
176
+ v .addKey (key )
197
177
}
198
- v .mu .Unlock ()
199
178
}
200
179
201
180
// Add to Float; ignore otherwise.
202
- if iv , ok := av .(* Float ); ok {
181
+ if iv , ok := i .(* Float ); ok {
203
182
iv .Add (delta )
204
183
}
205
184
}
@@ -208,45 +187,34 @@ func (v *Map) AddFloat(key string, delta float64) {
208
187
// The map is locked during the iteration,
209
188
// but existing entries may be concurrently updated.
210
189
func (v * Map ) Do (f func (KeyValue )) {
211
- v .mu .RLock ()
212
- defer v .mu .RUnlock ()
213
- v .doLocked (f )
214
- }
215
-
216
- // doLocked calls f for each entry in the map.
217
- // v.mu must be held for reads.
218
- func (v * Map ) doLocked (f func (KeyValue )) {
190
+ v .keysMu .RLock ()
191
+ defer v .keysMu .RUnlock ()
219
192
for _ , k := range v .keys {
220
- f (KeyValue {k , v .m [k ]})
193
+ i , _ := v .m .Load (k )
194
+ f (KeyValue {k , i .(Var )})
221
195
}
222
196
}
223
197
224
198
// String is a string variable, and satisfies the Var interface.
225
199
type String struct {
226
- mu sync.RWMutex
227
- s string
200
+ s atomic.Value // string
228
201
}
229
202
230
203
func (v * String ) Value () string {
231
- v .mu .RLock ()
232
- defer v .mu .RUnlock ()
233
- return v .s
204
+ p , _ := v .s .Load ().(string )
205
+ return p
234
206
}
235
207
236
208
// String implements the Val interface. To get the unquoted string
237
209
// use Value.
238
210
func (v * String ) String () string {
239
- v .mu .RLock ()
240
- s := v .s
241
- v .mu .RUnlock ()
211
+ s := v .Value ()
242
212
b , _ := json .Marshal (s )
243
213
return string (b )
244
214
}
245
215
246
216
func (v * String ) Set (value string ) {
247
- v .mu .Lock ()
248
- defer v .mu .Unlock ()
249
- v .s = value
217
+ v .s .Store (value )
250
218
}
251
219
252
220
// Func implements Var by calling the function
@@ -264,31 +232,30 @@ func (f Func) String() string {
264
232
265
233
// All published variables.
266
234
var (
267
- mutex sync.RWMutex
268
- vars = make ( map [ string ] Var )
269
- varKeys []string // sorted
235
+ vars sync.Map // map[string]Var
236
+ varKeysMu sync. RWMutex
237
+ varKeys []string // sorted
270
238
)
271
239
272
240
// Publish declares a named exported variable. This should be called from a
273
241
// package's init function when it creates its Vars. If the name is already
274
242
// registered then this will log.Panic.
275
243
func Publish (name string , v Var ) {
276
- mutex .Lock ()
277
- defer mutex .Unlock ()
278
- if _ , existing := vars [name ]; existing {
244
+ if _ , dup := vars .LoadOrStore (name , v ); dup {
279
245
log .Panicln ("Reuse of exported var name:" , name )
280
246
}
281
- vars [name ] = v
247
+ varKeysMu .Lock ()
248
+ defer varKeysMu .Unlock ()
282
249
varKeys = append (varKeys , name )
283
250
sort .Strings (varKeys )
284
251
}
285
252
286
253
// Get retrieves a named exported variable. It returns nil if the name has
287
254
// not been registered.
288
255
func Get (name string ) Var {
289
- mutex . RLock ( )
290
- defer mutex . RUnlock ( )
291
- return vars [ name ]
256
+ i , _ := vars . Load ( name )
257
+ v , _ := i .( Var )
258
+ return v
292
259
}
293
260
294
261
// Convenience functions for creating new exported variables.
@@ -321,10 +288,11 @@ func NewString(name string) *String {
321
288
// The global variable map is locked during the iteration,
322
289
// but existing entries may be concurrently updated.
323
290
func Do (f func (KeyValue )) {
324
- mutex .RLock ()
325
- defer mutex .RUnlock ()
291
+ varKeysMu .RLock ()
292
+ defer varKeysMu .RUnlock ()
326
293
for _ , k := range varKeys {
327
- f (KeyValue {k , vars [k ]})
294
+ val , _ := vars .Load (k )
295
+ f (KeyValue {k , val .(Var )})
328
296
}
329
297
}
330
298
0 commit comments