@@ -82,7 +82,7 @@ type JSONGateResolverBuilder struct {
82
82
targets map [string ][]targetHost
83
83
resolvers []* JSONGateResolver
84
84
85
- rand * rand. Rand
85
+ sorter * shuffleSorter
86
86
ticker * time.Ticker
87
87
checksum []byte
88
88
}
@@ -114,6 +114,7 @@ func RegisterJSONGateResolver(
114
114
poolTypeField : poolTypeField ,
115
115
affinityField : affinityField ,
116
116
affinityValue : affinityValue ,
117
+ sorter : newShuffleSorter (),
117
118
}
118
119
119
120
resolver .Register (jsonDiscovery )
@@ -133,9 +134,6 @@ func (*JSONGateResolverBuilder) Scheme() string { return "vtgate" }
133
134
134
135
// Parse and validate the format of the file and start watching for changes
135
136
func (b * JSONGateResolverBuilder ) start () error {
136
-
137
- b .rand = rand .New (rand .NewSource (time .Now ().UnixNano ()))
138
-
139
137
// Perform the initial parse
140
138
_ , err := b .parse ()
141
139
if err != nil {
@@ -288,11 +286,7 @@ func (b *JSONGateResolverBuilder) parse() (bool, error) {
288
286
}
289
287
290
288
for poolType := range targets {
291
- if b .affinityField != "" {
292
- sort .Slice (targets [poolType ], func (i , j int ) bool {
293
- return b .affinityValue == targets [poolType ][i ].Affinity
294
- })
295
- }
289
+ b .sorter .shuffleSort (targets [poolType ], b .affinityField , b .affinityValue )
296
290
if len (targets [poolType ]) > * numConnections {
297
291
targets [poolType ] = targets [poolType ][:* numConnections ]
298
292
}
@@ -324,32 +318,48 @@ func (b *JSONGateResolverBuilder) GetTargets(poolType string) []targetHost {
324
318
targets = append (targets , b .targets [poolType ]... )
325
319
b .mu .RUnlock ()
326
320
327
- // Shuffle to ensure every host has a different order to iterate through, putting
328
- // the affinity matching (e.g. same az) hosts at the front and the non-matching ones
329
- // at the end.
330
- //
331
- // Only need to do n-1 swaps since the last host is always in the right place.
321
+ b .sorter .shuffleSort (targets , b .affinityField , b .affinityValue )
322
+
323
+ return targets
324
+ }
325
+
326
+ type shuffleSorter struct {
327
+ rand * rand.Rand
328
+ mu * sync.Mutex
329
+ }
330
+
331
+ func newShuffleSorter () * shuffleSorter {
332
+ return & shuffleSorter {
333
+ rand : rand .New (rand .NewSource (time .Now ().UnixNano ())),
334
+ mu : & sync.Mutex {},
335
+ }
336
+ }
337
+
338
+ // shuffleSort shuffles a slice of targetHost to ensure every host has a
339
+ // different order to iterate through, putting the affinity matching (e.g. same
340
+ // az) hosts at the front and the non-matching ones at the end.
341
+ func (s * shuffleSorter ) shuffleSort (targets []targetHost , affinityField , affinityValue string ) {
332
342
n := len (targets )
333
343
head := 0
344
+ // Only need to do n-1 swaps since the last host is always in the right place.
334
345
tail := n - 1
335
346
for i := 0 ; i < n - 1 ; i ++ {
336
- j := head + b .rand .Intn (tail - head + 1 )
347
+ s .mu .Lock ()
348
+ j := head + s .rand .Intn (tail - head + 1 )
349
+ s .mu .Unlock ()
337
350
338
- if * affinityField != "" && * affinityValue == targets [j ].Affinity {
351
+ if affinityField != "" && affinityValue == targets [j ].Affinity {
339
352
targets [head ], targets [j ] = targets [j ], targets [head ]
340
353
head ++
341
354
} else {
342
355
targets [tail ], targets [j ] = targets [j ], targets [tail ]
343
356
tail --
344
357
}
345
358
}
346
-
347
- return targets
348
359
}
349
360
350
361
// Update the current list of hosts for the given resolver
351
362
func (b * JSONGateResolverBuilder ) update (r * JSONGateResolver ) {
352
-
353
363
log .V (100 ).Infof ("resolving target %s to %d connections\n " , r .target .URL .String (), * numConnections )
354
364
355
365
targets := b .GetTargets (r .poolType )
0 commit comments