Files
redis-go/cluster/commands/tcc_utils.go
2025-03-23 21:51:07 +08:00

67 lines
1.8 KiB
Go

package commands
import (
"github.com/hdt3213/godis/cluster/core"
"github.com/hdt3213/godis/interface/redis"
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/protocol"
)
type CmdLine = [][]byte
// node -> keys on the node
type RouteMap map[string][]string
func getRouteMap(cluster *core.Cluster, keys []string) RouteMap {
m := make(RouteMap)
for _, key := range keys {
slot := cluster.GetSlot(key)
node := cluster.PickNode(slot)
m[node] = append(m[node], key)
}
return m
}
type TccTx struct {
rawCmdLine CmdLine
routeMap RouteMap
cmdLines map[string]CmdLine // node -> CmdLine
}
// execute tcc
// returns node->result map
func doTcc(cluster *core.Cluster, c redis.Connection, tx *TccTx) (map[string]redis.Reply, protocol.ErrorReply) {
txId := utils.RandString(6)
// send prepare request
for node, cmdLine := range tx.cmdLines {
prepareCmd := utils.ToCmdLine("prepare", txId)
prepareCmd = append(prepareCmd, cmdLine...)
reply := cluster.Relay(node, c, prepareCmd)
if err := protocol.Try2ErrorReply(reply); err != nil {
requestRollback(cluster, c, txId, tx.routeMap)
return nil, protocol.MakeErrReply("prepare failed: " + err.Error())
}
}
// send commit request
commiteCmd := utils.ToCmdLine("commit", txId)
result := make(map[string]redis.Reply)
for node := range tx.routeMap {
reply := cluster.Relay(node, c, commiteCmd)
if err := protocol.Try2ErrorReply(reply); err != nil {
requestRollback(cluster, c, txId, tx.routeMap)
return nil, protocol.MakeErrReply("commit failed: " + err.Error())
}
result[node] = reply
}
return result, nil
}
func requestRollback(cluster *core.Cluster, c redis.Connection, txId string, routeMap RouteMap) {
rollbackCmd := utils.ToCmdLine("rollback", txId)
for node := range routeMap {
cluster.Relay(node, c, rollbackCmd)
}
}