standalone_database.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Author: simon (ynwdlxm@163.com)
  2. // Date: 2025/9/25 11:27
  3. // Desc: 处理 RESP-SPEC 命令
  4. package database
  5. import (
  6. "strconv"
  7. "strings"
  8. "github.com/runningwater/go-redis/aof"
  9. "github.com/runningwater/go-redis/config"
  10. "github.com/runningwater/go-redis/interface/resp"
  11. "github.com/runningwater/go-redis/lib/logger"
  12. "github.com/runningwater/go-redis/resp/reply"
  13. )
  14. // StandaloneDatabase 表示独立运行的Redis数据库实例
  15. //
  16. // 包含多个数据库以及AOF持久化处理器
  17. type StandaloneDatabase struct {
  18. dbSet []*DB // 数据库集合,每个元素代表一个独立的数据库
  19. aofHandler *aof.Handler // AOF持久化处理器,负责处理AOF相关操作
  20. }
  21. // NewStandaloneDatabase 创建并初始化一个新的独立数据库实例
  22. //
  23. // 根据配置决定数据库数量和是否启用AOF持久化
  24. func NewStandaloneDatabase() *StandaloneDatabase {
  25. // 如果未设置数据库数量,默认创建16个数据库
  26. if config.Properties.Databases == 0 {
  27. config.Properties.Databases = 16
  28. }
  29. // 创建数据库实例
  30. database := &StandaloneDatabase{}
  31. // 初始化数据库集合
  32. database.dbSet = make([]*DB, config.Properties.Databases)
  33. // 为每个数据库索引创建对应的DB实例
  34. for i := range database.dbSet {
  35. db := NewDB()
  36. db.index = i
  37. database.dbSet[i] = db
  38. }
  39. // 如果启用了AOF持久化,则初始化AOF处理器
  40. if config.Properties.AppendOnly {
  41. aofHandler, err := aof.NewAofHandler(database)
  42. if err != nil {
  43. panic(err)
  44. }
  45. database.aofHandler = aofHandler
  46. }
  47. // 为每个数据库设置AOF记录函数
  48. for _, db := range database.dbSet {
  49. d := db
  50. // addAof 函数用于向AOF日志中添加命令记录
  51. d.addAof = func(line CmdLine) {
  52. database.aofHandler.AddAof(d.index, line)
  53. }
  54. }
  55. return database
  56. }
  57. // Exec 执行客户端发送的命令
  58. //
  59. // client: 客户端连接对象
  60. // args: 命令参数列表,第一个参数为命令名称
  61. // 返回命令执行结果
  62. func (d *StandaloneDatabase) Exec(client resp.Connection, args [][]byte) resp.Reply {
  63. // 使用defer捕获可能发生的panic,防止程序崩溃
  64. defer func() {
  65. if err := recover(); err != nil {
  66. logger.Error(err)
  67. }
  68. }()
  69. // 获取命令名称并转换为小写
  70. cmdName := strings.ToLower(string(args[0]))
  71. // 处理SELECT命令 - 切换数据库
  72. if cmdName == "select" {
  73. // 检查参数数量是否正确
  74. if len(args) != 2 {
  75. return reply.NewErrReply("ERR wrong number of arguments for 'select' command")
  76. }
  77. // 执行数据库选择操作
  78. return execSelect(client, d, args[1:])
  79. } else if cmdName == "command" {
  80. // COMMAND命令返回OK
  81. return reply.NewOkReply()
  82. }
  83. // 获取客户端当前选择的数据库索引
  84. index := client.GetDBIndex()
  85. // 在对应的数据库中执行命令
  86. return d.dbSet[index].Exec(client, args)
  87. }
  88. // Close 关闭数据库连接
  89. // TODO 实现数据库关闭逻辑
  90. func (d *StandaloneDatabase) Close() {
  91. // TODO implement me
  92. }
  93. // AfterClientClose 处理客户端连接关闭后的清理工作
  94. // TODO 实现客户端关闭后的处理逻辑
  95. func (d *StandaloneDatabase) AfterClientClose(client resp.Connection) {
  96. // TODO implement me
  97. }
  98. // execSelect 处理数据库选择命令
  99. //
  100. // 参数:
  101. //
  102. // c: 客户端连接对象,用于执行数据库切换操作
  103. // database: 数据库实例,包含所有可用的数据库集合
  104. // args: 命令参数,第一个参数为要选择的数据库索引
  105. //
  106. // 返回值:
  107. //
  108. // resp.Reply: 执行结果回复,成功返回OK,失败返回错误信息
  109. func execSelect(c resp.Connection, database *StandaloneDatabase, args [][]byte) resp.Reply {
  110. // 解析数据库索引参数
  111. dbIndex, err := strconv.Atoi(string(args[0]))
  112. if err != nil {
  113. return reply.NewErrReply("ERR invalid DB index")
  114. }
  115. // 验证数据库索引范围是否有效
  116. if dbIndex >= len(database.dbSet) {
  117. return reply.NewErrReply("ERR DB index is out of range")
  118. }
  119. // 执行数据库切换操作
  120. c.SelectDB(dbIndex)
  121. return reply.NewOkReply()
  122. }