Mongodb源码分析之插入操作(二)

本文我们分析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})就是走这里的流程
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值