mongodb源码分析(七)查询3之mongod的cursor的产生(续)

来源:互联网 发布:淘宝top排行榜 编辑:程序博客网 时间:2024/05/19 23:54

        上一篇文章我们说道了mongod对于QueryPlan的选取,由于篇幅过长,所以另起一篇文章接上一篇文章

继续谈plan的实际查询流程.

        上一篇文章说完了QueryPlanSet::make我们回到:MultiPlanScanner::init.

        // if _or == false, don't use or clauses for index selection        if ( !_or ) {            ++_i;//若query为{$or:[{a:1},{:1}]}这种以or开头的语句,那么frsp是无用的,具体见FieldRangeSet::handleMatchField            auto_ptr<FieldRangeSetPair> frsp( new FieldRangeSetPair( _ns.c_str(), _query, true ) );            updateCurrentQps( QueryPlanSet::make( _ns.c_str(), frsp, auto_ptr<FieldRangeSetPair>(),                                                 _query, order, _parsedQuery, _hint,                                                 _recordedPlanPolicy,                                                 min, max, true ) );        }        else {//继续来看看这里的handleBeginningOfClause函数            BSONElement e = _query.getField( "$or" );            massert( 13268, "invalid $or spec",                    e.type() == Array && e.embeddedObject().nFields() > 0 );            handleBeginningOfClause();        }

    void MultiPlanScanner::handleBeginningOfClause() {        assertHasMoreClauses();        ++_i;//这里使用$or的第一个语句执行QueryPlanSet::make得到其中的plan,过程和一般查询一样        auto_ptr<FieldRangeSetPair> frsp( _org->topFrsp() );//这里的第一个语句如:{$or:[{x:1},{y:1}]}这里的{x:1},第一个QueryPlanSet执行完后会继续产生一个新的QueryPlanSet继续执行{y:1}的查询动作,后面会说到.        auto_ptr<FieldRangeSetPair> originalFrsp( _org->topFrspOriginal() );        updateCurrentQps( QueryPlanSet::make( _ns.c_str(), frsp, originalFrsp, _query,                                             BSONObj(), _parsedQuery, _hint, _recordedPlanPolicy,                                             BSONObj(), BSONObj(),                                             // 'Special' plans are not supported within $or.                                             false ) );    }
我们继续向上回到CursorGenerator::generate函数:

    shared_ptr<Cursor> CursorGenerator::generate() {        setArgumentsHint();        shared_ptr<Cursor> cursor = shortcutCursor();        if ( cursor ) {            return cursor;        }        setMultiPlanScanner();        cursor = singlePlanCursor();//这里产生实际的cursor,只有单个plan时才会产生        if ( cursor ) {            return cursor;        }        return newQueryOptimizerCursor( _mps, _planPolicy, isOrderRequired(), explain() );    }
CursorGenerator::generate->CursorGenerator::singlePlanCursor:

  

    shared_ptr<Cursor> CursorGenerator::singlePlanCursor() {        const QueryPlan *singlePlan = _mps->singlePlan();//确实是单plan并且$or语句不起作用,且没有额外的plan这个额外的plan参加QueryPlanSet::hasPossiblyExcludedPlans函数,那么就会返回plan        if ( !singlePlan || ( isOrderRequired() && singlePlan->scanAndOrderRequired() ) ) {            return shared_ptr<Cursor>();        }//之前传入的_planPolicy为any支持任意的plan        if ( !_planPolicy.permitPlan( *singlePlan ) ) {            return shared_ptr<Cursor>();        }        if ( _singlePlanSummary ) {            *_singlePlanSummary = singlePlan->summary();        }//根据QueryPlan产生相应的Cursor        shared_ptr<Cursor> single = singlePlan->newCursor();        if ( !_query.isEmpty() && !single->matcher() ) {//建立相应的查询            single->setMatcher( singlePlan->matcher() );        }        if ( singlePlan->keyFieldsOnly() ) {            single->setKeyFieldsOnly( singlePlan->keyFieldsOnly() );        }        if ( _simpleEqualityMatch ) {            if ( singlePlan->exactKeyMatch() && !single->matcher()->needRecord() ) {                *_simpleEqualityMatch = true;            }        }        return single;    }
继续前进CursorGenerator::generate->CursorGenerator::singlePlanCursor->QueryPlan::newCursor

    shared_ptr<Cursor> QueryPlan::newCursor( const DiskLoc &startLoc ) const {        if ( _type ) {//index plugin            // hopefully safe to use original query in these contexts - don't think we can mix type with $or clause separation yet            int numWanted = 0;//类似的空间地理索引            if ( _parsedQuery ) {                // SERVER-5390                numWanted = _parsedQuery->getSkip() + _parsedQuery->getNumToReturn();            }            return _type->newCursor( _originalQuery , _order , numWanted );        }        if ( _utility == Impossible ) {//之前分析到如果产生了Impossible的plan那么将产生一个不带任何数据的游标,其就是在这里产生的            // Dummy table scan cursor returning no results.  Allowed in --notablescan mode.            return shared_ptr<Cursor>( new BasicCursor( DiskLoc() ) );        }        if ( willScanTable() ) {//要扫描全表的情况,根据_order情况建立BasicCursor或者ReverseCursor.            checkTableScanAllowed();            return findTableScan( _frs.ns(), _order, startLoc );        }               massert( 10363 ,  "newCursor() with start location not implemented for indexed plans", startLoc.isNull() );        if ( _startOrEndSpec ) {//建立Btree索引树并传入相应的范围条件            // we are sure to spec _endKeyInclusive            return shared_ptr<Cursor>( BtreeCursor::make( _d, _idxNo, *_index, _startKey, _endKey, _endKeyInclusive, _direction >= 0 ? 1 : -1 ) );        }        else if ( _index->getSpec().getType() ) {            return shared_ptr<Cursor>( BtreeCursor::make( _d, _idxNo, *_index, _frv->startKey(), _frv->endKey(), true, _direction >= 0 ? 1 : -1 ) );        }        else {            return shared_ptr<Cursor>( BtreeCursor::make( _d, _idxNo, *_index, _frv,                                                         independentRangesSingleIntervalLimit(),                                                         _direction >= 0 ? 1 : -1 ) );        }    }
        这里完成后那么cursor就建立了.回过来到CursorGenerator::generate函数,当singlePlanCursor无法返回

cursor时就将去到newQueryOptimizerCursor函数,在我们继续来分析这个函数之前先介绍下这个函数的流程.

        这个函数是处理多plan状况或者说$or操作符有效的情况.

一,当$or为false时,对于每一个plan那么建立一个QueryOptimizerCursorOp,这个结构内部保存了这个plan,在

初始化QueryOptimizerCursorOp时会根据其内部保存的plan产生cursor.QueryOptimizerCursorImpl的操作

对象就是这里的QueryOptimizerCursorOp,其内部每一次循环时都选择一个当前扫描对象最少的

QueryOptimizerCursorOp,选取它作为使用的QueryOptimizerCursorOp,当操作QueryOptimizerCursorOp

时,其内部做的动作就是操作cursor,然后做匹配,因为每次每一个QueryOptimizerCursorOp扫描的对象其实是

一样多的,这就相当于多plan的轮流执行,当一个QueryOptimizerCursorOp操作完成了也就是cursor不能再返

回document了那么这次查询也就结束了,第一个结束的plan表明这个plan是最优的,因为其查询的对象最少.

二.当$or语句有效时,举例db.coll.find({$or:[{a:1,c:1},{b:1,d:1}]}),这里之前也分析过首先执行查询的条件是

{a:1,c:1},根据这里的条件产生plan,然后照第一步的过程执行,当结束时继续对这里的{b:1,d:1}执行第一步描述

的流程.

下面来看代码吧.

    shared_ptr<Cursor> newQueryOptimizerCursor( auto_ptr<MultiPlanScanner> mps,                                               const QueryPlanSelectionPolicy &planPolicy,                                               bool requireOrder, bool explain ) {            shared_ptr<QueryOptimizerCursorImpl> ret                    ( QueryOptimizerCursorImpl::make( mps, planPolicy, requireOrder, explain ) );            return ret;    }
又是make函数.

        QueryOptimizerCursorImpl( auto_ptr<MultiPlanScanner> &mps,                                 const QueryPlanSelectionPolicy &planPolicy,                                 bool requireOrder ) :        _requireOrder( requireOrder ),        _mps( mps ),        _initialCandidatePlans( _mps->possibleInOrderPlan(), _mps->possibleOutOfOrderPlan() ),        _originalOp( new QueryOptimizerCursorOp( _nscanned, planPolicy, _requireOrder,                                                !_initialCandidatePlans.hybridPlanSet() ) ),        _currOp(),        _completePlanOfHybridSetScanAndOrderRequired(),        _nscanned() {        }                void init( bool explain ) {            _mps->initialOp( _originalOp );            if ( explain ) {                _explainQueryInfo = _mps->generateExplainInfo();            }            shared_ptr<QueryOp> op = _mps->nextOp();            rethrowOnError( op );            if ( !op->complete() ) {                _currOp = dynamic_cast<QueryOptimizerCursorOp*>( op.get() );            }        }
继续去到:MultiPlanScanner::nextOp

    shared_ptr<QueryOp> MultiPlanScanner::nextOp() {        verify( !doneOps() );//查询时存在$or这种语言并且其是有意义的,具体什么时候有意义请看上一篇文章        shared_ptr<QueryOp> ret = _or ? nextOpOr() : nextOpSimple();        if ( ret->error() || ret->complete() ) {            _doneOps = true;        }        return ret;    }    shared_ptr<QueryOp> MultiPlanScanner::nextOpSimple() {        return iterateRunner( *_baseOp );    }    shared_ptr<QueryOp> MultiPlanScanner::nextOpOr() {        shared_ptr<QueryOp> op;        do {            op = nextOpSimple();            if ( !op->completeWithoutStop() ) {                return op;            }//记得$or语句中比如说{$or:[{a:1},{b:1}]},之前_or语句只传入了一部分{a:1},这里就是{a:1}这个查询条件结束后继续开始{b:1}的查询条件,同样的过程,创建QueryPlanSet继续执行.            handleEndOfClause( op->queryPlan() );            _baseOp = op;        } while( mayHandleBeginningOfClause() );        return op;    }
去到nextOpSimple->iterateRunner:

    shared_ptr<QueryOp> MultiPlanScanner::iterateRunner( QueryOp &originalOp, bool retried ) {        if ( _runner ) {//第一次还未初始化为null            return _runner->next();        }        _runner.reset( new QueryPlanSet::Runner( *_currentQps, originalOp ) );//简单创建一个对象        shared_ptr<QueryOp> op = _runner->next();        if ( op->error() &&            _currentQps->prepareToRetryQuery() ) {            // Avoid an infinite loop here - this should never occur.            verify( !retried );            _runner.reset();            return iterateRunner( originalOp, true );        }        return op;    }
nextOpSimple->iterateRunner->QueryPlanSet::Runner::next

    shared_ptr<QueryOp> QueryPlanSet::Runner::next() {        if ( _ops.empty() ) {//首先还没有开始初始化.            shared_ptr<QueryOp> initialRet = init();            if ( initialRet ) {//初始化遇到错误或者plan中已经有执行完毕的plan                _done = true;                return initialRet;            }        }        shared_ptr<QueryOp> ret;        do {            ret = _next();//选取一个QueryOp这里一个QueryOp其实对应于一个plan.        } while( ret->error() && !_queue.empty() );        if ( _queue.empty() ) {            _done = true;        }        return ret;    }

nextOpSimple->iterateRunner->QueryPlanSet::Runner::next->QueryPlanSet::Runner::init

    shared_ptr<QueryOp> QueryPlanSet::Runner::init() {        if ( _plans._plans.size() > 1 )//之前建立的多plan查询            log(1) << "  running multiple plans" << endl;        for( PlanSet::iterator i = _plans._plans.begin(); i != _plans._plans.end(); ++i ) {            shared_ptr<QueryOp> op( _op.createChild() );            op->setQueryPlan( i->get() );//一个plan建立一个QueryOptimizerCursorOp            _ops.push_back( op );        }        // Initialize ops.        for( vector<shared_ptr<QueryOp> >::iterator i = _ops.begin(); i != _ops.end(); ++i ) {            initOp( **i );//这里不再输入,说明下这是调用QueryOptimizerCursorOp的init函数,根据上面的plan创建cursor,建立matcher这里的matcher是下一篇文章分析的内容            if ( _explainClauseInfo ) {                _explainClauseInfo->addPlanInfo( (*i)->generateExplainInfo() );            }        }        // See if an op has completed.        for( vector<shared_ptr<QueryOp> >::iterator i = _ops.begin(); i != _ops.end(); ++i ) {            if ( (*i)->complete() ) {//如果一个plan完成则说明任务完成                return *i;            }        }        // Put runnable ops in the priority queue.        for( vector<shared_ptr<QueryOp> >::iterator i = _ops.begin(); i != _ops.end(); ++i ) {            if ( !(*i)->error() ) {//建立一个Queryop的队列,需要注意的是这里的_queue的定义,our_priority_queue<OpHolder> _queue,其是一个优先级队列,每次选取执行扫描数最少的QueryOp                _queue.push( *i );            }        }        if ( _queue.empty() ) {            return _ops.front();        }        return shared_ptr<QueryOp>();    }
nextOpSimple->iterateRunner->QueryPlanSet::Runner::next->QueryPlanSet::Runner::_next

    shared_ptr<QueryOp> QueryPlanSet::Runner::_next() {        OpHolder holder = _queue.pop();//这里优先级队列选取已扫描最少对象的plan,一样则选取        QueryOp &op = *holder._op;//第一个plan        nextOp( op );//QueryOptimizerCursorOp::nextOp的调用,目的是记录当前扫描的对象数,可能的游标前进动作,检查游标是否已经执行完毕        if ( op.complete() ) {//几个plan中最早结束的plan,将其cache,以后查找时直接找到这个plan,节约查找时间            if ( _plans._mayRecordPlan && op.mayRecordPlan() ) {                op.queryPlan().registerSelf( op.nscanned(), _plans.characterizeCandidatePlans() );            }            _done = true;            return holder._op;        }        if ( _plans.hasPossiblyExcludedPlans() &&            op.nscanned() > _plans._oldNScanned * 10 ) {            verify( _plans.nPlans() == 1 && _plans.firstPlan()->special().empty() );            holder._offset = -op.nscanned();            _plans.addFallbackPlans();            PlanSet::iterator i = _plans._plans.begin();            ++i;            for( ; i != _plans._plans.end(); ++i ) {                shared_ptr<QueryOp> op( _op.createChild() );                op->setQueryPlan( i->get() );                _ops.push_back( op );                initOp( *op );                if ( op->complete() )                    return op;                _queue.push( op );            }            _plans._usingCachedPlan = false;        }//将这个QueryOp插入到优先级队列末尾,最后构成了多plan的轮流执行.        _queue.push( holder );        return holder._op;    }
回到nextOpSimple->iterateRunner,到此时QueryOp就已经选定了.退回到QueryOptimizerCursorImpl::init

        void init( bool explain ) {            shared_ptr<QueryOp> op = _mps->nextOp();//这里就是之前返回的op            if ( !op->complete() ) {//没有执行完毕则将其设置为当前的QueryOptimizerCursorOp                _currOp = dynamic_cast<QueryOptimizerCursorOp*>( op.get() );            }        }
来看看QueryOptimizerCursorImpl::OK和QueryOptimizerCursorImpl::advance这两个函数.

        virtual bool ok() { return _takeover ? _takeover->ok() : !currLoc().isNull(); }//这里_takeover还没设置为null        virtual DiskLoc currLoc() { return _takeover ? _takeover->currLoc() : _currLoc(); }        DiskLoc _currLoc() const {//这里就是调用之前得到的当前操作的QueryOptimizerCursorOp            return _currOp ? _currOp->currLoc() : DiskLoc();        }//这里_c是实际的cursor,调用其currLoc查看当前是否还有数据        DiskLoc QueryOptimizerCursorOp::currLoc() const { return _c ? _c->currLoc() : DiskLoc(); }
        virtual bool advance() {return _advance( false );}bool _advance( bool force ) {            if ( _takeover ) {//目前还为空                return _takeover->advance();            }            if ( !force && !ok() ) {                return false;            }            _currOp = 0;//上面已经分析了这个函数,这里是循环选取下一个QueryOp            shared_ptr<QueryOp> op = _mps->nextOp();            // Avoiding dynamic_cast here for performance.  Soon we won't need to            // do a cast at all.            QueryOptimizerCursorOp *qocop = (QueryOptimizerCursorOp*)( op.get() );            if ( !op->complete() ) {//这里查询数据还未结束                // The 'qocop' will be valid until we call _mps->nextOp() again.  We return 'current' values from this op.                _currOp = qocop;//改变了当前的QueryOp            }//一次查询最多会达到101条满足查询要求的docment,超过这个数目QueryOp就会设置为complete,但是并不是说数据查询完了            else if ( op->stopRequested() ) {//cursor仍然有效,但是已查出的document已经达到了上限101                if ( qocop->cursor() ) {//一次查询时得到的document数目有限,并不会一次返回所有数据.                    _takeover.reset( new MultiCursor( _mps,                                                     qocop->cursor(),                                                     op->queryPlan().matcher(),                                                     qocop->explainInfo(),                                                     *op,                                                     _nscanned - qocop->cursor()->nscanned() ) );                }            }            else {                if ( _initialCandidatePlans.hybridPlanSet() ) {                    _completePlanOfHybridSetScanAndOrderRequired =                            op->queryPlan().scanAndOrderRequired();                }            }            return ok();        }
        到这里所有cursor产生的执行流程以及分析完了,其流程是相当的复杂的,本人感觉查询部分是mongodb

中执行流程最复杂的部分了,因为空间有限,部分函数并未继续深入探讨,感兴趣的自己研究吧,也可以提出来大家

一起来讨论.下一篇文章我们将主要介绍docment的匹配.


原文链接: http://blog.csdn.net/yhjj0108/article/details/8260518

作者:yhjj0108,杨浩













原创粉丝点击