mongodb核心原始碼實現及效能優化系列:Mongodb write寫(增、刪、改)模組原始碼實現

y123456yzzyz發表於2021-03-07

Mongodb write ( 增、刪、改 ) 模組原始碼實現

前面的《transport_layer 網路傳輸層模組原始碼實現》和《 command 命令處理模組原始碼實現》詳細的分析了 mongodb 核心網路資料收發過程以及命令解析處理的整個過程,本文將繼續分析該系列的第三個子模組 - write ( 增、刪、改 ) 模組原始碼實現》。

1.  write 寫模組與 command 命令處理模組銜接回顧

 

 

上面兩圖是command 命令處理模組的大體流程,最終經過 command 模組處理後,會執行對應的命令 run 介面,本文要分析的 write 模組也將從本入口入手。增、刪、改三個最基本的寫操作對應的命令入口如下表:

操作型別

命令 Run() 入口

CmdInsert::runImpl()

CmdDelete::runImpl()

CmdUpdate::runImpl()

mongodb 核心 write 模組主要由如下目錄程式碼實現:

 

 

   下面章節將分析增刪改操作的詳細核心實現流程,注意包括請求序列化解析儲存、insert 寫入流程、 update 更新計劃執行器、 delete 刪除計劃執行器等。

2.  增、刪、改序列化解析及結構化統一儲存

本章節詳細分析增、刪、改三個操作的序列化解析及結構化統一儲存核心實現過程。

2.1 增刪改寫入操作語法及其主要含義說明

insert 插入語法及說明

insert 主要完成資料的寫入操作,其命令語法如下:

