@@ -349,17 +349,16 @@ func (c *ringSharding) newRingShards(
349
349
return
350
350
}
351
351
352
+ // Warning: External exposure of `c.shards.list` may cause data races.
353
+ // So keep internal or implement deep copy if exposed.
352
354
func (c * ringSharding ) List () []* ringShard {
353
- var list []* ringShard
354
-
355
355
c .mu .RLock ()
356
- if ! c .closed {
357
- list = make ([]* ringShard , len (c .shards .list ))
358
- copy (list , c .shards .list )
359
- }
360
- c .mu .RUnlock ()
356
+ defer c .mu .RUnlock ()
361
357
362
- return list
358
+ if c .closed {
359
+ return nil
360
+ }
361
+ return c .shards .list
363
362
}
364
363
365
364
func (c * ringSharding ) Hash (key string ) string {
@@ -423,6 +422,7 @@ func (c *ringSharding) Heartbeat(ctx context.Context, frequency time.Duration) {
423
422
case <- ticker .C :
424
423
var rebalance bool
425
424
425
+ // note: `c.List()` return a shadow copy of `[]*ringShard`.
426
426
for _ , shard := range c .List () {
427
427
err := shard .Client .Ping (ctx ).Err ()
428
428
isUp := err == nil || err == pool .ErrPoolTimeout
@@ -582,6 +582,7 @@ func (c *Ring) retryBackoff(attempt int) time.Duration {
582
582
583
583
// PoolStats returns accumulated connection pool stats.
584
584
func (c * Ring ) PoolStats () * PoolStats {
585
+ // note: `c.List()` return a shadow copy of `[]*ringShard`.
585
586
shards := c .sharding .List ()
586
587
var acc PoolStats
587
588
for _ , shard := range shards {
@@ -651,6 +652,7 @@ func (c *Ring) ForEachShard(
651
652
ctx context.Context ,
652
653
fn func (ctx context.Context , client * Client ) error ,
653
654
) error {
655
+ // note: `c.List()` return a shadow copy of `[]*ringShard`.
654
656
shards := c .sharding .List ()
655
657
var wg sync.WaitGroup
656
658
errCh := make (chan error , 1 )
@@ -682,6 +684,7 @@ func (c *Ring) ForEachShard(
682
684
}
683
685
684
686
func (c * Ring ) cmdsInfo (ctx context.Context ) (map [string ]* CommandInfo , error ) {
687
+ // note: `c.List()` return a shadow copy of `[]*ringShard`.
685
688
shards := c .sharding .List ()
686
689
var firstErr error
687
690
for _ , shard := range shards {
@@ -810,7 +813,7 @@ func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) er
810
813
811
814
for _ , key := range keys {
812
815
if key != "" {
813
- shard , err := c .sharding .GetByKey (hashtag . Key ( key ) )
816
+ shard , err := c .sharding .GetByKey (key )
814
817
if err != nil {
815
818
return err
816
819
}
0 commit comments