Mongodb源碼分析--消息(message)

在Mongodb中,客戶端和服務端進行通信是基於mongodb wire protocol 。說白了,該協議是一個簡單的基於socket,請求/響應方式的協議,客戶端使用常規的TCP/IP套接字(socket)進行通信。

      客戶端與服務端使用約定的消息(格式)進行通信,其消息頭結構與C語言中的struct類似。具體的代碼(位於message.cpp):
    
  
  1. struct MSGHEADER {  
  2.        int32 messageLength; // 消息長度(字節),包括它自身  
  3.        int32 requestID;     // 消息標識符,用於在請求響應過程中唯一標識該消息  
  4.        int32 responseTo;  // 源請求id(用於服務端發送應答信息時)requestID from the original request  
  5.        //   (used in reponses from db)  
  6.        int32 opCode; //消息類型,參見enum中描述  
  7.    };  
  8.    enum Operations {  
  9.        opReply = 1,     /* 對客戶端請求的響應. */  
  10.        dbMsg = 1000,    /* 通常的消息命令(跟着字符串) */  
  11.        dbUpdate = 2001, /* 更新document消息 */  
  12.        dbInsert = 2002, /* 插入新document消息*/  
  13.        //dbGetByOID = 2003,/*保留*/  
  14.        dbQuery = 2004,  /* 查詢一個集合*/  
  15.        dbGetMore = 2005, /* 從(一個)查詢中獲取更多數據,參見 Cursors */  
  16.        dbDelete = 2006, /* 刪除一個或多個document*/  
  17.        dbKillCursors = 2007 /* 通知數據庫,客戶端已執行完畢,可以關閉該Cursors*/  
  18.    };  


       注:客戶端可以使用除上面Reply之外的所有消息類型,因爲Reply是數據庫保留使用的。同時客戶端可以使用QUERY和GETMORE消息來讓服務端發送響應信息,其它消息類型則不會。 

      下面分別進行介紹。


Client 請求消息包括: 

    1.對於更新 (document)消息,其消息結構如下:

  1. struct  OP_UPDATE {  
  2.     MsgHeader header;              //  前面介紹的標準消息類信息  
  3.     int32     ZERO;                //  0 - 爲將來使用而保留的數據位  
  4.     cstring   fullCollectionName;  //  完整的集合名稱,形如:"dbname.collectionname"  
  5.     int32     flags;               //  位向量,參見下面介紹  
  6.     document  selector;            //  查詢選擇器,用於指定查詢條件  
  7.     document  update;              //  指定要執行的更新(document)  
  8. }  


      flags 標誌位向量:

bit         名稱              描述  
0        Upsert             如設置該位爲0,同時未查詢到相關document時,數據庫會把提供的對象插入到集合中 
1        MultiUpdate      如設置該位爲1,則數據庫會更新所有查詢到的document,否則僅更新查詢到的第一個

                                document 
2-31    Reserved         必須設置爲0.   



    2.對於插入 (document)消息,其結構如下:

  1. struct  {  
  2.     MsgHeader header;              //  前面介紹的標準消息類信息  
  3.     int32     ZERO;                //  0 - 爲將來使用而保留的數據位  
  4.     cstring   fullCollectionName;  //  完整的集合名稱,形如:"dbname.collectionname"  
  5.     document *  documents;      //  要插入的一個或多個document,如爲多個時,這些document會依次逐個寫到socket裏  
  6. }  


    3. 對於查詢 (document)消息,其結構如下:

  1. struct  
  2.   OP_QUERY {  
  3.     MsgHeader header;                 //  標準消息類信息  
  4.     int32     flags;                  //  位向量,參見下面介紹  
  5.     cstring   fullCollectionName;     //    
  6. 完整的集合名稱,形如:"dbname.collectionname"  
  7.     int32     numberToSkip;           //    
  8. 設置從第一個document起,跳過(忽略)的document數  
  9.     int32     numberToReturn;         //  返回的document數  
  10.                                       //   in the first OP_REPLY batch  
  11.     document  query;                  //  查詢對象,該對象同時包括一個或多個元素($query,   
  12. $orderby, $hint, $explain, $snapshot),這些元素用於匹配(match)包含在結果集(result   
  13. set)中的對象  
  14.   [ document  returnFieldSelector; ]  //  可選頂.   
  15. 要求返回的document應包含的字段(fields)                                   
  16. }  


     flags 標誌位向量:

bit     名稱                   描述 
0       保留                   必須設置爲0   
1       TailableCursor     Tailable 表示在返回最後一條數據後,不要關閉當前 cursor。這是因爲系統

                                考慮到稍後你可以再次使用該cursor.   
2       SlaveOk             是否允許查詢replica slave結點. 通過返回錯誤信息,除非是在"local"名空間.   
3       OplogReplay       僅限內部replication時使用   
4       NoCursorTimeout   服務器爲了防止內存使用過量,會在一段時間(10分鐘)後將空閒的cursors

                                暫停(times out).   
5       AwaitData          與TailableCursor配合使用. 如果在數據尾部, 阻塞一會而不是返回無數據信息

                                 (no data). 當(阻塞)時間之後,通常執行返回(return)操作.   
6       Exhaust             個人理解:把數據作爲一個包,整個下載下來。後面是英文原文說明:

                                  Stream the data down  full blast in multiple "more" packages,

                                  on the assumption that the client will fully read all data queried.

                                Faster when you are pulling a lot of data and know you want to pull it

                                all down. Note: the client is not allowed to not read all the data unless

                                it closes the   connection.   
7       Partial                 如一些shards宕掉,爲了不拋出異常,則從 mongos 那裏返回部分結果   
8-31    Reserved           必須設置爲0   



      4. 對於查詢更多 (document)消息,其結構如下:

  1. struct  {  
  2.     MsgHeader header;              //  標準消息類信息  
  3.     int32     ZERO;                //  0 - 爲將來使用而保留的數據位  
  4.     cstring   fullCollectionName;  //  完整的集合名稱,形如:"dbname.collectionname"  
  5.     int32     numberToReturn;      //  返回的document數  
  6.     int64     cursorID;            //  在REPLY消息中的Cursor標識符,其必須來自於數據庫  
  7. }  



     5.  對於刪除 (document)消息,其結構如下:

  1. struct  {  
  2.     MsgHeader header;              //  標準消息類信息  
  3.     int32     ZERO;                //  0 - 爲將來使用而保留的數據位  
  4.     cstring   fullCollectionName;  //  完整的集合名稱,形如:"dbname.collectionname"  
  5.     int32     flags;               //  位向量,參見下面介紹  
  6.     document  selector;            //  查詢條件  
  7. }  


     flags 標誌位向量:

bit     名稱                      描述 
0       SingleRemove      如設置,則僅刪除查詢到的第一個document,否則刪除所有查詢到的document   
1-31   Reserved            必須設置爲0   


      6.對於KILL_CURSORS 消息,該消息用於在數據庫裏關閉一個活動(active)的遊標, 其結構如下:

  1. struct  {  
  2.     MsgHeader header;             //  標準消息類信息  
  3.     int32     ZERO;               //  0 - 爲將來使用而保留的數據位  
  4.     int32     numberOfCursorIDs;  //  消息中游標數  
  5.     int64 *     cursorIDs;          //  cursorIDs的關閉順序,其會依次寫入到socket中  
  6. }  



      注意:如果遊標正在讀時,如果未exhausted (直到 OP_QUERY 或 OP_GETMORE 返回 zero ), 則不必關閉遊標


      7.對於MSG (document)消息,它是向數據庫發送診斷消息(diagnostic message). 而數據庫到發送確定(fixed)順應其結構如下:

  1. struct  {  
  2.     MsgHeader header;   //  標準消息類信息  
  3.     cstring   message;  //  message for the database  
  4. }  



   
數據庫響應消息(針對QUERY或GET_MORE的順應)包括:

      對於REPLY 消息,其結構如下:

 

  1. struct  {  
  2.     MsgHeader header;          //  標準消息類信息  
  3.     int32     responseFlags;   //  位向量,參見下面介紹  
  4.     int64     cursorID;        //  cursor id if client needs to do get more's  
  5.     int32     startingFrom;    //  應答(reply)的遊標中的起始位置  
  6.     int32     numberReturned;  //  應答中的document數  
  7.     document *  documents;       //  應答的document(一或多個)  
  8. }  

 

      responseFlags 標誌位向量:

bit     名稱                       描述 
0       CursorNotFound      當執行getMore時,服務器上當前遊標失效.返回 zero 結果信息.   
1       QueryFailure           查詢失敗時. 在返回信息(document)中包括一個 "$err" 字段對該

                                    失敗加以描述.   
2       ShardConfigStale     Drivers should ignore this. Only mongos will ever see this set,

                                    in which case, it needs to update config from the server.   
3       AwaitCapable          在服務器支持AwaitData查詢選項時進行設置. 如不設置,客戶端會在

                                     一個Tailable 遊標的兩個getMore操作之間停止(sleep)一會.

                                     在Mongod 1.6版本中支持該選項並一直設置.   
4-31    Reserved              可忽略 



     上面是一些關於消息類型的介紹,下面讓我們來看一下MongoDB的具體實現類。

     在mongodb中,其提供瞭如下幾個類對消息進行定義,封裝及解析, 接收/發送等操作(位於message.h和dbmessage.h):
  

其中:
    MsgData (struct類型):提供了對消息數據信息部分的結構定義,如操作標誌位_operation,以及上面所說的flags.

    Message : 對MsgData封裝以及對消息的操作方法(比如:設置消息數信息(MsgData),獲取消息頭信息,消息信息重置,消息設置追加等)

    MessagingPort :提供消息的發送,接收等。並將接收到的信息(如char *類型)進行分解,並調用消息(Message)的相關方法將分解結果作爲參數傳入,反之一樣,這裏它相當於一個轉換器。

    DbMessage :特別的消息類型,它是對Message封裝,用於提供針對數據庫操作類型消息的訪問

    QueryMessage : 對DbMessage中的查詢請求消息進行解析封裝

    好了,今天的內容就先到這裏了。



    參考鏈接:http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol

    原文鏈接:http://www.cnblogs.com/daizhj/archive/2011/04/02/2003335.html 
    作者: daizhj, 代震軍   
    微博: http://t.sina.com.cn/daizhj
    Tags: mongodb,message,protocol,c++

發佈了27 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章