1.  {  

2.     insert: <collection>,  

3.     documents: [ <document>, <document>, <document>, ... ],  

4.     ordered: <boolean>,  

5.     writeConcern: { <write concern> },  

6.     bypassDocumentValidation: <boolean>  

7. 

insert 操作主要由五個欄位型別組成,具體欄位功能說明如下:

欄位名

功能說明

insert

集合名

documents

具體的文件內容

ordered

一次性插入多條文件資料,前面的資料寫入失敗,是否繼續後面的資料寫入

writeConcern

writeConcern 寫策略配置,寫多少個節點才算成功

bypassDocumentValidation

是否進行 validator 相關 schema 文件驗證

 

update 更新語法及說明

update 操作實現資料更新操作,其命令語法如下:

1.  {  

2.     update: <collection>,  

3.     updates: [  

4.        { q: <query>, u: <update>, upsert: <boolean>, multi: <boolean>,  

5.          collation: <document>, arrayFilters: <array> },  

6.        { q: <query>, u: <update>, upsert: <boolean>, multi: <boolean>,  

7.          collation: <document>, arrayFilters: <array> },  

8.        { q: <query>, u: <update>, upsert: <boolean>, multi: <boolean>,  

9.          collation: <document>, arrayFilters: <array> },  

10.        ...  

11.     ],  

12.     ordered: <boolean>,  

13.     writeConcern: { <write concern> },  

14.     bypassDocumentValidation: <boolean>  

15.  }  

上述語法各欄位功能說明如表:

欄位名

功能說明

update

對那個表做 update 操作

updates .q

查詢條件

updates .u

更新操作方法

updates . upsert

如果需要更新的資料不存在,是否直接插入新資料

updates . multi

query 滿足條件資料有多條,是隻更新一條還是多條一起更新

updates . collation

根據不同語言定義不同排序規則

updates . arrayFilters

陣列中成員內容跟新

ordered

一次更新多條文件資料,前面的資料更新失敗,是否繼續後面的資料更新操作

writeConcern

更新多少個節點成功才返回 OK

bypassDocumentValidation

是否進行 validator 相關 schema 文件驗證

 

delete 更新語法及說明

delete 刪除操作對應語法如下:

1.  {  

2.     delete: <collection>,  

3.     deletes: [  

4.        { q : <query>, limit : <integer>, collation: <document> },  

5.        { q : <query>, limit : <integer>, collation: <document> },  

6.        { q : <query>, limit : <integer>, collation: <document> },  

7.        ...  

8.     ],  

9.     ordered: <boolean>,  

10.     writeConcern: { <write concern> }  

11. 

如上,delete 語法各個欄位功能說明如下:

欄位名

功能說明

delete

對那個表做 delete 操作

deletes .q

需要刪除那一部分資料,也就是刪除資料的條件

deletes . limit 

刪除所有滿足條件的資料還是隻刪除一條,取值 0 1

deletes . collation

根據不同語言定義不同排序規則

ordered

刪除一批資料,如果前面某資料刪除失敗,是否還需要刪除後面滿足條件的資料

writeConcern

刪除多少個節點成功才返回 OK

 

2.2 增、刪、改序列化解析

2.2.1 增、刪、改核心資料結構

從上面的insert delete update 語法可以看出,這三個操作有一部分欄位名是一樣的,核心在程式碼實現的時候也重複利用了這一特定,把這部分成員抽象為公共類,不同的欄位則在各自操作類中封裝。

最終,三個操作的欄位資訊通過公用類WriteCommandBase 和各自私有類 Insert Update Delete 保持及解析封裝。如下圖所示:

 

公共基類由WriteCommandBase 類實現,如下:

1.  class WriteCommandBase {    

2.  public:  

3.     //基類介面  

4.     ......  

5.     //mongodb欄位驗證規則(schema validation)  

6.     bool _bypassDocumentValidation{false};  

7.     //一次對多條資料進行插入或者刪除或者更新的時候,前面的資料操作失敗,是否繼續後面的操作  

8.     bool _ordered{true};  

9.     //事務相關,等4.2版本回頭分析  

10.     boost::optional<std::vector<std::int32_t>> _stmtIds;  

11.  }  

Insert 類包含 WriteCommandBase 類成員,同時包括 Insert 操作對應的私有成員資訊,如下:

1.  class Insert {    

2.  public:  

3.      ......  

4.      //也就是db.collection  

5.      NamespaceString _nss;  

6.      //公共結構資訊  

7.      WriteCommandBase _writeCommandBase;  

8.      //真正的文件在這裡documents  

9.      std::vector<mongo::BSONObj> _documents;  

10.      //庫資訊  

11.      std::string _dbName;  

12.      //是否有documents  

13.  }  

delete 刪除操作對應 Delete 類核心成員資訊如下:

1.  class Delete {    

2.  public:  

3.      ......  

4.      //DB.COLLECTION資訊  

5.      NamespaceString _nss;  

6.      WriteCommandBase _writeCommandBase;  

7.      //具體的delete內容在這裡  

8.      std::vector<DeleteOpEntry> _deletes;  

9.  }  

update 更新操作對應的 Update 類核心成員資訊如下 :

1.  class Update {   

2.  public:  

3.        ......  

4.      //db.collection資訊,也就是庫.表資訊  

5.      NamespaceString _nss;  

6.      WriteCommandBase _writeCommandBase;  

7.      //需要更新的具體內容在該成員中     

8.      std::vector<UpdateOpEntry> _updates;  

9. 

上面的類結構中, _documents _deletes _updates 三個成員分別對應增、刪、改操作的集體操作資訊,都是陣列型別,可以一次進行多條資料操作。

2.2.2 增、刪、改解析過程

增刪改三個操作對應三個不同的類,由這三個類來完成各自操作的協議解析及封裝,整體程式碼實現大同小異,本文只分析insert 解析及封裝過程,主要程式碼實現如下 :

1.  Insert Insert::parse(const IDLParserErrorContext& ctxt, const BSONObj& bsonObject) {  

2.      ......  

3.      //呼叫Insert::parseProtected  

4.      object.parseProtected(ctxt, bsonObject);  

5.      return object;  

6.  }  

7.    

8.  void Insert::parseProtected(...)  

9.  {  

10.      //解析出insert類的對應成員資訊  

11.      for (const auto& element :request.body) {  

12.          const auto fieldName = element.fieldNameStringData();  

13.    

14.          //解析bypassDocumentValidation資訊  

15.          if (fieldName == kBypassDocumentValidationFieldName) {  

16.                ......  

17.          }  

18.          //解析ordered資訊  

19.          else if (fieldName == kOrderedFieldName) {  

20.               ......  

21.          }  

22.          //解析stmtIds資訊  

23.          else if (fieldName == kStmtIdsFieldName) {  

24.               ......  

25.          }  

26.          //解析需要插入的文件資訊  

27.          else if (fieldName == kDocumentsFieldName) {  

28.             //解析的文件保持到_documents陣列  

29.              _documents = std::move(values);  

30.          }  

31.          //解析db名  

32.          else if (fieldName == kDbNameFieldName) {  

33.              ......  

34.          }  

35.          ......  

36.      }  

37.      //從request中解析出_writeCommandBase基礎成員內容  

38.      _writeCommandBase = WriteCommandBase::parse(ctxt, request.body);  

39.    

40.      ......  

41.      //根據db+collection構造出db.collection字串  

42.      _nss = ctxt.parseNSCollectionRequired(_dbName, commandElement);  

43. 

 

insert 操作類似, update delete 操作的解析過程與 insert 流程一樣比較簡單,因此不在分析。

最終,所有解析出的資料儲存到各自類中,總結如下圖所示:

 

此外,增刪改操作的序列化封裝由write_ops_gen.cpp 中的 Insert::serialize() Update::serialize() Delete::serialize() 完成,主要根據各自類完成 Bson 統一封裝,整個實現過程比較簡單,這裡不在詳細分析。

增刪改介面解析及序列化相關幾個核心介面功能說明如下:

函式介面

功能說明

write_ops::Insert

InsertOp::parse(...)

insert 操作解析

Insert::toBSON(...)

insert Bson 序列化

write_ops::Update

UpdateOp::parse(...)

update 操作解析

Update::toBSON(...)

update Bson 序列化

write_ops::Delete

DeleteOp::parse(...)

delete 操作解析

DeleteOp::toBSON(...)

delete Bson 序列化

 

注意: insert update delete 中還有如下一個細節,為何不見 writeConcern 相關成員儲存?原因是 writeConcern 解析放到了外層 runCommandImpl 中通過 setWriteConcern() 保持到該請求對應得 opCtx 操作上下文中。

3.  Insert 資料寫操作核心實現

insert 處理和 command 命令處理模組通過 CmdInsert::runImpl() 銜接,該介面程式碼實現如下:

1.  //插入文件會走這裡面  CmdInsert::runImpl  

2.  void runImpl (... ) final {  

3.      //從request中解析出write_ops::Insert類成員資訊  

4.      const auto batch = InsertOp::parse(request);  

5.      const auto reply = performInserts(opCtx, batch);  

6.      ......  

7. 

InsertOp::parse () 在前面章節已經分析,主要完成資料的統一解析儲存。 insert 請求解析儲存到 write_ops::Insert 類後,開始呼叫 performInserts (...) 處理。在該介面中完成如下流程:分批資料組裝、批量資料寫入、事務封裝、寫入儲存引擎等。

3.1 資料分批組裝

由於inset 一次可以插入多條資料,為了最大化滿足效能要求,當寫入資料很多的時候, mongodb 核心通過把這些資料按照指定規則拆分到多個 batch 中,這樣每個 batch 代表一批資料,然後進行統一處理。分批資料組裝拆分過程核心程式碼實現如下 :

1.  //資料分批寫入核心程式碼實現  

2.  WriteResult performInserts(OperationContext* opCtx, const write_ops::Insert& wholeOp) {  

3.      .......  

4.      //寫入資料成功後的會掉處理  

5.      //主要完成表級tps及時延統計  

6.      ON_BLOCK_EXIT([&] {  

7.      //performInserts執行完成後呼叫,記錄執行結束時間   

8.          curOp.done();      

9.          //表級tps及時延統計  

10.          Top::get(opCtx->getServiceContext())  

11.              .record(...);  

12.    

13.      });  

14.    

15.      ......  

16.      size_t bytesInBatch = 0;  

17.      //batch陣列  

18.      std::vector<InsertStatement> batch;   

19.      //預設64,可以通過db.adminCommand( { setParameter: 1, internalInsertMaxBatchSize:xx } )配置  

20.      const size_t maxBatchSize = internalInsertMaxBatchSize.load();  

21.      //當寫入的資料小於64時,也就是一個batch即可一起處理  

22.      //batch最大限制為寫入資料大於64或者batch中總位元組數超過256K  

23.      batch.reserve(std::min(wholeOp.getDocuments().size(), maxBatchSize));  

24.      for (auto&& doc : wholeOp.getDocuments()) {  

25.      ......  

26.      //doc檢查,例如是否巢狀過多,是否一個doc帶有多個_id等  

27.          auto fixedDoc = fixDocumentForInsert(opCtx->getServiceContext(), doc);  

28.      //如果這個文件檢測有異常,則跳過這個文件,進行下一個文件操作  

29.          if (!fixedDoc.isOK()) {   

30.              //啥也不做,直接忽略該doc  

31.          } else {  

32.              //事務相關,先忽略,以後會回頭專門分析事務  

33.              const auto stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++);  

34.              ......  

35.          //把文件插入到batch陣列  

36.              BSONObj toInsert = fixedDoc.getValue().isEmpty() ? doc : std::move(fixedDoc.getValue());  

37.              batch.emplace_back(stmtId, toInsert);  

38.              bytesInBatch += batch.back().doc.objsize();  

39.          //這裡continue,就是為了把批量插入的文件組成到一個batch陣列中,到達一定量一次性插入  

40.          //batch裡面一次最多插入64個文件或者總位元組數256K,則後續的資料拆分到下一個batch  

41.              if (!isLastDoc && batch.size() < maxBatchSize && bytesInBatch < insertVectorMaxBytes)  

42.                  continue;  // Add more to batch before inserting.  

43.          }  

44.    

45.      //把本batch中的資料交由該介面統一處理  

46.          bool canContinue = insertBatchAndHandleErrors(opCtx, wholeOp, batch, &lastOpFixer, &out);  

47.      //清空batch,開始下一輪處理  

48.          batch.clear();     

49.          bytesInBatch = 0;  

50.      ......  

51.  }  

上面的程式碼可以總結為以下圖形:

 

說明,上面假設64 條資料總大小不超過 256KB batch 圖,如果 64 doc 文件資料總大小超過 256kb ,這時候閥值則以總資料 256K 為限制。單個 batch 最大上限限制條件如下:

最多64 doc 文件資料。

單個batch 總資料長度不超過 256Kb

 

3.2 batch 資料事務寫入流程及其異常補償機制

一批資料通過分批拆分存入多個batch 後,呼叫 insertBatchAndHandleErrors() 介面來完成單個 batch 的資料寫入。整個 batch 資料寫入可以在一個 transaction 事務完成,也可以一條資料一個事務來完成寫入,具體核心程式碼實現如下 :

1.  bool insertBatchAndHandleErrors(...) {  

2.      ......  

3.      try {  

4.          //如果對應collection不存在則建立  

5.          acquireCollection(); //執行上面定義的函式  

6.          //如果collection不是固定capped集合,並且batch中資料大於一條  

7.          //則試著在一個事務中一次性寫入所有的資料  

8.          if (!collection->getCollection()->isCapped() && batch.size() > 1) {    

9.              ......  

10.              //為什麼這裡沒有檢查返回值?預設全部成功? 實際上通過try catch獲取到異常後,再後續改為一條一條插入  

11.              insertDocuments(opCtx, collection->getCollection(), batch.begin(), batch.end());  

12.              //insert統計計數及返回值賦值  

13.              globalOpCounters.gotInserts(batch.size());  

14.              ......  

15.              std::fill_n(std::back_inserter(out->results), batch.size(), std::move(result));  

16.              curOp.debug().ninserted += batch.size();  

17.              //一個事務寫入多個doc成功,直接返回  

18.              return true;  

19.          }  

20.      } catch (const DBException&) { //批量寫入失敗,則後面一條一條的寫  

21.          collection.reset();  

22.          //注意這裡沒有return,在後續一條一個事務寫入  

23.      }  

24.    

25.      //這裡迴圈解析batch,實現一條資料一個在一個事務中處理  

26.      for (auto it = batch.begin(); it != batch.end(); ++it) {  

27.          globalOpCounters.gotInsert(); //insert操作計數  

28.          try {  

29.              //log() << "yang test ............getNamespace().ns():" << wholeOp.getNamespace().ns();  

30.              //writeConflictRetry裡面會執行{}中的函式體   

31.              writeConflictRetry(opCtx, "insert", wholeOp.getNamespace().ns(), [&] {  

32.                  try {  

33.                      ......  

34.                      //把該條文件插入    

35.                      insertDocuments(opCtx, collection->getCollection(), it, it + 1);  

36.                      //統計計數處理  

37.                      SingleWriteResult result;  

38.                      result.setN(1);  

39.                      out->results.emplace_back(std::move(result));  

40.                      curOp.debug().ninserted++;  

41.                  } catch (...) {  

42.                       ......

43.                  }  

44.              });  

45.          } catch (const DBException& ex) {//寫入異常  

46.              //注意這裡,如果失敗是否還可以繼續後續資料的寫入  

47.              bool canContinue =  

48.                  handleError(opCtx, ex, wholeOp.getNamespace(), wholeOp.getWriteCommandBase(), out);  

49.              if (!canContinue)  

50.                  return false; //注意這裡直接退出迴圈,也就是本批次資料後續資料沒有寫入了  

51.          }  

52.      }  

53.    

54.      return true;  

55.  }  

一批batch 資料 ( 假設 64 ) 寫入過程,如果不是 capped 固定集合,則這 64 條資料首先放入一個 transaction 事務中完成寫入。如果寫入異常,則繼續一個事務一條資料寫入。資料放入事務執行流程如下 :

1.  void insertDocuments(OperationContext* opCtx,  

2.                       Collection* collection,  

3.                       std::vector<InsertStatement>::iterator begin,  

4.                       std::vector<InsertStatement>::iterator end)  

5.      //事務開始  

6.      WriteUnitOfWork wuow(opCtx);  

7.      ......  

8.      //把陣列begin到end之間的所有doc文件資料放入該事務中  

9.      uassertStatusOK(collection->insertDocuments(  

10.          opCtx, begin, end, &CurOp::get(opCtx)->debug(), /*enforceQuota*/ true));  

11.      //事務結束  

12.      wuow.commit(); //WriteUnitOfWork::commit  

13. 

到這裡後,insert 操作在 write 模組中的流程就結束了,後續的 doc 寫入流程儲存引擎將交由 storage 模組實現。

上面的核心程式碼分析可以總結為如下總結:

 

當這個batch 中的資料放入同一個事務執行失敗後,則改為一條一個事務迴圈處理,如下圖所示:

 

3.3 中間資料寫入異常如何處理

假設一個batch 資料 64 條資料,如果第 23 條資料寫入失敗了,後續的第 24-64 條資料是否需要繼續寫入,這就是本章節需要分析的問題。 mongodb 核心實現的時候通過 handleError() 介面判斷是否需要繼續寫入,該介面程式碼如下:

1.  // 前面資料寫入失敗,是否可以繼續後續資料寫入

2.  bool handleError(...) {  

3.      ......  

4.    

5.      //判斷是什麼原因引起的異常,從而返回不同的值  

6.      //如果是isInterruption錯誤,直接返回true,意思是不需要後續資料寫入  

7.      if (ErrorCodes::isInterruption(ex.code())) {  

8.          //如果是interrupt異常,則整批資料寫失敗,也就是不進行後續資料寫入  

9.          throw;  // These have always failed the whole batch.  

10.      }  

11.    

12.      ......  

13.      //如果ordered為false則忽略這條寫入失敗的資料,繼續後續資料寫入  

14.      return !wholeOp.getOrdered();  

15. 

從上面的程式碼可以看出,只要出現以下異常情況,就不可繼續後續資料insert 寫入操作了,如下:

Interruption 錯誤: 包括Interrupted InterruptedAtShutdown ExceededTimeLimit InterruptedDueToReplStateChange 四種異常,其他異常情況可以繼續寫入。

ordered 引數配置為 false: 如果該配置為false 則遇到異常不繼續處理後續 doc 寫入。

 

寫入異常後是否繼續寫總結如下圖所示:

 

3.4 後續

通過前面的分析可以得出,mongodb 核心把多條 doc 文件按照指定限制把文件封裝到不同 batch 中,然後一個 batch 一個 batch 分批處理。最終,這些 batch 對應資料將會通過 mongodb 核心的 storage 儲存模組來完成 insert 事務處理,最終在 CollectionImpl::insertDocuments() 實現。

Insert 寫入流程核心介面呼叫關係圖如下:

 

說明:資料如何組裝存入wiredtiger 儲存引擎將在後續《 storage 儲存模組原始碼實現》中詳細分析。

 

4.  delete 刪除操作核心實現

delete 資料刪除通過命令處理模組中的 CmdDelete::runImpl(...) ->performDeletes 介面完成和 write 寫模組 delete 操作對接,下面我們分析該介面核心程式碼實現,如下:

1.  WriteResult performDeletes(...)  

2.  {  

3.      ......  

4.    

5.      //singleOp型別為DeleteOpEntry     write_ops::Delete::getDeletes  

6.      for (auto&& singleOp : wholeOp.getDeletes()) {  

7.          //事務相關,先跳過,以後相關章節專門分析  

8.          const auto stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++);  

9.           ......  

10. 

11.          //該函式介面執行完後執行該finishCurOp  

12.          //finishCurOp實現表級QPS及時延統計 本op操作的慢日誌記錄等  

13.          ON_BLOCK_EXIT([&] { finishCurOp(opCtx, &curOp); });  

14.          try {  

15.              lastOpFixer.startingOp();  

16.              out.results.emplace_back(  

17.                  //該delete op操作真正執行在這裡,singleOp型別為DeleteOpEntry  

18.                  performSingleDeleteOp(opCtx, wholeOp.getNamespace(), stmtId, singleOp));  

19.              lastOpFixer.finishedOpSuccessfully();  

20.          } catch (const DBException& ex) {  

21.              ......  

22.      }  

23.    

24.      return out;  

25.  }  

從上面程式碼分析可以看出,如果wholeOp 攜帶有多個 DeleteOpEntry( 也就是 singleOp  ) 操作,則迴圈對 singleOp  進行處理,這個處理過程由performSingleDeleteOp(...) 介面實現,具體如下 :

 

performSingleDeleteOp(...) 介面核心程式碼實現如下:

1.  static SingleWriteResult performSingleDeleteOp(...) {  

2.      ......  

3.    

4.      //根據ns構造DeleteReques  

5.      //根據請求相關資訊初始化賦值DeleteRequest  

6.      DeleteRequest request(ns);  

7.      request.setQuery(op.getQ());  

8.      request.setCollation(write_ops::collationOf(op));  

9.      request.setMulti(op.getMulti());  

10.      request.setYieldPolicy(PlanExecutor::YIELD_AUTO);  // ParsedDelete overrides this for $isolated.  

11.      request.setStmtId(stmtId);  

12.    

13.      //根據DeleteRequest構造ParsedDelete  

14.      ParsedDelete parsedDelete(opCtx, &request);  

15.      //從request解析出對應成員存入parsedDelete  

16.      uassertStatusOK(parsedDelete.parseRequest());  

17.      //檢查該請求是否已經被kill掉了  

18.      opCtx->checkForInterrupt();  

19.    

20.      ......  

21.      //寫必須走主節點判斷及版本判斷  

22.      assertCanWrite_inlock(opCtx, ns);  

23.    

24.      //從查詢引擎中獲取delete執行器  

25.      auto exec = uassertStatusOK(  

26.          getExecutorDelete(opCtx, &curOp.debug(), collection.getCollection(), &parsedDelete));  

27.    

28.      {  

29.          stdx::lock_guard<Client> lk(*opCtx->getClient());  

30.          CurOp::get(opCtx)->setPlanSummary_inlock(Explain::getPlanSummary(exec.get()));  

31.      }  

32.    

33.      //執行該執行器  

34.      uassertStatusOK(exec->executePlan());  

35.    

36.      //下面流程是記錄各種統計資訊  

37.      long long n = DeleteStage::getNumDeleted(*exec);  

38.      curOp.debug().ndeleted = n;  

39.    

40.      PlanSummaryStats summary;  

41.      //獲取執行器執行過程中的各種統計資訊  

42.      Explain::getSummaryStats(*exec, &summary);  

43.      if (collection.getCollection()) {  

44.          collection.getCollection()->infoCache()->notifyOfQuery(opCtx, summary.indexesUsed);  

45.      }  

46.      curOp.debug().setPlanSummaryMetrics(summary);  

47.      //統計資訊序列化  

48.      if (curOp.shouldDBProfile()) {  

49.          BSONObjBuilder execStatsBob;  

50.          Explain::getWinningPlanStats(exec.get(), &execStatsBob);  

51.          curOp.debug().execStats = execStatsBob.obj();  

52.      }  

53.        

54.      ......  

55.      return result;  

56.  }  

該介面最核心的部分為獲取delete 執行器並執行,執行器由 query 查詢引擎模組實現,因此 getExecutorDelete(...) 獲取 delete 執行器及其執行過程具體實現流程將在後續《 query 查詢引擎模組實現原理》章節詳細分析,這裡暫時跳過這一邏輯。 write 模組中 delete 操作主要介面呼叫流程如下:

 

5.  update 更新操作核心實現

update 資料更新操作過程和 delete 操作過程類似,這裡不在累述,其核心介面呼叫流程如下圖所示:

 

 

6. 下期預告

   下期將分析《storage 儲存模組原始碼實現》, storage 模組分析完成後將分析 mongodb 最複雜的《 query 查詢引擎原始碼實現》,敬請關注。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69984922/viewspace-2761596/,如需轉載,請註明出處,否則將追究法律責任。

相關文章