MongoDB源碼閱讀之BSON源碼分析


1. BSON源碼結構

涉及BSON的源碼有:

builder.h 包含bson所需的內存管理類和將bson對象轉成內存的工具方法

bsontypes.h 定義了bson所需的數據類型列表

oid.h 定義Object ID的數據結構及實現

bsonelement.h 定義了bson的節點

bsonobj.h bson對象(主要對象,提供了數據的基本操作)

bsonmisc.h 定義了與bson相關的助手函數(流輸入/輸出)

bsonobjbuilder.h 創建bsonObj的類,用到了builder中定義的內存管理類

bsonobjiterator.h 提供了一個類似STL的接口是element的iterator封裝(只實現了基本接口)

2. Builder的基本結構

~I_`$@KWKC@6G5W6F@G2$Y3

以上是builder相關的類圖

_BufBuilder是所有builder的基礎,通過對模板的實例化,生產出BufBuilder和StackBufBuilder兩種Buffer Builder類。BSONObjBuilder將不同數據類型根據Key/Value形式填入BufBuilder。BuilderObj包含了一個BSONObjBuilder和一個fieldName(Key值),並提供了以fieldName為Key向BSONObjBuilder輸送數據的方法。其中對應的Array版本,添加了對std::vector和std::list的支持。

3. Buffer Builder(builder.h for BufBuilder)

在builder中提供了兩種內存的申請方式:

a) TrivialAllocator
     class TrivialAllocator { 
     public:
         void* Malloc(size_t sz) {  return malloc(sz); }
         void* Realloc( void *p, size_t sz) {  return realloc(p, sz); }
         void Free( void *p) { free(p); }
    };

 從源碼上看就是調用了系統的內存申請方式。

b) StackAllocator

建立了一個buffer緩存,防止反復創建,之后的操作在緩存中進行。如果需要的內存大於緩存大小則調用系統函數分配新的內存空間。利用這種內存申請方式減少內存碎片。

     class StackAllocator {
     public:
         enum { SZ =  512 };                 // 默認緩存大小為512bytes
         void* Malloc(size_t sz) {
             if( sz <= SZ )  return buf;         // 優先使用緩存
             return malloc(sz);              // 若緩存不能夠提供需求則直接調用系統函數申請內存
        }

         // 重新分配內存
         void* Realloc( void *p, size_t sz) { 
             if( p == buf ) {                 // 使用的是緩存內存
                 if( sz <= SZ )  return buf;     // 需要的內存小於緩存,直接返回緩存
                 void *d = malloc(sz);        // 所需內存大於緩存,直接調用系統函數申請內存
                 if ( d ==  0 )                // 沒申請出內存說明內存不足,拋出錯誤提示
                    msgasserted(  15912 ,  " out of memory StackAllocator::Realloc " );
                memcpy(d, p, SZ);
                 return d;
            }
             return realloc(p, sz);             // 如果已經是用系統函數申請的內存直接調用系統函數重新分配
        }
         void Free( void *p) { 
             if( p != buf )
                free(p); 
        }
     private:
         char buf[SZ]; 
    };

 

c) _BufBuilder模板類

BSON利用模板創建了一個可替換內存申請方式的buffer builder。

Builder本身是一個以內存塊為基礎的,各種數據向內存尾部添加,當內存大小不夠時,再申請比當前大小為2倍的大小。

// 模板類聲明
    template<  class Allocator >
     class _BufBuilder {
         //  non-copyable, non-assignable(禁止復制)
        _BufBuilder(  const _BufBuilder& );
        _BufBuilder&  operator=(  const _BufBuilder& );
        Allocator al;               // 為內存申請類創建實例
      public:
         // ……
}

 

向內存尾部添加數據,舉例:

         void appendUChar(unsigned  char j) {
            *((unsigned  char*)grow( sizeof(unsigned  char))) = j;
        }
         void appendChar( char j) {
            *(( char*)grow( sizeof( char))) = j;
        }
         void appendNum( char j) {
            *(( char*)grow( sizeof( char))) = j;
        }
         void appendNum( short j) {
            *(( short*)grow( sizeof( short))) = j;
        }
         void appendNum( int j) {
            *(( int*)grow( sizeof( int))) = j;
        }
         void appendNum(unsigned j) {
            *((unsigned*)grow( sizeof(unsigned))) = j;
        }
        // ……

       
// grow判斷內存大小長度
        /*  returns the pre-grow write position  */
        inline  char* grow( int by) {
             int oldlen = l;
            l += by;
             if ( l > size ) {    // 當長度不夠時,擴展長度
                grow_reallocate();
            }
             return data + oldlen;
        }

     private:
         /*  "slow" portion of 'grow()'   */
         void grow_reallocate() {
             int a =  64;             // 起始長度64
             while( a < l )           // 以64二倍的長度找到合適的長度
                a = a *  2;
             if ( a > BufferMaxSize ) {        // buf長度大於最大長度,拋出錯誤
                std::stringstream ss;
                ss <<  " BufBuilder attempted to grow() to  " << a <<  "  bytes, past the 64MB limit. ";
                msgasserted( 13548, ss.str().c_str());
            }
            data = ( char *) al.Realloc(data, a);     // 從內存類中重新申請內存
             if ( data == NULL )
                msgasserted(  16070 ,  " out of memory BufBuilder::grow_reallocate " );
            size = a;
        }

 

d) BSONObjBuilder

BSONObjBuilder以BufBuilder為基礎,按照數據類型、數據名稱、數據值的序列將數據項排列進BufBuilder。

         /* * Append a boolean element  */
        BSONObjBuilder& append( const StringData& fieldName,  bool val) {
            _b.appendNum(( char) Bool);               // 存入數據類型
            _b.appendStr(fieldName);                  // 存入Key值
            _b.appendNum(( char) (val? 1: 0));            // 存入數據
             return * this;
        }

         /* * Append a 32 bit integer element  */
        BSONObjBuilder& append( const StringData& fieldName,  int n) {
            _b.appendNum(( char) NumberInt);
            _b.appendStr(fieldName);
            _b.appendNum(n);
             return * this;
        }

         /* * Append a 32 bit unsigned element - cast to a signed int.  */
        BSONObjBuilder& append( const StringData& fieldName, unsigned n) {
             return append(fieldName, ( int) n);
        }

         /* * Append a NumberLong  */
        BSONObjBuilder& append( const StringData& fieldName,  long  long n) {
            _b.appendNum(( char) NumberLong);
            _b.appendStr(fieldName);
            _b.appendNum(n);
             return * this;
        }

 

4. BSONObj的數據讀取

$L{O5H@)6JZ62B55A8VVX)4

BSONElement是用來從數據流中按照數據類型、名稱(Key)、數據獲得數據。BSON是對BSONElement的調用方,通過BSONElement以輪詢的方式對Key值比較讀取數據。猜測MongoDB用這么笨拙的方法對基礎數據進行操作是考慮跨文件搜索數據時可以以任意一段數據為開始查找數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM