diff options
Diffstat (limited to 'src/mongo/db/queryoptimizercursorimpl.cpp')
| -rw-r--r-- | src/mongo/db/queryoptimizercursorimpl.cpp | 542 |
1 files changed, 0 insertions, 542 deletions
diff --git a/src/mongo/db/queryoptimizercursorimpl.cpp b/src/mongo/db/queryoptimizercursorimpl.cpp deleted file mode 100644 index 2c4d05c590d..00000000000 --- a/src/mongo/db/queryoptimizercursorimpl.cpp +++ /dev/null @@ -1,542 +0,0 @@ -// @file queryoptimizercursorimpl.cpp - A cursor interleaving multiple candidate cursors. - -/** - * Copyright (C) 2011 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "pch.h" - -#include "mongo/db/queryoptimizercursorimpl.h" - -#include "mongo/db/btreecursor.h" -#include "mongo/db/queryoptimizer.h" - -namespace mongo { - - extern bool useHints; - - QueryPlanSelectionPolicy::Any QueryPlanSelectionPolicy::__any; - const QueryPlanSelectionPolicy &QueryPlanSelectionPolicy::any() { return __any; } - - bool QueryPlanSelectionPolicy::IndexOnly::permitPlan( const QueryPlan &plan ) const { - return !plan.willScanTable(); - } - QueryPlanSelectionPolicy::IndexOnly QueryPlanSelectionPolicy::__indexOnly; - const QueryPlanSelectionPolicy &QueryPlanSelectionPolicy::indexOnly() { return __indexOnly; } - - bool QueryPlanSelectionPolicy::IdElseNatural::permitPlan( const QueryPlan &plan ) const { - return !plan.indexed() || plan.index()->isIdIndex(); - } - BSONObj QueryPlanSelectionPolicy::IdElseNatural::planHint( const StringData& ns ) const { - NamespaceDetails *nsd = nsdetails( ns ); - if ( !nsd || !nsd->haveIdIndex() ) { - return BSON( "$hint" << BSON( "$natural" << 1 ) ); - } - return BSON( "$hint" << nsd->idx( nsd->findIdIndex() ).indexName() ); - } - QueryPlanSelectionPolicy::IdElseNatural QueryPlanSelectionPolicy::__idElseNatural; - const QueryPlanSelectionPolicy &QueryPlanSelectionPolicy::idElseNatural() { - return __idElseNatural; - } - - QueryOptimizerCursorImpl* QueryOptimizerCursorImpl::make - ( auto_ptr<MultiPlanScanner>& mps, - const QueryPlanSelectionPolicy& planPolicy, - bool requireOrder, - bool explain ) { - auto_ptr<QueryOptimizerCursorImpl> ret( new QueryOptimizerCursorImpl( mps, planPolicy, - requireOrder ) ); - ret->init( explain ); - return ret.release(); - } - - bool QueryOptimizerCursorImpl::ok() { - return _takeover ? _takeover->ok() : !currLoc().isNull(); - } - - Record* QueryOptimizerCursorImpl::_current() { - if ( _takeover ) { - return _takeover->_current(); - } - assertOk(); - return currLoc().rec(); - } - - BSONObj QueryOptimizerCursorImpl::current() { - if ( _takeover ) { - return _takeover->current(); - } - assertOk(); - return currLoc().obj(); - } - - DiskLoc QueryOptimizerCursorImpl::currLoc() { - return _takeover ? _takeover->currLoc() : _currLoc(); - } - - DiskLoc QueryOptimizerCursorImpl::_currLoc() const { - dassert( !_takeover ); - return _currRunner ? _currRunner->currLoc() : DiskLoc(); - } - - bool QueryOptimizerCursorImpl::advance() { - return _advance( false ); - } - - BSONObj QueryOptimizerCursorImpl::currKey() const { - if ( _takeover ) { - return _takeover->currKey(); - } - assertOk(); - return _currRunner->currKey(); - } - - DiskLoc QueryOptimizerCursorImpl::refLoc() { - return _takeover ? _takeover->refLoc() : DiskLoc(); - } - - BSONObj QueryOptimizerCursorImpl::indexKeyPattern() { - if ( _takeover ) { - return _takeover->indexKeyPattern(); - } - assertOk(); - return _currRunner->cursor()->indexKeyPattern(); - } - - void QueryOptimizerCursorImpl::prepareToTouchEarlierIterate() { - if ( _takeover ) { - _takeover->prepareToTouchEarlierIterate(); - } - else if ( _currRunner ) { - if ( _mps->currentNPlans() == 1 ) { - // This single plan version is a bit more performant, so we use it when possible. - _currRunner->prepareToTouchEarlierIterate(); - } - else { - // With multiple plans, the 'earlier iterate' could be the current iterate of one of - // the component plans. We do a full yield of all plans, using ClientCursors. - _mps->prepareToYield(); - } - } - } - - void QueryOptimizerCursorImpl::recoverFromTouchingEarlierIterate() { - if ( _takeover ) { - _takeover->recoverFromTouchingEarlierIterate(); - } - else if ( _currRunner ) { - if ( _mps->currentNPlans() == 1 ) { - _currRunner->recoverFromTouchingEarlierIterate(); - } - else { - recoverFromYield(); - } - } - } - - void QueryOptimizerCursorImpl::prepareToYield() { - if ( _takeover ) { - _takeover->prepareToYield(); - } - else if ( _currRunner ) { - _mps->prepareToYield(); - } - } - - void QueryOptimizerCursorImpl::recoverFromYield() { - if ( _takeover ) { - _takeover->recoverFromYield(); - return; - } - if ( _currRunner ) { - _mps->recoverFromYield(); - if ( _currRunner->error() || !ok() ) { - // Advance to a non error op if one of the ops errored out. - // Advance to a following $or clause if the $or clause returned all results. - verify( !_mps->doneRunners() ); - _advance( true ); - } - } - } - - bool QueryOptimizerCursorImpl::getsetdup(DiskLoc loc) { - if ( _takeover ) { - if ( getdupInternal( loc ) ) { - return true; - } - return _takeover->getsetdup( loc ); - } - assertOk(); - return getsetdupInternal( loc ); - } - - bool QueryOptimizerCursorImpl::isMultiKey() const { - if ( _takeover ) { - return _takeover->isMultiKey(); - } - assertOk(); - return _currRunner->cursor()->isMultiKey(); - } - - bool QueryOptimizerCursorImpl::capped() const { - // Initial capped wrapping cases (before takeover) are handled internally by a component - // ClientCursor. - return _takeover ? _takeover->capped() : false; - } - - long long QueryOptimizerCursorImpl::nscanned() { - return _takeover ? _takeover->nscanned() : _nscanned; - } - - CoveredIndexMatcher* QueryOptimizerCursorImpl::matcher() const { - if ( _takeover ) { - return _takeover->matcher(); - } - assertOk(); - return _currRunner->queryPlan().matcher().get(); - } - - bool QueryOptimizerCursorImpl::currentMatches( MatchDetails* details ) { - if ( _takeover ) { - return _takeover->currentMatches( details ); - } - assertOk(); - return _currRunner->currentMatches( details ); - } - - const FieldRangeSet* QueryOptimizerCursorImpl::initialFieldRangeSet() const { - if ( _takeover ) { - return 0; - } - assertOk(); - return &_currRunner->queryPlan().multikeyFrs(); - } - - bool QueryOptimizerCursorImpl::currentPlanScanAndOrderRequired() const { - if ( _takeover ) { - return _takeover->queryPlan().scanAndOrderRequired(); - } - assertOk(); - return _currRunner->queryPlan().scanAndOrderRequired(); - } - - const Projection::KeyOnly* QueryOptimizerCursorImpl::keyFieldsOnly() const { - if ( _takeover ) { - return _takeover->keyFieldsOnly(); - } - assertOk(); - return _currRunner->keyFieldsOnly(); - } - - bool QueryOptimizerCursorImpl::runningInitialInOrderPlan() const { - if ( _takeover ) { - return false; - } - assertOk(); - return _mps->haveInOrderPlan(); - } - - bool QueryOptimizerCursorImpl::hasPossiblyExcludedPlans() const { - if ( _takeover ) { - return false; - } - assertOk(); - return _mps->hasPossiblyExcludedPlans(); - } - - void QueryOptimizerCursorImpl::clearIndexesForPatterns() { - if ( !_takeover ) { - _mps->clearIndexesForPatterns(); - } - } - - void QueryOptimizerCursorImpl::abortOutOfOrderPlans() { - _requireOrder = true; - } - - void QueryOptimizerCursorImpl::noteIterate( bool match, bool loadedDocument, bool chunkSkip ) { - if ( _explainQueryInfo ) { - _explainQueryInfo->noteIterate( match, loadedDocument, chunkSkip ); - } - if ( _takeover ) { - _takeover->noteIterate( match, loadedDocument ); - } - } - - void QueryOptimizerCursorImpl::noteYield() { - if ( _explainQueryInfo ) { - _explainQueryInfo->noteYield(); - } - } - - QueryOptimizerCursorImpl::QueryOptimizerCursorImpl( auto_ptr<MultiPlanScanner>& mps, - const QueryPlanSelectionPolicy& planPolicy, - bool requireOrder ) : - _requireOrder( requireOrder ), - _mps( mps ), - _initialCandidatePlans( _mps->possibleInOrderPlan(), _mps->possibleOutOfOrderPlan() ), - _originalRunner( new QueryPlanRunner( _nscanned, - planPolicy, - _requireOrder, - !_initialCandidatePlans.hybridPlanSet() ) ), - _currRunner(), - _completePlanOfHybridSetScanAndOrderRequired(), - _nscanned() { - } - - void QueryOptimizerCursorImpl::init( bool explain ) { - _mps->initialRunner( _originalRunner ); - if ( explain ) { - _explainQueryInfo = _mps->generateExplainInfo(); - } - shared_ptr<QueryPlanRunner> runner = _mps->nextRunner(); - rethrowOnError( runner ); - if ( !runner->complete() ) { - _currRunner = runner.get(); - } - } - - bool QueryOptimizerCursorImpl::_advance( bool force ) { - if ( _takeover ) { - return _takeover->advance(); - } - - if ( !force && !ok() ) { - return false; - } - - _currRunner = 0; - shared_ptr<QueryPlanRunner> runner = _mps->nextRunner(); - rethrowOnError( runner ); - - if ( !runner->complete() ) { - // The 'runner' will be valid until we call _mps->nextOp() again. We return 'current' - // values from this op. - _currRunner = runner.get(); - } - else if ( runner->stopRequested() ) { - if ( runner->cursor() ) { - _takeover.reset( new MultiCursor( _mps, - runner->cursor(), - runner->queryPlan().matcher(), - runner->explainInfo(), - *runner, - _nscanned - runner->cursor()->nscanned() ) ); - } - } - else { - if ( _initialCandidatePlans.hybridPlanSet() ) { - _completePlanOfHybridSetScanAndOrderRequired = - runner->queryPlan().scanAndOrderRequired(); - } - } - - return ok(); - } - - /** Forward an exception when the runner errs out. */ - void QueryOptimizerCursorImpl::rethrowOnError( const shared_ptr< QueryPlanRunner > &runner ) { - if ( runner->error() ) { - throw MsgAssertionException( runner->exception() ); - } - } - - bool QueryOptimizerCursorImpl::getsetdupInternal(const DiskLoc &loc) { - return _dups.getsetdup( loc ); - } - - bool QueryOptimizerCursorImpl::getdupInternal(const DiskLoc &loc) { - dassert( _takeover ); - return _dups.getdup( loc ); - } - - shared_ptr<Cursor> newQueryOptimizerCursor( auto_ptr<MultiPlanScanner> mps, - const QueryPlanSelectionPolicy &planPolicy, - bool requireOrder, bool explain ) { - try { - shared_ptr<QueryOptimizerCursorImpl> ret - ( QueryOptimizerCursorImpl::make( mps, planPolicy, requireOrder, explain ) ); - return ret; - } catch( const AssertionException &e ) { - if ( e.getCode() == OutOfOrderDocumentsAssertionCode ) { - // If no indexes follow the requested sort order, return an - // empty pointer. This is legacy behavior based on bestGuessCursor(). - return shared_ptr<Cursor>(); - } - throw; - } - return shared_ptr<Cursor>(); - } - - shared_ptr<Cursor> - NamespaceDetailsTransient::getCursor( const StringData &ns, - const BSONObj &query, - const BSONObj &order, - const QueryPlanSelectionPolicy &planPolicy, - const shared_ptr<const ParsedQuery> &parsedQuery, - bool requireOrder, - QueryPlanSummary *singlePlanSummary ) { - - CursorGenerator generator( ns, - query, - order, - planPolicy, - parsedQuery, - requireOrder, - singlePlanSummary ); - return generator.generate(); - } - - CursorGenerator::CursorGenerator( const StringData &ns, - const BSONObj &query, - const BSONObj &order, - const QueryPlanSelectionPolicy &planPolicy, - const shared_ptr<const ParsedQuery> &parsedQuery, - bool requireOrder, - QueryPlanSummary *singlePlanSummary ) : - _ns( ns ), - _query( query ), - _order( order ), - _planPolicy( planPolicy ), - _parsedQuery( parsedQuery ), - _requireOrder( requireOrder ), - _singlePlanSummary( singlePlanSummary ) { - // Initialize optional return variables. - if ( _singlePlanSummary ) { - *_singlePlanSummary = QueryPlanSummary(); - } - } - - void CursorGenerator::setArgumentsHint() { - if ( useHints && _parsedQuery ) { - _argumentsHint = _parsedQuery->getHint(); - } - - if ( snapshot() ) { - NamespaceDetails *d = nsdetails( _ns ); - if ( d ) { - int i = d->findIdIndex(); - if( i < 0 ) { - if ( _ns.find( ".system." ) == string::npos ) - log() << "warning: no _id index on $snapshot query, ns:" << _ns << endl; - } - else { - /* [dm] the name of an _id index tends to vary, so we build the hint the hard - way here. probably need a better way to specify "use the _id index" as a hint. - if someone is in the query optimizer please fix this then! - */ - _argumentsHint = BSON( "$hint" << d->idx(i).indexName() ); - } - } - } - } - - shared_ptr<Cursor> CursorGenerator::shortcutCursor() const { - if ( !mayShortcutQueryOptimizer() ) { - return shared_ptr<Cursor>(); - } - - if ( _planPolicy.permitOptimalNaturalPlan() && _query.isEmpty() && _order.isEmpty() ) { - return theDataFileMgr.findAll( _ns ); - } - if ( _planPolicy.permitOptimalIdPlan() && isSimpleIdQuery( _query ) ) { - Database *database = cc().database(); - verify( database ); - NamespaceDetails *d = database->namespaceIndex.details( _ns ); - if ( d ) { - int idxNo = d->findIdIndex(); - if ( idxNo >= 0 ) { - IndexDetails& i = d->idx( idxNo ); - BSONObj key = i.getKeyFromQuery( _query ); - return shared_ptr<Cursor>( BtreeCursor::make( d, i, key, key, true, 1 ) ); - } - } - } - - return shared_ptr<Cursor>(); - } - - void CursorGenerator::setMultiPlanScanner() { - _mps.reset( MultiPlanScanner::make( _ns, _query, _order, _parsedQuery, hint(), - explain() ? QueryPlanGenerator::Ignore : - QueryPlanGenerator::Use, - min(), max() ) ); - } - - shared_ptr<Cursor> CursorGenerator::singlePlanCursor() { - const QueryPlan *singlePlan = _mps->singlePlan(); - if ( !singlePlan || ( isOrderRequired() && singlePlan->scanAndOrderRequired() ) ) { - return shared_ptr<Cursor>(); - } - if ( !_planPolicy.permitPlan( *singlePlan ) ) { - return shared_ptr<Cursor>(); - } - - if ( _singlePlanSummary ) { - *_singlePlanSummary = singlePlan->summary(); - } - shared_ptr<Cursor> single = singlePlan->newCursor( DiskLoc(), - _planPolicy.requestIntervalCursor() ); - if ( !_query.isEmpty() && !single->matcher() ) { - - // The query plan must have a matcher. The matcher's constructor performs some aspects - // of query validation that should occur before a cursor is returned. - fassert( 16449, singlePlan->matcher() ); - - if ( // If a matcher is requested or ... - _planPolicy.requestMatcher() || - // ... the index ranges do not exactly match the query or ... - singlePlan->mayBeMatcherNecessary() || - // ... the matcher must look at the full record ... - singlePlan->matcher()->needRecord() ) { - - // ... then set the cursor's matcher to the query plan's matcher. - single->setMatcher( singlePlan->matcher() ); - } - } - if ( singlePlan->keyFieldsOnly() ) { - single->setKeyFieldsOnly( singlePlan->keyFieldsOnly() ); - } - return single; - } - - shared_ptr<Cursor> CursorGenerator::generate() { - - setArgumentsHint(); - shared_ptr<Cursor> cursor = shortcutCursor(); - if ( cursor ) { - return cursor; - } - - setMultiPlanScanner(); - cursor = singlePlanCursor(); - if ( cursor ) { - return cursor; - } - - return newQueryOptimizerCursor( _mps, _planPolicy, isOrderRequired(), explain() ); - } - - /** This interface is just available for testing. */ - shared_ptr<Cursor> newQueryOptimizerCursor - ( const char *ns, const BSONObj &query, const BSONObj &order, - const QueryPlanSelectionPolicy &planPolicy, bool requireOrder, - const shared_ptr<const ParsedQuery> &parsedQuery ) { - auto_ptr<MultiPlanScanner> mps( MultiPlanScanner::make( ns, query, order, parsedQuery ) ); - return newQueryOptimizerCursor( mps, planPolicy, requireOrder, false ); - } - -} // namespace mongo; |
