mongodb源码分析(十一)数据的删除

本文深入探讨了MongoDB中数据删除的操作流程,主要涉及接收删除请求、删除索引记录以及回收删除空间到deletelist。删除的起点在receiveDelete函数,随后调用deleteObjects和deleteRecord进行具体操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        本文我们将删除,删除操作概括起来就是遍历将collection中数据对应的索引删除,然后是删除数据,最后将删除

的空间加入到之前文章描述的deletelist中.下面我们来看具体的代码吧.删除的入口是receiveDelete函数.

    void receivedDelete(Message& m, CurOp& op) {
        DbMessage d(m);
        const char *ns = d.getns();
        op.debug().ns = ns;
        int flags = d.pullInt();
        bool justOne = flags & RemoveOption_JustOne;//值删除单条doc
        bool broadcast = flags & RemoveOption_Broadcast;
        verify( d.moreJSObjs() );
        BSONObj pattern = d.nextJsObj();
        op.debug().query = pattern;
        op.setQuery(pattern);
        PageFaultRetryableSection s;
        while ( 1 ) {
            try {
                Lock::DBWrite lk(ns);
                // writelock is used to synchronize stepdowns w/ writes
                uassert( 10056 ,  "not master", isMasterNs( ns ) );
                // if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit
                if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) )
                    return;
                Client::Context ctx(ns);//具体的删除函数
                long long n = deleteObjects(ns, pattern, justOne, true);
                lastError.getSafe()->recordDelete( n );
                break;
            }
            catch ( PageFaultException& e ) {
                LOG(2) << "recordDelete got a PageFaultException" << endl;
                e.touch();
            }
        }
    }
receiveDelete->deleteObjects

    long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop, bool god, RemoveSaver * rs ) {
        long long nDeleted = 0;//根据查询条件得到游标
        shared_ptr< Cursor > creal = NamespaceDetailsTransient::getCursor( ns, pattern );
        if( !creal->ok() )
            return nDeleted;
        shared_ptr< Cursor > cPtr = creal;
        auto_ptr<ClientCursor> cc( new ClientCursor( QueryOption_NoCursorTimeout, cPtr, ns) );
        cc->setDoingDeletes( true );
        CursorId id = cc->cursorid();
        bool canYield = !god && !(creal->matcher() && creal->matcher()->docMatcher().atomic());
        do {
            // TODO: we can generalize this I believe
            //       
            bool willNeedRecord = (creal->matcher() && creal->matcher()->needRecord()) || pattern.isEmpty() || isSimpleIdQuery( pattern );
            if ( ! willNeedRecord ) {
                // TODO: this is a total hack right now
                // check if the index full encompasses query
                if ( pattern.nFields() == 1 && 
                     str::equals( pattern.firstElement().fieldName() , creal->indexKeyPattern().firstElement().fieldName() ) )
                    willNeedRecord = true;
            }
            if ( canYield && ! cc->yieldSometimes( willNeedRecord ? ClientCursor::WillNeed : ClientCursor::MaybeCovered ) ) {
                cc.release(); // has already been deleted elsewhere
                // TODO should we assert or something?
                break;
            }
            if ( !cc->ok() ) {
                break; // if we yielded, could have hit the end
            }
            // this way we can avoid calling prepareToYield() every time (expensive)
            // as well as some other nuances handled
            cc->setDoingDeletes( true );
            DiskLoc rloc = cc->currLoc();
            BSONObj key = cc->currKey();
            bool match = creal->currentMatches();
            cc->advance();
            if ( ! match )
                continue;
            // SERVER-5198 Advance past the document to be modified, but see SERVER-5725.
            while( cc->ok() && rloc == cc->currLoc() ) {//多值索引就会出现这种状况,需要跳过同一条记录
                cc->advance();
            }
            bool foundAllResults = ( justOne || !cc->ok() );
            if ( !foundAllResults ) {
                // NOTE: Saving and restoring a btree cursor's position was historically described
                // as slow here.
                cc->c()->prepareToTouchEarlierIterate();
            }
            if ( logop ) {//记录删除动作
                BSONElement e;
                if( BSONObj::make( rloc.rec() ).getObjectID( e ) ) {
                    BSONObjBuilder b;
                    b.append( e );
                    bool replJustOne = true;
                    logOp( "d", ns, b.done(), 0, &replJustOne );
                }
                else {
                    problem() << "deleted object without id, not logging" << endl;
                }
            }
            if ( rs )//将要删除的doc记录下来
                rs->goingToDelete( rloc.obj() /*cc->c->current()*/ );
            theDataFileMgr.deleteRecord(ns, rloc.rec(), rloc);//记录的删除
            nDeleted++;
            if ( foundAllResults ) {
                break;
            }
            cc->c()->recoverFromTouchingEarlierIterate();
            if( !god ) 
                getDur().commitIfNeeded();
            if( debug && god && nDeleted == 100 ) 
                log() << "warning high number of deletes with god=true which could use significant memory" << endl;
        }
        while ( cc->ok() );
        if ( cc.get() && ClientCursor::find( id , false ) == 0 ) {
            // TODO: remove this and the id declaration above if this doesn't trigger
            //       if it does, then i'm very confused (ERH 06/2011)
            error() << "this should be impossible" << endl;
            printStackTrace();
            cc.release();
        }
        return nDeleted;
    }

receiveDelete->deleteObjects->deleteRecord

    void DataFileMgr::deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK, bool noWarn, bool doLog ) {
        NamespaceDetails* d = nsdetails(ns);
        if ( d->isCapped() && !cappedOK ) {
            out() << "failing remove on a capped ns " << ns << endl;
            uassert( 10089 ,  "can't remove from a capped collection" , 0 );
            return;
        }
        BSONObj toDelete;
        if ( doLog ) {
            BSONElement e = dl.obj()["_id"];
            if ( e.type() ) {
                toDelete = e.wrap();
            }
        }
        /* check if any cursors point to us.  if so, advance them. */
        ClientCursor::aboutToDelete(dl);
        unindexRecord(d, todelete, dl, noWarn);//删除索引,循环删除所有索引中记录todelete的部分.
        _deleteRecord(d, ns, todelete, dl);//实际的数据删除并将其空间添加到deletedList中
        NamespaceDetailsTransient::get( ns ).notifyOfWriteOp();
        if ( ! toDelete.isEmpty() ) {
            logOp( "d" , ns , toDelete );
        }
    }
         到这里删除过程结束,可见这部分流程是很简单的.


原文链接: mongodb源码分析(十一)数据的删除

作者: yhjj0108,杨浩





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值