閱讀574 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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,在釋放的時候,它將被放在空閑鏈表裏麵,備後續使用.

最後更新:2017-09-22 16:04:11

  上一篇:go  錯過至少等一年!阿裏雲西南服務支持中心20+職位虛席以待,來吧,成就最好的自己!
  下一篇:go  道旅鬼穀子分享:如何打好業務監控的組合拳