Files
mongo/db/queryoptimizer.h

581 lines
24 KiB
C
Raw Normal View History

2011-04-07 16:07:29 -07:00
// @file queryoptimizer.h
2008-11-15 19:04:01 -05:00
2008-11-14 16:19:47 -05:00
/**
* Copyright (C) 2008 10gen Inc.
2008-12-28 20:28:49 -05:00
*
2008-11-14 16:19:47 -05:00
* 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.
2008-12-28 20:28:49 -05:00
*
2008-11-14 16:19:47 -05:00
* 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.
2008-12-28 20:28:49 -05:00
*
2008-11-14 16:19:47 -05:00
* 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/>.
*/
2008-12-28 20:28:49 -05:00
#pragma once
2008-11-14 16:19:47 -05:00
2009-02-17 15:53:19 -05:00
#include "cursor.h"
#include "jsobj.h"
2009-02-24 14:14:45 -05:00
#include "queryutil.h"
#include "matcher.h"
#include "../util/net/listen.h"
#include <queue>
2009-02-17 15:53:19 -05:00
2009-01-14 17:09:51 -05:00
namespace mongo {
2011-01-04 00:40:41 -05:00
2009-02-20 11:08:22 -05:00
class IndexDetails;
2010-03-10 22:44:51 -05:00
class IndexType;
class ElapsedTracker;
2010-03-10 22:44:51 -05:00
2011-04-07 12:12:08 -07:00
/** A plan for executing a query using the given index spec and FieldRangeSet. */
2009-07-07 14:12:53 -04:00
class QueryPlan : boost::noncopyable {
public:
2010-11-12 18:16:49 -05:00
/**
* @param originalFrsp - original constraints for this query clause. If null, frsp will be used instead.
*/
2011-01-04 00:40:41 -05:00
QueryPlan(NamespaceDetails *d,
2010-11-12 18:16:49 -05:00
int idxNo, // -1 = no index
const FieldRangeSetPair &frsp,
const FieldRangeSetPair *originalFrsp,
const BSONObj &originalQuery,
const BSONObj &order,
bool mustAssertOnYieldFailure = true,
const BSONObj &startKey = BSONObj(),
2011-04-07 12:12:08 -07:00
const BSONObj &endKey = BSONObj(),
2010-02-25 16:24:34 -05:00
string special="" );
2009-07-07 14:12:53 -04:00
2011-04-07 12:12:08 -07:00
/** @return true iff no other plans should be considered. */
2010-11-12 18:16:49 -05:00
bool optimal() const { return _optimal; }
2011-04-07 12:12:08 -07:00
/* @return true iff this plan should not be considered at all. */
bool unhelpful() const { return _unhelpful; }
/** @return true iff ScanAndOrder processing will be required for result set. */
2010-11-12 18:16:49 -05:00
bool scanAndOrderRequired() const { return _scanAndOrderRequired; }
2011-04-07 12:12:08 -07:00
/**
* @return true iff the index we are using has keys such that it can completely resolve the
* query expression to match by itself without ever checking the main object.
2009-02-17 20:57:36 -05:00
*/
2010-11-12 18:16:49 -05:00
bool exactKeyMatch() const { return _exactKeyMatch; }
2011-04-07 12:12:08 -07:00
/** @return true iff this QueryPlan would perform an unindexed scan. */
bool willScanTable() const { return _idxNo < 0 && !_impossible; }
2011-04-07 12:12:08 -07:00
/** @return a new cursor based on this QueryPlan's index and FieldRangeSet. */
shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const;
2011-04-07 12:12:08 -07:00
/** @return a new reverse cursor if this is an unindexed plan. */
shared_ptr<Cursor> newReverseCursor() const;
2011-04-07 12:12:08 -07:00
/** Register this plan as a winner for its QueryPattern, with specified 'nscanned'. */
void registerSelf( long long nScanned ) const;
int direction() const { return _direction; }
BSONObj indexKey() const;
2010-12-07 23:01:19 -08:00
bool indexed() const { return _index; }
int idxNo() const { return _idxNo; }
2011-04-05 18:57:09 -07:00
const char *ns() const { return _frs.ns(); }
2010-11-12 18:16:49 -05:00
NamespaceDetails *nsd() const { return _d; }
BSONObj originalQuery() const { return _originalQuery; }
2011-04-05 18:57:09 -07:00
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return _frs.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return _frs.range( fieldName ); }
2011-04-07 16:07:29 -07:00
shared_ptr<FieldRangeVector> originalFrv() const { return _originalFrv; }
2011-04-07 12:12:08 -07:00
const FieldRangeSet &multikeyFrs() const { return _frsMulti; }
bool mustAssertOnYieldFailure() const { return _mustAssertOnYieldFailure; }
2011-04-07 12:12:08 -07:00
/** just for testing */
2011-04-07 16:07:29 -07:00
shared_ptr<FieldRangeVector> frv() const { return _frv; }
bool isMultiKey() const;
2010-11-12 18:16:49 -05:00
2009-02-17 20:57:36 -05:00
private:
2010-11-12 18:16:49 -05:00
NamespaceDetails * _d;
int _idxNo;
2011-04-05 18:57:09 -07:00
const FieldRangeSet &_frs;
const FieldRangeSet &_frsMulti;
const BSONObj &_originalQuery;
2010-11-12 18:16:49 -05:00
const BSONObj &_order;
const IndexDetails * _index;
bool _optimal;
bool _scanAndOrderRequired;
bool _exactKeyMatch;
int _direction;
2011-04-07 16:07:29 -07:00
shared_ptr<FieldRangeVector> _frv;
shared_ptr<FieldRangeVector> _originalFrv;
2010-07-16 01:49:15 -07:00
BSONObj _startKey;
BSONObj _endKey;
2010-10-19 09:13:57 -04:00
bool _endKeyInclusive;
2010-11-12 18:16:49 -05:00
bool _unhelpful;
bool _impossible;
2010-02-25 16:24:34 -05:00
string _special;
IndexType * _type;
2010-07-07 12:26:20 -07:00
bool _startOrEndSpec;
bool _mustAssertOnYieldFailure;
};
2011-04-07 12:12:08 -07:00
/**
* Inherit from this interface to implement a new query operation.
* The query optimizer will clone the QueryOp that is provided, giving
* each clone its own query plan.
*
* Normal sequence of events:
* 1) A new QueryOp is generated using createChild().
* 2) A QueryPlan is assigned to this QueryOp with setQueryPlan().
* 3) _init() is called on the QueryPlan.
* 4) next() is called repeatedly, with nscanned() checked after each call.
* 5) In one of these calls to next(), setComplete() is called.
* 6) The QueryPattern for the QueryPlan may be recorded as a winner.
*/
2009-02-20 11:08:22 -05:00
class QueryOp {
public:
QueryOp() : _complete(), _stopRequested(), _qp(), _error() {}
2011-04-07 12:12:08 -07:00
/** Used when handing off from one QueryOp to another. */
QueryOp( const QueryOp &other ) :
2011-01-04 00:40:41 -05:00
_complete(), _stopRequested(), _qp(), _error(), _matcher( other._matcher ),
_orConstraint( other._orConstraint ) {}
2009-02-20 11:08:22 -05:00
virtual ~QueryOp() {}
2011-01-04 00:40:41 -05:00
2011-04-07 12:12:08 -07:00
/** @return QueryPlan assigned to this QueryOp by the query optimizer. */
const QueryPlan &qp() const { return *_qp; }
/** Advance to next potential matching document (eg using a cursor). */
virtual void next() = 0;
2011-04-07 12:12:08 -07:00
/**
* @return current 'nscanned' metric for this QueryOp. Used to compare
* cost to other QueryOps.
*/
virtual long long nscanned() = 0;
/** Take any steps necessary before the db mutex is yielded. */
2010-08-02 15:43:53 -07:00
virtual bool prepareToYield() { massert( 13335, "yield not supported", false ); return false; }
2011-04-07 12:12:08 -07:00
/** Recover once the db mutex is regained. */
virtual void recoverFromYield() { massert( 13336, "yield not supported", false ); }
2011-04-07 12:12:08 -07:00
/**
* @return true iff the QueryPlan for this QueryOp may be registered
* as a winning plan.
*/
virtual bool mayRecordPlan() const = 0;
2011-01-04 00:40:41 -05:00
2011-04-07 12:12:08 -07:00
/** @return true iff the implementation called setComplete() or setStop(). */
2010-05-12 11:03:51 -07:00
bool complete() const { return _complete; }
2011-04-07 12:12:08 -07:00
/** @return true iff the implementation called steStop(). */
bool stopRequested() const { return _stopRequested; }
2011-04-07 12:12:08 -07:00
/** @return true iff the implementation threw an exception. */
bool error() const { return _error; }
/** @return the exception thrown by implementation if one was thrown. */
2010-06-21 13:41:34 -04:00
ExceptionInfo exception() const { return _exception; }
2011-04-07 12:12:08 -07:00
/** To be called by QueryPlanSet::Runner only. */
QueryOp *createChild();
2011-04-07 13:02:40 -07:00
void setQueryPlan( const QueryPlan *qp ) { _qp = qp; assert( _qp != NULL ); }
2011-04-07 12:12:08 -07:00
void init();
2010-06-21 13:41:34 -04:00
void setException( const DBException &e ) {
2010-05-12 11:03:51 -07:00
_error = true;
2010-06-21 13:41:34 -04:00
_exception = e.getInfo();
2009-02-24 15:45:18 -05:00
}
shared_ptr<CoveredIndexMatcher> matcher( const shared_ptr<Cursor>& c ) const {
return matcher( c.get() );
}
shared_ptr<CoveredIndexMatcher> matcher( Cursor* c ) const {
if( ! c ) return _matcher;
return c->matcher() ? c->matcherPtr() : _matcher;
}
2011-04-07 12:12:08 -07:00
protected:
2011-04-07 12:12:08 -07:00
/** Call if all results have been found. */
void setComplete() {
_orConstraint = qp().originalFrv();
_complete = true;
}
2011-04-07 12:12:08 -07:00
/** Call if the scan is complete even if not all results have been found. */
2010-05-12 11:03:51 -07:00
void setStop() { setComplete(); _stopRequested = true; }
2011-04-07 12:12:08 -07:00
/** Handle initialization after a QueryPlan has been set. */
virtual void _init() = 0;
2011-01-04 00:40:41 -05:00
2011-04-07 12:12:08 -07:00
/** @return a copy of the inheriting class, which will be run with its own query plan. */
virtual QueryOp *_createChild() const = 0;
2011-01-04 00:40:41 -05:00
virtual bool alwaysUseRecord() const { return false; }
2011-01-04 00:40:41 -05:00
2009-02-20 11:08:22 -05:00
private:
2010-05-12 11:03:51 -07:00
bool _complete;
bool _stopRequested;
2010-06-21 13:41:34 -04:00
ExceptionInfo _exception;
2010-05-12 11:03:51 -07:00
const QueryPlan *_qp;
bool _error;
2011-04-07 16:07:29 -07:00
shared_ptr<CoveredIndexMatcher> _matcher;
shared_ptr<CoveredIndexMatcher> _oldMatcher;
shared_ptr<FieldRangeVector> _orConstraint;
2009-02-20 11:08:22 -05:00
};
2011-01-04 00:40:41 -05:00
2011-05-26 01:35:48 -04:00
// temp. this class works if T::operator< is variant unlike a regular stl priority queue.
// but it's very slow. however if v.size() is always very small, it would be fine,
// maybe even faster than a smart impl that does more memory allocations.
template<class T>
class our_priority_queue : boost::noncopyable {
vector<T> v;
public:
our_priority_queue() {
v.reserve(4);
}
int size() const { return v.size(); }
bool empty() const { return v.empty(); }
void push(const T & x) {
v.push_back(x);
}
T pop() {
size_t t = 0;
2011-05-26 22:22:40 -04:00
for( size_t i = 1; i < v.size(); i++ ) {
2011-05-26 01:35:48 -04:00
if( v[t] < v[i] )
t = i;
}
T ret = v[t];
v.erase(v.begin()+t);
return ret;
2011-05-26 01:35:48 -04:00
}
};
2011-04-07 12:12:08 -07:00
/**
* A set of candidate query plans for a query. This class can return a best buess plan or run a
* QueryOp on all the plans.
*/
class QueryPlanSet {
public:
2010-03-29 12:55:44 -04:00
2011-04-07 16:07:29 -07:00
typedef boost::shared_ptr<QueryPlan> QueryPlanPtr;
typedef vector<QueryPlanPtr> PlanSet;
2010-03-29 12:55:44 -04:00
/**
* @param originalFrsp - original constraints for this query clause; if null, frsp will be used.
*/
QueryPlanSet( const char *ns,
auto_ptr<FieldRangeSetPair> frsp,
auto_ptr<FieldRangeSetPair> originalFrsp,
2011-01-04 00:40:41 -05:00
const BSONObj &originalQuery,
const BSONObj &order,
bool mustAssertOnYieldFailure = true,
2011-01-04 00:40:41 -05:00
const BSONElement *hint = 0,
bool honorRecordedPlan = true,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj(),
bool bestGuessOnly = false,
bool mayYield = false);
2011-04-07 12:12:08 -07:00
/** @return number of candidate plans. */
2010-11-12 18:22:19 -05:00
int nPlans() const { return _plans.size(); }
2011-04-07 12:12:08 -07:00
/**
* Clone op for each query plan, and @return the first cloned op to call
* setComplete() or setStop().
*/
2011-04-07 16:07:29 -07:00
shared_ptr<QueryOp> runOp( QueryOp &op );
template<class T>
shared_ptr<T> runOp( T &op ) {
return dynamic_pointer_cast<T>( runOp( static_cast<QueryOp&>( op ) ) );
}
2011-04-07 12:12:08 -07:00
/** Initialize or iterate a runner generated from @param originalOp. */
shared_ptr<QueryOp> nextOp( QueryOp &originalOp, bool retried = false );
/** Yield the runner member. */
bool prepareToYield();
void recoverFromYield();
QueryPlanPtr firstPlan() const { return _plans[ 0 ]; }
2011-04-07 12:12:08 -07:00
/** @return metadata about cursors and index bounds for all plans, suitable for explain output. */
BSONObj explain() const;
2011-04-07 12:12:08 -07:00
/** @return true iff a plan is selected based on previous success of this plan. */
2010-11-12 18:22:19 -05:00
bool usingPrerecordedPlan() const { return _usingPrerecordedPlan; }
2011-04-07 12:12:08 -07:00
/** @return a single plan that may work well for the specified query. */
2010-11-12 18:08:51 -05:00
QueryPlanPtr getBestGuess() const;
2011-04-07 12:12:08 -07:00
2010-05-12 10:58:16 -07:00
//for testing
const FieldRangeSetPair &frsp() const { return *_frsp; }
const FieldRangeSetPair *originalFrsp() const { return _originalFrsp.get(); }
bool modifiedKeys() const;
2010-11-15 10:22:20 -05:00
bool hasMultiKey() const;
2010-11-12 18:22:19 -05:00
private:
void addOtherPlans( bool checkFirst );
2010-11-12 18:08:51 -05:00
void addPlan( QueryPlanPtr plan, bool checkFirst ) {
2010-11-12 18:22:19 -05:00
if ( checkFirst && plan->indexKey().woCompare( _plans[ 0 ]->indexKey() ) == 0 )
return;
2010-11-12 18:22:19 -05:00
_plans.push_back( plan );
}
2009-02-25 10:48:41 -05:00
void init();
void addHint( IndexDetails &id );
class Runner {
public:
Runner( QueryPlanSet &plans, QueryOp &op );
/**
* Iterate interactively through candidate documents on all plans.
* QueryOp objects are returned at each interleaved step.
*/
/** @return a plan that has completed, otherwise an arbitrary plan. */
shared_ptr<QueryOp> init();
/**
* Move the Runner forward one iteration, and @return the plan for
* this iteration.
*/
shared_ptr<QueryOp> next();
/** @return next non error op if there is one, otherwise an error op. */
shared_ptr<QueryOp> nextNonError();
bool prepareToYield();
void recoverFromYield();
/** Run until first op completes. */
shared_ptr<QueryOp> runUntilFirstCompletes();
void mayYield();
2010-11-12 18:22:19 -05:00
QueryOp &_op;
QueryPlanSet &_plans;
2009-02-26 10:28:27 -05:00
static void initOp( QueryOp &op );
static void nextOp( QueryOp &op );
static bool prepareToYieldOp( QueryOp &op );
static void recoverFromYieldOp( QueryOp &op );
private:
vector<shared_ptr<QueryOp> > _ops;
struct OpHolder {
OpHolder( const shared_ptr<QueryOp> &op ) : _op( op ), _offset() {}
shared_ptr<QueryOp> _op;
long long _offset;
bool operator<( const OpHolder &other ) const {
return _op->nscanned() + _offset > other._op->nscanned() + other._offset;
}
};
2011-05-26 01:35:48 -04:00
our_priority_queue<OpHolder> _queue;
2009-02-20 11:08:22 -05:00
};
2010-11-12 18:22:19 -05:00
const char *_ns;
BSONObj _originalQuery;
auto_ptr<FieldRangeSetPair> _frsp;
auto_ptr<FieldRangeSetPair> _originalFrsp;
2010-11-12 18:22:19 -05:00
PlanSet _plans;
bool _mayRecordPlan;
bool _usingPrerecordedPlan;
BSONObj _hint;
2010-11-12 18:16:49 -05:00
BSONObj _order;
2010-11-12 18:22:19 -05:00
long long _oldNScanned;
bool _honorRecordedPlan;
BSONObj _min;
BSONObj _max;
string _special;
2010-05-24 23:51:24 -07:00
bool _bestGuessOnly;
bool _mayYield;
ElapsedTracker _yieldSometimesTracker;
shared_ptr<Runner> _runner;
bool _mustAssertOnYieldFailure;
};
2009-01-14 17:09:51 -05:00
2011-04-07 12:12:08 -07:00
/** Handles $or type queries by generating a QueryPlanSet for each $or clause. */
2010-05-12 10:38:58 -07:00
class MultiPlanScanner {
public:
MultiPlanScanner( const char *ns,
2011-01-04 00:40:41 -05:00
const BSONObj &query,
const BSONObj &order,
const BSONElement *hint = 0,
bool honorRecordedPlan = true,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj(),
bool bestGuessOnly = false,
bool mayYield = false);
2011-04-07 12:12:08 -07:00
/**
* Clone op for each query plan of a single $or clause, and @return the first cloned op
* to call setComplete() or setStop().
*/
2011-04-07 16:07:29 -07:00
shared_ptr<QueryOp> runOpOnce( QueryOp &op );
template<class T>
shared_ptr<T> runOpOnce( T &op ) {
return dynamic_pointer_cast<T>( runOpOnce( static_cast<QueryOp&>( op ) ) );
2011-01-04 00:40:41 -05:00
}
2011-04-07 12:12:08 -07:00
/**
* For each $or clause, calls runOpOnce on the child QueryOp cloned from the winning QueryOp
* of the previous $or clause (or from the supplied 'op' for the first $or clause).
*/
2011-04-07 16:07:29 -07:00
shared_ptr<QueryOp> runOp( QueryOp &op );
template<class T>
shared_ptr<T> runOp( T &op ) {
return dynamic_pointer_cast<T>( runOp( static_cast<QueryOp&>( op ) ) );
2011-04-07 12:12:08 -07:00
}
/** Initialize or iterate a runner generated from @param originalOp. */
void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = originalOp; }
shared_ptr<QueryOp> nextOp();
/** Yield the runner member. */
bool prepareToYield();
void recoverFromYield();
/**
* @return a single simple cursor if the scanner would run a single cursor
* for this query, otherwise return an empty shared_ptr.
*/
shared_ptr<Cursor> singleCursor() const;
2011-04-07 12:12:08 -07:00
/** @return true iff more $or clauses need to be scanned. */
bool mayRunMore() const { return _or ? ( !_tableScanned && !_org->orFinished() ) : _i == 0; }
2011-04-07 12:12:08 -07:00
/** @return non-$or version of explain output. */
2010-05-26 01:30:50 -07:00
BSONObj oldExplain() const { assertNotOr(); return _currentQps->explain(); }
2011-04-07 12:12:08 -07:00
/** @return true iff this is not a $or query and a plan is selected based on previous success of this plan. */
bool usingPrerecordedPlan() const { return !_or && _currentQps->usingPrerecordedPlan(); }
/** Don't attempt to scan multiple plans, just use the best guess. */
2010-05-24 23:51:24 -07:00
void setBestGuessOnly() { _bestGuessOnly = true; }
2011-04-07 12:12:08 -07:00
/** Yielding is allowed while running each QueryPlan. */
void mayYield( bool val ) { _mayYield = val; }
bool modifiedKeys() const { return _currentQps->modifiedKeys(); }
2010-11-15 10:22:20 -05:00
bool hasMultiKey() const { return _currentQps->hasMultiKey(); }
2010-05-12 10:38:58 -07:00
private:
void assertNotOr() const {
massert( 13266, "not implemented for $or query", !_or );
}
void assertMayRunMore() const {
massert( 13271, "can't run more ops", mayRunMore() );
}
shared_ptr<QueryOp> nextOpBeginningClause();
shared_ptr<QueryOp> nextOpHandleEndOfClause();
2010-06-09 11:18:56 -07:00
bool uselessOr( const BSONElement &hint ) const;
2010-05-12 10:38:58 -07:00
const char * _ns;
bool _or;
BSONObj _query;
shared_ptr<OrRangeGenerator> _org; // May be null in certain non $or query cases.
2011-04-07 16:07:29 -07:00
auto_ptr<QueryPlanSet> _currentQps;
2010-05-12 10:38:58 -07:00
int _i;
bool _honorRecordedPlan;
2010-05-24 23:51:24 -07:00
bool _bestGuessOnly;
2010-06-09 11:18:56 -07:00
BSONObj _hint;
bool _mayYield;
bool _tableScanned;
shared_ptr<QueryOp> _baseOp;
2010-05-12 10:38:58 -07:00
};
2011-01-04 00:40:41 -05:00
2011-04-07 12:12:08 -07:00
/** Provides a cursor interface for certain limited uses of a MultiPlanScanner. */
class MultiCursor : public Cursor {
public:
class CursorOp : public QueryOp {
public:
CursorOp() {}
CursorOp( const QueryOp &other ) : QueryOp( other ) {}
2011-04-07 16:07:29 -07:00
virtual shared_ptr<Cursor> newCursor() const = 0;
};
2011-04-07 12:12:08 -07:00
/** takes ownership of 'op' */
2011-04-07 16:07:29 -07:00
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op = shared_ptr<CursorOp>(), bool mayYield = false );
/**
* Used
* 1. To handoff a query to a getMore()
* 2. To handoff a QueryOptimizerCursor
* @param nscanned is an optional initial value, if not supplied nscanned()
* will always return -1
*/
MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Cursor> &c, const shared_ptr<CoveredIndexMatcher> &matcher, const QueryOp &op, long long nscanned = -1 );
2011-04-07 12:12:08 -07:00
virtual bool ok() { return _c->ok(); }
virtual Record* _current() { return _c->_current(); }
virtual BSONObj current() { return _c->current(); }
virtual DiskLoc currLoc() { return _c->currLoc(); }
virtual bool advance() {
_c->advance();
while( !ok() && _mps->mayRunMore() ) {
nextClause();
}
return ok();
}
virtual BSONObj currKey() const { return _c->currKey(); }
virtual DiskLoc refLoc() { return _c->refLoc(); }
2011-04-07 12:12:08 -07:00
virtual void noteLocation() { _c->noteLocation(); }
virtual void checkLocation() { _c->checkLocation(); }
virtual bool supportGetMore() { return true; }
2010-07-24 21:58:39 -04:00
virtual bool supportYields() { return _c->supportYields(); }
virtual BSONObj indexKeyPattern() { return _c->indexKeyPattern(); }
2011-04-07 12:12:08 -07:00
/**
* with update we could potentially get the same document on multiple
* indexes, but update appears to already handle this with seenObjects
* so we don't have to do anything special here.
*/
virtual bool getsetdup(DiskLoc loc) { return _c->getsetdup( loc ); }
2011-01-04 00:40:41 -05:00
virtual bool autoDedup() const { return _c->autoDedup(); }
virtual bool modifiedKeys() const { return _mps->modifiedKeys(); }
2011-01-04 00:40:41 -05:00
2010-11-15 10:22:20 -05:00
virtual bool isMultiKey() const { return _mps->hasMultiKey(); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { return _matcher; }
virtual CoveredIndexMatcher* matcher() const { return _matcher.get(); }
2011-04-07 12:12:08 -07:00
/** return -1 if we're a getmore handoff */
virtual long long nscanned() { return _nscanned >= 0 ? _nscanned + _c->nscanned() : _nscanned; }
2011-04-07 12:12:08 -07:00
/** just for testing */
2011-04-07 16:07:29 -07:00
shared_ptr<Cursor> sub_c() const { return _c; }
private:
2010-05-24 23:51:24 -07:00
class NoOp : public CursorOp {
public:
NoOp() {}
NoOp( const QueryOp &other ) : CursorOp( other ) {}
virtual void _init() { setComplete(); }
2010-05-24 23:51:24 -07:00
virtual void next() {}
virtual bool mayRecordPlan() const { return false; }
virtual QueryOp *_createChild() const { return new NoOp(); }
2011-04-07 16:07:29 -07:00
virtual shared_ptr<Cursor> newCursor() const { return qp().newCursor(); }
virtual long long nscanned() { assert( false ); return 0; }
2010-05-24 23:51:24 -07:00
};
2011-04-07 12:12:08 -07:00
void nextClause();
2011-04-07 16:07:29 -07:00
shared_ptr<CursorOp> _op;
shared_ptr<Cursor> _c;
auto_ptr<MultiPlanScanner> _mps;
shared_ptr<CoveredIndexMatcher> _matcher;
long long _nscanned;
};
2011-01-04 00:40:41 -05:00
2011-04-07 12:12:08 -07:00
/** NOTE min, max, and keyPattern will be updated to be consistent with the selected index. */
IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern );
2010-02-05 12:02:01 -05:00
2011-04-07 12:12:08 -07:00
bool isSimpleIdQuery( const BSONObj& query );
2011-04-07 12:12:08 -07:00
/**
* @return a single cursor that may work well for the given query.
2011-04-07 12:12:08 -07:00
* It is possible no cursor is returned if the sort is not supported by an index. Clients are responsible
* for checking this if they are not sure an index for a sort exists, and defaulting to a non-sort if
* no suitable indices exist.
*/
2011-04-07 16:07:29 -07:00
shared_ptr<Cursor> bestGuessCursor( const char *ns, const BSONObj &query, const BSONObj &sort );
2011-01-04 00:40:41 -05:00
/**
* Add-on functionality for queryutil classes requiring access to indexing
* functionality not currently linked to mongos.
* TODO Clean this up a bit, possibly with separate sharded and non sharded
* implementations for the appropriate queryutil classes or by pulling index
* related functionality into separate wrapper classes.
*/
struct QueryUtilIndexed {
/** @return true if the index may be useful according to its KeySpec. */
static bool indexUseful( const FieldRangeSetPair &frsp, NamespaceDetails *d, int idxNo, const BSONObj &order );
/** Clear any indexes recorded as the best for either the single or multi key pattern. */
static void clearIndexesForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order );
/** Return a recorded best index for the single or multi key pattern. */
static pair< BSONObj, long long > bestIndexForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order );
static bool uselessOr( const OrRangeGenerator& org, NamespaceDetails *d, int hintIdx );
};
2009-01-14 17:09:51 -05:00
} // namespace mongo