mirror of
https://github.com/HDT3213/godis.git
synced 2025-09-27 21:22:22 +08:00
104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package database
|
|
|
|
import (
|
|
"github.com/hdt3213/godis/interface/redis"
|
|
"github.com/hdt3213/godis/redis/protocol"
|
|
"strings"
|
|
)
|
|
|
|
var cmdTable = make(map[string]*command)
|
|
|
|
type command struct {
|
|
name string
|
|
executor ExecFunc
|
|
// prepare returns related keys command
|
|
prepare PreFunc
|
|
// undo generates undo-log before command actually executed, in case the command needs to be rolled back
|
|
undo UndoFunc
|
|
// arity means allowed number of cmdArgs, arity < 0 means len(args) >= -arity.
|
|
// for example: the arity of `get` is 2, `mget` is -2
|
|
arity int
|
|
flags int
|
|
extra *commandExtra
|
|
}
|
|
|
|
type commandExtra struct {
|
|
signs []string
|
|
firstKey int
|
|
lastKey int
|
|
keyStep int
|
|
}
|
|
|
|
const flagWrite = 0
|
|
|
|
const (
|
|
flagReadOnly = 1 << iota
|
|
flagSpecial // command invoked in Exec
|
|
)
|
|
|
|
// registerCommand registers a normal command, which only read or modify a limited number of keys
|
|
func registerCommand(name string, executor ExecFunc, prepare PreFunc, rollback UndoFunc, arity int, flags int) *command {
|
|
name = strings.ToLower(name)
|
|
cmd := &command{
|
|
name: name,
|
|
executor: executor,
|
|
prepare: prepare,
|
|
undo: rollback,
|
|
arity: arity,
|
|
flags: flags,
|
|
}
|
|
cmdTable[name] = cmd
|
|
return cmd
|
|
}
|
|
|
|
// registerSpecialCommand registers a special command, such as publish, select, keys, flushAll
|
|
func registerSpecialCommand(name string, arity int, flags int) *command {
|
|
name = strings.ToLower(name)
|
|
flags |= flagSpecial
|
|
cmd := &command{
|
|
name: name,
|
|
arity: arity,
|
|
flags: flags,
|
|
}
|
|
cmdTable[name] = cmd
|
|
return cmd
|
|
}
|
|
|
|
func isReadOnlyCommand(name string) bool {
|
|
name = strings.ToLower(name)
|
|
cmd := cmdTable[name]
|
|
if cmd == nil {
|
|
return false
|
|
}
|
|
return cmd.flags&flagReadOnly > 0
|
|
}
|
|
|
|
func (cmd *command) toDescReply() redis.Reply {
|
|
args := make([]redis.Reply, 0, 6)
|
|
args = append(args,
|
|
protocol.MakeBulkReply([]byte(cmd.name)),
|
|
protocol.MakeIntReply(int64(cmd.arity)))
|
|
if cmd.extra != nil {
|
|
signs := make([][]byte, len(cmd.extra.signs))
|
|
for i, v := range cmd.extra.signs {
|
|
signs[i] = []byte(v)
|
|
}
|
|
args = append(args,
|
|
protocol.MakeMultiBulkReply(signs),
|
|
protocol.MakeIntReply(int64(cmd.extra.firstKey)),
|
|
protocol.MakeIntReply(int64(cmd.extra.lastKey)),
|
|
protocol.MakeIntReply(int64(cmd.extra.keyStep)),
|
|
)
|
|
}
|
|
return protocol.MakeMultiRawReply(args)
|
|
}
|
|
|
|
func (cmd *command) attachCommandExtra(signs []string, firstKey int, lastKey int, keyStep int) {
|
|
cmd.extra = &commandExtra{
|
|
signs: signs,
|
|
firstKey: firstKey,
|
|
lastKey: lastKey,
|
|
keyStep: keyStep,
|
|
}
|
|
}
|