mongodb源码分析-数据插入

(-)

mongdb启动代码流程

-------db.cpp-----
main
--mongoDbMain
----initAndListen
------_initAndListen
---------Listen
------------createServer(options, new MyMessageHandler() );
------------startReplication

其中 MyMessageHandler 类就是用来处理 客户端操作的

主要函数如下

virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) {
//log()<<"-----liguoqing MyMessageHandler->process----"<<this<<"-----"<<getpid()<<endl;
            while ( true ) {
                if ( inShutdown() ) {
                    log() << "got request after shutdown()" << endl;
                    break;
                }
                lastError.startRequest( m , le );
//log()<<"-------liguoqing---process"<<endl;
                DbResponse dbresponse;
                try {
                    assembleResponse( m, dbresponse, port->remote() );    
处理请求参数
                }
                catch ( const ClockSkewException & ) {
                    log() << "ClockSkewException - shutting down" << endl;
                    exitCleanly( EXIT_CLOCK_SKEW );
                }


                if ( dbresponse.response ) {
                    port->reply(m, *dbresponse.response, dbresponse.responseTo);
                    if( dbresponse.exhaustNS.size() > 0 ) {
                        MsgData *header = dbresponse.response->header();
                        QueryResult *qr = (QueryResult *) header;
                        long long cursorid = qr->cursorId;
                        if( cursorid ) {
                            verify( dbresponse.exhaustNS.size() && dbresponse.exhaustNS[0] );
                            string ns = dbresponse.exhaustNS; // before reset() free's it...
                            m.reset();
                            BufBuilder b(512);
                            b.appendNum((int) 0 /*size set later in appendData()*/);
                            b.appendNum(header->id);
                            b.appendNum(header->responseTo);
                            b.appendNum((int) dbGetMore);
                            b.appendNum((int) 0);
                            b.appendStr(ns);
                            b.appendNum((int) 0); // ntoreturn
                            b.appendNum(cursorid);
                            m.appendData(b.buf(), b.len());
                            b.decouple();
                            DEV log() << "exhaust=true sending more" << endl;
                            beNice();
                            continue; // this goes back to top loop
                        }
                    }
                }
//log()<<"-----liguoqing MyMessageHandler->process----break"<<endl;
                break;
            }
        }


        virtual void disconnected( AbstractMessagingPort* p ) {
            Client * c = currentClient.get();
            if( c ) c->shutdown();
            globalScriptEngine->threadDone();
        }
    };

这里只关心  assembleResponse( m, dbresponse, port->remote() );    函数的处理

