MongoDB 源码学习:Command 的执行与注册
简介
上一篇介绍了 CommandOpRunner,接下来会讲一下 ExecCommandDatabase 的执行流程,以及 Command 是如何注册到 MongoDB 中。
Command 与 Invocation
Command
主要文件在 src/mongo/db/commands.h
中,下来我们看下 Command 的结构
Invocation
作为 Command 的内部类,其主要的是 typedRun 方法,处理了主要的执行命令的逻辑,并且返回 Reply。
ExecCommandDatabase
上一篇 OpRunner 的时候讲到,在 CommandOpRunner::executeCommand 的时候,会做以下几个步骤:
初始化 ExecCommandDatabase,初始化的时候会执行执行 ExecCommandDatabase::_parseCommand
执行 ExecCommandDatabase::_initiateCommand
执行 ExecCommandDatabase::_commandExec
_parseCommand
这一步骤的主要逻辑是调用 Command 的 parse 方法,根据 request 生成 Invocation。见下面伪代码
_initiateCommand
这里会处理几个事情:
统计命令执行时间、客户端连接数等
设置 tracking
初步处理命令,例如 help 命令、设置超时时间等
调用_invocation->checkAuthorization 校验权限
检查命令是否可以执行,例如调用 commandCanRunHere 检查,调用 command->adminOnly()检查、事务的情况下检查 ReadConcern 等
事务的情况下需要加锁
_commandExec
这一步比较简单:
等待 ReadConcern,以及发生 ReadConcern 的时候的处理
如果是 GetMore 操作,调用 RunCommandAndWaitForWriteConcern::run,否则调用 RunCommandImpl::run(没有,又要看另外的实现了 T_T)
从代码可以看到,当支持 WriteConcern 并且是 GetMore 操作的时候,会使用 RunCommandAndWaitForWriteConcern::run,除此之外都是 RunCommandImpl::run
RunCommandImpl
先来看看 RunCommandImpl 的 run 方法,会先后调用两个方法:
_prologue 记录 ReadConcern 的信息(应该是统计用吧)
_runImpl 调用 RunCommandImpl::_runCommand 执行命令,然后这里又区分了两种情况(没错,真的很复杂)
CheckoutSessionAndInvokeCommand::run 需要检查 session 的时候调用
其余情况调用 InvokeCommand::run
CheckoutSessionAndInvokeCommand::run
和InvokeCommand::run
的区别是 CheckoutSessionAndInvokeCommand 会调用_checkOutSession,两者最后都是调用 runCommandInvocation 方法,通过 CommandHelpers::runCommandInvocation 最终调用invocation->run
RunCommandAndWaitForWriteConcern
接下来看下 RunCommandAndWaitForWriteConcern,看名字就是执行命令并且等到 WriteConcern。看下其定义
没错,它是继承自 RunCommandImpl 的,与 RunCommandImpl 的主要不同在于覆盖了_runImpl,在调用 RunCommandImpl::_runCommand 之后进行了以下操作
总结一下
因为是逻辑有点多,所以加个流程图帮助大家捋一捋(只展示了主要的逻辑)
命令注册
这里会看一下 Command 是怎样注册到 MongoDB 中的。首先要知道通过代码构建 MongoDB 需要执行执行python3 buildscripts/scons.py install-mongod
,这个过程会执行 buildscripts 中的脚本。
根据 IDL 生成 VersionGen 文件
IDL
我们先来看看创建 collection 的命令 CmdCreate 对应的 idl 文件src/mongo/db/commands/create.idl
伪代码
这里描述了 CmdCreate 的基本信息。
根据 IDL 生成文件
在 buildscripts 有一个目录 idl,这里负责根据 src 中的 idl 生成文件。其中主要看buildscripts/idl/idl/generator.py
文件,其中有一段逻辑
结合上面的 IDL 例子,可以看到意思就是遍历 commands 数据,调用 generate_versioned_command_base_class 生成 Command 相关文件。同样以 CmdCreate 为例子,大概会生成这几个对象。
然后我们的 CmdCreate 是长这个样子的
命令注册
知道如何通过 IDL 生成命令相关文件,那么这个 Command 又是如何注册的咧?接下来我们要看看src/mongo/db/commands/commands.h
和src/mongo/db/commands/commands.cpp
看到这里应该就了解了吧。
to be continue
版权声明: 本文为 InfoQ 作者【云里有只猫】的原创文章。
原文链接:【http://xie.infoq.cn/article/4c93661de282e217e0c6c987f】。文章转载请联系作者。
评论