ArgNumErrReply(cmdName)
}
fun := cmd.executor
return fun(db, cmdLine[1:]) // 把 set k v 中的set切掉
}
// 定长:set k v => arity=3;
// 变长:exists k1 k2 k3 ... => arity=-2,表示参数>=2个
func validateArity(arity int, cmdArgs [][]byte) bool {
argNum := len(cmdArgs)
if arity >= 0 {
return argNum == arity
}
return argNum >= -arity
}
func (db *DB) GetEntity(key string) (*database.DataEntity, bool) {
raw, ok := db.data.Get(key)
if !ok {
return nil, false
}
entity, _ := raw.(*database.DataEntity)
return entity, true
}
func (db *DB) PutEntity(key string, entity *database.DataEntity) int {
return db.data.Put(key, entity)
}
func (db *DB) PutIfExists(key string, entity *database.DataEntity) int {
return db.data.PutIfExists(key, entity)
}
func (db *DB) PutIfAbsent(key string, entity *database.DataEntity) int {
return db.data.PutIfAbsent(key, entity)
}
func (db *DB) Remove(key string) {
db.data.Remove(key)
}
func (db *DB) Removes(keys ...string) (deleted int) {
deleted = 0
for _, key := range keys {
_, exists := db.data.Get(key)
if exists {
db.Remove(key)
deleted++
}
}
return deleted
}
func (db *DB) Flush() {
db.data.Clear()
}
实现Redis中的分数据库
ExecFunc:所有Redis的指令都写成这样的类型
validateArity方法:
- 定长:set k v => arity=3;
- 变长:exists k1 k2 k3 ... => arity=-2,表示参数>=2个
database/command.go
var cmdTable = make(map[string]*command)
type command struct {
executor ExecFunc
arity int
}
func RegisterCommand(name string, executor ExecFunc, arity int) {
name = strings.ToLower(name)
cmdTable[name] = &command{
executor: executor,
arity: arity,
}
}
command:每一个command结构体都是一个指令,例如ping,keys等等
arity:参数数量
cmdTable:记录所有指令和command结构体的关系
RegisterCommand:注册指令的实现,在程序
database/ping.go
func Ping(db *DB, args [][]byte) resp.Reply {
if len(args) == 0 {
return &reply.PongReply{}
} else if len(args) == 1 {
return reply.MakeStatusReply(string(args[0]))
} else {
return reply.MakeErrReply("ERR wrong number of arguments for 'ping' command")
}
}
func init() {
RegisterCommand("ping", Ping, 1)
}
init方法:在启动程序时就会调用这个方法,用于初始化
database/keys.go
// execDel:del k1 k2 k3 ...
func execDel(db *DB, args [][]byte) resp.Reply {
keys := make([]string, len(args))
for i, v := range args {
keys[i] = string(v)
}
deleted := db.Removes(keys...)
return reply.MakeIntReply(int64(deleted))
}
// execExists:exist k1 k2 k3 ...
func execExists(db *DB, args [][]byte) resp.Reply {
result := int64(0)
for _, arg := range args {
key := string(arg)
_, exists := db.GetEntity(key)
if exists {
result++
}
}
return reply.MakeIntReply(result)
}
// execFlushDB:flushdb
func execFlushDB(db *DB, args [][]byte) resp.Reply {
db.Flush()
return &reply.OkReply{}
}
// execType:type k1
func execType(db *DB, args [][]byte) resp.Reply {
key := string(args[0])
entity, exists := db.GetEntity(key)
if !exists {
return reply.MakeStatusReply("none")
}
switch entity.Data.(type) {
case []byte:
return reply.MakeStatusReply("string")
}
return &reply.UnknownErrReply{}
}
// execRename:rename k1 k2
func execRename(db *DB, args [][]byte) resp.Reply {
if len(args) != 2 {
return reply.MakeErrReply("ERR wrong number of arguments for 'rename' command")
}
src := string(args[0])
dest := string(args[1])
entity, ok := db.GetEntity(src)
if !ok {
re