mongodb查询处理流程

MyMessageHandler
用于处理客户端的发送的请求消息,如CRUD操作,db命令等.
process函数是入口函数,函数主要执行做三件事
1 生成执行的上下文环境OperationContext
2 在1)的上下文环境上,处理这个请求消息
3 应答消息
生成执行环境
globalServiceContext
这是一个ServiceContext类型的 全局变量,ServiceContext是一个抽象类,有几种类型的子类 ServiceContextMongoD,ServiceContextNoop类,这里我们用到的是ServiceContextMongoD类.此 类用于初始化mongod的一些全局环境,
1 包括初始化存储引擎,因为monogdb支持多存储引擎,所以这里会初始化当前支持的存储引擎
2 为每个客户端生成执行上下文OperationContext
OperationContext
这是一个操作的执行上下文,每个客户端连接Client在执行一个操作的时候,都会生成一个上下文,OperationContext是一个基类,这里会创建一个OperationContextImpl类型的子类.这个类的主要作用有
1 关联当前客户端
2 获取一个新的操作Id
3 通过globalServiceContext得到当前使用的存储引擎
4 根据存储引擎类型,初始化成员变量_recovery,_recovery是RecoveryUnit类型的抽象类,这对应的子类是WiredTigerRecoveryUnit类型.
5 将当前客户端Client的执行上下文设置为自己
RecoveryUnit
这个类是负责将数据持久化,个人理解,所有对数据修改的操作,都将保存到这个类里面,最终一并提交或者回滚.WiredTigerRecoveryUnit类型是针对wiredtiger存储引擎的,主要封装了
1 存储引擎的session分配
2 接收所以这个操作相关的数据变更
3 开始一次事务
4 提交或者回滚一次事务
处理本次请求
assembleResponse
assembleResponse函数是处理本次请求的入口,这里处理所有类型的请求,我们以查询为例进行说明,它的处理流程
1 解析请求类型
2 记录操作日志
3 递增本次操作类型的数量
4 进入receivedCommand处理函数
receivedCommand
处理command类型的消息
1 初始化CurOp的一些成员对象
2 进入runCommands函数
runCommands
根据request消息类型查询这个command的类型,然后执行这个command.
1 调用Command::findCommand查找这个Command类型,实例化这个Command,Command也是一个基类,子类在初始化的时 候,会把command的名字写到Command的_commands成员变量里面,这是个静态变量.如果没有找到command则报错返回,否则返回这 个command类型,我们这里返回FindCmd类型.
2 然后调用Command::execCommand函数去执行FindCmd命令.
Command::execCommand
1 首先调用_checkAuthorization做了些权限校验工作.
2 如果是副本集,要校验发送的消息是否能在对应实例上执行,实例状态要正确,master才能写,slaveOK才能读等.
3 调用FindCmd的run方法
FindCmd::run
1 通过LiteParsedQuery类解析所有语法关键字.
2 通过MatchExpressionParser类的_parse函数解析LiteParsedQuery的filter成员,filter语法上可以形成树结构,所以最终解析出的表达式将会形成表达式树,每个节点是不同的表达式类型.
3 通过CanonicalQuery类的canonicalize函数进一步优化表达式树.
4 通过getExecutorFind函数,得到PlanExecutor.
5 循环调用PlanExecutor的getNext函数获得查询结果.
6 当取得的结果集满足一次返回的数量,将退出循环.
7 如果有剩下的记录还没有取完,则保存游标cursorId,后续会调用getMore记录遍历游标.
8 返回结果集合和cursorId.
getExecutorFind
根据CanonicalQuery得到的表达式树,调用getExecutor得到最终的PlanExecutor
1 调用prepareExecution函数通过CanonicalQuery类得到的表达式树得到大于等于一个查询计划和
2 调用PlanExecutor::make选择最有的PlanExecutor
prepareExecution
用于生成执行QuerySolution和PlanStage.
1 调用QueryPlanner::plan生成查询计划,这将会生成一个或者多个查询计划QuerySolution.
2 调用StageBuilder::build函数,根据查询计划生成计划阶段PlanStage,每个查询计划对应一个计划阶段.
PlanExecutor::make
它初始化PlanExecutor类型,并且调用pickBestPlan选取最优的Plan.里面包含了很多不同类型的PlanStage
PlanExecutor::getNext
PlanExecutor的getNext函数里面调用getNextImpl函数,getNextImpl里面调用了PlanStage的work函数.
CollectionScan::work
我们以如下explain为例,来说明PlanStage的工作.
mgset-4049517113:PRIMARY> db.test.find({item:"card"}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.test",
"indexFilterSet" : false,
"parsedQuery" : {
"item" : {
"$eq" : "card"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"item" : {
"$eq" : "card"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "127.0.0.1",
"port" : 27017,
"version" : "3.2.9",
"gitVersion" : "22ec9e93b40c85fc7cae7d56e7d6a02fd811088c"
},
"ok" : 1
}
1 首先需要初始化CollectionScan的游标_cursor成员变量
2 _cursor是调用Collection的getCursor函数得到的游标
3 然后调用_cursor的seekExact函数得到一条记录,将记录的_id字段记录到_lastSeenId成员变量,以便下次从这个记录之后取值,对于wiredtiger引擎直接调用_cursor->next()获取下一个值.
4 在WorkingSet集合中找到一个可用的位置来存放这条记录,WorkingSetMember的loc字段为记录的id字段,obj字段记录的bson文档,_state字段这里设置为WorkingSetMember::LOC_AND_OBJ.
5 最后调用returnIfMatches,查看这条全表扫描的记录是否符合我们的CollectionScan这个PlanStage的filter.如果符合则返回给PlanExecutor的getNext函数,否则继续往后遍历.
WorkingSet
工作集是用来保存从存储引擎返回的结 果,WorkingSet会保存一次查询的所有PlanStage的结果.它有一个数组成员_data,这个数组用于形成一个链表结构,每个节点是 MemberHolder类型用于保存一条记录和链表的下一个节点的位置,记录将被做一些调整存放在WorkingSetMember类型中.在一次查询 过程中需要很多次的申请与释放MemberHolder,在释放的时候,它将被放在空闲链表里面,备后续使用.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值