1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-19 11:43:14 +03:00

chore(txPipeline): refactor slottedCommands impl

This commit is contained in:
Nedyalko Dyakov
2025-06-23 17:41:14 +03:00
parent 50d1484dc4
commit 2bbcdaa32b

View File

@ -1526,46 +1526,26 @@ func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) err
return err
}
cmdsMap := map[int][]Cmder{}
keyedCmdsBySlot := c.slottedKeyedCommands(cmds)
slot := -1
// get only the keyed commands
keyedCmds := c.keyedCmds(cmds)
if len(keyedCmds) == 0 {
// no keyed commands try random slot
switch len(keyedCmdsBySlot) {
case 0:
slot = hashtag.RandomSlot()
} else {
// keyed commands, get slot from them
// if more than one slot, return cross slot error
cmdsBySlot := c.mapCmdsBySlot(keyedCmds)
if len(cmdsBySlot) > 1 {
// cross slot error, we have more than one slot for keyed commands
setCmdsErr(cmds, ErrCrossSlot)
return ErrCrossSlot
}
// get the slot, should be only one
for sl := range cmdsBySlot {
case 1:
for sl := range keyedCmdsBySlot {
slot = sl
break
}
}
// slot was not determined, try random one
if slot == -1 {
slot = hashtag.RandomSlot()
}
cmdsMap[slot] = cmds
default:
// TxPipeline does not support cross slot transaction.
// double check the commands are in the same slot
if len(cmdsMap) > 1 {
setCmdsErr(cmds, ErrCrossSlot)
return ErrCrossSlot
}
for slot, cmds := range cmdsMap {
node, err := state.slotMasterNode(slot)
if err != nil {
setCmdsErr(cmds, err)
continue
return err
}
cmdsMap := map[*clusterNode][]Cmder{node: cmds}
@ -1594,34 +1574,30 @@ func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) err
}
cmdsMap = failedCmds.m
}
}
return cmdsFirstErr(cmds)
}
func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
cmdsMap := make(map[int][]Cmder)
preferredRandomSlot := -1
for _, cmd := range cmds {
slot := c.cmdSlot(cmd, preferredRandomSlot)
if preferredRandomSlot == -1 {
preferredRandomSlot = slot
}
cmdsMap[slot] = append(cmdsMap[slot], cmd)
}
return cmdsMap
}
// slottedKeyedCommands returns a map of slot to commands taking into account
// only commands that have keys.
func (c *ClusterClient) slottedKeyedCommands(cmds []Cmder) map[int][]Cmder {
cmdsSlots := map[int][]Cmder{}
// keyedCmds returns all the keyed commands from the cmds slice
// it determines keyed commands by checking if the command has a first key position
func (c *ClusterClient) keyedCmds(cmds []Cmder) []Cmder {
keyedCmds := make([]Cmder, 0, len(cmds))
prefferedRandomSlot := -1
for _, cmd := range cmds {
if cmdFirstKeyPos(cmd) != 0 {
keyedCmds = append(keyedCmds, cmd)
if cmdFirstKeyPos(cmd) == 0 {
continue
}
slot := c.cmdSlot(cmd, prefferedRandomSlot)
if prefferedRandomSlot == -1 {
prefferedRandomSlot = slot
}
return keyedCmds
cmdsSlots[slot] = append(cmdsSlots[slot], cmd)
}
return cmdsSlots
}
func (c *ClusterClient) processTxPipelineNode(