Skip to content

Commit 2507be6

Browse files
committed
Merge pull request #96 from go-redis/fix/reload-slots-in-background
Reload slots in background goroutine.
2 parents d3a8d04 + 84dc1f9 commit 2507be6

File tree

4 files changed

+27
-43
lines changed

4 files changed

+27
-43
lines changed

cluster.go

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package redis
22

33
import (
4+
"log"
45
"math/rand"
56
"strings"
67
"sync"
@@ -21,7 +22,8 @@ type ClusterClient struct {
2122

2223
opt *ClusterOptions
2324

24-
_reload uint32
25+
// Reports where slots reloading is in progress.
26+
reloading uint32
2527
}
2628

2729
// NewClusterClient initializes a new cluster-aware client using given options.
@@ -32,10 +34,9 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient {
3234
slots: make([][]string, hashSlots),
3335
clients: make(map[string]*Client),
3436
opt: opt,
35-
_reload: 1,
3637
}
3738
client.commandable.process = client.process
38-
client.reloadIfDue()
39+
client.reloadSlots()
3940
go client.reaper()
4041
return client
4142
}
@@ -115,8 +116,6 @@ func (c *ClusterClient) randomClient() (client *Client, err error) {
115116
func (c *ClusterClient) process(cmd Cmder) {
116117
var ask bool
117118

118-
c.reloadIfDue()
119-
120119
slot := hashSlot(cmd.clusterKey())
121120

122121
var addr string
@@ -162,7 +161,7 @@ func (c *ClusterClient) process(cmd Cmder) {
162161
moved, ask, addr = isMovedError(err)
163162
if moved || ask {
164163
if moved {
165-
c.scheduleReload()
164+
c.lazyReloadSlots()
166165
}
167166
client, err = c.getClient(addr)
168167
if err != nil {
@@ -214,29 +213,28 @@ func (c *ClusterClient) setSlots(slots []ClusterSlotInfo) {
214213
c.slotsMx.Unlock()
215214
}
216215

217-
// Closes all connections and reloads slot cache, if due.
218-
func (c *ClusterClient) reloadIfDue() (err error) {
219-
if !atomic.CompareAndSwapUint32(&c._reload, 1, 0) {
220-
return
221-
}
216+
func (c *ClusterClient) reloadSlots() {
217+
defer atomic.StoreUint32(&c.reloading, 0)
222218

223219
client, err := c.randomClient()
224220
if err != nil {
225-
return err
221+
log.Printf("redis: randomClient failed: %s", err)
222+
return
226223
}
227224

228225
slots, err := client.ClusterSlots().Result()
229226
if err != nil {
230-
return err
227+
log.Printf("redis: ClusterSlots failed: %s", err)
228+
return
231229
}
232230
c.setSlots(slots)
233-
234-
return nil
235231
}
236232

237-
// Schedules slots reload on next request.
238-
func (c *ClusterClient) scheduleReload() {
239-
atomic.StoreUint32(&c._reload, 1)
233+
func (c *ClusterClient) lazyReloadSlots() {
234+
if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) {
235+
return
236+
}
237+
go c.reloadSlots()
240238
}
241239

242240
// reaper closes idle connections to the cluster.

cluster_client_test.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,8 @@ import (
55
. "github.com/onsi/gomega"
66
)
77

8-
// GetSlot returns the cached slot addresses
9-
func (c *ClusterClient) GetSlot(pos int) []string {
10-
c.slotsMx.RLock()
11-
defer c.slotsMx.RUnlock()
12-
13-
return c.slots[pos]
8+
func (c *ClusterClient) SlotAddrs(slot int) []string {
9+
return c.slotAddrs(slot)
1410
}
1511

1612
// SwapSlot swaps a slot's master/slave address
@@ -49,7 +45,6 @@ var _ = Describe("ClusterClient", func() {
4945
It("should initialize", func() {
5046
Expect(subject.addrs).To(HaveLen(3))
5147
Expect(subject.slots).To(HaveLen(16384))
52-
Expect(subject._reload).To(Equal(uint32(0)))
5348
})
5449

5550
It("should update slots cache", func() {
@@ -85,11 +80,4 @@ var _ = Describe("ClusterClient", func() {
8580
Expect(subject.slots[16383]).To(BeEmpty())
8681
Expect(subject.Ping().Err().Error()).To(Equal("redis: client is closed"))
8782
})
88-
89-
It("should check if reload is due", func() {
90-
subject._reload = 0
91-
Expect(subject._reload).To(Equal(uint32(0)))
92-
subject.scheduleReload()
93-
Expect(subject._reload).To(Equal(uint32(1)))
94-
})
9583
})

cluster_pipeline.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func (c *ClusterPipeline) execClusterCmds(
113113
failedCmds[""] = append(failedCmds[""], cmds[i:]...)
114114
break
115115
} else if moved, ask, addr := isMovedError(err); moved {
116-
c.cluster.scheduleReload()
116+
c.cluster.lazyReloadSlots()
117117
cmd.reset()
118118
failedCmds[addr] = append(failedCmds[addr], cmd)
119119
} else if ask {

cluster_test.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -258,25 +258,23 @@ var _ = Describe("Cluster", func() {
258258

259259
It("should follow redirects", func() {
260260
Expect(client.Set("A", "VALUE", 0).Err()).NotTo(HaveOccurred())
261-
Expect(redis.HashSlot("A")).To(Equal(6373))
262-
Expect(client.SwapSlot(6373)).To(Equal([]string{"127.0.0.1:8224", "127.0.0.1:8221"}))
261+
262+
slot := redis.HashSlot("A")
263+
Expect(client.SwapSlot(slot)).To(Equal([]string{"127.0.0.1:8224", "127.0.0.1:8221"}))
263264

264265
val, err := client.Get("A").Result()
265266
Expect(err).NotTo(HaveOccurred())
266267
Expect(val).To(Equal("VALUE"))
267-
Expect(client.GetSlot(6373)).To(Equal([]string{"127.0.0.1:8224", "127.0.0.1:8221"}))
268+
Expect(client.SlotAddrs(slot)).To(Equal([]string{"127.0.0.1:8224", "127.0.0.1:8221"}))
268269

269-
val, err = client.Get("A").Result()
270-
Expect(err).NotTo(HaveOccurred())
271-
Expect(val).To(Equal("VALUE"))
272-
Expect(client.GetSlot(6373)).To(Equal([]string{"127.0.0.1:8221", "127.0.0.1:8224"}))
270+
Eventually(func() []string {
271+
return client.SlotAddrs(slot)
272+
}).Should(Equal([]string{"127.0.0.1:8221", "127.0.0.1:8224"}))
273273
})
274274

275275
It("should perform multi-pipelines", func() {
276-
// Dummy command to load slots info.
277-
Expect(client.Ping().Err()).NotTo(HaveOccurred())
278-
279276
slot := redis.HashSlot("A")
277+
Expect(client.SlotAddrs(slot)).To(Equal([]string{"127.0.0.1:8221", "127.0.0.1:8224"}))
280278
Expect(client.SwapSlot(slot)).To(Equal([]string{"127.0.0.1:8224", "127.0.0.1:8221"}))
281279

282280
pipe := client.Pipeline()

0 commit comments

Comments
 (0)