1
0
mirror of https://github.com/redis/go-redis.git synced 2025-06-11 03:21:38 +03:00

perf: avoid unnecessary copy operation (#3376)

* optime: reduce unnecessary copy operations

* add a comment

* trigger CI without code changes, because the bug of docker

* add comments
This commit is contained in:
fukua95
2025-05-20 00:24:37 +08:00
committed by GitHub
parent ba26e35a2c
commit bc70b52b42

21
ring.go
View File

@ -349,17 +349,16 @@ func (c *ringSharding) newRingShards(
return return
} }
// Warning: External exposure of `c.shards.list` may cause data races.
// So keep internal or implement deep copy if exposed.
func (c *ringSharding) List() []*ringShard { func (c *ringSharding) List() []*ringShard {
var list []*ringShard
c.mu.RLock() c.mu.RLock()
if !c.closed { defer c.mu.RUnlock()
list = make([]*ringShard, len(c.shards.list))
copy(list, c.shards.list)
}
c.mu.RUnlock()
return list if c.closed {
return nil
}
return c.shards.list
} }
func (c *ringSharding) Hash(key string) string { func (c *ringSharding) Hash(key string) string {
@ -423,6 +422,7 @@ func (c *ringSharding) Heartbeat(ctx context.Context, frequency time.Duration) {
case <-ticker.C: case <-ticker.C:
var rebalance bool var rebalance bool
// note: `c.List()` return a shadow copy of `[]*ringShard`.
for _, shard := range c.List() { for _, shard := range c.List() {
err := shard.Client.Ping(ctx).Err() err := shard.Client.Ping(ctx).Err()
isUp := err == nil || err == pool.ErrPoolTimeout isUp := err == nil || err == pool.ErrPoolTimeout
@ -582,6 +582,7 @@ func (c *Ring) retryBackoff(attempt int) time.Duration {
// PoolStats returns accumulated connection pool stats. // PoolStats returns accumulated connection pool stats.
func (c *Ring) PoolStats() *PoolStats { func (c *Ring) PoolStats() *PoolStats {
// note: `c.List()` return a shadow copy of `[]*ringShard`.
shards := c.sharding.List() shards := c.sharding.List()
var acc PoolStats var acc PoolStats
for _, shard := range shards { for _, shard := range shards {
@ -651,6 +652,7 @@ func (c *Ring) ForEachShard(
ctx context.Context, ctx context.Context,
fn func(ctx context.Context, client *Client) error, fn func(ctx context.Context, client *Client) error,
) error { ) error {
// note: `c.List()` return a shadow copy of `[]*ringShard`.
shards := c.sharding.List() shards := c.sharding.List()
var wg sync.WaitGroup var wg sync.WaitGroup
errCh := make(chan error, 1) errCh := make(chan error, 1)
@ -682,6 +684,7 @@ func (c *Ring) ForEachShard(
} }
func (c *Ring) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) { func (c *Ring) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) {
// note: `c.List()` return a shadow copy of `[]*ringShard`.
shards := c.sharding.List() shards := c.sharding.List()
var firstErr error var firstErr error
for _, shard := range shards { for _, shard := range shards {
@ -810,7 +813,7 @@ func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) er
for _, key := range keys { for _, key := range keys {
if key != "" { if key != "" {
shard, err := c.sharding.GetByKey(hashtag.Key(key)) shard, err := c.sharding.GetByKey(key)
if err != nil { if err != nil {
return err return err
} }