00001
00002
00019 #pragma once
00020
00021 #include "cursor.h"
00022 #include "jsobj.h"
00023 #include "queryutil.h"
00024 #include "matcher.h"
00025 #include "../util/message.h"
00026
00027 namespace mongo {
00028
00029 class IndexDetails;
00030 class IndexType;
00031
00032 class QueryPlan : boost::noncopyable {
00033 public:
00034
00035 QueryPlan(NamespaceDetails *d,
00036 int idxNo,
00037 const FieldRangeSet &fbs,
00038 const FieldRangeSet &originalFrs,
00039 const BSONObj &originalQuery,
00040 const BSONObj &order,
00041 const BSONObj &startKey = BSONObj(),
00042 const BSONObj &endKey = BSONObj() ,
00043 string special="" );
00044
00045
00046 bool optimal() const { return _optimal; }
00047
00048 bool scanAndOrderRequired() const { return _scanAndOrderRequired; }
00049
00050
00051
00052 bool exactKeyMatch() const { return _exactKeyMatch; }
00053
00054
00055 bool unhelpful() const { return _unhelpful; }
00056 int direction() const { return _direction; }
00057 shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const;
00058 shared_ptr<Cursor> newReverseCursor() const;
00059 BSONObj indexKey() const;
00060 bool indexed() const { return _index; }
00061 bool willScanTable() const { return !_index && _fbs.matchPossible(); }
00062 const char *ns() const { return _fbs.ns(); }
00063 NamespaceDetails *nsd() const { return _d; }
00064 BSONObj originalQuery() const { return _originalQuery; }
00065 BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return _fbs.simplifiedQuery( fields ); }
00066 const FieldRange &range( const char *fieldName ) const { return _fbs.range( fieldName ); }
00067 void registerSelf( long long nScanned ) const;
00068 shared_ptr< FieldRangeVector > originalFrv() const { return _originalFrv; }
00069
00070 shared_ptr< FieldRangeVector > frv() const { return _frv; }
00071 bool isMultiKey() const;
00072
00073 private:
00074 NamespaceDetails * _d;
00075 int _idxNo;
00076 const FieldRangeSet &_fbs;
00077 const BSONObj &_originalQuery;
00078 const BSONObj &_order;
00079 const IndexDetails * _index;
00080 bool _optimal;
00081 bool _scanAndOrderRequired;
00082 bool _exactKeyMatch;
00083 int _direction;
00084 shared_ptr< FieldRangeVector > _frv;
00085 shared_ptr< FieldRangeVector > _originalFrv;
00086 BSONObj _startKey;
00087 BSONObj _endKey;
00088 bool _endKeyInclusive;
00089 bool _unhelpful;
00090 string _special;
00091 IndexType * _type;
00092 bool _startOrEndSpec;
00093 };
00094
00095
00096
00097
00098 class QueryOp {
00099 public:
00100 QueryOp() : _complete(), _stopRequested(), _qp(), _error() {}
00101
00102
00103 QueryOp( const QueryOp &other ) :
00104 _complete(), _stopRequested(), _qp(), _error(), _matcher( other._matcher ),
00105 _orConstraint( other._orConstraint ) {}
00106
00107 virtual ~QueryOp() {}
00108
00110 void init() {
00111 if ( _oldMatcher.get() ) {
00112 _matcher.reset( _oldMatcher->nextClauseMatcher( qp().indexKey() ) );
00113 }
00114 else {
00115 _matcher.reset( new CoveredIndexMatcher( qp().originalQuery(), qp().indexKey(), alwaysUseRecord() ) );
00116 }
00117 _init();
00118 }
00119 virtual void next() = 0;
00120
00121 virtual bool mayRecordPlan() const = 0;
00122
00123 virtual bool prepareToYield() { massert( 13335, "yield not supported", false ); return false; }
00124 virtual void recoverFromYield() { massert( 13336, "yield not supported", false ); }
00125
00126 virtual long long nscanned() = 0;
00127
00134 QueryOp *createChild() {
00135 if( _orConstraint.get() ) {
00136 _matcher->advanceOrClause( _orConstraint );
00137 _orConstraint.reset();
00138 }
00139 QueryOp *ret = _createChild();
00140 ret->_oldMatcher = _matcher;
00141 return ret;
00142 }
00143 bool complete() const { return _complete; }
00144 bool error() const { return _error; }
00145 bool stopRequested() const { return _stopRequested; }
00146 ExceptionInfo exception() const { return _exception; }
00147 const QueryPlan &qp() const { return *_qp; }
00148
00149 void setQueryPlan( const QueryPlan *qp ) { _qp = qp; }
00150 void setException( const DBException &e ) {
00151 _error = true;
00152 _exception = e.getInfo();
00153 }
00154 shared_ptr< CoveredIndexMatcher > matcher() const { return _matcher; }
00155 protected:
00156 void setComplete() {
00157 _orConstraint = qp().originalFrv();
00158 _complete = true;
00159 }
00160 void setStop() { setComplete(); _stopRequested = true; }
00161
00162 virtual void _init() = 0;
00163
00164 virtual QueryOp *_createChild() const = 0;
00165
00166 virtual bool alwaysUseRecord() const { return false; }
00167
00168 private:
00169 bool _complete;
00170 bool _stopRequested;
00171 ExceptionInfo _exception;
00172 const QueryPlan *_qp;
00173 bool _error;
00174 shared_ptr< CoveredIndexMatcher > _matcher;
00175 shared_ptr< CoveredIndexMatcher > _oldMatcher;
00176 shared_ptr< FieldRangeVector > _orConstraint;
00177 };
00178
00179
00180
00181 class QueryPlanSet {
00182 public:
00183
00184 typedef boost::shared_ptr< QueryPlan > QueryPlanPtr;
00185 typedef vector< QueryPlanPtr > PlanSet;
00186
00187 QueryPlanSet( const char *ns,
00188 auto_ptr< FieldRangeSet > frs,
00189 auto_ptr< FieldRangeSet > originalFrs,
00190 const BSONObj &originalQuery,
00191 const BSONObj &order,
00192 const BSONElement *hint = 0,
00193 bool honorRecordedPlan = true,
00194 const BSONObj &min = BSONObj(),
00195 const BSONObj &max = BSONObj(),
00196 bool bestGuessOnly = false,
00197 bool mayYield = false);
00198 int nPlans() const { return _plans.size(); }
00199 shared_ptr< QueryOp > runOp( QueryOp &op );
00200 template< class T >
00201 shared_ptr< T > runOp( T &op ) {
00202 return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) );
00203 }
00204 BSONObj explain() const;
00205 bool usingPrerecordedPlan() const { return _usingPrerecordedPlan; }
00206 QueryPlanPtr getBestGuess() const;
00207
00208 const FieldRangeSet &fbs() const { return *_fbs; }
00209 const FieldRangeSet &originalFrs() const { return *_originalFrs; }
00210 bool modifiedKeys() const;
00211 bool hasMultiKey() const;
00212
00213 private:
00214 void addOtherPlans( bool checkFirst );
00215 void addPlan( QueryPlanPtr plan, bool checkFirst ) {
00216 if ( checkFirst && plan->indexKey().woCompare( _plans[ 0 ]->indexKey() ) == 0 )
00217 return;
00218 _plans.push_back( plan );
00219 }
00220 void init();
00221 void addHint( IndexDetails &id );
00222 struct Runner {
00223 Runner( QueryPlanSet &plans, QueryOp &op );
00224 shared_ptr< QueryOp > run();
00225 void mayYield( const vector< shared_ptr< QueryOp > > &ops );
00226 QueryOp &_op;
00227 QueryPlanSet &_plans;
00228 static void initOp( QueryOp &op );
00229 static void nextOp( QueryOp &op );
00230 static bool prepareToYield( QueryOp &op );
00231 static void recoverFromYield( QueryOp &op );
00232 };
00233
00234 const char *_ns;
00235 BSONObj _originalQuery;
00236 auto_ptr< FieldRangeSet > _fbs;
00237 auto_ptr< FieldRangeSet > _originalFrs;
00238 PlanSet _plans;
00239 bool _mayRecordPlan;
00240 bool _usingPrerecordedPlan;
00241 BSONObj _hint;
00242 BSONObj _order;
00243 long long _oldNScanned;
00244 bool _honorRecordedPlan;
00245 BSONObj _min;
00246 BSONObj _max;
00247 string _special;
00248 bool _bestGuessOnly;
00249 bool _mayYield;
00250 ElapsedTracker _yieldSometimesTracker;
00251 };
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 class MultiPlanScanner {
00277 public:
00278 MultiPlanScanner( const char *ns,
00279 const BSONObj &query,
00280 const BSONObj &order,
00281 const BSONElement *hint = 0,
00282 bool honorRecordedPlan = true,
00283 const BSONObj &min = BSONObj(),
00284 const BSONObj &max = BSONObj(),
00285 bool bestGuessOnly = false,
00286 bool mayYield = false);
00287 shared_ptr< QueryOp > runOp( QueryOp &op );
00288 template< class T >
00289 shared_ptr< T > runOp( T &op ) {
00290 return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) );
00291 }
00292 shared_ptr< QueryOp > runOpOnce( QueryOp &op );
00293 template< class T >
00294 shared_ptr< T > runOpOnce( T &op ) {
00295 return dynamic_pointer_cast< T >( runOpOnce( static_cast< QueryOp& >( op ) ) );
00296 }
00297 bool mayRunMore() const { return _or ? ( !_tableScanned && !_fros.orFinished() ) : _i == 0; }
00298 BSONObj oldExplain() const { assertNotOr(); return _currentQps->explain(); }
00299
00300 bool usingPrerecordedPlan() const {
00301 return !_or && _currentQps->usingPrerecordedPlan();
00302 }
00303 void setBestGuessOnly() { _bestGuessOnly = true; }
00304 void mayYield( bool val ) { _mayYield = val; }
00305 bool modifiedKeys() const { return _currentQps->modifiedKeys(); }
00306 bool hasMultiKey() const { return _currentQps->hasMultiKey(); }
00307
00308 private:
00309 void assertNotOr() const {
00310 massert( 13266, "not implemented for $or query", !_or );
00311 }
00312 bool uselessOr( const BSONElement &hint ) const;
00313 const char * _ns;
00314 bool _or;
00315 BSONObj _query;
00316 FieldRangeOrSet _fros;
00317 auto_ptr< QueryPlanSet > _currentQps;
00318 int _i;
00319 bool _honorRecordedPlan;
00320 bool _bestGuessOnly;
00321 BSONObj _hint;
00322 bool _mayYield;
00323 bool _tableScanned;
00324 };
00325
00326 class MultiCursor : public Cursor {
00327 public:
00328 class CursorOp : public QueryOp {
00329 public:
00330 CursorOp() {}
00331 CursorOp( const QueryOp &other ) : QueryOp( other ) {}
00332 virtual shared_ptr< Cursor > newCursor() const = 0;
00333 };
00334
00335 MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >(), bool mayYield = false )
00336 : _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj(), BSONObj(), !op.get(), mayYield ) ), _nscanned() {
00337 if ( op.get() ) {
00338 _op = op;
00339 }
00340 else {
00341 _op.reset( new NoOp() );
00342 }
00343 if ( _mps->mayRunMore() ) {
00344 nextClause();
00345 if ( !ok() ) {
00346 advance();
00347 }
00348 }
00349 else {
00350 _c.reset( new BasicCursor( DiskLoc() ) );
00351 }
00352 }
00353
00354 MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cursor > &c, const shared_ptr< CoveredIndexMatcher > &matcher, const QueryOp &op )
00355 : _op( new NoOp( op ) ), _c( c ), _mps( mps ), _matcher( matcher ), _nscanned( -1 ) {
00356 _mps->setBestGuessOnly();
00357 _mps->mayYield( false );
00358 if ( !ok() ) {
00359
00360 advance();
00361 }
00362 }
00363 virtual bool ok() { return _c->ok(); }
00364 virtual Record* _current() { return _c->_current(); }
00365 virtual BSONObj current() { return _c->current(); }
00366 virtual DiskLoc currLoc() { return _c->currLoc(); }
00367 virtual bool advance() {
00368 _c->advance();
00369 while( !ok() && _mps->mayRunMore() ) {
00370 nextClause();
00371 }
00372 return ok();
00373 }
00374 virtual BSONObj currKey() const { return _c->currKey(); }
00375 virtual DiskLoc refLoc() { return _c->refLoc(); }
00376 virtual void noteLocation() {
00377 _c->noteLocation();
00378 }
00379 virtual void checkLocation() {
00380 _c->checkLocation();
00381 }
00382 virtual bool supportGetMore() { return true; }
00383 virtual bool supportYields() { return _c->supportYields(); }
00384
00385
00386
00387
00388 virtual bool getsetdup(DiskLoc loc) {
00389 return _c->getsetdup( loc );
00390 }
00391
00392 virtual bool modifiedKeys() const { return _mps->modifiedKeys(); }
00393
00394 virtual bool isMultiKey() const { return _mps->hasMultiKey(); }
00395
00396 virtual CoveredIndexMatcher *matcher() const { return _matcher.get(); }
00397
00398 virtual long long nscanned() { return _nscanned >= 0 ? _nscanned + _c->nscanned() : _nscanned; }
00399
00400 shared_ptr< Cursor > sub_c() const { return _c; }
00401 private:
00402 class NoOp : public CursorOp {
00403 public:
00404 NoOp() {}
00405 NoOp( const QueryOp &other ) : CursorOp( other ) {}
00406 virtual void _init() { setComplete(); }
00407 virtual void next() {}
00408 virtual bool mayRecordPlan() const { return false; }
00409 virtual QueryOp *_createChild() const { return new NoOp(); }
00410 virtual shared_ptr< Cursor > newCursor() const { return qp().newCursor(); }
00411 virtual long long nscanned() { assert( false ); return 0; }
00412 };
00413 void nextClause() {
00414 if ( _nscanned >= 0 && _c.get() ) {
00415 _nscanned += _c->nscanned();
00416 }
00417 shared_ptr< CursorOp > best = _mps->runOpOnce( *_op );
00418 if ( ! best->complete() )
00419 throw MsgAssertionException( best->exception() );
00420 _c = best->newCursor();
00421 _matcher = best->matcher();
00422 _op = best;
00423 }
00424 shared_ptr< CursorOp > _op;
00425 shared_ptr< Cursor > _c;
00426 auto_ptr< MultiPlanScanner > _mps;
00427 shared_ptr< CoveredIndexMatcher > _matcher;
00428 long long _nscanned;
00429 };
00430
00431
00432 IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern );
00433
00434 inline bool isSimpleIdQuery( const BSONObj& query ) {
00435 BSONObjIterator i(query);
00436 if( !i.more() ) return false;
00437 BSONElement e = i.next();
00438 if( i.more() ) return false;
00439 if( strcmp("_id", e.fieldName()) != 0 ) return false;
00440 return e.isSimpleType();
00441 }
00442
00443
00444 inline shared_ptr< Cursor > bestGuessCursor( const char *ns, const BSONObj &query, const BSONObj &sort ) {
00445 if( !query.getField( "$or" ).eoo() ) {
00446 return shared_ptr< Cursor >( new MultiCursor( ns, query, sort ) );
00447 }
00448 else {
00449 auto_ptr< FieldRangeSet > frs( new FieldRangeSet( ns, query ) );
00450 auto_ptr< FieldRangeSet > origFrs( new FieldRangeSet( *frs ) );
00451 shared_ptr< Cursor > ret = QueryPlanSet( ns, frs, origFrs, query, sort ).getBestGuess()->newCursor();
00452 if ( !query.isEmpty() ) {
00453 shared_ptr< CoveredIndexMatcher > matcher( new CoveredIndexMatcher( query, ret->indexKeyPattern() ) );
00454 ret->setMatcher( matcher );
00455 }
00456 return ret;
00457 }
00458 }
00459
00460 }