// Author: simon (ynwdlxm@163.com) // Date: 2025/9/15 18:04 // Desc: Redis 数据库核心实现 package database import ( "strings" "github.com/runningwater/go-redis/datastruct/dict" "github.com/runningwater/go-redis/interface/database" "github.com/runningwater/go-redis/interface/resp" "github.com/runningwater/go-redis/resp/reply" ) // DB 表示一个 Redis 数据库实例(Database 里面的 dbSet) type DB struct { index int // 数据库索引 data dict.Dict // 存储键值对的数据结构 addAof func(CmdLine) // 添加AOF记录的函数指针 } // ExecFunc 定义命令执行函数的类型 // 参数: // - db: 数据库实例 // - args: 命令参数列表(不包括命令名称) // // 返回值: // - resp.Reply: 命令执行结果的回复 type ExecFunc func(db *DB, args [][]byte) resp.Reply // CmdLine 定义命令行类型,是字节切片的切片 type CmdLine = [][]byte // NewDB 创建一个新的数据库实例 // 返回值: // - *DB: 新创建的数据库实例 func NewDB() *DB { return &DB{ data: dict.NewSyncDict(), addAof: func(cmd CmdLine) {}, // 默认的添加AOF记录函数 } } // Exec 执行一个redis命令 // 参数: // - c: 客户端连接对象,表示发送命令的客户端连接 // - cmdLine: 命令行参数,包含命令名称和所有参数的字节切片 // // 返回值: // - resp.Reply: 命令执行结果的回复 func (d *DB) Exec(c resp.Connection, cmdLine CmdLine) resp.Reply { // 检查命令行参数是否为空 if len(cmdLine) == 0 { return reply.NewErrReply("empty command") } // 获取命令名称并转换为小写 cmdName := strings.ToLower(string(cmdLine[0])) // 查找命令 cmd, ok := cmdTable[cmdName] if !ok { return reply.NewUnknownErrReply(cmdName) } // 参数校验 if !validateArity(cmd.arity, cmdLine) { return reply.NewArgNumErrReply(cmdName) } if cmd.executor == nil { return reply.NewErrReply("command not implement") } return cmd.executor(d, cmdLine[1:]) } // validateArity 验证命令参数数量是否正确 // 参数: // - arity: 命令期望的参数数量 // - 正数表示精确匹配该数量 // - 负数表示至少需要 -arity 个参数 // - args: 实际传入的参数列表 // // 返回值: // - bool: 参数数量是否符合要求 func validateArity(arity int, args [][]byte) bool { if arity >= 0 { return arity == len(args) } // 变长的 arity 设置为 负的最小个数 return len(args) >= -arity } // GetEntity 根据键获取数据实体 // 参数: // - key: 要获取的键 // // 返回值: // - *database.DataEntity: 键对应的数据实体 // - bool: 键是否存在 func (d *DB) GetEntity(key string) (*database.DataEntity, bool) { raw, ok := d.data.Get(key) if !ok { return nil, false } entity, _ := raw.(*database.DataEntity) return entity, true } // PutEntity 插入或更新键值对 // 参数: // - key: 键 // - entity: 数据实体 // // 返回值: // - int: 操作结果,1表示新增,0表示更新 func (d *DB) PutEntity(key string, entity *database.DataEntity) int { return d.data.Put(key, entity) } // PuIfExists 当键存在时才更新键值对 // 参数: // - key: 键 // - entity: 数据实体 // // 返回值: // - int: 操作结果,1表示更新成功,0表示键不存在未更新 func (d *DB) PuIfExists(key string, entity *database.DataEntity) int { return d.data.PutIfExists(key, entity) } // PutIfAbsent 当键不存在时才插入键值对 // 参数: // - key: 键 // - entity: 数据实体 // // 返回值: // - int: 操作结果,1表示插入成功,0表示键已存在未插入 func (d *DB) PutIfAbsent(key string, entity *database.DataEntity) int { return d.data.PutIfAbsent(key, entity) } // Remove 根据键删除键值对 // 参数: // - key: 要删除的键 // // 返回值: // - int: 操作结果,1表示删除成功,0表示键不存在 func (d *DB) Remove(key string) int { return d.data.Remove(key) } // Removes 批量删除多个键 // 参数: // - keys: 要删除的键列表 // // 返回值: // - deleted: 成功删除的键数量 func (d *DB) Removes(keys ...string) (deleted int) { deleted = 0 for _, key := range keys { // 使用Remove方法的返回值判断是否删除成功,避免两次查找 if d.data.Remove(key) > 0 { deleted++ } } return deleted } // Flush 清空数据库中的所有键值对 func (d *DB) Flush() { d.data.Clear() }