mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-05 16:57:06 +08:00
67 lines
1.8 KiB
Go
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)
|
|
}
|
|
} |