Merge pull request #688 from go-redis/fix/random-node

Pick random node when command does not have keys
This commit is contained in:
Vladimir Mihailenco 2017-12-28 17:12:13 +02:00 committed by GitHub
commit 73b70592cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 11 deletions

View File

@ -5,7 +5,6 @@ services:
- redis-server - redis-server
go: go:
- 1.4.x
- 1.7.x - 1.7.x
- 1.8.x - 1.8.x
- 1.9.x - 1.9.x
@ -13,7 +12,6 @@ go:
matrix: matrix:
allow_failures: allow_failures:
- go: 1.4.x
- go: tip - go: tip
install: install:

View File

@ -533,16 +533,22 @@ func (c *ClusterClient) cmdInfo(name string) *CommandInfo {
return info return info
} }
func cmdSlot(cmd Cmder, pos int) int {
if pos == 0 {
return hashtag.RandomSlot()
}
firstKey := cmd.stringArg(pos)
return hashtag.Slot(firstKey)
}
func (c *ClusterClient) cmdSlot(cmd Cmder) int { func (c *ClusterClient) cmdSlot(cmd Cmder) int {
cmdInfo := c.cmdInfo(cmd.Name()) cmdInfo := c.cmdInfo(cmd.Name())
firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) return cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo))
return hashtag.Slot(firstKey)
} }
func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *clusterNode, error) { func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *clusterNode, error) {
cmdInfo := c.cmdInfo(cmd.Name()) cmdInfo := c.cmdInfo(cmd.Name())
firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) slot := cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo))
slot := hashtag.Slot(firstKey)
if cmdInfo != nil && cmdInfo.ReadOnly && c.opt.ReadOnly { if cmdInfo != nil && cmdInfo.ReadOnly && c.opt.ReadOnly {
if c.opt.RouteByLatency { if c.opt.RouteByLatency {

View File

@ -536,6 +536,32 @@ var _ = Describe("ClusterClient", func() {
Expect(nodesList).Should(HaveLen(1)) Expect(nodesList).Should(HaveLen(1))
}) })
It("should RANDOMKEY", func() {
const nkeys = 100
for i := 0; i < nkeys; i++ {
err := client.Set(fmt.Sprintf("key%d", i), "value", 0).Err()
Expect(err).NotTo(HaveOccurred())
}
var keys []string
addKey := func(key string) {
for _, k := range keys {
if k == key {
return
}
}
keys = append(keys, key)
}
for i := 0; i < nkeys*10; i++ {
key := client.RandomKey().Val()
addKey(key)
}
Expect(len(keys)).To(BeNumerically("~", nkeys, nkeys/10))
})
assertClusterClient() assertClusterClient()
}) })

View File

@ -82,13 +82,13 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
if cmd.stringArg(2) != "0" { if cmd.stringArg(2) != "0" {
return 3 return 3
} else { } else {
return -1 return 0
} }
case "publish": case "publish":
return 1 return 1
} }
if info == nil { if info == nil {
return -1 return 0
} }
return int(info.FirstKeyPos) return int(info.FirstKeyPos)
} }

View File

@ -55,13 +55,17 @@ func Key(key string) string {
return key return key
} }
func RandomSlot() int {
return rand.Intn(SlotNumber)
}
// hashSlot returns a consistent slot number between 0 and 16383 // hashSlot returns a consistent slot number between 0 and 16383
// for any given string key. // for any given string key.
func Slot(key string) int { func Slot(key string) int {
key = Key(key)
if key == "" { if key == "" {
return rand.Intn(SlotNumber) return RandomSlot()
} }
key = Key(key)
return int(crc16sum(key)) % SlotNumber return int(crc16sum(key)) % SlotNumber
} }

View File

@ -298,6 +298,9 @@ func (c *Ring) cmdInfo(name string) *CommandInfo {
if err != nil { if err != nil {
return nil return nil
} }
if c.cmdsInfo == nil {
return nil
}
info := c.cmdsInfo[name] info := c.cmdsInfo[name]
if info == nil { if info == nil {
internal.Logf("info for cmd=%s not found", name) internal.Logf("info for cmd=%s not found", name)
@ -343,7 +346,11 @@ func (c *Ring) shardByName(name string) (*ringShard, error) {
func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) { func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) {
cmdInfo := c.cmdInfo(cmd.Name()) cmdInfo := c.cmdInfo(cmd.Name())
firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) pos := cmdFirstKeyPos(cmd, cmdInfo)
if pos == 0 {
return c.randomShard()
}
firstKey := cmd.stringArg(pos)
return c.shardByKey(firstKey) return c.shardByKey(firstKey)
} }