else {
           
                else if ( !nsString.isValid() ) {
                    // Only killCursors doesn't care about namespaces
                    uassert( 16257, str::stream() << "Invalid ns [" << ns << "]", false );
                }
                else if ( op == dbInsert ) {
                    receivedInsert(m, currentOp);                   处理数据插入
                } 
                else if ( op == dbUpdate ) {
                    receivedUpdate(m, currentOp);              处理数据更新
                }
                else if ( op == dbDelete ) {
                    receivedDelete(m, currentOp);                处理数据删除
                }
这里只关心    receivedInsert(m, currentOp);  函数处理流程

void receivedInsert(Message& m, CurOp& op) {

bool isIndexWrite = NamespaceString(ns).coll == "system.indexes";-----------------------------创建索引,后续我们在分析索引
        // Auth checking for index writes happens further down in this function.
        if (!isIndexWrite) {
            Status status = cc().getAuthorizationManager()->checkAuthForInsert(ns);
            uassert(16544, status.reason(), status.isOK());
        }

while (d.moreJSObjs()){

            BSONObj obj = d.nextJsObj();
            multi.push_back(obj);
            if (isIndexWrite) {
                string indexNS = obj.getStringField("ns");
                uassert(16548,
                        mongoutils::str::stream() << "not authorized to create index on "
                                << indexNS,
                        cc().getAuthorizationManager()->checkAuthorization(
                                indexNS, ActionType::ensureIndex));
            }
        }

 while ( true ) {
            try {
                Lock::DBWrite lk(ns);
                
                // CONCURRENCY TODO: is being read locked in big log sufficient here?
                // writelock is used to synchronize stepdowns w/ writes
                uassert( 10058 , "not master", isMasterNs(ns) );
                
                if ( handlePossibleShardedMessage( m , 0 ) )
                    return;
                
                Client::Context ctx(ns);
log()<<"------liguoqing---receivedInsert   multi="<<multi.size()<<endl;
                
                if (multi.size() > 1) {
                    const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError;
                    insertMulti(keepGoing, ns, multi, op);--------------------------------------------------------------批量插入数据,也是在循环中调用单条插入
                } else {
                    checkAndInsert(ns, multi[0]);---------------------------------------------------------------------单条数据插入
                    globalOpCounters.incInsertInWriteLock(1);
                    op.debug().ninserted = 1;
                }
                return;
            }
            catch ( PageFaultException& e ) {
                e.touch();
            }

  void checkAndInsert(const char *ns, /*modifies*/BSONObj& js) { 
        uassert( 10059 , "object to insert too large", js.objsize() <= BSONObjMaxUserSize);------------------------
        {
            BSONObjIterator i( js );
            while ( i.more() ) {
                BSONElement e = i.next();
                // check no $ modifiers.  note we only check top level.  
                // (scanning deep would be quite expensive)    

                uassert( 13511, "document to insert can't have $ fields", e.fieldName()[0] != '$' );
                
                // check no regexp for _id (SERVER-9502)
                if (str::equals(e.fieldName(), "_id")) {
                    uassert(16824, "can't use a regex for _id", e.type() != RegEx);
                }
            }
        }


        theDataFileMgr.insertWithObjMod(ns,
                                        // May be modified in the call to add an _id field.
                                        js,
                                        // Only permit interrupting an (index build) insert if the
                                        // insert comes from a socket client request rather than a
                                        // parent operation using the client interface.  The parent
                                        // operation might not support interrupts.

                                        cc().curop()->parent() == NULL,
                                        false);
sleep(1);
        logOp("i", ns, js);

}

这里看insertWithObjMod 函数的处理流程
     /** @param o the object to insert. can be modified to add _id and thus be an in/out param
     */
    DiskLoc DataFileMgr::insertWithObjMod(const char* ns, BSONObj& o, bool mayInterrupt, bool god) {
        bool addedID = false;
        DiskLoc loc = insert( ns, o.objdata(), o.objsize(), mayInterrupt, god, true, &addedID );
        if( addedID && !loc.isNull() )
            o = BSONObj::make( loc.rec() );
        return loc;
    }

   DiskLoc DataFileMgr::insert(const char* ns,
                                const void* obuf,
                                int32_t len,
                                bool mayInterrupt,
                                bool god,
                                bool mayAddIndex,
                                bool* addedID) {

bool addIndex = wouldAddIndex && mayAddIndex; ---------------------这部分是添加索引相关,下期介绍,如 db.coll.ensureIndex({x:1})


        NamespaceDetails *d = nsdetails(ns);
        if ( d == 0 ) {
            d = insert_newNamespace(ns, len, god);
        }
        NamespaceDetails *tableToIndex = 0;
        string tabletoidxns;
        BSONObj fixedIndexObject;
        if ( addIndex ) {
            verify( obuf );
            BSONObj io((const char *) obuf);
            if( !prepareToBuildIndex(io,
                                     mayInterrupt,
                                     god,
                                     tabletoidxns,
                                     tableToIndex,
                                     fixedIndexObject) ) {
                // prepare creates _id itself, or this indicates to fail the build silently (such 
                // as if index already exists)
                return DiskLoc();
            }
            if ( ! fixedIndexObject.isEmpty() ) {
                obuf = fixedIndexObject.objdata();
                len = fixedIndexObject.objsize();
            }
        }

    if( !god ) {
            /* Check if we have an _id field. If we don't, we'll add it.
               Note that btree buckets which we insert aren't BSONObj's, but in that case god==true 判断是否有 _id 字段,如如果没有就加一个

            BSONObj io((const char *) obuf);
            BSONElement idField = io.getField( "_id" );
            uassert( 10099 ,  "_id cannot be an array", idField.type() != Array );
            // we don't add _id for capped collections in local as they don't have an _id index
            if( idField.eoo() &&
                !wouldAddIndex &&
                nsToDatabase( ns ) != "local" &&
                d->haveIdIndex() ) {

                if( addedID )
                    *addedID = true;
                idToInsert.init();--------------------------------------  生成_id 的结构体
                len += idToInsert.size();
            }

 // If the collection is capped, check if the new object will violate a unique index
        // constraint before allocating space.     处理唯一索引冲突

        if (d->nIndexes && 
            d->isCapped() && 
            !god) {
            checkNoIndexConflicts( d, BSONObj( reinterpret_cast<const char *>( obuf ) ) );
        }

。。。。。。。。。。。。。。

 Record *r = loc.rec();
        {
            verify( r->lengthWithHeaders() >= lenWHdr );
            r = (Record*) getDur().writingPtr(r, lenWHdr);
            if( idToInsert.needed() ) {
                /* a little effort was made here to avoid a double copy when we add an ID */
                int originalSize = *((int*) obuf);
                ((int&)*r->data()) = originalSize + idToInsert.size();
                memcpy(r->data()+4, idToInsert.rawdata(), idToInsert.size());----------------------------memcpy函数将_id和数据插入文件中
                memcpy(r->data()+4+idToInsert.size(), ((char*)obuf)+4, originalSize-4);
            }
            else {
                if( obuf ) // obuf can be null from internal callers
                    memcpy(r->data(), obuf, len);
            }
        }

至此,数据插入流程结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值