diff --git a/cluster/commands/del.go b/cluster/commands/del.go new file mode 100644 index 0000000..3cbf89b --- /dev/null +++ b/cluster/commands/del.go @@ -0,0 +1,69 @@ +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" +) + +func init() { + core.RegisterCmd("del_", execDelInLocal) + core.RegisterCmd("del", execDel) +} + +func execDelInLocal(cluster *core.Cluster, c redis.Connection, cmdLine CmdLine) redis.Reply { + if len(cmdLine) < 2 { + return protocol.MakeArgNumErrReply("del") + } + cmdLine[0] = []byte("del") + return cluster.LocalExec(c, cmdLine) +} + +func execDel(cluster *core.Cluster, c redis.Connection, cmdLine CmdLine) redis.Reply { + if len(cmdLine) < 2 { + return protocol.MakeArgNumErrReply("del") + } + var keys []string + keyValues := make(map[string][]byte) + for i := 1; i < len(cmdLine); i++ { + key := string(cmdLine[i]) + keys = append(keys, key) + } + routeMap := getRouteMap(cluster, keys) + if len(routeMap) == 1 { + // only one node, do it fast + for node := range routeMap { + cmdLine[0] = []byte("del_") + return cluster.Relay(node, c, cmdLine) + } + } + + // tcc + cmdLineMap := make(map[string]CmdLine) + for node, keys := range routeMap { + nodeCmdLine := utils.ToCmdLine("del") + for _, key := range keys { + val := keyValues[key] + nodeCmdLine = append(nodeCmdLine, []byte(key), val) + } + cmdLineMap[node] = nodeCmdLine + } + tx := &TccTx{ + rawCmdLine: cmdLine, + routeMap: routeMap, + cmdLines: cmdLineMap, + } + results, err := doTcc(cluster, c, tx) + if err != nil { + return err + } + var count int64 = 0 + for _, res := range results { + res2, ok := res.(*protocol.IntReply) + if ok { + count += res2.Code + } + } + return protocol.MakeIntReply(count) +} diff --git a/cluster/commands/del_test.go b/cluster/commands/del_test.go new file mode 100644 index 0000000..fa5edcf --- /dev/null +++ b/cluster/commands/del_test.go @@ -0,0 +1,39 @@ +package commands + +import ( + "testing" + + "github.com/hdt3213/godis/cluster/core" + "github.com/hdt3213/godis/lib/utils" + "github.com/hdt3213/godis/redis/connection" + "github.com/hdt3213/godis/redis/protocol/asserts" +) + +func TestDel(t *testing.T) { + id1 := "1" + id2 := "2" + nodes := core.MakeTestCluster([]string{id1, id2}) + node1 := nodes[id1] + c := connection.NewFakeConn() + core.RegisterDefaultCmd("set") + core.RegisterDefaultCmd("exists") + node1.Exec(c, utils.ToCmdLine("set", "1", "1")) + node1.Exec(c, utils.ToCmdLine("set", "2", "2")) + + // 1, 2 will be routed to node1 and node2, see MakeTestCluster + res := execDel(node1, c, utils.ToCmdLine("del", "1", "2")) + asserts.AssertIntReply(t, res, 2) + + res = node1.Exec(c, utils.ToCmdLine("exists", "1")) + asserts.AssertIntReply(t, res, 0) + + res = node1.Exec(c, utils.ToCmdLine("exists", "2")) + asserts.AssertIntReply(t, res, 0) + + // in one node + node1.Exec(c, utils.ToCmdLine("set", "3", "3")) + res = execDel(node1, c, utils.ToCmdLine("del", "3")) + asserts.AssertIntReply(t, res, 1) + res = node1.Exec(c, utils.ToCmdLine("exists", "3")) + asserts.AssertIntReply(t, res, 0) +} \ No newline at end of file