github.com/hdt3213/godis@v1.2.9/cluster/rename.go (about) 1 package cluster 2 3 import ( 4 "github.com/hdt3213/godis/interface/redis" 5 "github.com/hdt3213/godis/lib/utils" 6 "github.com/hdt3213/godis/redis/protocol" 7 "strconv" 8 ) 9 10 // Rename renames a key, the origin and the destination must within the same node 11 func Rename(cluster *Cluster, c redis.Connection, args [][]byte) redis.Reply { 12 if len(args) != 3 { 13 return protocol.MakeErrReply("ERR wrong number of arguments for 'rename' command") 14 } 15 srcKey := string(args[1]) 16 destKey := string(args[2]) 17 srcNode := cluster.peerPicker.PickNode(srcKey) 18 destNode := cluster.peerPicker.PickNode(destKey) 19 if srcNode == destNode { // do fast 20 return cluster.relay(srcNode, c, args) 21 } 22 groupMap := map[string][]string{ 23 srcNode: {srcKey}, 24 destNode: {destKey}, 25 } 26 txID := cluster.idGenerator.NextID() 27 txIDStr := strconv.FormatInt(txID, 10) 28 // prepare rename from 29 srcPrepareResp := cluster.relayPrepare(srcNode, c, makeArgs("Prepare", txIDStr, "RenameFrom", srcKey)) 30 if protocol.IsErrorReply(srcPrepareResp) { 31 // rollback src node 32 requestRollback(cluster, c, txID, map[string][]string{srcNode: {srcKey}}) 33 return srcPrepareResp 34 } 35 srcPrepareMBR, ok := srcPrepareResp.(*protocol.MultiBulkReply) 36 if !ok || len(srcPrepareMBR.Args) < 2 { 37 requestRollback(cluster, c, txID, map[string][]string{srcNode: {srcKey}}) 38 return protocol.MakeErrReply("ERR invalid prepare response") 39 } 40 // prepare rename to 41 destPrepareResp := cluster.relayPrepare(destNode, c, utils.ToCmdLine3("Prepare", []byte(txIDStr), 42 []byte("RenameTo"), []byte(destKey), srcPrepareMBR.Args[0], srcPrepareMBR.Args[1])) 43 if protocol.IsErrorReply(destPrepareResp) { 44 // rollback src node 45 requestRollback(cluster, c, txID, groupMap) 46 return destPrepareResp 47 } 48 if _, errReply := requestCommit(cluster, c, txID, groupMap); errReply != nil { 49 requestRollback(cluster, c, txID, groupMap) 50 return errReply 51 } 52 return protocol.MakeOkReply() 53 } 54 55 // prepareRenameFrom is prepare-function for RenameFrom, see prepareFuncMap 56 func prepareRenameFrom(cluster *Cluster, conn redis.Connection, cmdLine CmdLine) redis.Reply { 57 if len(cmdLine) != 2 { 58 return protocol.MakeArgNumErrReply("RenameFrom") 59 } 60 key := string(cmdLine[1]) 61 existResp := cluster.db.ExecWithLock(conn, utils.ToCmdLine("Exists", key)) 62 if protocol.IsErrorReply(existResp) { 63 return existResp 64 } 65 existIntResp := existResp.(*protocol.IntReply) 66 if existIntResp.Code == 0 { 67 return protocol.MakeErrReply("ERR no such key") 68 } 69 return cluster.db.ExecWithLock(conn, utils.ToCmdLine2("DumpKey", key)) 70 } 71 72 func prepareRenameNxTo(cluster *Cluster, conn redis.Connection, cmdLine CmdLine) redis.Reply { 73 if len(cmdLine) != 4 { 74 return protocol.MakeArgNumErrReply("RenameNxTo") 75 } 76 key := string(cmdLine[1]) 77 existResp := cluster.db.ExecWithLock(conn, utils.ToCmdLine("Exists", key)) 78 if protocol.IsErrorReply(existResp) { 79 return existResp 80 } 81 existIntResp := existResp.(*protocol.IntReply) 82 if existIntResp.Code == 1 { 83 return protocol.MakeErrReply(keyExistsErr) 84 } 85 return protocol.MakeOkReply() 86 } 87 88 func init() { 89 registerPrepareFunc("RenameFrom", prepareRenameFrom) 90 registerPrepareFunc("RenameNxTo", prepareRenameNxTo) 91 } 92 93 // RenameNx renames a key, only if the new key does not exist. 94 // The origin and the destination must within the same node 95 func RenameNx(cluster *Cluster, c redis.Connection, args [][]byte) redis.Reply { 96 if len(args) != 3 { 97 return protocol.MakeErrReply("ERR wrong number of arguments for 'renamenx' command") 98 } 99 srcKey := string(args[1]) 100 destKey := string(args[2]) 101 srcNode := cluster.peerPicker.PickNode(srcKey) 102 destNode := cluster.peerPicker.PickNode(destKey) 103 if srcNode == destNode { 104 return cluster.relay(srcNode, c, args) 105 } 106 groupMap := map[string][]string{ 107 srcNode: {srcKey}, 108 destNode: {destKey}, 109 } 110 txID := cluster.idGenerator.NextID() 111 txIDStr := strconv.FormatInt(txID, 10) 112 // prepare rename from 113 srcPrepareResp := cluster.relayPrepare(srcNode, c, makeArgs("Prepare", txIDStr, "RenameFrom", srcKey)) 114 if protocol.IsErrorReply(srcPrepareResp) { 115 // rollback src node 116 requestRollback(cluster, c, txID, map[string][]string{srcNode: {srcKey}}) 117 return srcPrepareResp 118 } 119 srcPrepareMBR, ok := srcPrepareResp.(*protocol.MultiBulkReply) 120 if !ok || len(srcPrepareMBR.Args) < 2 { 121 requestRollback(cluster, c, txID, map[string][]string{srcNode: {srcKey}}) 122 return protocol.MakeErrReply("ERR invalid prepare response") 123 } 124 // prepare rename to 125 destPrepareResp := cluster.relayPrepare(destNode, c, utils.ToCmdLine3("Prepare", []byte(txIDStr), 126 []byte("RenameNxTo"), []byte(destKey), srcPrepareMBR.Args[0], srcPrepareMBR.Args[1])) 127 if protocol.IsErrorReply(destPrepareResp) { 128 // rollback src node 129 requestRollback(cluster, c, txID, groupMap) 130 if re := destPrepareResp.(protocol.ErrorReply); re.Error() == keyExistsErr { 131 return protocol.MakeIntReply(0) 132 } 133 return destPrepareResp 134 } 135 if _, errReply := requestCommit(cluster, c, txID, groupMap); errReply != nil { 136 requestRollback(cluster, c, txID, groupMap) 137 return errReply 138 } 139 return protocol.MakeIntReply(1) 140 }