背景
我们希望通过阅读 Pika 的源码来熟悉 Pika 接收到一个命令时怎么进行处理的
Pika执行命令流程
src/pika_client_conn.cc
Pika 执行命令的流程从 PikaClientConn::Docmd 这个函数开始,这个函数的三个参数 argv 里面存命令的参数,是一个 vector,比如一条 set 命令(examlpe:argv[0] 为 set,argv[1] 为 key,argv[2] 为 value),第二个参数 opt 为命令名称,第三个参数 resp_ptr 是一个指向 string(reply) 的指针,这里的 g_pika_cmd_table_manager->GetCmd(opt) 函数查询 Cmd 中是否有存在的命令,如果没有则 return,对于返回值不为空的 c_ptr,我们会执行 SetConn 和 SetResp 操作,给 conn_ 和 resp_ptr 初始化.
这里的 c_ptr->Inital 是对命令进行初始化操作,各个命令覆写了 Cmd 的 Initial,以 Get 命令为例,执行 DoInitial一般是对命令传进来的参数数量判断是否合理.接下来的 UpdageQueryNumAndExecCountDB 是对 Qps 等信息进行统计.
c_ptr->Executer() 是执行命令的函数,下面我们可以看下这个函数里面的具体逻辑
src/pika_command.cc
在 Execute 函数里面有几层逻辑,我们以 Del 命令举例,我们会走到最后一层逻辑,这里是根据 cmd 名字来走不同的逻辑,接着我们继续看下 ProcessSingleSlotCmd() 这个函数.
在 ProcessSingleSlotCmd 里面,通过 GetSlotByDBName和GetSyncMasterSlotByname 获取 slot 和sync_slot,然后执行 ProcessCommand
我们以 Del 命令为例,会走到 InternalProcessCommand 这层逻辑.
在 InternalProcessCommand 里面,通过加锁 record_lock 防止多并发情况下对同一个 key 进行写请求,即单线程安全.程序首先执行 DoCommand,DoCommand 中有个 Do(slot) 函数,每个子命令覆写了 Do 函数,对于写操作的命令,我们会执行 DoBinlog。以下我以 Del 命令为例讲解:
src/pika_kv.cc
每个命令都有自己的 Do 方法,这里的是 Del 命令为例的执行情况,我们可以继续往下看看这个 Del 指令的具体执行逻辑
可以看到这里就是存储引擎 Storage(Blackwidow) 的处理流程,对于 del 命令,对 5 种数据结构下的某一个 key进行删除并计数最终返回一个 count.这里我们可以继续对某一个数据结构比如 string 来看具体这个 Del 做了什么操作. 图中的 string_db_ 是 std::unique_ptr<Redisstrings>
类型。
这里我们可以看到,首先我们会先 Get 一下这个 key 看是否存在,如果存在我们继续执行if里面的逻辑,我们可以继续看下 ParsedStringsValue 这层逻辑
可以发现这里的 internal_value_str 就是数据库里面要删除的那个 Key 对应的 value,这里是对过期时间进行了设置,我们对 db_->Delete 继续往下看
pika/deps/include/rocksdb/db.h
这里就是调用 RocksDB 层的函数 Delete 了
src/pika_command.cc
看完命令执行后我们继续看下 DoBinlog 这个函数
这里会判断是否是写命令,如果是的话,则进行 DoBinlog 操作,可以看到这个 DoBinlog 是父类方法为子类用