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的基本結構
以上是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
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緩存,防止反復創建,之后的操作在緩存中進行。如果需要的內存大於緩存大小則調用系統函數分配新的內存空間。利用這種內存申請方式減少內存碎片。
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:
// ……
}
向內存尾部添加數據,舉例:
*((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。
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的數據讀取
BSONElement是用來從數據流中按照數據類型、名稱(Key)、數據獲得數據。BSON是對BSONElement的調用方,通過BSONElement以輪詢的方式對Key值比較讀取數據。猜測MongoDB用這么笨拙的方法對基礎數據進行操作是考慮跨文件搜索數據時可以以任意一段數據為開始查找數據。