Pick random node when command does not have keys

This commit is contained in:
Vladimir Mihailenco 2017-12-28 16:41:05 +02:00
parent cfed9ab470
commit 3de5605ab2
5 changed files with 49 additions and 9 deletions

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

@ -343,7 +343,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)
} }