@@ -160,6 +160,7 @@ func (opt *RingOptions) clientOptions() *Options {
160
160
type ringShard struct {
161
161
Client * Client
162
162
down int32
163
+ addr string
163
164
}
164
165
165
166
func newRingShard (opt * RingOptions , name , addr string ) * ringShard {
@@ -168,6 +169,7 @@ func newRingShard(opt *RingOptions, name, addr string) *ringShard {
168
169
169
170
return & ringShard {
170
171
Client : opt .NewClient (name , clopt ),
172
+ addr : addr ,
171
173
}
172
174
}
173
175
@@ -212,33 +214,68 @@ type ringShards struct {
212
214
opt * RingOptions
213
215
214
216
mu sync.RWMutex
217
+ muClose sync.Mutex
215
218
hash ConsistentHash
216
- shards map [string ]* ringShard // read only
217
- list []* ringShard // read only
219
+ shards map [string ]* ringShard // read only, updated by SetAddrs
220
+ list []* ringShard // read only, updated by SetAddrs
218
221
numShard int
219
222
closed bool
220
223
}
221
224
222
225
func newRingShards (opt * RingOptions ) * ringShards {
223
- shards := make (map [string ]* ringShard , len (opt .Addrs ))
224
- list := make ([]* ringShard , 0 , len (shards ))
226
+ c := & ringShards {
227
+ opt : opt ,
228
+ }
229
+ c .SetAddrs (opt .Addrs )
225
230
226
- for name , addr := range opt .Addrs {
227
- shard := newRingShard (opt , name , addr )
228
- shards [name ] = shard
231
+ return c
232
+ }
229
233
230
- list = append (list , shard )
234
+ // SetAddrs replaces the shards in use, such that you can increase and
235
+ // decrease number of shards, that you use. It will reuse shards that
236
+ // existed before and close the ones that will not be used anymore.
237
+ func (c * ringShards ) SetAddrs (addrs map [string ]string ) {
238
+ c .muClose .Lock ()
239
+ defer c .muClose .Unlock ()
240
+ if c .closed {
241
+ return
231
242
}
232
243
233
- c := & ringShards {
234
- opt : opt ,
244
+ shards := make (map [string ]* ringShard )
245
+ unusedShards := make (map [string ]* ringShard )
246
+
247
+ for k , shard := range c .shards {
248
+ if addr , ok := addrs [k ]; ok && shard .addr == addr {
249
+ shards [k ] = shard
250
+ } else {
251
+ unusedShards [k ] = shard
252
+ }
253
+ }
235
254
236
- shards : shards ,
237
- list : list ,
255
+ for k , addr := range addrs {
256
+ if shard , ok := c .shards [k ]; ! ok || shard .addr != addr {
257
+ shards [k ] = newRingShard (c .opt , k , addr )
258
+ }
238
259
}
239
- c .rebalance ()
240
260
241
- return c
261
+ list := make ([]* ringShard , 0 , len (shards ))
262
+ for _ , shard := range shards {
263
+ list = append (list , shard )
264
+ }
265
+
266
+ c .mu .Lock ()
267
+ c .shards = shards
268
+ c .list = list
269
+
270
+ c .rebalanceLocked ()
271
+ c .mu .Unlock ()
272
+
273
+ for k , shard := range unusedShards {
274
+ err := shard .Client .Close ()
275
+ if err != nil {
276
+ internal .Logger .Printf (context .Background (), "Failed to close ring shard client %s %s: %v" , k , shard .addr , err )
277
+ }
278
+ }
242
279
}
243
280
244
281
func (c * ringShards ) List () []* ringShard {
@@ -355,6 +392,23 @@ func (c *ringShards) rebalance() {
355
392
c .mu .Unlock ()
356
393
}
357
394
395
+ // rebalanceLocked removes dead shards from the Ring and callers need to hold the locl
396
+ func (c * ringShards ) rebalanceLocked () {
397
+ shards := c .shards
398
+ liveShards := make ([]string , 0 , len (shards ))
399
+
400
+ for name , shard := range shards {
401
+ if shard .IsUp () {
402
+ liveShards = append (liveShards , name )
403
+ }
404
+ }
405
+
406
+ hash := c .opt .NewConsistentHash (liveShards )
407
+
408
+ c .hash = hash
409
+ c .numShard = len (liveShards )
410
+ }
411
+
358
412
func (c * ringShards ) Len () int {
359
413
c .mu .RLock ()
360
414
l := c .numShard
@@ -363,6 +417,8 @@ func (c *ringShards) Len() int {
363
417
}
364
418
365
419
func (c * ringShards ) Close () error {
420
+ c .muClose .Lock ()
421
+ defer c .muClose .Unlock ()
366
422
c .mu .Lock ()
367
423
defer c .mu .Unlock ()
368
424
@@ -430,6 +486,10 @@ func NewRing(opt *RingOptions) *Ring {
430
486
return & ring
431
487
}
432
488
489
+ func (c * Ring ) SetAddrs (ctx context.Context , addrs map [string ]string ) {
490
+ c .shards .SetAddrs (addrs )
491
+ }
492
+
433
493
// Do creates a Cmd from the args and processes the cmd.
434
494
func (c * Ring ) Do (ctx context.Context , args ... interface {}) * Cmd {
435
495
cmd := NewCmd (ctx , args ... )
0 commit comments