Files
mongo/db/queryoptimizer.h

200 lines
7.0 KiB
C
Raw Normal View History

2008-11-15 19:04:01 -05:00
/* queryoptimizer.h */
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-01-14 17:09:51 -05:00
namespace mongo {
2009-02-17 15:53:19 -05:00
class FieldBound {
public:
2009-02-19 14:23:07 -05:00
FieldBound( const BSONElement &e = emptyObj.firstElement() );
2009-02-17 15:53:19 -05:00
FieldBound &operator&=( const FieldBound &other );
BSONElement lower() const { return lower_; }
BSONElement upper() const { return upper_; }
2009-02-17 20:57:36 -05:00
bool equality() const { return lower_.woCompare( upper_, false ) == 0; }
bool nontrivial() const {
return
minKey.firstElement().woCompare( lower_, false ) != 0 ||
maxKey.firstElement().woCompare( upper_, false ) != 0;
}
2009-02-17 15:53:19 -05:00
private:
2009-02-19 14:23:07 -05:00
BSONObj addObj( const BSONObj &o );
2009-02-17 15:53:19 -05:00
string simpleRegexEnd( string regex );
BSONElement lower_;
BSONElement upper_;
vector< BSONObj > objData_;
};
class FieldBoundSet {
public:
2009-02-20 11:08:22 -05:00
FieldBoundSet( const char *ns, const BSONObj &query );
2009-02-17 20:57:36 -05:00
const FieldBound &bound( const char *fieldName ) const {
map< string, FieldBound >::const_iterator f = bounds_.find( fieldName );
if ( f == bounds_.end() )
return trivialBound();
2009-02-17 20:57:36 -05:00
return f->second;
}
2009-02-18 15:25:50 -05:00
int nBounds() const {
int count = 0;
for( map< string, FieldBound >::const_iterator i = bounds_.begin(); i != bounds_.end(); ++i )
++count;
return count;
}
2009-02-17 20:57:36 -05:00
int nNontrivialBounds() const {
int count = 0;
for( map< string, FieldBound >::const_iterator i = bounds_.begin(); i != bounds_.end(); ++i )
if ( i->second.nontrivial() )
++count;
return count;
}
2009-02-20 11:08:22 -05:00
const char *ns() const { return ns_; }
BSONObj query() const { return query_; }
2009-02-17 15:53:19 -05:00
private:
static FieldBound *trivialBound_;
static FieldBound &trivialBound();
2009-02-17 15:53:19 -05:00
map< string, FieldBound > bounds_;
2009-02-20 11:08:22 -05:00
const char *ns_;
2009-02-17 15:53:19 -05:00
BSONObj query_;
};
2009-02-20 11:08:22 -05:00
class IndexDetails;
class QueryPlan {
public:
2009-02-20 11:08:22 -05:00
QueryPlan( const FieldBoundSet &fbs, const BSONObj &order, const IndexDetails *index = 0 );
QueryPlan( const QueryPlan &other );
/* If true, no other index can do better. */
2009-02-17 20:57:36 -05:00
bool optimal() const { return optimal_; }
/* ScanAndOrder processing will be required if true */
2009-02-17 20:57:36 -05:00
bool scanAndOrderRequired() const { return scanAndOrderRequired_; }
/* When true, the index we are using has keys such that it can completely resolve the
2009-02-17 20:57:36 -05:00
query expression to match by itself without ever checking the main object.
*/
bool keyMatch() const { return keyMatch_; }
/* True if keyMatch() is true, and all matches will be equal according to woEqual() */
2009-02-17 20:57:36 -05:00
bool exactKeyMatch() const { return exactKeyMatch_; }
2009-02-19 13:58:22 -05:00
int direction() const { return direction_; }
2009-02-19 15:04:10 -05:00
BSONObj startKey() const { return startKey_; }
BSONObj endKey() const { return endKey_; }
2009-02-20 11:08:22 -05:00
auto_ptr< Cursor > newCursor() const;
BSONObj indexKey() const;
const char *ns() const { return fbs_.ns(); }
BSONObj query() const { return fbs_.query(); }
2009-02-17 20:57:36 -05:00
private:
2009-02-20 11:08:22 -05:00
const FieldBoundSet &fbs_;
const BSONObj &order_;
const IndexDetails *index_;
2009-02-17 20:57:36 -05:00
bool optimal_;
bool scanAndOrderRequired_;
bool keyMatch_;
bool exactKeyMatch_;
2009-02-19 13:58:22 -05:00
int direction_;
2009-02-19 15:04:10 -05:00
BSONObj startKey_;
BSONObj endKey_;
};
2009-02-20 11:08:22 -05:00
class QueryAborter {
public:
QueryAborter( const bool &firstDone ) :
2009-02-20 11:08:22 -05:00
firstDone_( firstDone ){}
class AbortException : public std::exception {
};
void mayAbort() const {
2009-02-20 11:08:22 -05:00
if ( firstDone_ )
throw AbortException();
}
private:
const bool &firstDone_;
2009-02-20 11:08:22 -05:00
};
// Inherit from this interface to implement a new query operation.
2009-02-20 11:08:22 -05:00
class QueryOp {
public:
QueryOp() : done_() {}
2009-02-20 11:08:22 -05:00
virtual ~QueryOp() {}
// Called by the runner, to execute this query operation using the
// given query plan. The implementation should call qa.mayAbort()
// periodically in order to abort if the operation on another query
// plan is complete.
virtual void run( const QueryPlan &qp, const QueryAborter &qa ) = 0;
// Return a copy of the inheriting class, which will be run with its own
// query plan.
2009-02-20 11:08:22 -05:00
virtual QueryOp *clone() const = 0;
bool done() const { return done_; }
// To be called by the runner only.
2009-02-20 11:08:22 -05:00
void setDone() { done_ = true; }
private:
bool done_;
};
class QueryPlanSet {
public:
2009-02-19 14:23:07 -05:00
QueryPlanSet( const char *ns, const BSONObj &query, const BSONObj &order, const BSONElement *hint = 0 );
int nPlans() const { return plans_.size(); }
2009-02-20 15:37:24 -05: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 ) ) );
}
private:
2009-02-20 11:08:22 -05:00
struct RunnerSet {
RunnerSet( QueryPlanSet &plans, QueryOp &op );
2009-02-20 15:37:24 -05:00
shared_ptr< QueryOp > run();
2009-02-20 11:08:22 -05:00
QueryOp &op_;
QueryPlanSet &plans_;
boost::barrier startBarrier_;
bool firstDone_;
};
struct Runner {
Runner( QueryPlan &plan, RunnerSet &set, QueryOp &op ) :
plan_( plan ),
set_( set ),
op_( op ) {}
void operator()() {
try {
set_.startBarrier_.wait();
QueryAborter aborter( set_.firstDone_ );
op_.run( plan_, aborter );
set_.firstDone_ = true;
op_.setDone();
} catch ( const QueryAborter::AbortException & ) {
}
}
QueryPlan &plan_;
RunnerSet &set_;
QueryOp &op_;
};
FieldBoundSet fbs_;
2009-02-20 11:08:22 -05:00
typedef boost::shared_ptr< QueryPlan > PlanPtr;
typedef vector< PlanPtr > PlanSet;
PlanSet plans_;
};
2009-02-17 20:57:36 -05:00
// class QueryOptimizer {
// public:
// static QueryPlan getPlan(
// const char *ns,
// BSONObj* query,
// BSONObj* order = 0,
// BSONObj* hint = 0);
// };
2009-01-14 17:09:51 -05:00
} // namespace mongo