diff --git a/README.md b/README.md index 3efcbc4..9f4599c 100644 --- a/README.md +++ b/README.md @@ -142,8 +142,8 @@ I suggest focusing on the following directories: - set: a hash set based on map - sortedset: a sorted set implements based on skiplist - database: the core of storage engine - - server.go: a standalone redis server, with multiple database - - db.go: data structure and base functions of single database + - database.go: a standalone redis server, with multiple database + - single_db.go: data structure and base functions of single database - exec.go: the gateway of database - router.go: the command table - keys.go: handlers for keys commands diff --git a/README_CN.md b/README_CN.md index f7956e5..4feda44 100644 --- a/README_CN.md +++ b/README_CN.md @@ -132,7 +132,8 @@ MSET (10 keys): 65487.89 requests per second - set: 基于hash表的集合 - sortedset: 基于跳表实现的有序集合 - database: 存储引擎核心 - - db.go: 单个 database 的数据结构和基本功能 + - database.go: 支持多数据库的单机版 redis 服务实例 + - single_db.go: 单个 database 的数据结构和基本功能 - router.go: 将命令路由给响应的处理函数 - keys.go: del、ttl、expire 等通用命令实现 - string.go: get、set 等字符串命令实现 diff --git a/database/server.go b/database/database.go similarity index 98% rename from database/server.go rename to database/database.go index cf17be8..8936f68 100644 --- a/database/server.go +++ b/database/database.go @@ -87,8 +87,7 @@ func (mdb *MultiDB) Exec(c redis.Connection, cmdLine [][]byte) (result redis.Rep return protocol.MakeErrReply("NOAUTH Authentication required") } - // todo: merge special commands into router - // special commands + // special commands which cannot execute within transaction if cmdName == "subscribe" { if len(cmdLine) < 2 { return protocol.MakeArgNumErrReply("subscribe") diff --git a/database/keys.go b/database/keys.go index d739224..344e2bd 100644 --- a/database/keys.go +++ b/database/keys.go @@ -321,6 +321,5 @@ func init() { RegisterCommand("Type", execType, readFirstKey, nil, 2) RegisterCommand("Rename", execRename, prepareRename, undoRename, 3) RegisterCommand("RenameNx", execRenameNx, prepareRename, undoRename, 3) - RegisterCommand("FlushDB", execFlushDB, noPrepare, nil, -1) RegisterCommand("Keys", execKeys, noPrepare, nil, 2) } diff --git a/database/db.go b/database/single_db.go similarity index 90% rename from database/db.go rename to database/single_db.go index 588b63a..d4c600a 100644 --- a/database/db.go +++ b/database/single_db.go @@ -80,6 +80,7 @@ func makeBasicDB() *DB { // Exec executes command within one database func (db *DB) Exec(c redis.Connection, cmdLine [][]byte) redis.Reply { + // transaction control commands and other commands which cannot execute within transaction cmdName := strings.ToLower(string(cmdLine[0])) if cmdName == "multi" { if len(cmdLine) != 1 { @@ -101,6 +102,14 @@ func (db *DB) Exec(c redis.Connection, cmdLine [][]byte) redis.Reply { return protocol.MakeArgNumErrReply(cmdName) } return Watch(db, c, cmdLine[1:]) + } else if cmdName == "flushdb" { + if !validateArity(1, cmdLine) { + return protocol.MakeArgNumErrReply(cmdName) + } + if c.InMultiState() { + return protocol.MakeErrReply("ERR command 'FlushDB' cannot be used in MULTI") + } + return execFlushDB(db, cmdLine[1:]) } if c != nil && c.InMultiState() { EnqueueCmd(c, cmdLine) @@ -129,6 +138,20 @@ func (db *DB) execNormalCommand(cmdLine [][]byte) redis.Reply { return fun(db, cmdLine[1:]) } +// execWithLock executes normal commands, invoker should provide locks +func (db *DB) execWithLock(cmdLine [][]byte) redis.Reply { + cmdName := strings.ToLower(string(cmdLine[0])) + cmd, ok := cmdTable[cmdName] + if !ok { + return protocol.MakeErrReply("ERR unknown command '" + cmdName + "'") + } + if !validateArity(cmd.arity, cmdLine) { + return protocol.MakeArgNumErrReply(cmdName) + } + fun := cmd.executor + return fun(db, cmdLine[1:]) +} + func validateArity(arity int, cmdArgs [][]byte) bool { argNum := len(cmdArgs) if arity >= 0 { diff --git a/database/transaction.go b/database/transaction.go index 520f9c6..788c66e 100644 --- a/database/transaction.go +++ b/database/transaction.go @@ -164,20 +164,6 @@ func (db *DB) GetUndoLogs(cmdLine [][]byte) []CmdLine { return undo(db, cmdLine[1:]) } -// execWithLock executes normal commands, invoker should provide locks -func (db *DB) execWithLock(cmdLine [][]byte) redis.Reply { - cmdName := strings.ToLower(string(cmdLine[0])) - cmd, ok := cmdTable[cmdName] - if !ok { - return protocol.MakeErrReply("ERR unknown command '" + cmdName + "'") - } - if !validateArity(cmd.arity, cmdLine) { - return protocol.MakeArgNumErrReply(cmdName) - } - fun := cmd.executor - return fun(db, cmdLine[1:]) -} - // GetRelatedKeys analysis related keys func GetRelatedKeys(cmdLine [][]byte) ([]string, []string) { cmdName := strings.ToLower(string(cmdLine[0]))