summaryrefslogtreecommitdiff
path: root/src/mongo/db/queryoptimizercursorimpl.cpp
diff options
context:
space:
mode:
authorApollon Oikonomopoulos <apoikos@debian.org>2016-01-14 00:10:06 +0200
committerApollon Oikonomopoulos <apollon@skroutz.gr>2016-01-14 00:10:06 +0200
commit374e1947abcd3e127a2a613aff73ecffdb9199ea (patch)
treed83973c3c9802450acd5b5e86fe0d4e8e60a3a1b /src/mongo/db/queryoptimizercursorimpl.cpp
parent65585c90b12d6523bea75a2aebaae2a2fdf9e641 (diff)
Imported Upstream version 2.6.11upstream/2.6.11
Diffstat (limited to 'src/mongo/db/queryoptimizercursorimpl.cpp')
-rw-r--r--src/mongo/db/queryoptimizercursorimpl.cpp542
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;