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  }