本文我们分析mongodb中数据的插入流程.插入的简单流程可以归结于如下:
1. 如果存在对应collection则从collection中分配空间,然后将数据保存到分配的空间中,不存在则先从database中分配对应的collection,若database不存在则分配database,建立xx.ns和xx.0 等文件.
2. 根据插入数据更新collection中的索引.
下面来看代码,根据前面的分析我们知道插入操作的入口函数为:receivedInsert.
void receivedInsert(Message& m, CurOp& op) {
BSONObj first = d.nextJsObj();
vector<BSONObj> multi;
while (d.moreJSObjs()){//批量数据的插入
if (multi.empty()) // first pass
multi.push_back(first);
multi.push_back( d.nextJsObj() );
}
while ( true ) {
Lock::DBWrite lk(ns);
if ( handlePossibleShardedMessage( m , 0 ) )
return;
Client::Context ctx(ns);
if( !multi.empty() ) {
const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError;
insertMulti(keepGoing, ns, multi);//循环调用checkAndInsert做插入操作,keepGoing为true表示当插入操作错误时继续进行插入操作,否则终止插入操作
return;
}
checkAndInsert(ns, first);
globalOpCounters.incInsertInWriteLock(1);
return;
}
}
}
void checkAndInsert(const char *ns, /*modifies*/BSONObj& js) {
uassert( 10059 , "object to insert too large", js.objsize() <= BSONObjMaxUserSize);//单条doc超过BSONObjMaxUserSize的不允许插入,可以通过修改代码的方式调整这个值
{
// check no $ modifiers. note we only check top level. (scanning deep would be quite expensive)
BSONObjIterator i( js );//field中不允许以'$'开始
while ( i.more() ) {
BSONElement e = i.next();
uassert( 13511 , "document to insert can't have $ fields" , e.fieldName()[0] != '$' );
}
}
theDataFileMgr.insertWithObjMod(ns, js, false); // js may be modified in the call to add an _id field.
logOp("i", ns, js);//为master/slave或者replset记录操作.
}
DiskLoc DataFileMgr::insertWithObjMod(const char *ns, BSONObj &o, bool god) {
bool addedID = false;
DiskLoc loc = insert( ns, o.objdata(), o.objsize(), god, true, &addedID );
if( addedID && !loc.isNull() )
o = BSONObj::make( loc.rec() );
return loc;
}
insert是mongodb数据的插入操作,其中包括了普通数据和索引数据的插入,下面的代码中大家将看到.
DiskLoc DataFileMgr::insert(const char *ns, const void *obuf, int len, bool god, bool mayAddIndex, bool *addedID) {
bool wouldAddIndex = false;
{
const char *sys = strstr(ns, "system.");
if ( sys && !insert_checkSys(sys, ns, wouldAddIndex, obuf, god) )
return DiskLoc();
}
bool addIndex = wouldAddIndex && mayAddIndex;//这是插入index的操作
NamespaceDetails *d = nsdetails(ns);
if ( d == 0 ) {//当前collection并不存在,首先分配一个collection,具体操作时根据插入的数据分配一个extent,分配一个namespacedetails,并且根据记录该namespacedetails.god为false则创建一个_id的索引,将该collection记录到system.namespaces collection中
d = insert_newNamespace(ns, len, god);
}
NamespaceDetails *tableToIndex = 0;
string tabletoidxns;
BSONObj fixedIndexObject;
if ( addIndex ) {//插入index的操作,如db.coll.ensureIndex({x:1})就是走这里的流程
verify( obuf );
BSONObj io((const char *) obuf);