github.com/hdt3213/godis@v1.2.9/database/router.go (about) 1 package database 2 3 import ( 4 "github.com/hdt3213/godis/interface/redis" 5 "github.com/hdt3213/godis/redis/protocol" 6 "strings" 7 ) 8 9 var cmdTable = make(map[string]*command) 10 11 type command struct { 12 name string 13 executor ExecFunc 14 // prepare returns related keys command 15 prepare PreFunc 16 // undo generates undo-log before command actually executed, in case the command needs to be rolled back 17 undo UndoFunc 18 // arity means allowed number of cmdArgs, arity < 0 means len(args) >= -arity. 19 // for example: the arity of `get` is 2, `mget` is -2 20 arity int 21 flags int 22 extra *commandExtra 23 } 24 25 type commandExtra struct { 26 signs []string 27 firstKey int 28 lastKey int 29 keyStep int 30 } 31 32 const flagWrite = 0 33 34 const ( 35 flagReadOnly = 1 << iota 36 flagSpecial // command invoked in Exec 37 ) 38 39 // registerCommand registers a normal command, which only read or modify a limited number of keys 40 func registerCommand(name string, executor ExecFunc, prepare PreFunc, rollback UndoFunc, arity int, flags int) *command { 41 name = strings.ToLower(name) 42 cmd := &command{ 43 name: name, 44 executor: executor, 45 prepare: prepare, 46 undo: rollback, 47 arity: arity, 48 flags: flags, 49 } 50 cmdTable[name] = cmd 51 return cmd 52 } 53 54 // registerSpecialCommand registers a special command, such as publish, select, keys, flushAll 55 func registerSpecialCommand(name string, arity int, flags int) *command { 56 name = strings.ToLower(name) 57 flags |= flagSpecial 58 cmd := &command{ 59 name: name, 60 arity: arity, 61 flags: flags, 62 } 63 cmdTable[name] = cmd 64 return cmd 65 } 66 67 func isReadOnlyCommand(name string) bool { 68 name = strings.ToLower(name) 69 cmd := cmdTable[name] 70 if cmd == nil { 71 return false 72 } 73 return cmd.flags&flagReadOnly > 0 74 } 75 76 func (cmd *command) toDescReply() redis.Reply { 77 args := make([]redis.Reply, 0, 6) 78 args = append(args, 79 protocol.MakeBulkReply([]byte(cmd.name)), 80 protocol.MakeIntReply(int64(cmd.arity))) 81 if cmd.extra != nil { 82 signs := make([][]byte, len(cmd.extra.signs)) 83 for i, v := range cmd.extra.signs { 84 signs[i] = []byte(v) 85 } 86 args = append(args, 87 protocol.MakeMultiBulkReply(signs), 88 protocol.MakeIntReply(int64(cmd.extra.firstKey)), 89 protocol.MakeIntReply(int64(cmd.extra.lastKey)), 90 protocol.MakeIntReply(int64(cmd.extra.keyStep)), 91 ) 92 } 93 return protocol.MakeMultiRawReply(args) 94 } 95 96 func (cmd *command) attachCommandExtra(signs []string, firstKey int, lastKey int, keyStep int) { 97 cmd.extra = &commandExtra{ 98 signs: signs, 99 firstKey: firstKey, 100 lastKey: lastKey, 101 keyStep: keyStep, 102 } 103 }