github.com/hdt3213/godis@v1.2.9/database/cluster_helper.go (about) 1 package database 2 3 import ( 4 "github.com/hdt3213/godis/aof" 5 "github.com/hdt3213/godis/interface/redis" 6 "github.com/hdt3213/godis/redis/parser" 7 "github.com/hdt3213/godis/redis/protocol" 8 ) 9 10 // execExistIn returns existing key in given keys 11 // example: ExistIn key1 key2 key3..., returns [key1, key2] 12 // custom command for MSetNX tcc transaction 13 func execExistIn(db *DB, args [][]byte) redis.Reply { 14 var result [][]byte 15 for _, arg := range args { 16 key := string(arg) 17 _, exists := db.GetEntity(key) 18 if exists { 19 result = append(result, []byte(key)) 20 } 21 } 22 if len(result) == 0 { 23 return protocol.MakeEmptyMultiBulkReply() 24 } 25 return protocol.MakeMultiBulkReply(result) 26 } 27 28 // execDumpKey returns redis serialization protocol data of given key (see aof.EntityToCmd) 29 func execDumpKey(db *DB, args [][]byte) redis.Reply { 30 key := string(args[0]) 31 entity, ok := db.GetEntity(key) 32 if !ok { 33 return protocol.MakeEmptyMultiBulkReply() 34 } 35 dumpCmd := aof.EntityToCmd(key, entity) 36 ttlCmd := toTTLCmd(db, key) 37 resp := protocol.MakeMultiBulkReply([][]byte{ 38 dumpCmd.ToBytes(), 39 ttlCmd.ToBytes(), 40 }) 41 return resp 42 } 43 44 // execRenameFrom is exactly same as execDel, used for cluster.Rename 45 func execRenameFrom(db *DB, args [][]byte) redis.Reply { 46 key := string(args[0]) 47 db.Remove(key) 48 return protocol.MakeOkReply() 49 } 50 51 // execRenameTo accepts result of execDumpKey and load the dumped key 52 // args format: key dumpCmd ttlCmd 53 // execRenameTo may be partially successful, do not use it without transaction 54 func execRenameTo(db *DB, args [][]byte) redis.Reply { 55 key := args[0] 56 dumpRawCmd, err := parser.ParseOne(args[1]) 57 if err != nil { 58 return protocol.MakeErrReply("illegal dump cmd: " + err.Error()) 59 } 60 dumpCmd, ok := dumpRawCmd.(*protocol.MultiBulkReply) 61 if !ok { 62 return protocol.MakeErrReply("dump cmd is not multi bulk reply") 63 } 64 dumpCmd.Args[1] = key // change key 65 ttlRawCmd, err := parser.ParseOne(args[2]) 66 if err != nil { 67 return protocol.MakeErrReply("illegal ttl cmd: " + err.Error()) 68 } 69 ttlCmd, ok := ttlRawCmd.(*protocol.MultiBulkReply) 70 if !ok { 71 return protocol.MakeErrReply("ttl cmd is not multi bulk reply") 72 } 73 ttlCmd.Args[1] = key 74 db.Remove(string(key)) 75 dumpResult := db.execWithLock(dumpCmd.Args) 76 if protocol.IsErrorReply(dumpResult) { 77 return dumpResult 78 } 79 ttlResult := db.execWithLock(ttlCmd.Args) 80 if protocol.IsErrorReply(ttlResult) { 81 return ttlResult 82 } 83 return protocol.MakeOkReply() 84 } 85 86 // execRenameNxTo is exactly same as execRenameTo, used for cluster.RenameNx, not exists check in cluster.prepareRenameNxTo 87 func execRenameNxTo(db *DB, args [][]byte) redis.Reply { 88 return execRenameTo(db, args) 89 } 90 91 // execCopyFrom just reply "OK" message, used for cluster.Copy 92 func execCopyFrom(db *DB, args [][]byte) redis.Reply { 93 return protocol.MakeOkReply() 94 } 95 96 // execCopyTo accepts result of execDumpKey and load the dumped key 97 // args format: key dumpCmd ttlCmd 98 // execCopyTo may be partially successful, do not use it without transaction 99 func execCopyTo(db *DB, args [][]byte) redis.Reply { 100 key := args[0] 101 dumpRawCmd, err := parser.ParseOne(args[1]) 102 if err != nil { 103 return protocol.MakeErrReply("illegal dump cmd: " + err.Error()) 104 } 105 dumpCmd, ok := dumpRawCmd.(*protocol.MultiBulkReply) 106 if !ok { 107 return protocol.MakeErrReply("dump cmd is not multi bulk reply") 108 } 109 dumpCmd.Args[1] = key // change key 110 ttlRawCmd, err := parser.ParseOne(args[2]) 111 if err != nil { 112 return protocol.MakeErrReply("illegal ttl cmd: " + err.Error()) 113 } 114 ttlCmd, ok := ttlRawCmd.(*protocol.MultiBulkReply) 115 if !ok { 116 return protocol.MakeErrReply("ttl cmd is not multi bulk reply") 117 } 118 ttlCmd.Args[1] = key 119 db.Remove(string(key)) 120 dumpResult := db.execWithLock(dumpCmd.Args) 121 if protocol.IsErrorReply(dumpResult) { 122 return dumpResult 123 } 124 ttlResult := db.execWithLock(ttlCmd.Args) 125 if protocol.IsErrorReply(ttlResult) { 126 return ttlResult 127 } 128 return protocol.MakeOkReply() 129 } 130 131 func init() { 132 registerCommand("DumpKey", execDumpKey, writeAllKeys, undoDel, 2, flagReadOnly) 133 registerCommand("ExistIn", execExistIn, readAllKeys, nil, -1, flagReadOnly) 134 registerCommand("RenameFrom", execRenameFrom, readFirstKey, nil, 2, flagWrite) 135 registerCommand("RenameTo", execRenameTo, writeFirstKey, rollbackFirstKey, 4, flagWrite) 136 registerCommand("RenameNxTo", execRenameTo, writeFirstKey, rollbackFirstKey, 4, flagWrite) 137 registerCommand("CopyFrom", execCopyFrom, readFirstKey, nil, 2, flagReadOnly) 138 registerCommand("CopyTo", execCopyTo, writeFirstKey, rollbackFirstKey, 5, flagWrite) 139 }