summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/distinct1.js2
-rw-r--r--jstests/core/distinct_index1.js19
-rw-r--r--jstests/core/fts2.js2
-rw-r--r--jstests/core/idhack.js2
-rw-r--r--jstests/core/index_filter_commands.js39
-rw-r--r--src/mongo/db/catalog/collection_cursor_cache.cpp52
-rw-r--r--src/mongo/db/catalog/collection_cursor_cache.h24
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp4
-rw-r--r--src/mongo/db/catalog/index_create.cpp14
-rw-r--r--src/mongo/db/clientcursor.cpp14
-rw-r--r--src/mongo/db/clientcursor.h14
-rw-r--r--src/mongo/db/commands/collection_to_capped.cpp14
-rw-r--r--src/mongo/db/commands/count.cpp2
-rw-r--r--src/mongo/db/commands/dbhash.cpp28
-rw-r--r--src/mongo/db/commands/distinct.cpp42
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp17
-rw-r--r--src/mongo/db/commands/geo_near_cmd.cpp25
-rw-r--r--src/mongo/db/commands/group.cpp14
-rw-r--r--src/mongo/db/commands/mr.cpp40
-rw-r--r--src/mongo/db/commands/parallel_collection_scan.cpp87
-rw-r--r--src/mongo/db/commands/pipeline_command.cpp159
-rw-r--r--src/mongo/db/commands/test_commands.cpp10
-rw-r--r--src/mongo/db/db.cpp5
-rw-r--r--src/mongo/db/dbcommands.cpp24
-rw-r--r--src/mongo/db/dbhelpers.cpp48
-rw-r--r--src/mongo/db/exec/and_hash.cpp4
-rw-r--r--src/mongo/db/exec/and_hash.h2
-rw-r--r--src/mongo/db/exec/and_sorted.cpp4
-rw-r--r--src/mongo/db/exec/and_sorted.h2
-rw-r--r--src/mongo/db/exec/cached_plan.cpp6
-rw-r--r--src/mongo/db/exec/cached_plan.h2
-rw-r--r--src/mongo/db/exec/collection_scan.cpp2
-rw-r--r--src/mongo/db/exec/collection_scan.h2
-rw-r--r--src/mongo/db/exec/count.cpp2
-rw-r--r--src/mongo/db/exec/count.h4
-rw-r--r--src/mongo/db/exec/distinct_scan.cpp2
-rw-r--r--src/mongo/db/exec/distinct_scan.h2
-rw-r--r--src/mongo/db/exec/eof.cpp2
-rw-r--r--src/mongo/db/exec/eof.h2
-rw-r--r--src/mongo/db/exec/fetch.cpp4
-rw-r--r--src/mongo/db/exec/fetch.h2
-rw-r--r--src/mongo/db/exec/idhack.cpp20
-rw-r--r--src/mongo/db/exec/idhack.h5
-rw-r--r--src/mongo/db/exec/index_scan.cpp2
-rw-r--r--src/mongo/db/exec/index_scan.h2
-rw-r--r--src/mongo/db/exec/keep_mutations.cpp4
-rw-r--r--src/mongo/db/exec/keep_mutations.h2
-rw-r--r--src/mongo/db/exec/limit.cpp4
-rw-r--r--src/mongo/db/exec/limit.h2
-rw-r--r--src/mongo/db/exec/merge_sort.cpp4
-rw-r--r--src/mongo/db/exec/merge_sort.h2
-rw-r--r--src/mongo/db/exec/mock_stage.h2
-rw-r--r--src/mongo/db/exec/multi_plan.cpp12
-rw-r--r--src/mongo/db/exec/multi_plan.h4
-rw-r--r--src/mongo/db/exec/near.cpp4
-rw-r--r--src/mongo/db/exec/near.h2
-rw-r--r--src/mongo/db/exec/oplogstart.cpp4
-rw-r--r--src/mongo/db/exec/oplogstart.h2
-rw-r--r--src/mongo/db/exec/or.cpp4
-rw-r--r--src/mongo/db/exec/or.h2
-rw-r--r--src/mongo/db/exec/plan_stage.h10
-rw-r--r--src/mongo/db/exec/projection.cpp4
-rw-r--r--src/mongo/db/exec/projection.h2
-rw-r--r--src/mongo/db/exec/shard_filter.cpp4
-rw-r--r--src/mongo/db/exec/shard_filter.h2
-rw-r--r--src/mongo/db/exec/skip.cpp4
-rw-r--r--src/mongo/db/exec/skip.h2
-rw-r--r--src/mongo/db/exec/sort.cpp4
-rw-r--r--src/mongo/db/exec/sort.h2
-rw-r--r--src/mongo/db/exec/subplan.cpp15
-rw-r--r--src/mongo/db/exec/subplan.h2
-rw-r--r--src/mongo/db/exec/text.cpp4
-rw-r--r--src/mongo/db/exec/text.h2
-rw-r--r--src/mongo/db/fts/fts_command_mongod.cpp28
-rw-r--r--src/mongo/db/index/haystack_access_method.cpp4
-rw-r--r--src/mongo/db/ops/delete_executor.cpp36
-rw-r--r--src/mongo/db/ops/update.cpp5
-rw-r--r--src/mongo/db/pipeline/document_source.h14
-rw-r--r--src/mongo/db/pipeline/document_source_cursor.cpp43
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp44
-rw-r--r--src/mongo/db/pipeline/pipeline_d.h6
-rw-r--r--src/mongo/db/query/SConscript1
-rw-r--r--src/mongo/db/query/eof_runner.cpp2
-rw-r--r--src/mongo/db/query/eof_runner.h2
-rw-r--r--src/mongo/db/query/explain.cpp92
-rw-r--r--src/mongo/db/query/explain.h11
-rw-r--r--src/mongo/db/query/explain_plan.cpp2
-rw-r--r--src/mongo/db/query/get_executor.cpp4
-rw-r--r--src/mongo/db/query/get_executor.h2
-rw-r--r--src/mongo/db/query/get_runner.cpp12
-rw-r--r--src/mongo/db/query/get_runner.h18
-rw-r--r--src/mongo/db/query/idhack_runner.cpp2
-rw-r--r--src/mongo/db/query/idhack_runner.h2
-rw-r--r--src/mongo/db/query/internal_plans.h50
-rw-r--r--src/mongo/db/query/internal_runner.cpp118
-rw-r--r--src/mongo/db/query/internal_runner.h101
-rw-r--r--src/mongo/db/query/new_find.cpp183
-rw-r--r--src/mongo/db/query/plan_executor.cpp63
-rw-r--r--src/mongo/db/query/plan_executor.h63
-rw-r--r--src/mongo/db/query/runner.h2
-rw-r--r--src/mongo/db/query/single_solution_runner.cpp4
-rw-r--r--src/mongo/db/query/single_solution_runner.h2
-rw-r--r--src/mongo/db/query/stage_types.h11
-rw-r--r--src/mongo/db/query/subplan_runner.cpp2
-rw-r--r--src/mongo/db/query/subplan_runner.h2
-rw-r--r--src/mongo/db/repl/master_slave.cpp8
-rw-r--r--src/mongo/db/repl/repl_info.cpp4
-rw-r--r--src/mongo/db/repl/rs_rollback.cpp8
-rw-r--r--src/mongo/dbtests/documentsourcetests.cpp21
-rw-r--r--src/mongo/dbtests/executor_registry.cpp (renamed from src/mongo/dbtests/runner_registry.cpp)106
-rw-r--r--src/mongo/dbtests/oplogstarttests.cpp8
-rw-r--r--src/mongo/dbtests/query_plan_executor.cpp (renamed from src/mongo/dbtests/query_single_solution_runner.cpp)128
-rw-r--r--src/mongo/dbtests/query_stage_and.cpp8
-rw-r--r--src/mongo/dbtests/query_stage_collscan.cpp4
-rw-r--r--src/mongo/dbtests/query_stage_count.cpp10
-rw-r--r--src/mongo/dbtests/query_stage_merge_sort.cpp2
-rw-r--r--src/mongo/dbtests/query_stage_near.cpp2
-rw-r--r--src/mongo/dbtests/query_stage_sort.cpp4
-rw-r--r--src/mongo/s/d_migrate.cpp87
-rw-r--r--src/mongo/s/d_split.cpp26
120 files changed, 1127 insertions, 1115 deletions
diff --git a/jstests/core/distinct1.js b/jstests/core/distinct1.js
index 03e425af761..5d809e20c97 100644
--- a/jstests/core/distinct1.js
+++ b/jstests/core/distinct1.js
@@ -26,7 +26,7 @@ t.save( { a : { b : "c" } , c : 12 } );
res = t.distinct( "a.b" );
assert.eq( "a,b,c" , res.toString() , "B1" );
printjson(t._distinct( "a.b" ).stats);
-assert.eq( "BasicCursor" , t._distinct( "a.b" ).stats.cursor , "B2" )
+assert.eq( "COLLSCAN" , t._distinct( "a.b" ).stats.planSummary , "B2" )
t.drop();
diff --git a/jstests/core/distinct_index1.js b/jstests/core/distinct_index1.js
index 73682788bda..6149400d566 100644
--- a/jstests/core/distinct_index1.js
+++ b/jstests/core/distinct_index1.js
@@ -16,18 +16,24 @@ for ( i=0; i<1000; i++ ){
}
x = d( "a" );
+// Collection scan looks at all 1000 documents and gets 1000
+// distinct values. Looks at 0 index keys.
assert.eq( 1000 , x.stats.n , "AA1" )
-assert.eq( 1000 , x.stats.nscanned , "AA2" )
+assert.eq( 0 , x.stats.nscanned , "AA2" )
assert.eq( 1000 , x.stats.nscannedObjects , "AA3" )
x = d( "a" , { a : { $gt : 5 } } );
+// Collection scan looks at all 1000 documents and gets 398
+// distinct values which match the query. Looks at 0 index keys.
assert.eq( 398 , x.stats.n , "AB1" )
-assert.eq( 1000 , x.stats.nscanned , "AB2" )
+assert.eq( 0 , x.stats.nscanned , "AB2" )
assert.eq( 1000 , x.stats.nscannedObjects , "AB3" )
x = d( "b" , { a : { $gt : 5 } } );
+// Collection scan looks at all 1000 documents and gets 398
+// distinct values which match the query. Looks at 0 index keys.
assert.eq( 398 , x.stats.n , "AC1" )
-assert.eq( 1000 , x.stats.nscanned , "AC2" )
+assert.eq( 0 , x.stats.nscanned , "AC2" )
assert.eq( 1000 , x.stats.nscannedObjects , "AC3" )
@@ -61,12 +67,9 @@ printjson(x);
assert.lte(x.stats.n, 171);
assert.eq(171, x.stats.nscannedObjects , "BD3" )
-
-
-// Cursor name should not be empty when using $or with hashed index.
-//
+// Should use an index scan over the hashed index.
t.dropIndexes();
t.ensureIndex( { a : "hashed" } );
x = d( "a", { $or : [ { a : 3 }, { a : 5 } ] } );
assert.eq( 188, x.stats.n, "DA1" );
-assert.neq( "", x.stats.cursor, "DA2" );
+assert.eq( "IXSCAN { a: \"hashed\" }", x.stats.planSummary );
diff --git a/jstests/core/fts2.js b/jstests/core/fts2.js
index e0e7469fa5e..bfd11728779 100644
--- a/jstests/core/fts2.js
+++ b/jstests/core/fts2.js
@@ -19,6 +19,6 @@ assert.eq( [1] , queryIDS( t , "az" , { z : 1 } ) , "B1" );
assert.eq( [1] , queryIDS( t , "d" , { z : 1 } ) , "B2" );
printjson(lastCommadResult);
-assert.eq( 2 , lastCommadResult.stats.nscannedObjects , "B3" );
+assert.eq( 4 , lastCommadResult.stats.nscannedObjects , "B3" );
assert.eq( 2 , lastCommadResult.stats.nscanned , "B4" );
diff --git a/jstests/core/idhack.js b/jstests/core/idhack.js
index 11fb1e0f447..e40c043d455 100644
--- a/jstests/core/idhack.js
+++ b/jstests/core/idhack.js
@@ -30,8 +30,6 @@ assert.eq( 1 , explain.n , "D1" );
assert.eq( 1 , explain.nscanned , "D2" );
assert.neq( undefined , explain.cursor , "D3" );
assert.neq( "" , explain.cursor , "D4" );
-assert.neq( undefined , explain.indexBounds , "D5" );
-assert.neq( {} , explain.indexBounds , "D6" );
// ID hack cannot be used with hint().
var query = { _id : { x : 2 } };
diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js
index 4fa1e533a8a..dddc69a688d 100644
--- a/jstests/core/index_filter_commands.js
+++ b/jstests/core/index_filter_commands.js
@@ -145,42 +145,3 @@ assert(!planCacheContains(shape), 'plan cache for query shape not flushed after
print('Plan details before setting filter = ' + tojson(planBeforeSetFilter.details, '', true));
print('Plan details after setting filter = ' + tojson(planAfterSetFilter.details, '', true));
-
-//
-// explain.filterSet
-// cursor.explain() should indicate if index filter has been applied.
-// The following 3 runners should always provide a value for 'filterSet':
-// - SingleSolutionRunner
-// - MultiPlanRunner
-// - CachedPlanRuner
-//
-
-// No filter set.
-
-t.getPlanCache().clear();
-// SingleSolutionRunner
-assert.eq(false, t.find({z: 1}).explain().filterSet,
- 'missing or invalid filterSet field in SingleSolutionRunner explain');
-// MultiPlanRunner
-assert.eq(false, t.find(queryA1, projectionA1).sort(sortA1).explain().filterSet,
- 'missing or invalid filterSet field in MultiPlanRunner explain');
-// CachedPlanRunner
-assert.eq(false, t.find(queryA1, projectionA1).sort(sortA1).explain().filterSet,
- 'missing or invalid filterSet field in CachedPlanRunner explain');
-
-// Add index filter.
-assert.commandWorked(t.runCommand('planCacheSetFilter',
- {query: queryA1, sort: sortA1, projection: projectionA1, indexes: [indexA1B1, indexA1C1]}));
-// Index filter with non-existent index key pattern to force use of single solution runner.
-assert.commandWorked(t.runCommand('planCacheSetFilter', {query: {z: 1}, indexes: [{z: 1}]}));
-
-t.getPlanCache().clear();
-// SingleSolutionRunner
-assert.eq(true, t.find({z: 1}).explain().filterSet,
- 'missing or invalid filterSet field in SingleSolutionRunner explain');
-// MultiPlanRunner
-assert.eq(true, t.find(queryA1, projectionA1).sort(sortA1).explain().filterSet,
- 'missing or invalid filterSet field in MultiPlanRunner explain');
-// CachedPlanRunner
-assert.eq(true, t.find(queryA1, projectionA1).sort(sortA1).explain().filterSet,
- 'missing or invalid filterSet field in CachedPlanRunner explain');
diff --git a/src/mongo/db/catalog/collection_cursor_cache.cpp b/src/mongo/db/catalog/collection_cursor_cache.cpp
index c8e8feae704..d358e7a4a52 100644
--- a/src/mongo/db/catalog/collection_cursor_cache.cpp
+++ b/src/mongo/db/catalog/collection_cursor_cache.cpp
@@ -37,7 +37,7 @@
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/client.h"
#include "mongo/db/operation_context_impl.h"
-#include "mongo/db/query/runner.h"
+#include "mongo/db/query/plan_executor.h"
#include "mongo/platform/random.h"
#include "mongo/util/startup_test.h"
@@ -276,16 +276,16 @@ namespace mongo {
void CollectionCursorCache::invalidateAll( bool collectionGoingAway ) {
SimpleMutex::scoped_lock lk( _mutex );
- for ( RunnerSet::iterator it = _nonCachedRunners.begin();
- it != _nonCachedRunners.end();
+ for ( ExecSet::iterator it = _nonCachedExecutors.begin();
+ it != _nonCachedExecutors.end();
++it ) {
- // we kill the runner, but it deletes itself
- Runner* runner = *it;
- runner->kill();
- invariant( runner->collection() == NULL );
+ // we kill the executor, but it deletes itself
+ PlanExecutor* exec = *it;
+ exec->kill();
+ invariant( exec->collection() == NULL );
}
- _nonCachedRunners.clear();
+ _nonCachedExecutors.clear();
if ( collectionGoingAway ) {
// we're going to wipe out the world
@@ -294,7 +294,7 @@ namespace mongo {
cc->kill();
- invariant( cc->getRunner() == NULL || cc->getRunner()->collection() == NULL );
+ invariant( cc->getExecutor() == NULL || cc->getExecutor()->collection() == NULL );
// If there is a pinValue >= 100, somebody is actively using the CC and we do
// not delete it. Instead we notify the holder that we killed it. The holder
@@ -310,7 +310,7 @@ namespace mongo {
else {
CursorMap newMap;
- // collection will still be around, just all Runners are invalid
+ // collection will still be around, just all PlanExecutors are invalid
for ( CursorMap::const_iterator i = _cursors.begin(); i != _cursors.end(); ++i ) {
ClientCursor* cc = i->second;
@@ -320,10 +320,10 @@ namespace mongo {
continue;
}
- // Note that a valid ClientCursor state is "no cursor no runner." This is because
+ // Note that a valid ClientCursor state is "no cursor no executor." This is because
// the set of active cursor IDs in ClientCursor is used as representation of query
// state. See sharding_block.h. TODO(greg,hk): Move this out.
- if (NULL == cc->getRunner() ) {
+ if (NULL == cc->getExecutor() ) {
newMap.insert( *i );
continue;
}
@@ -334,9 +334,9 @@ namespace mongo {
}
else {
// this is pinned, so still alive, so we leave around
- // we kill the Runner to signal
- if ( cc->getRunner() )
- cc->getRunner()->kill();
+ // we kill the PlanExecutor to signal
+ if ( cc->getExecutor() )
+ cc->getExecutor()->kill();
newMap.insert( *i );
}
@@ -350,18 +350,18 @@ namespace mongo {
InvalidationType type ) {
SimpleMutex::scoped_lock lk( _mutex );
- for ( RunnerSet::iterator it = _nonCachedRunners.begin();
- it != _nonCachedRunners.end();
+ for ( ExecSet::iterator it = _nonCachedExecutors.begin();
+ it != _nonCachedExecutors.end();
++it ) {
- Runner* runner = *it;
- runner->invalidate(dl, type);
+ PlanExecutor* exec = *it;
+ exec->invalidate(dl, type);
}
for ( CursorMap::const_iterator i = _cursors.begin(); i != _cursors.end(); ++i ) {
- Runner* runner = i->second->getRunner();
- if ( runner ) {
- runner->invalidate(dl, type);
+ PlanExecutor* exec = i->second->getExecutor();
+ if ( exec ) {
+ exec->invalidate(dl, type);
}
}
}
@@ -387,18 +387,18 @@ namespace mongo {
return toDelete.size();
}
- void CollectionCursorCache::registerRunner( Runner* runner ) {
+ void CollectionCursorCache::registerExecutor( PlanExecutor* exec ) {
if (!useExperimentalDocLocking) {
SimpleMutex::scoped_lock lk(_mutex);
- const std::pair<RunnerSet::iterator, bool> result = _nonCachedRunners.insert(runner);
+ const std::pair<ExecSet::iterator, bool> result = _nonCachedExecutors.insert(exec);
invariant(result.second); // make sure this was inserted
}
}
- void CollectionCursorCache::deregisterRunner( Runner* runner ) {
+ void CollectionCursorCache::deregisterExecutor( PlanExecutor* exec ) {
if (!useExperimentalDocLocking) {
SimpleMutex::scoped_lock lk(_mutex);
- _nonCachedRunners.erase(runner);
+ _nonCachedExecutors.erase(exec);
}
}
diff --git a/src/mongo/db/catalog/collection_cursor_cache.h b/src/mongo/db/catalog/collection_cursor_cache.h
index c1f3647b021..524f1e12e11 100644
--- a/src/mongo/db/catalog/collection_cursor_cache.h
+++ b/src/mongo/db/catalog/collection_cursor_cache.h
@@ -41,14 +41,14 @@ namespace mongo {
class OperationContext;
class PseudoRandom;
- class Runner;
+ class PlanExecutor;
class CollectionCursorCache {
public:
CollectionCursorCache( const StringData& ns );
/**
- * will kill() all Runner instances it has
+ * will kill() all PlanExecutor instances it has
*/
~CollectionCursorCache();
@@ -62,8 +62,8 @@ namespace mongo {
void invalidateAll( bool collectionGoingAway );
/**
- * Broadcast a document invalidation to all relevant Runner(s). invalidateDocument must
- * called *before* the provided DiskLoc is about to be deleted or mutated.
+ * Broadcast a document invalidation to all relevant PlanExecutor(s). invalidateDocument
+ * must called *before* the provided DiskLoc is about to be deleted or mutated.
*/
void invalidateDocument( const DiskLoc& dl,
InvalidationType type );
@@ -78,16 +78,16 @@ namespace mongo {
// -----------------
/**
- * Register a runner so that it can be notified of deletion/invalidation during yields.
- * Must be called before a runner yields. If a runner is cached (inside a ClientCursor) it
- * MUST NOT be registered; the two are mutually exclusive.
+ * Register an executor so that it can be notified of deletion/invalidation during yields.
+ * Must be called before an executor yields. If an executor is cached (inside a
+ * ClientCursor) it MUST NOT be registered; the two are mutually exclusive.
*/
- void registerRunner(Runner* runner);
+ void registerExecutor(PlanExecutor* exec);
/**
- * Remove a runner from the runner registry.
+ * Remove an executor from the registry.
*/
- void deregisterRunner(Runner* runner);
+ void deregisterExecutor(PlanExecutor* exec);
// -----------------
@@ -130,8 +130,8 @@ namespace mongo {
SimpleMutex _mutex;
- typedef unordered_set<Runner*> RunnerSet;
- RunnerSet _nonCachedRunners;
+ typedef unordered_set<PlanExecutor*> ExecSet;
+ ExecSet _nonCachedExecutors;
typedef std::map<CursorId,ClientCursor*> CursorMap;
CursorMap _cursors;
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp
index 310f224657e..edb6219f607 100644
--- a/src/mongo/db/catalog/index_catalog.cpp
+++ b/src/mongo/db/catalog/index_catalog.cpp
@@ -221,14 +221,14 @@ namespace mongo {
return Status::OK(); // these checks have already been done
}
- auto_ptr<Runner> runner(
+ auto_ptr<PlanExecutor> exec(
InternalPlanner::collectionScan(txn,
db->_indexesName,
db->getCollection(txn, db->_indexesName)));
BSONObj index;
Runner::RunnerState state;
- while ( Runner::RUNNER_ADVANCED == (state = runner->getNext(&index, NULL)) ) {
+ while ( Runner::RUNNER_ADVANCED == (state = exec->getNext(&index, NULL)) ) {
const BSONObj key = index.getObjectField("key");
const string plugin = IndexNames::findPluginName(key);
if ( IndexNames::existedBefore24(plugin) )
diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp
index b230121d533..96bf25f1c94 100644
--- a/src/mongo/db/catalog/index_create.cpp
+++ b/src/mongo/db/catalog/index_create.cpp
@@ -104,7 +104,7 @@ namespace mongo {
unsigned long long n = 0;
unsigned long long numDropped = 0;
- auto_ptr<Runner> runner(InternalPlanner::collectionScan(txn,ns,collection));
+ auto_ptr<PlanExecutor> exec(InternalPlanner::collectionScan(txn,ns,collection));
std::string idxName = descriptor->indexName();
@@ -114,7 +114,7 @@ namespace mongo {
BSONObj js;
DiskLoc loc;
- while (Runner::RUNNER_ADVANCED == runner->getNext(&js, &loc)) {
+ while (Runner::RUNNER_ADVANCED == exec->getNext(&js, &loc)) {
try {
if ( !dupsAllowed && dropDups ) {
LastError::Disabled led( lastError.get() );
@@ -131,15 +131,15 @@ namespace mongo {
// TODO: Does exception really imply dropDups exception?
if (dropDups) {
- bool runnerEOF = runner->isEOF();
- runner->saveState();
+ bool execEOF = exec->isEOF();
+ exec->saveState();
BSONObj toDelete;
collection->deleteDocument( txn, loc, false, true, &toDelete );
repl::logOp(txn, "d", ns.c_str(), toDelete);
- if (!runner->restoreState(txn)) {
- // Runner got killed somehow. This probably shouldn't happen.
- if (runnerEOF) {
+ if (!exec->restoreState(txn)) {
+ // PlanExecutor got killed somehow. This probably shouldn't happen.
+ if (execEOF) {
// Quote: "We were already at the end. Normal.
// TODO: Why is this normal?
}
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 80fb8d0694e..ae6d16a2998 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -69,16 +69,16 @@ namespace mongo {
return cursorStatsOpen.get();
}
- ClientCursor::ClientCursor(const Collection* collection, Runner* runner,
+ ClientCursor::ClientCursor(const Collection* collection, PlanExecutor* exec,
int qopts, const BSONObj query)
: _collection( collection ),
_countedYet( false ) {
- _runner.reset(runner);
- _ns = runner->ns();
+ _exec.reset(exec);
+ _ns = exec->ns();
_query = query;
_queryOptions = qopts;
- if ( runner->collection() ) {
- invariant( collection == runner->collection() );
+ if ( exec->collection() ) {
+ invariant( collection == exec->collection() );
}
init();
}
@@ -141,8 +141,8 @@ namespace mongo {
}
void ClientCursor::kill() {
- if ( _runner.get() )
- _runner->kill();
+ if ( _exec.get() )
+ _exec->kill();
_collection = NULL;
}
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index 252212a712a..1b0f323c49d 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -33,7 +33,7 @@
#include "mongo/db/diskloc.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/keypattern.h"
-#include "mongo/db/query/runner.h"
+#include "mongo/db/query/plan_executor.h"
#include "mongo/s/collection_metadata.h"
#include "mongo/util/background.h"
#include "mongo/util/net/message.h"
@@ -57,7 +57,7 @@ namespace mongo {
*/
class ClientCursor : private boost::noncopyable {
public:
- ClientCursor(const Collection* collection, Runner* runner,
+ ClientCursor(const Collection* collection, PlanExecutor* exec,
int qopts = 0, const BSONObj query = BSONObj());
ClientCursor(const Collection* collection);
@@ -77,7 +77,7 @@ namespace mongo {
* goes through killing cursors.
* It removes the responsiilibty of de-registering from ClientCursor.
* Responsibility for deleting the ClientCursor doesn't change from this call
- * see Runner::kill.
+ * see PlanExecutor::kill.
*/
void kill();
@@ -115,10 +115,10 @@ namespace mongo {
OpTime getSlaveReadTill() const { return _slaveReadTill; }
//
- // Query-specific functionality that may be adapted for the Runner.
+ // Query-specific functionality that may be adapted for the PlanExecutor.
//
- Runner* getRunner() const { return _runner.get(); }
+ PlanExecutor* getExecutor() const { return _exec.get(); }
int queryOptions() const { return _queryOptions; }
// Used by ops/query.cpp to stash how many results have been returned by a query.
@@ -129,7 +129,7 @@ namespace mongo {
/**
* Is this ClientCursor backed by an aggregation pipeline. Defaults to false.
*
- * Agg Runners differ from others in that they manage their own locking internally and
+ * Agg executors differ from others in that they manage their own locking internally and
* should not be killed or destroyed when the underlying collection is deleted.
*
* Note: This should *not* be set for the internal cursor used as input to an aggregation.
@@ -200,7 +200,7 @@ namespace mongo {
//
// The underlying execution machinery.
//
- scoped_ptr<Runner> _runner;
+ scoped_ptr<PlanExecutor> _exec;
};
/**
diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp
index d2dbf60e565..aaa1674a40a 100644
--- a/src/mongo/db/commands/collection_to_capped.cpp
+++ b/src/mongo/db/commands/collection_to_capped.cpp
@@ -83,24 +83,24 @@ namespace mongo {
static_cast<long long>( fromCollection->dataSize() -
( toCollection->getRecordStore()->storageSize( txn ) * 2 ) );
- scoped_ptr<Runner> runner( InternalPlanner::collectionScan(txn,
- fromNs,
- fromCollection,
- InternalPlanner::FORWARD ) );
+ scoped_ptr<PlanExecutor> exec( InternalPlanner::collectionScan(txn,
+ fromNs,
+ fromCollection,
+ InternalPlanner::FORWARD ) );
while ( true ) {
BSONObj obj;
- Runner::RunnerState state = runner->getNext(&obj, NULL);
+ Runner::RunnerState state = exec->getNext(&obj, NULL);
switch( state ) {
case Runner::RUNNER_EOF:
return Status::OK();
case Runner::RUNNER_DEAD:
db->dropCollection( txn, toNs );
- return Status( ErrorCodes::InternalError, "runner turned dead while iterating" );
+ return Status( ErrorCodes::InternalError, "executor turned dead while iterating" );
case Runner::RUNNER_ERROR:
- return Status( ErrorCodes::InternalError, "runner error while iterating" );
+ return Status( ErrorCodes::InternalError, "executor error while iterating" );
case Runner::RUNNER_ADVANCED:
if ( excessSize > 0 ) {
excessSize -= ( 4 * obj.objsize() ); // 4x is for padding, power of 2, etc...
diff --git a/src/mongo/db/commands/count.cpp b/src/mongo/db/commands/count.cpp
index f68f7488785..306af80f311 100644
--- a/src/mongo/db/commands/count.cpp
+++ b/src/mongo/db/commands/count.cpp
@@ -113,6 +113,8 @@ namespace mongo {
}
try {
+ ScopedExecutorRegistration safety(exec.get());
+
long long count = 0;
Runner::RunnerState state;
while (Runner::RUNNER_ADVANCED == (state = exec->getNext(NULL, NULL))) {
diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp
index 47405dd9888..2c5e5cee6f9 100644
--- a/src/mongo/db/commands/dbhash.cpp
+++ b/src/mongo/db/commands/dbhash.cpp
@@ -82,21 +82,21 @@ namespace mongo {
IndexDescriptor* desc = collection->getIndexCatalog()->findIdIndex();
- auto_ptr<Runner> runner;
+ auto_ptr<PlanExecutor> exec;
if ( desc ) {
- runner.reset(InternalPlanner::indexScan(opCtx,
- collection,
- desc,
- BSONObj(),
- BSONObj(),
- false,
- InternalPlanner::FORWARD,
- InternalPlanner::IXSCAN_FETCH));
+ exec.reset(InternalPlanner::indexScan(opCtx,
+ collection,
+ desc,
+ BSONObj(),
+ BSONObj(),
+ false,
+ InternalPlanner::FORWARD,
+ InternalPlanner::IXSCAN_FETCH));
}
else if ( collection->isCapped() ) {
- runner.reset(InternalPlanner::collectionScan(opCtx,
- fullCollectionName,
- collection));
+ exec.reset(InternalPlanner::collectionScan(opCtx,
+ fullCollectionName,
+ collection));
}
else {
log() << "can't find _id index for: " << fullCollectionName << endl;
@@ -109,8 +109,8 @@ namespace mongo {
long long n = 0;
Runner::RunnerState state;
BSONObj c;
- verify(NULL != runner.get());
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&c, NULL))) {
+ verify(NULL != exec.get());
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&c, NULL))) {
md5_append( &st , (const md5_byte_t*)c.objdata() , c.objsize() );
n++;
}
diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp
index ce582933d7a..27769ffcfee 100644
--- a/src/mongo/db/commands/distinct.cpp
+++ b/src/mongo/db/commands/distinct.cpp
@@ -39,9 +39,9 @@
#include "mongo/db/commands.h"
#include "mongo/db/instance.h"
#include "mongo/db/jsobj.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/query_planner_common.h"
-#include "mongo/db/query/type_explain.h"
+#include "mongo/db/query/explain.h"
#include "mongo/util/timer.h"
namespace mongo {
@@ -98,10 +98,6 @@ namespace mongo {
BSONArrayBuilder arr( bb );
BSONElementSet values;
- long long nscanned = 0; // locations looked at
- long long nscannedObjects = 0; // full objects looked at
- long long n = 0; // matches
-
Client::ReadContext ctx(txn, ns);
Collection* collection = ctx.ctx().db()->getCollection( txn, ns );
@@ -114,21 +110,20 @@ namespace mongo {
return true;
}
- Runner* rawRunner;
- Status status = getRunnerDistinct(txn, collection, query, key, &rawRunner);
+ PlanExecutor* rawExec;
+ Status status = getExecutorDistinct(txn, collection, query, key, &rawExec);
if (!status.isOK()) {
uasserted(17216, mongoutils::str::stream() << "Can't get runner for query "
<< query << ": " << status.toString());
return 0;
}
- auto_ptr<Runner> runner(rawRunner);
- const ScopedRunnerRegistration safety(runner.get());
+ auto_ptr<PlanExecutor> exec(rawExec);
+ const ScopedExecutorRegistration safety(exec.get());
- string cursorName;
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
// Distinct expands arrays.
//
// If our query is covered, each value of the key should be in the index key and
@@ -150,17 +145,10 @@ namespace mongo {
values.insert(x);
}
}
- TypeExplain* bareExplain;
- Status res = runner->getInfo(&bareExplain, NULL);
- if (res.isOK()) {
- auto_ptr<TypeExplain> explain(bareExplain);
- if (explain->isCursorSet()) {
- cursorName = explain->getCursor();
- }
- n = explain->getN();
- nscanned = explain->getNScanned();
- nscannedObjects = explain->getNScannedObjects();
- }
+
+ // Get summary information about the plan.
+ PlanSummaryStats stats;
+ Explain::getSummaryStats(exec.get(), &stats);
verify( start == bb.buf() );
@@ -168,11 +156,11 @@ namespace mongo {
{
BSONObjBuilder b;
- b.appendNumber( "n" , n );
- b.appendNumber( "nscanned" , nscanned );
- b.appendNumber( "nscannedObjects" , nscannedObjects );
+ b.appendNumber( "n" , stats.nReturned );
+ b.appendNumber( "nscanned" , stats.totalKeysExamined );
+ b.appendNumber( "nscannedObjects" , stats.totalDocsExamined );
b.appendNumber( "timems" , t.millis() );
- b.append( "cursor" , cursorName );
+ b.append( "planSummary" , stats.summaryStr );
result.append( "stats" , b.obj() );
}
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index 9df4c363b62..ea90af2cb66 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/ops/delete.h"
#include "mongo/db/ops/update.h"
#include "mongo/db/ops/update_lifecycle_impl.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/util/log.h"
@@ -151,17 +151,18 @@ namespace mongo {
massert(17383, "Could not canonicalize " + queryOriginal.toString(),
CanonicalQuery::canonicalize(ns, queryOriginal, &cq, whereCallback).isOK());
- Runner* rawRunner;
- massert(17384, "Could not get runner for query " + queryOriginal.toString(),
- getRunner(txn, collection, cq, &rawRunner, QueryPlannerParams::DEFAULT).isOK());
+ PlanExecutor* rawExec;
+ massert(17384, "Could not get plan executor for query " + queryOriginal.toString(),
+ getExecutor(txn, collection, cq, &rawExec, QueryPlannerParams::DEFAULT).isOK());
- auto_ptr<Runner> runner(rawRunner);
+ auto_ptr<PlanExecutor> exec(rawExec);
- // Set up automatic yielding
- const ScopedRunnerRegistration safety(runner.get());
+ // We need to keep this PlanExecutor registration: we are concurrently modifying
+ // state and may continue doing that with document-level locking (approach is TBD).
+ const ScopedExecutorRegistration safety(exec.get());
Runner::RunnerState state;
- if (Runner::RUNNER_ADVANCED == (state = runner->getNext(&doc, NULL))) {
+ if (Runner::RUNNER_ADVANCED == (state = exec->getNext(&doc, NULL))) {
found = true;
}
}
diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp
index 7fb6b972efd..ddb89a4f48a 100644
--- a/src/mongo/db/commands/geo_near_cmd.cpp
+++ b/src/mongo/db/commands/geo_near_cmd.cpp
@@ -40,8 +40,8 @@
#include "mongo/db/index_names.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/jsobj.h"
-#include "mongo/db/query/get_runner.h"
-#include "mongo/db/query/type_explain.h"
+#include "mongo/db/query/get_executor.h"
+#include "mongo/db/query/explain.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/platform/unordered_map.h"
@@ -186,14 +186,14 @@ namespace mongo {
return false;
}
- Runner* rawRunner;
- if (!getRunner(txn, collection, cq, &rawRunner, 0).isOK()) {
+ PlanExecutor* rawExec;
+ if (!getExecutor(txn, collection, cq, &rawExec, 0).isOK()) {
errmsg = "can't get query runner";
return false;
}
- auto_ptr<Runner> runner(rawRunner);
- const ScopedRunnerRegistration safety(runner.get());
+ auto_ptr<PlanExecutor> exec(rawExec);
+ const ScopedExecutorRegistration safety(exec.get());
double totalDistance = 0;
BSONObjBuilder resultBuilder(result.subarrayStart("results"));
@@ -201,7 +201,7 @@ namespace mongo {
BSONObj currObj;
int results = 0;
- while ((results < numWanted) && Runner::RUNNER_ADVANCED == runner->getNext(&currObj, NULL)) {
+ while ((results < numWanted) && Runner::RUNNER_ADVANCED == exec->getNext(&currObj, NULL)) {
// Come up with the correct distance.
double dist = currObj["$dis"].number() * distanceMultiplier;
@@ -246,13 +246,10 @@ namespace mongo {
BSONObjBuilder stats(result.subobjStart("stats"));
// Fill in nscanned from the explain.
- TypeExplain* bareExplain;
- Status res = runner->getInfo(&bareExplain, NULL);
- if (res.isOK()) {
- auto_ptr<TypeExplain> explain(bareExplain);
- stats.append("nscanned", explain->getNScanned());
- stats.append("objectsLoaded", explain->getNScannedObjects());
- }
+ PlanSummaryStats summary;
+ Explain::getSummaryStats(exec.get(), &summary);
+ stats.appendNumber("nscanned", summary.totalKeysExamined);
+ stats.appendNumber("objectsLoaded", summary.totalDocsExamined);
stats.append("avgDistance", totalDistance / results);
stats.append("maxDistance", farthestDist);
diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp
index aed8e699e83..9bfa3259a6f 100644
--- a/src/mongo/db/commands/group.cpp
+++ b/src/mongo/db/commands/group.cpp
@@ -41,7 +41,7 @@
#include "mongo/db/commands.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/instance.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/scripting/engine.h"
@@ -146,18 +146,18 @@ namespace mongo {
return 0;
}
- Runner* rawRunner;
- if (!getRunner(txn,collection, cq, &rawRunner).isOK()) {
- uasserted(17213, "Can't get runner for query " + query.toString());
+ PlanExecutor* rawExec;
+ if (!getExecutor(txn,collection, cq, &rawExec).isOK()) {
+ uasserted(17213, "Can't get executor for query " + query.toString());
return 0;
}
- auto_ptr<Runner> runner(rawRunner);
- const ScopedRunnerRegistration safety(runner.get());
+ auto_ptr<PlanExecutor> exec(rawExec);
+ const ScopedExecutorRegistration safety(exec.get());
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
BSONObj key = getKey(obj , keyPattern , keyFunction , keysize / keynum,
s.get() );
keysize += key.objsize();
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index df0a6e7b9e3..f2501f99e80 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -42,7 +42,7 @@
#include "mongo/db/dbhelpers.h"
#include "mongo/db/instance.h"
#include "mongo/db/matcher/matcher.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/query_planner.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/repl_coordinator_global.h"
@@ -987,17 +987,23 @@ namespace mongo {
&cq,
whereCallback).isOK());
- Runner* rawRunner;
- verify(getRunner(_txn, ctx->ctx().db()->getCollection(_txn, _config.incLong),
- cq, &rawRunner, QueryPlannerParams::NO_TABLE_SCAN).isOK());
+ PlanExecutor* rawExec;
+ verify(getExecutor(_txn, ctx->ctx().db()->getCollection(_txn, _config.incLong),
+ cq, &rawExec, QueryPlannerParams::NO_TABLE_SCAN).isOK());
- auto_ptr<Runner> runner(rawRunner);
- const ScopedRunnerRegistration safety(runner.get());
+ auto_ptr<PlanExecutor> exec(rawExec);
+
+ // This registration is necessary because we may manually yield the read lock
+ // below (in order to acquire a write lock and dump some data to a temporary
+ // collection).
+ //
+ // TODO: don't do this in the future.
+ const ScopedExecutorRegistration safety(exec.get());
// iterate over all sorted objects
BSONObj o;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&o, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&o, NULL))) {
pm.hit();
if ( o.woSortOrder( prev , sortKey ) == 0 ) {
@@ -1009,7 +1015,7 @@ namespace mongo {
continue;
}
- runner->saveState();
+ exec->saveState();
ctx.reset();
@@ -1022,7 +1028,7 @@ namespace mongo {
prev = o;
all.push_back( o );
- if (!runner->restoreState(_txn)) {
+ if (!exec->restoreState(_txn)) {
break;
}
@@ -1330,20 +1336,24 @@ namespace mongo {
return 0;
}
- Runner* rawRunner;
- if (!getRunner(txn, ctx->db()->getCollection(txn, config.ns), cq, &rawRunner).isOK()) {
- uasserted(17239, "Can't get runner for query " + config.filter.toString());
+ PlanExecutor* rawExec;
+ if (!getExecutor(txn, ctx->db()->getCollection(txn, config.ns),
+ cq, &rawExec).isOK()) {
+ uasserted(17239, "Can't get executor for query "
+ + config.filter.toString());
return 0;
}
- auto_ptr<Runner> runner(rawRunner);
- const ScopedRunnerRegistration safety(runner.get());
+ auto_ptr<PlanExecutor> exec(rawExec);
+
+ // XXX: is this registration necessary?
+ const ScopedExecutorRegistration safety(exec.get());
Timer mt;
// go through each doc
BSONObj o;
- while (Runner::RUNNER_ADVANCED == runner->getNext(&o, NULL)) {
+ while (Runner::RUNNER_ADVANCED == exec->getNext(&o, NULL)) {
// check to see if this is a new object we don't own yet
// because of a chunk migration
if ( collMetadata ) {
diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp
index c10cf053534..fbfda3e8138 100644
--- a/src/mongo/db/commands/parallel_collection_scan.cpp
+++ b/src/mongo/db/commands/parallel_collection_scan.cpp
@@ -33,6 +33,7 @@
#include "mongo/db/catalog/database.h"
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
+#include "mongo/db/exec/plan_stage.h"
#include "mongo/util/touch_pages.h"
namespace mongo {
@@ -49,58 +50,59 @@ namespace mongo {
size_t size;
};
- class MultiIteratorRunner : public Runner {
+ // XXX: move this to the exec/ directory.
+ class MultiIteratorStage : public PlanStage {
public:
- MultiIteratorRunner( const StringData& ns, Collection* collection )
- : _ns( ns.toString() ),
- _collection( collection ) {
- }
- ~MultiIteratorRunner() {
- }
+ MultiIteratorStage(WorkingSet* ws, Collection* collection)
+ : _collection(collection),
+ _ws(ws) { }
+
+ ~MultiIteratorStage() { }
// takes ownership of it
void addIterator(RecordIterator* it) {
_iterators.push_back(it);
}
- virtual RunnerState getNext(BSONObj* objOut, DiskLoc* dlOut) {
+ virtual StageState work(WorkingSetID* out) {
if ( _collection == NULL )
- return RUNNER_DEAD;
+ return PlanStage::DEAD;
DiskLoc next = _advance();
if (next.isNull())
- return RUNNER_EOF;
+ return PlanStage::IS_EOF;
- if ( objOut )
- *objOut = _collection->docFor( next );
- if ( dlOut )
- *dlOut = next;
- return RUNNER_ADVANCED;
+ *out = _ws->allocate();
+ WorkingSetMember* member = _ws->get(*out);
+ member->loc = next;
+ member->obj = _collection->docFor(next);
+ member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ return PlanStage::ADVANCED;
}
virtual bool isEOF() {
return _collection == NULL || _iterators.empty();
}
- virtual void kill() {
+
+ void kill() {
_collection = NULL;
_iterators.clear();
}
- virtual void saveState() {
+
+ virtual void prepareToYield() {
for (size_t i = 0; i < _iterators.size(); i++) {
_iterators[i]->prepareToYield();
}
}
- virtual bool restoreState(OperationContext* opCtx) {
+
+ virtual void recoverFromYield(OperationContext* opCtx) {
for (size_t i = 0; i < _iterators.size(); i++) {
if (!_iterators[i]->recoverFromYield()) {
kill();
- return false;
}
}
- return true;
}
- virtual const string& ns() { return _ns; }
virtual void invalidate(const DiskLoc& dl, InvalidationType type) {
switch ( type ) {
case INVALIDATION_DELETION:
@@ -113,12 +115,22 @@ namespace mongo {
break;
}
}
- virtual const Collection* collection() {
- return _collection;
- }
- virtual Status getInfo(TypeExplain** explain, PlanInfo** planInfo) const {
- return Status( ErrorCodes::InternalError, "no" );
+
+ //
+ // These should not be used.
+ //
+
+ virtual PlanStageStats* getStats() { return NULL; }
+ virtual CommonStats* getCommonStats() { return NULL; }
+ virtual SpecificStats* getSpecificStats() { return NULL; }
+
+ virtual std::vector<PlanStage*> getChildren() const {
+ vector<PlanStage*> empty;
+ return empty;
}
+
+ virtual StageType stageType() const { return STAGE_MULTI_ITERATOR; }
+
private:
/**
@@ -136,9 +148,11 @@ namespace mongo {
return DiskLoc();
}
- string _ns;
Collection* _collection;
OwnedPointerVector<RecordIterator> _iterators;
+
+ // Not owned by us.
+ WorkingSet* _ws;
};
// ------------------------------------------------
@@ -191,23 +205,28 @@ namespace mongo {
numCursors = iterators.size();
}
- OwnedPointerVector<MultiIteratorRunner> runners;
+ OwnedPointerVector<PlanExecutor> execs;
for ( size_t i = 0; i < numCursors; i++ ) {
- runners.push_back(new MultiIteratorRunner(ns.ns(), collection));
+ WorkingSet* ws = new WorkingSet();
+ MultiIteratorStage* mis = new MultiIteratorStage(ws, collection);
+ // Takes ownership of 'ws' and 'mis'.
+ execs.push_back(new PlanExecutor(ws, mis, collection));
}
- // transfer iterators to runners using a round-robin distribution.
+ // transfer iterators to executors using a round-robin distribution.
// TODO consider using a common work queue once invalidation issues go away.
for (size_t i = 0; i < iterators.size(); i++) {
- runners[i % runners.size()]->addIterator(iterators.releaseAt(i));
+ PlanExecutor* theExec = execs[i % execs.size()];
+ MultiIteratorStage* mis = static_cast<MultiIteratorStage*>(theExec->getStages());
+ mis->addIterator(iterators.releaseAt(i));
}
{
BSONArrayBuilder bucketsBuilder;
- for (size_t i = 0; i < runners.size(); i++) {
- // transfer ownership of a runner to the ClientCursor (which manages its own
+ for (size_t i = 0; i < execs.size(); i++) {
+ // transfer ownership of an executor to the ClientCursor (which manages its own
// lifetime).
- ClientCursor* cc = new ClientCursor( collection, runners.releaseAt(i) );
+ ClientCursor* cc = new ClientCursor( collection, execs.releaseAt(i) );
// we are mimicking the aggregation cursor output here
// that is why there are ns, ok and empty firstBatch
diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp
index 5033dd05da7..de49bc61d1c 100644
--- a/src/mongo/db/commands/pipeline_command.cpp
+++ b/src/mongo/db/commands/pipeline_command.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/client.h"
#include "mongo/db/curop.h"
#include "mongo/db/commands.h"
+#include "mongo/db/exec/plan_stage.h"
#include "mongo/db/pipeline/accumulator.h"
#include "mongo/db/pipeline/document.h"
#include "mongo/db/pipeline/document_source.h"
@@ -46,7 +47,7 @@
#include "mongo/db/pipeline/pipeline_d.h"
#include "mongo/db/pipeline/pipeline.h"
#include "mongo/db/query/find_constants.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/storage_options.h"
namespace mongo {
@@ -54,33 +55,46 @@ namespace mongo {
namespace {
/**
- * This is a Runner implementation backed by an aggregation pipeline.
+ * Stage for pulling results out from an aggregation pipeline.
+ *
+ * XXX: move this stage to the exec/ directory.
*/
- class PipelineRunner : public Runner {
+ class PipelineProxyStage : public PlanStage {
public:
- PipelineRunner(intrusive_ptr<Pipeline> pipeline, const boost::shared_ptr<Runner>& child)
+ PipelineProxyStage(intrusive_ptr<Pipeline> pipeline,
+ const boost::shared_ptr<PlanExecutor>& child,
+ WorkingSet* ws)
: _pipeline(pipeline)
, _includeMetaData(_pipeline->getContext()->inShard) // send metadata to merger
- , _childRunner(child)
+ , _childExec(child)
+ , _ws(ws)
{}
- virtual RunnerState getNext(BSONObj* objOut, DiskLoc* dlOut) {
- if (!objOut || dlOut)
- return RUNNER_ERROR;
+ virtual StageState work(WorkingSetID* out) {
+ if (!out) {
+ return PlanStage::FAILURE;
+ }
if (!_stash.empty()) {
- *objOut = _stash.back();
+ *out = _ws->allocate();
+ WorkingSetMember* member = _ws->get(*out);
+ member->obj = _stash.back();
_stash.pop_back();
- return RUNNER_ADVANCED;
+ member->state = WorkingSetMember::OWNED_OBJ;
+ return PlanStage::ADVANCED;
}
if (boost::optional<BSONObj> next = getNextBson()) {
- *objOut = *next;
- return RUNNER_ADVANCED;
+ *out = _ws->allocate();
+ WorkingSetMember* member = _ws->get(*out);
+ member->obj = *next;
+ member->state = WorkingSetMember::OWNED_OBJ;
+ return PlanStage::ADVANCED;
}
- return RUNNER_EOF;
+ return PlanStage::IS_EOF;
}
+
virtual bool isEOF() {
if (!_stash.empty())
return false;
@@ -92,41 +106,23 @@ namespace {
return true;
}
- virtual const string& ns() {
- return _pipeline->getContext()->ns.ns();
- }
-
- virtual Status getInfo(TypeExplain** explain,
- PlanInfo** planInfo) const {
- // This should never get called in practice anyway.
- return Status(ErrorCodes::InternalError,
- "PipelineCursor doesn't implement getExplainPlan");
- }
- // propagate to child runner if still in use
+ // propagate to child executor if still in use
virtual void invalidate(const DiskLoc& dl, InvalidationType type) {
- if (boost::shared_ptr<Runner> runner = _childRunner.lock()) {
- runner->invalidate(dl, type);
- }
- }
- virtual void kill() {
- if (boost::shared_ptr<Runner> runner = _childRunner.lock()) {
- runner->kill();
+ if (boost::shared_ptr<PlanExecutor> exec = _childExec.lock()) {
+ exec->invalidate(dl, type);
}
}
- // Manage our OperationContext. We intentionally don't propagate to child Runner as that is
- // handled by DocumentSourceCursor as it needs to.
- virtual void saveState() {
+ // Manage our OperationContext. We intentionally don't propagate to the child
+ // Runner as that is handled by DocumentSourceCursor as it needs to.
+ virtual void prepareToYield() {
_pipeline->getContext()->opCtx = NULL;
}
- virtual bool restoreState(OperationContext* opCtx) {
+ virtual void recoverFromYield(OperationContext* opCtx) {
_pipeline->getContext()->opCtx = opCtx;
- return true;
}
- virtual const Collection* collection() { return NULL; }
-
/**
* Make obj the next object returned by getNext().
*/
@@ -134,6 +130,23 @@ namespace {
_stash.push_back(obj);
}
+ //
+ // These should not be used.
+ //
+
+ virtual PlanStageStats* getStats() { return NULL; }
+ virtual CommonStats* getCommonStats() { return NULL; }
+ virtual SpecificStats* getSpecificStats() { return NULL; }
+
+ // Not used.
+ virtual std::vector<PlanStage*> getChildren() const {
+ vector<PlanStage*> empty;
+ return empty;
+ }
+
+ // Not used.
+ virtual StageType stageType() const { return STAGE_PIPELINE_PROXY; }
+
private:
boost::optional<BSONObj> getNextBson() {
if (boost::optional<Document> next = _pipeline->output()->getNext()) {
@@ -152,7 +165,10 @@ namespace {
const intrusive_ptr<Pipeline> _pipeline;
vector<BSONObj> _stash;
const bool _includeMetaData;
- boost::weak_ptr<Runner> _childRunner;
+ boost::weak_ptr<PlanExecutor> _childExec;
+
+ // Not owned by us.
+ WorkingSet* _ws;
};
}
@@ -185,14 +201,14 @@ namespace {
static void handleCursorCommand(OperationContext* txn,
const string& ns,
ClientCursorPin* pin,
- PipelineRunner* runner,
+ PlanExecutor* exec,
const BSONObj& cmdObj,
BSONObjBuilder& result) {
ClientCursor* cursor = pin ? pin->c() : NULL;
if (pin) {
invariant(cursor);
- invariant(cursor->getRunner() == runner);
+ invariant(cursor->getExecutor() == exec);
invariant(cursor->isAggCursor);
}
@@ -206,32 +222,34 @@ namespace {
const int byteLimit = MaxBytesToReturnToClientAtOnce;
BSONObj next;
for (int objCount = 0; objCount < batchSize; objCount++) {
- // The initial getNext() on a PipelineRunner may be very expensive so we don't
+ // The initial getNext() on a PipelineProxyStage may be very expensive so we don't
// do it when batchSize is 0 since that indicates a desire for a fast return.
- if (runner->getNext(&next, NULL) != Runner::RUNNER_ADVANCED) {
+ if (exec->getNext(&next, NULL) != Runner::RUNNER_ADVANCED) {
if (pin) pin->deleteUnderlying();
- // make it an obvious error to use cursor or runner after this point
+ // make it an obvious error to use cursor or executor after this point
cursor = NULL;
- runner = NULL;
+ exec = NULL;
break;
}
if (resultsArray.len() + next.objsize() > byteLimit) {
+ // Get the pipeline proxy stage wrapped by this PlanExecutor.
+ PipelineProxyStage* proxy = static_cast<PipelineProxyStage*>(exec->getStages());
// too big. next will be the first doc in the second batch
- runner->pushBack(next);
+ proxy->pushBack(next);
break;
}
resultsArray.append(next);
}
- // NOTE: runner->isEOF() can have side effects such as writing by $out. However, it should
+ // NOTE: exec->isEOF() can have side effects such as writing by $out. However, it should
// be relatively quick since if there was no pin then the input is empty. Also, this
// violates the contract for batchSize==0. Sharding requires a cursor to be returned in that
// case. This is ok for now however, since you can't have a sharded collection that doesn't
// exist.
const bool canReturnMoreBatches = pin;
- if (!canReturnMoreBatches && runner && !runner->isEOF()) {
+ if (!canReturnMoreBatches && exec && !exec->isEOF()) {
// msgasserting since this shouldn't be possible to trigger from today's aggregation
// language. The wording assumes that the only reason pin would be null is if the
// collection doesn't exist.
@@ -308,13 +326,13 @@ namespace {
}
#endif
- PipelineRunner* runner = NULL;
- scoped_ptr<ClientCursorPin> pin; // either this OR the runnerHolder will be non-null
- auto_ptr<PipelineRunner> runnerHolder;
+ PlanExecutor* exec = NULL;
+ scoped_ptr<ClientCursorPin> pin; // either this OR the execHolder will be non-null
+ auto_ptr<PlanExecutor> execHolder;
{
// This will throw if the sharding version for this connection is out of date. The
// lock must be held continuously from now until we have we created both the output
- // ClientCursor and the input Runner. This ensures that both are using the same
+ // ClientCursor and the input executor. This ensures that both are using the same
// sharding version that we synchronize on here. This is also why we always need to
// create a ClientCursor even when we aren't outputting to a cursor. See the comment
// on ShardFilterStage for more details.
@@ -322,26 +340,37 @@ namespace {
Collection* collection = ctx.ctx().db()->getCollection(txn, ns);
- // This does mongod-specific stuff like creating the input Runner and adding to the
- // front of the pipeline if needed.
- boost::shared_ptr<Runner> input = PipelineD::prepareCursorSource(txn,
- collection,
- pPipeline,
- pCtx);
+ // This does mongod-specific stuff like creating the input PlanExecutor and adding
+ // it to the front of the pipeline if needed.
+ boost::shared_ptr<PlanExecutor> input = PipelineD::prepareCursorSource(txn,
+ collection,
+ pPipeline,
+ pCtx);
pPipeline->stitch();
- runnerHolder.reset(new PipelineRunner(pPipeline, input));
- runner = runnerHolder.get();
+ // Create the PlanExecutor which returns results from the pipeline. The WorkingSet
+ // ('ws') and the PipelineProxyStage ('proxy') will be owned by the created
+ // PlanExecutor.
+ auto_ptr<WorkingSet> ws(new WorkingSet());
+ auto_ptr<PipelineProxyStage> proxy(
+ new PipelineProxyStage(pPipeline, input, ws.get()));
+ if (NULL == collection) {
+ execHolder.reset(new PlanExecutor(ws.release(), proxy.release(), ns));
+ }
+ else {
+ execHolder.reset(new PlanExecutor(ws.release(), proxy.release(), collection));
+ }
+ exec = execHolder.get();
if (!collection && input) {
- // If we don't have a collection, we won't be able to register any Runners, so
- // make sure that the input Runner (likely an EOFRunner) doesn't need to be
- // registered.
+ // If we don't have a collection, we won't be able to register any executors, so
+ // make sure that the input PlanExecutor (likely wrapping an EOFStage) doesn't
+ // need to be registered.
invariant(!input->collection());
}
if (collection) {
- ClientCursor* cursor = new ClientCursor(collection, runnerHolder.release());
+ ClientCursor* cursor = new ClientCursor(collection, execHolder.release());
cursor->isAggCursor = true; // enable special locking behavior
pin.reset(new ClientCursorPin(collection, cursor->cursorid()));
// Don't add any code between here and the start of the try block.
@@ -357,7 +386,7 @@ namespace {
result << "stages" << Value(pPipeline->writeExplainOps());
}
else if (isCursorCommand(cmdObj)) {
- handleCursorCommand(txn, ns, pin.get(), runner, cmdObj, result);
+ handleCursorCommand(txn, ns, pin.get(), exec, cmdObj, result);
keepCursor = true;
}
else {
diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp
index 9036445a88b..fb5f38c7897 100644
--- a/src/mongo/db/commands/test_commands.cpp
+++ b/src/mongo/db/commands/test_commands.cpp
@@ -150,14 +150,14 @@ namespace mongo {
Collection* collection = ctx.ctx().db()->getCollection( txn, nss.ns() );
massert( 13417, "captrunc collection not found or empty", collection);
- boost::scoped_ptr<Runner> runner(InternalPlanner::collectionScan(txn,
- nss.ns(),
- collection,
- InternalPlanner::BACKWARD));
+ boost::scoped_ptr<PlanExecutor> exec(
+ InternalPlanner::collectionScan(txn, nss.ns(), collection,
+ InternalPlanner::BACKWARD));
+
DiskLoc end;
// We remove 'n' elements so the start is one past that
for( int i = 0; i < n + 1; ++i ) {
- Runner::RunnerState state = runner->getNext(NULL, &end);
+ Runner::RunnerState state = exec->getNext(NULL, &end);
massert( 13418, "captrunc invalid n", Runner::RUNNER_ADVANCED == state);
}
collection->temp_cappedTruncateAfter( txn, end, inc );
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 076b2fac59d..fad3e98d9da 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -365,10 +365,11 @@ namespace mongo {
const string systemIndexes = ctx.db()->name() + ".system.indexes";
Collection* coll = ctx.db()->getCollection( &txn, systemIndexes );
- auto_ptr<Runner> runner(InternalPlanner::collectionScan(&txn, systemIndexes,coll));
+ auto_ptr<PlanExecutor> exec(
+ InternalPlanner::collectionScan(&txn, systemIndexes,coll));
BSONObj index;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&index, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&index, NULL))) {
const BSONObj key = index.getObjectField("key");
const string plugin = IndexNames::findPluginName(key);
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index e6c6d36ce41..147f86d9161 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -62,7 +62,7 @@
#include "mongo/db/lasterror.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/ops/insert.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/query/query_planner.h"
#include "mongo/db/repair_database.h"
@@ -673,23 +673,23 @@ namespace mongo {
return 0;
}
- Runner* rawRunner;
- if (!getRunner(txn, coll, cq, &rawRunner, QueryPlannerParams::NO_TABLE_SCAN).isOK()) {
- uasserted(17241, "Can't get runner for query " + query.toString());
+ PlanExecutor* rawExec;
+ if (!getExecutor(txn, coll, cq, &rawExec, QueryPlannerParams::NO_TABLE_SCAN).isOK()) {
+ uasserted(17241, "Can't get executor for query " + query.toString());
return 0;
}
- auto_ptr<Runner> runner(rawRunner);
+ auto_ptr<PlanExecutor> exec(rawExec);
- // The runner must be registered to be informed of DiskLoc deletions and NS dropping
+ // The executor must be registered to be informed of DiskLoc deletions and NS dropping
// when we yield the lock below.
- const ScopedRunnerRegistration safety(runner.get());
+ const ScopedExecutorRegistration safety(exec.get());
const ChunkVersion shardVersionAtStart = shardingState.getVersion(ns);
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
BSONElement ne = obj["n"];
verify(ne.isNumber());
int myn = ne.numberInt();
@@ -788,7 +788,7 @@ namespace mongo {
result.appendBool( "estimate" , estimate );
- auto_ptr<Runner> runner;
+ auto_ptr<PlanExecutor> exec;
if ( min.isEmpty() && max.isEmpty() ) {
if ( estimate ) {
result.appendNumber( "size" , static_cast<long long>(collection->dataSize()) );
@@ -797,7 +797,7 @@ namespace mongo {
result.append( "millis" , timer.millis() );
return 1;
}
- runner.reset(InternalPlanner::collectionScan(txn, ns,collection));
+ exec.reset(InternalPlanner::collectionScan(txn, ns,collection));
}
else if ( min.isEmpty() || max.isEmpty() ) {
errmsg = "only one of min or max specified";
@@ -822,7 +822,7 @@ namespace mongo {
min = Helpers::toKeyFormat( kp.extendRangeBound( min, false ) );
max = Helpers::toKeyFormat( kp.extendRangeBound( max, false ) );
- runner.reset(InternalPlanner::indexScan(txn, collection, idx, min, max, false));
+ exec.reset(InternalPlanner::indexScan(txn, collection, idx, min, max, false));
}
long long avgObjSize = collection->dataSize() / collection->numRecords();
@@ -835,7 +835,7 @@ namespace mongo {
DiskLoc loc;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, &loc))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(NULL, &loc))) {
if ( estimate )
size += avgObjSize;
else
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index ae6b560dbad..db0132d5aa0 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -46,7 +46,7 @@
#include "mongo/db/ops/update_lifecycle_impl.h"
#include "mongo/db/ops/update_request.h"
#include "mongo/db/ops/update_result.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/query/query_planner.h"
#include "mongo/db/repl/oplog.h"
@@ -112,15 +112,15 @@ namespace mongo {
massert(17244, "Could not canonicalize " + query.toString(),
CanonicalQuery::canonicalize(collection->ns(), query, &cq, whereCallback).isOK());
- Runner* rawRunner;
+ PlanExecutor* rawExec;
size_t options = requireIndex ? QueryPlannerParams::NO_TABLE_SCAN : QueryPlannerParams::DEFAULT;
- massert(17245, "Could not get runner for query " + query.toString(),
- getRunner(txn, collection, cq, &rawRunner, options).isOK());
+ massert(17245, "Could not get executor for query " + query.toString(),
+ getExecutor(txn, collection, cq, &rawExec, options).isOK());
- auto_ptr<Runner> runner(rawRunner);
+ auto_ptr<PlanExecutor> exec(rawExec);
Runner::RunnerState state;
DiskLoc loc;
- if (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, &loc))) {
+ if (Runner::RUNNER_ADVANCED == (state = exec->getNext(NULL, &loc))) {
return loc;
}
return DiskLoc();
@@ -184,11 +184,10 @@ namespace mongo {
*/
bool Helpers::getSingleton(OperationContext* txn, const char *ns, BSONObj& result) {
Client::Context context(txn, ns);
- auto_ptr<Runner> runner(InternalPlanner::collectionScan(txn,
- ns,
- context.db()->getCollection(txn,
- ns)));
- Runner::RunnerState state = runner->getNext(&result, NULL);
+ auto_ptr<PlanExecutor> exec(
+ InternalPlanner::collectionScan(txn, ns, context.db()->getCollection(txn, ns)));
+
+ Runner::RunnerState state = exec->getNext(&result, NULL);
context.getClient()->curop()->done();
return Runner::RUNNER_ADVANCED == state;
}
@@ -196,11 +195,10 @@ namespace mongo {
bool Helpers::getLast(OperationContext* txn, const char *ns, BSONObj& result) {
Client::Context ctx(txn, ns);
Collection* coll = ctx.db()->getCollection( txn, ns );
- auto_ptr<Runner> runner(InternalPlanner::collectionScan(txn,
- ns,
- coll,
- InternalPlanner::BACKWARD));
- Runner::RunnerState state = runner->getNext(&result, NULL);
+ auto_ptr<PlanExecutor> exec(
+ InternalPlanner::collectionScan(txn, ns, coll, InternalPlanner::BACKWARD));
+
+ Runner::RunnerState state = exec->getNext(&result, NULL);
return Runner::RUNNER_ADVANCED == state;
}
@@ -362,17 +360,18 @@ namespace mongo {
IndexDescriptor* desc =
collection->getIndexCatalog()->findIndexByKeyPattern( indexKeyPattern.toBSON() );
- auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, desc, min, max,
- maxInclusive,
- InternalPlanner::FORWARD,
- InternalPlanner::IXSCAN_FETCH));
+ auto_ptr<PlanExecutor> exec(InternalPlanner::indexScan(txn, collection, desc,
+ min, max,
+ maxInclusive,
+ InternalPlanner::FORWARD,
+ InternalPlanner::IXSCAN_FETCH));
DiskLoc rloc;
BSONObj obj;
Runner::RunnerState state;
// This may yield so we cannot touch nsd after this.
- state = runner->getNext(&obj, &rloc);
- runner.reset();
+ state = exec->getNext(&obj, &rloc);
+ exec.reset();
if (Runner::RUNNER_EOF == state) { break; }
if (Runner::RUNNER_DEAD == state) {
@@ -520,13 +519,14 @@ namespace mongo {
bool isLargeChunk = false;
long long docCount = 0;
- auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max, false));
+ auto_ptr<PlanExecutor> exec(
+ InternalPlanner::indexScan(txn, collection, idx, min, max, false));
// we can afford to yield here because any change to the base data that we might miss is
// already being queued and will be migrated in the 'transferMods' stage
DiskLoc loc;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, &loc))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(NULL, &loc))) {
if ( !isLargeChunk ) {
locs->insert( loc );
}
diff --git a/src/mongo/db/exec/and_hash.cpp b/src/mongo/db/exec/and_hash.cpp
index 4dc0b255576..4e43f55da82 100644
--- a/src/mongo/db/exec/and_hash.cpp
+++ b/src/mongo/db/exec/and_hash.cpp
@@ -440,11 +440,11 @@ namespace mongo {
}
}
- void AndHashStage::recoverFromYield() {
+ void AndHashStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->recoverFromYield();
+ _children[i]->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/and_hash.h b/src/mongo/db/exec/and_hash.h
index fc2f24ad4fe..3ae34cca5a7 100644
--- a/src/mongo/db/exec/and_hash.h
+++ b/src/mongo/db/exec/and_hash.h
@@ -76,7 +76,7 @@ namespace mongo {
virtual bool isEOF();
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/and_sorted.cpp b/src/mongo/db/exec/and_sorted.cpp
index 58d17a2c557..42025074b70 100644
--- a/src/mongo/db/exec/and_sorted.cpp
+++ b/src/mongo/db/exec/and_sorted.cpp
@@ -265,11 +265,11 @@ namespace mongo {
}
}
- void AndSortedStage::recoverFromYield() {
+ void AndSortedStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->recoverFromYield();
+ _children[i]->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/and_sorted.h b/src/mongo/db/exec/and_sorted.h
index 13c8a663426..f3660b17881 100644
--- a/src/mongo/db/exec/and_sorted.h
+++ b/src/mongo/db/exec/and_sorted.h
@@ -62,7 +62,7 @@ namespace mongo {
virtual bool isEOF();
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/cached_plan.cpp b/src/mongo/db/exec/cached_plan.cpp
index f93935fb224..488daf003f3 100644
--- a/src/mongo/db/exec/cached_plan.cpp
+++ b/src/mongo/db/exec/cached_plan.cpp
@@ -104,13 +104,13 @@ namespace mongo {
++_commonStats.yields;
}
- void CachedPlanStage::recoverFromYield() {
+ void CachedPlanStage::recoverFromYield(OperationContext* opCtx) {
if (NULL != _backupChildPlan.get()) {
- _backupChildPlan->recoverFromYield();
+ _backupChildPlan->recoverFromYield(opCtx);
}
if (! _usingBackupChild) {
- _mainChildPlan->recoverFromYield();
+ _mainChildPlan->recoverFromYield(opCtx);
}
++_commonStats.unyields;
}
diff --git a/src/mongo/db/exec/cached_plan.h b/src/mongo/db/exec/cached_plan.h
index 7049f6e35f1..8041e5f3e26 100644
--- a/src/mongo/db/exec/cached_plan.h
+++ b/src/mongo/db/exec/cached_plan.h
@@ -57,7 +57,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp
index c424cc6ba6d..a939aee0b84 100644
--- a/src/mongo/db/exec/collection_scan.cpp
+++ b/src/mongo/db/exec/collection_scan.cpp
@@ -151,7 +151,7 @@ namespace mongo {
}
}
- void CollectionScan::recoverFromYield() {
+ void CollectionScan::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
if (NULL != _iter) {
if (!_iter->recoverFromYield()) {
diff --git a/src/mongo/db/exec/collection_scan.h b/src/mongo/db/exec/collection_scan.h
index a6cfa4eb541..f70dc5facbf 100644
--- a/src/mongo/db/exec/collection_scan.h
+++ b/src/mongo/db/exec/collection_scan.h
@@ -57,7 +57,7 @@ namespace mongo {
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/count.cpp b/src/mongo/db/exec/count.cpp
index 08cd7869baa..092f3bc1006 100644
--- a/src/mongo/db/exec/count.cpp
+++ b/src/mongo/db/exec/count.cpp
@@ -152,7 +152,7 @@ namespace mongo {
_endCursor->savePosition();
}
- void Count::recoverFromYield() {
+ void Count::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
if (_hitEnd || (NULL == _btreeCursor.get())) { return; }
diff --git a/src/mongo/db/exec/count.h b/src/mongo/db/exec/count.h
index 11e477f8822..60873374cdc 100644
--- a/src/mongo/db/exec/count.h
+++ b/src/mongo/db/exec/count.h
@@ -63,7 +63,7 @@ namespace mongo {
* any WorkingSetMember(s) for any of the data, instead returning ADVANCED to indicate to the
* caller that another result should be counted.
*
- * Only created through the getRunnerCount path, as count is the only operation that doesn't
+ * Only created through the getExecutorCount path, as count is the only operation that doesn't
* care about its data.
*/
class Count : public PlanStage {
@@ -74,7 +74,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual bool isEOF();
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/distinct_scan.cpp b/src/mongo/db/exec/distinct_scan.cpp
index 7c6e8b1285d..a3d0fe57994 100644
--- a/src/mongo/db/exec/distinct_scan.cpp
+++ b/src/mongo/db/exec/distinct_scan.cpp
@@ -158,7 +158,7 @@ namespace mongo {
_btreeCursor->savePosition();
}
- void DistinctScan::recoverFromYield() {
+ void DistinctScan::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
if (_hitEnd || (NULL == _btreeCursor.get())) { return; }
diff --git a/src/mongo/db/exec/distinct_scan.h b/src/mongo/db/exec/distinct_scan.h
index 453cb37efac..15935c83cb5 100644
--- a/src/mongo/db/exec/distinct_scan.h
+++ b/src/mongo/db/exec/distinct_scan.h
@@ -85,7 +85,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual bool isEOF();
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/eof.cpp b/src/mongo/db/exec/eof.cpp
index 076e5426028..c160f2a5ef7 100644
--- a/src/mongo/db/exec/eof.cpp
+++ b/src/mongo/db/exec/eof.cpp
@@ -54,7 +54,7 @@ namespace mongo {
++_commonStats.yields;
}
- void EOFStage::recoverFromYield() {
+ void EOFStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
}
diff --git a/src/mongo/db/exec/eof.h b/src/mongo/db/exec/eof.h
index c7050716f3b..5475fa9dbe7 100644
--- a/src/mongo/db/exec/eof.h
+++ b/src/mongo/db/exec/eof.h
@@ -46,7 +46,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/fetch.cpp b/src/mongo/db/exec/fetch.cpp
index 7efade26230..e13cf3857f7 100644
--- a/src/mongo/db/exec/fetch.cpp
+++ b/src/mongo/db/exec/fetch.cpp
@@ -116,9 +116,9 @@ namespace mongo {
_child->prepareToYield();
}
- void FetchStage::recoverFromYield() {
+ void FetchStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void FetchStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/fetch.h b/src/mongo/db/exec/fetch.h
index 7e4c807c1b5..7933fc583ab 100644
--- a/src/mongo/db/exec/fetch.h
+++ b/src/mongo/db/exec/fetch.h
@@ -56,7 +56,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/idhack.cpp b/src/mongo/db/exec/idhack.cpp
index 310d08f0a04..5d15b2d7418 100644
--- a/src/mongo/db/exec/idhack.cpp
+++ b/src/mongo/db/exec/idhack.cpp
@@ -32,6 +32,7 @@
#include "mongo/client/dbclientinterface.h"
#include "mongo/db/exec/projection.h"
+#include "mongo/db/exec/working_set_computed_data.h"
#include "mongo/db/index/btree_access_method.h"
#include "mongo/s/d_logic.h"
@@ -48,7 +49,14 @@ namespace mongo {
_key(query->getQueryObj()["_id"].wrap()),
_killed(false),
_done(false),
- _commonStats(kStageType) { }
+ _commonStats(kStageType) {
+ if (NULL != query->getProj()) {
+ _addKeyMetadata = query->getProj()->wantIndexKey();
+ }
+ else {
+ _addKeyMetadata = false;
+ }
+ }
IDHackStage::IDHackStage(OperationContext* txn, Collection* collection,
const BSONObj& key, WorkingSet* ws)
@@ -58,6 +66,7 @@ namespace mongo {
_key(key),
_killed(false),
_done(false),
+ _addKeyMetadata(false),
_commonStats(kStageType) { }
IDHackStage::~IDHackStage() { }
@@ -108,6 +117,13 @@ namespace mongo {
member->obj = _collection->docFor(loc);
member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ if (_addKeyMetadata) {
+ BSONObjBuilder bob;
+ BSONObj ownedKeyObj = member->obj["_id"].wrap().getOwned();
+ bob.appendKeys(_key, ownedKeyObj);
+ member->addComputed(new IndexKeyComputedData(bob.obj()));
+ }
+
_done = true;
++_commonStats.advanced;
*out = id;
@@ -118,7 +134,7 @@ namespace mongo {
++_commonStats.yields;
}
- void IDHackStage::recoverFromYield() {
+ void IDHackStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
}
diff --git a/src/mongo/db/exec/idhack.h b/src/mongo/db/exec/idhack.h
index b365374d893..a708a332c27 100644
--- a/src/mongo/db/exec/idhack.h
+++ b/src/mongo/db/exec/idhack.h
@@ -54,7 +54,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
/**
@@ -93,6 +93,9 @@ namespace mongo {
// Have we returned our one document?
bool _done;
+ // Do we need to add index key metadata for $returnKey?
+ bool _addKeyMetadata;
+
CommonStats _commonStats;
IDHackStats _specificStats;
};
diff --git a/src/mongo/db/exec/index_scan.cpp b/src/mongo/db/exec/index_scan.cpp
index 5e0bd22b899..0be67cda714 100644
--- a/src/mongo/db/exec/index_scan.cpp
+++ b/src/mongo/db/exec/index_scan.cpp
@@ -248,7 +248,7 @@ namespace mongo {
_indexCursor->savePosition();
}
- void IndexScan::recoverFromYield() {
+ void IndexScan::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
if (_hitEnd || (NULL == _indexCursor.get())) { return; }
diff --git a/src/mongo/db/exec/index_scan.h b/src/mongo/db/exec/index_scan.h
index 50e2336a9f9..40ad7a7315c 100644
--- a/src/mongo/db/exec/index_scan.h
+++ b/src/mongo/db/exec/index_scan.h
@@ -90,7 +90,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual bool isEOF();
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/keep_mutations.cpp b/src/mongo/db/exec/keep_mutations.cpp
index 7d452852317..af76962a383 100644
--- a/src/mongo/db/exec/keep_mutations.cpp
+++ b/src/mongo/db/exec/keep_mutations.cpp
@@ -108,9 +108,9 @@ namespace mongo {
_child->prepareToYield();
}
- void KeepMutationsStage::recoverFromYield() {
+ void KeepMutationsStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void KeepMutationsStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/keep_mutations.h b/src/mongo/db/exec/keep_mutations.h
index 1a41cef0fb1..fc3bfbd4323 100644
--- a/src/mongo/db/exec/keep_mutations.h
+++ b/src/mongo/db/exec/keep_mutations.h
@@ -52,7 +52,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/limit.cpp b/src/mongo/db/exec/limit.cpp
index bc2c24649c5..d13a378fcb3 100644
--- a/src/mongo/db/exec/limit.cpp
+++ b/src/mongo/db/exec/limit.cpp
@@ -88,9 +88,9 @@ namespace mongo {
_child->prepareToYield();
}
- void LimitStage::recoverFromYield() {
+ void LimitStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void LimitStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/limit.h b/src/mongo/db/exec/limit.h
index 9e1ffdc2e85..8a14d4ddea9 100644
--- a/src/mongo/db/exec/limit.h
+++ b/src/mongo/db/exec/limit.h
@@ -50,7 +50,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/merge_sort.cpp b/src/mongo/db/exec/merge_sort.cpp
index b40d2db66a3..c9f449caa53 100644
--- a/src/mongo/db/exec/merge_sort.cpp
+++ b/src/mongo/db/exec/merge_sort.cpp
@@ -189,10 +189,10 @@ namespace mongo {
}
}
- void MergeSortStage::recoverFromYield() {
+ void MergeSortStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->recoverFromYield();
+ _children[i]->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/merge_sort.h b/src/mongo/db/exec/merge_sort.h
index bc3852ab16c..1475f811793 100644
--- a/src/mongo/db/exec/merge_sort.h
+++ b/src/mongo/db/exec/merge_sort.h
@@ -66,7 +66,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/mock_stage.h b/src/mongo/db/exec/mock_stage.h
index c5241a669d3..4742cc3aa7a 100644
--- a/src/mongo/db/exec/mock_stage.h
+++ b/src/mongo/db/exec/mock_stage.h
@@ -59,7 +59,7 @@ namespace mongo {
// Some day we could count the # of calls to the yield functions to check that other stages
// have correct yielding behavior.
virtual void prepareToYield() { }
- virtual void recoverFromYield() { }
+ virtual void recoverFromYield(OperationContext* opCtx) { }
virtual void invalidate(const DiskLoc& dl, InvalidationType type) { }
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/multi_plan.cpp b/src/mongo/db/exec/multi_plan.cpp
index c3749acaa48..c2c394cc21c 100644
--- a/src/mongo/db/exec/multi_plan.cpp
+++ b/src/mongo/db/exec/multi_plan.cpp
@@ -418,7 +418,7 @@ namespace mongo {
}
}
- void MultiPlanStage::recoverFromYield() {
+ void MultiPlanStage::recoverFromYield(OperationContext* opCtx) {
if (_failure) return;
// this logic is from multi_plan_runner
@@ -426,13 +426,13 @@ namespace mongo {
// the _bestPlan if we've switched to the backup?
if (bestPlanChosen()) {
- _candidates[_bestPlanIdx].root->recoverFromYield();
+ _candidates[_bestPlanIdx].root->recoverFromYield(opCtx);
if (hasBackupPlan()) {
- _candidates[_backupPlanIdx].root->recoverFromYield();
+ _candidates[_backupPlanIdx].root->recoverFromYield(opCtx);
}
}
else {
- allPlansRestoreState();
+ allPlansRestoreState(opCtx);
}
}
@@ -506,9 +506,9 @@ namespace mongo {
}
}
- void MultiPlanStage::allPlansRestoreState() {
+ void MultiPlanStage::allPlansRestoreState(OperationContext* opCtx) {
for (size_t i = 0; i < _candidates.size(); ++i) {
- _candidates[i].root->recoverFromYield();
+ _candidates[i].root->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/multi_plan.h b/src/mongo/db/exec/multi_plan.h
index d709652f6ee..bb43873d843 100644
--- a/src/mongo/db/exec/multi_plan.h
+++ b/src/mongo/db/exec/multi_plan.h
@@ -64,7 +64,7 @@ namespace mongo {
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
@@ -140,7 +140,7 @@ namespace mongo {
void allPlansSaveState();
- void allPlansRestoreState();
+ void allPlansRestoreState(OperationContext* opCtx);
static const int kNoSuchPlan = -1;
diff --git a/src/mongo/db/exec/near.cpp b/src/mongo/db/exec/near.cpp
index 370f7a3d0d0..32cfa6e7464 100644
--- a/src/mongo/db/exec/near.cpp
+++ b/src/mongo/db/exec/near.cpp
@@ -288,10 +288,10 @@ namespace mongo {
}
}
- void NearStage::recoverFromYield() {
+ void NearStage::recoverFromYield(OperationContext* opCtx) {
++_stats->common.unyields;
if (_nextInterval) {
- _nextInterval->covering->recoverFromYield();
+ _nextInterval->covering->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/near.h b/src/mongo/db/exec/near.h
index 64cbfe2fd1c..681d86f32a4 100644
--- a/src/mongo/db/exec/near.h
+++ b/src/mongo/db/exec/near.h
@@ -90,7 +90,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/oplogstart.cpp b/src/mongo/db/exec/oplogstart.cpp
index 93d4028ed10..e7624b5668b 100644
--- a/src/mongo/db/exec/oplogstart.cpp
+++ b/src/mongo/db/exec/oplogstart.cpp
@@ -164,9 +164,9 @@ namespace mongo {
}
}
- void OplogStart::recoverFromYield() {
+ void OplogStart::recoverFromYield(OperationContext* opCtx) {
if (_cs) {
- _cs->recoverFromYield();
+ _cs->recoverFromYield(opCtx);
}
for (size_t i = 0; i < _subIterators.size(); i++) {
diff --git a/src/mongo/db/exec/oplogstart.h b/src/mongo/db/exec/oplogstart.h
index 3fc96ac9736..7b0b8d17ecf 100644
--- a/src/mongo/db/exec/oplogstart.h
+++ b/src/mongo/db/exec/oplogstart.h
@@ -71,7 +71,7 @@ namespace mongo {
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/or.cpp b/src/mongo/db/exec/or.cpp
index 2bd97c81389..c82e75a2237 100644
--- a/src/mongo/db/exec/or.cpp
+++ b/src/mongo/db/exec/or.cpp
@@ -144,10 +144,10 @@ namespace mongo {
}
}
- void OrStage::recoverFromYield() {
+ void OrStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->recoverFromYield();
+ _children[i]->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/or.h b/src/mongo/db/exec/or.h
index 53f928dc622..22ce3660dc0 100644
--- a/src/mongo/db/exec/or.h
+++ b/src/mongo/db/exec/or.h
@@ -55,7 +55,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/plan_stage.h b/src/mongo/db/exec/plan_stage.h
index 4187334eb87..4c8f27d3a08 100644
--- a/src/mongo/db/exec/plan_stage.h
+++ b/src/mongo/db/exec/plan_stage.h
@@ -36,6 +36,7 @@ namespace mongo {
class Collection;
class DiskLoc;
+ class OperationContext;
/**
* A PlanStage ("stage") is the basic building block of a "Query Execution Plan." A stage is
@@ -176,6 +177,8 @@ namespace mongo {
/**
* Notifies the stage that all locks are about to be released. The stage must save any
* state required to resume where it was before prepareToYield was called.
+ *
+ * XXX: rename to saveState()
*/
virtual void prepareToYield() = 0;
@@ -184,8 +187,13 @@ namespace mongo {
* any saved state and be ready to handle calls to work().
*
* Can only be called after prepareToYield.
+ *
+ * XXX: rename to restoreState()
+ *
+ * XXX: We may not need to pass down 'opCtx' if getMore'd queries use the same
+ * OperationContext they were created with.
*/
- virtual void recoverFromYield() = 0;
+ virtual void recoverFromYield(OperationContext* opCtx) = 0;
/**
* Notifies a stage that a DiskLoc is going to be deleted (or in-place updated) so that the
diff --git a/src/mongo/db/exec/projection.cpp b/src/mongo/db/exec/projection.cpp
index ecbb03704e2..b21bc14a985 100644
--- a/src/mongo/db/exec/projection.cpp
+++ b/src/mongo/db/exec/projection.cpp
@@ -240,9 +240,9 @@ namespace mongo {
_child->prepareToYield();
}
- void ProjectionStage::recoverFromYield() {
+ void ProjectionStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void ProjectionStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/projection.h b/src/mongo/db/exec/projection.h
index 1e79af2bf44..03bb1839102 100644
--- a/src/mongo/db/exec/projection.h
+++ b/src/mongo/db/exec/projection.h
@@ -84,7 +84,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/shard_filter.cpp b/src/mongo/db/exec/shard_filter.cpp
index b427a1d6373..831421aacd2 100644
--- a/src/mongo/db/exec/shard_filter.cpp
+++ b/src/mongo/db/exec/shard_filter.cpp
@@ -89,9 +89,9 @@ namespace mongo {
_child->prepareToYield();
}
- void ShardFilterStage::recoverFromYield() {
+ void ShardFilterStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void ShardFilterStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/shard_filter.h b/src/mongo/db/exec/shard_filter.h
index 31f23bee535..f2374b5ddd7 100644
--- a/src/mongo/db/exec/shard_filter.h
+++ b/src/mongo/db/exec/shard_filter.h
@@ -81,7 +81,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/skip.cpp b/src/mongo/db/exec/skip.cpp
index d03d39d9f06..e7e7b1710d1 100644
--- a/src/mongo/db/exec/skip.cpp
+++ b/src/mongo/db/exec/skip.cpp
@@ -92,9 +92,9 @@ namespace mongo {
_child->prepareToYield();
}
- void SkipStage::recoverFromYield() {
+ void SkipStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void SkipStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/skip.h b/src/mongo/db/exec/skip.h
index 6ce6ce03ca8..fc8814e2699 100644
--- a/src/mongo/db/exec/skip.h
+++ b/src/mongo/db/exec/skip.h
@@ -49,7 +49,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/sort.cpp b/src/mongo/db/exec/sort.cpp
index d7075cfd09a..2816b9e4815 100644
--- a/src/mongo/db/exec/sort.cpp
+++ b/src/mongo/db/exec/sort.cpp
@@ -420,9 +420,9 @@ namespace mongo {
_child->prepareToYield();
}
- void SortStage::recoverFromYield() {
+ void SortStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
void SortStage::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/exec/sort.h b/src/mongo/db/exec/sort.h
index efd0f2fcccc..119f4f59019 100644
--- a/src/mongo/db/exec/sort.h
+++ b/src/mongo/db/exec/sort.h
@@ -150,7 +150,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp
index 4019aae418b..7d2ca07d682 100644
--- a/src/mongo/db/exec/subplan.cpp
+++ b/src/mongo/db/exec/subplan.cpp
@@ -395,7 +395,16 @@ namespace mongo {
if (isEOF()) { return PlanStage::IS_EOF; }
invariant(_child.get());
- return _child->work(out);
+ StageState state = _child->work(out);
+
+ if (PlanStage::NEED_TIME == state) {
+ ++_commonStats.needTime;
+ }
+ else if (PlanStage::ADVANCED == state) {
+ ++_commonStats.advanced;
+ }
+
+ return state;
}
void SubplanStage::prepareToYield() {
@@ -411,7 +420,7 @@ namespace mongo {
}
}
- void SubplanStage::recoverFromYield() {
+ void SubplanStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
if (_killed) {
return;
@@ -420,7 +429,7 @@ namespace mongo {
// We're ranking a sub-plan via an MPR or we're streaming results from this stage. Either
// way, pass on the request.
if (NULL != _child.get()) {
- _child->recoverFromYield();
+ _child->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/subplan.h b/src/mongo/db/exec/subplan.h
index 5655e429901..3ff3da921c4 100644
--- a/src/mongo/db/exec/subplan.h
+++ b/src/mongo/db/exec/subplan.h
@@ -72,7 +72,7 @@ namespace mongo {
virtual StageState work(WorkingSetID* out);
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/exec/text.cpp b/src/mongo/db/exec/text.cpp
index 3d1cb7560a5..17fa93eff68 100644
--- a/src/mongo/db/exec/text.cpp
+++ b/src/mongo/db/exec/text.cpp
@@ -112,11 +112,11 @@ namespace mongo {
}
}
- void TextStage::recoverFromYield() {
+ void TextStage::recoverFromYield(OperationContext* opCtx) {
++_commonStats.unyields;
for (size_t i = 0; i < _scanners.size(); ++i) {
- _scanners.mutableVector()[i]->recoverFromYield();
+ _scanners.mutableVector()[i]->recoverFromYield(opCtx);
}
}
diff --git a/src/mongo/db/exec/text.h b/src/mongo/db/exec/text.h
index ffaaa7b2971..288c6e3d23d 100644
--- a/src/mongo/db/exec/text.h
+++ b/src/mongo/db/exec/text.h
@@ -106,7 +106,7 @@ namespace mongo {
virtual bool isEOF();
virtual void prepareToYield();
- virtual void recoverFromYield();
+ virtual void recoverFromYield(OperationContext* opCtx);
virtual void invalidate(const DiskLoc& dl, InvalidationType type);
virtual std::vector<PlanStage*> getChildren() const;
diff --git a/src/mongo/db/fts/fts_command_mongod.cpp b/src/mongo/db/fts/fts_command_mongod.cpp
index bebfa07cdfc..146d0159faf 100644
--- a/src/mongo/db/fts/fts_command_mongod.cpp
+++ b/src/mongo/db/fts/fts_command_mongod.cpp
@@ -36,8 +36,8 @@
#include "mongo/db/catalog/database.h"
#include "mongo/db/fts/fts_command.h"
#include "mongo/db/fts/fts_util.h"
-#include "mongo/db/query/get_runner.h"
-#include "mongo/db/query/type_explain.h"
+#include "mongo/db/query/get_executor.h"
+#include "mongo/db/query/explain.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/timer.h"
@@ -112,14 +112,15 @@ namespace mongo {
return false;
}
- Runner* rawRunner;
- Status getRunnerStatus = getRunner(txn, ctx.ctx().db()->getCollection(txn, ns), cq, &rawRunner);
- if (!getRunnerStatus.isOK()) {
- errmsg = getRunnerStatus.reason();
+ PlanExecutor* rawExec;
+ Status getExecStatus = getExecutor(
+ txn, ctx.ctx().db()->getCollection(txn, ns), cq, &rawExec);
+ if (!getExecStatus.isOK()) {
+ errmsg = getExecStatus.reason();
return false;
}
- auto_ptr<Runner> runner(rawRunner);
+ auto_ptr<PlanExecutor> exec(rawExec);
BSONArrayBuilder resultBuilder(result.subarrayStart("results"));
@@ -129,7 +130,7 @@ namespace mongo {
int numReturned = 0;
BSONObj obj;
- while (Runner::RUNNER_ADVANCED == runner->getNext(&obj, NULL)) {
+ while (Runner::RUNNER_ADVANCED == exec->getNext(&obj, NULL)) {
if ((resultSize + obj.objsize()) >= BSONObjMaxUserSize) {
break;
}
@@ -158,13 +159,10 @@ namespace mongo {
BSONObjBuilder stats(result.subobjStart("stats"));
// Fill in nscanned from the explain.
- TypeExplain* bareExplain;
- Status res = runner->getInfo(&bareExplain, NULL);
- if (res.isOK()) {
- auto_ptr<TypeExplain> explain(bareExplain);
- stats.append("nscanned", explain->getNScanned());
- stats.append("nscannedObjects", explain->getNScannedObjects());
- }
+ PlanSummaryStats summary;
+ Explain::getSummaryStats(exec.get(), &summary);
+ stats.appendNumber("nscanned", summary.totalKeysExamined);
+ stats.appendNumber("nscannedObjects", summary.totalDocsExamined);
stats.appendNumber( "n" , numReturned );
stats.append( "timeMicros", (int)comm.micros() );
diff --git a/src/mongo/db/index/haystack_access_method.cpp b/src/mongo/db/index/haystack_access_method.cpp
index f849e708d5b..8d2e72a474f 100644
--- a/src/mongo/db/index/haystack_access_method.cpp
+++ b/src/mongo/db/index/haystack_access_method.cpp
@@ -100,11 +100,11 @@ namespace mongo {
unordered_set<DiskLoc, DiskLoc::Hasher> thisPass;
- scoped_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection,
+ scoped_ptr<PlanExecutor> exec(InternalPlanner::indexScan(txn, collection,
_descriptor, key, key, true));
Runner::RunnerState state;
DiskLoc loc;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, &loc))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(NULL, &loc))) {
if (hopper.limitReached()) { break; }
pair<unordered_set<DiskLoc, DiskLoc::Hasher>::iterator, bool> p
= thisPass.insert(loc);
diff --git a/src/mongo/db/ops/delete_executor.cpp b/src/mongo/db/ops/delete_executor.cpp
index d2c36f3ba3c..17b2123c8f1 100644
--- a/src/mongo/db/ops/delete_executor.cpp
+++ b/src/mongo/db/ops/delete_executor.cpp
@@ -36,7 +36,7 @@
#include "mongo/db/curop.h"
#include "mongo/db/ops/delete_request.h"
#include "mongo/db/query/canonical_query.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/lite_parsed_query.h"
#include "mongo/db/query/query_planner_common.h"
#include "mongo/db/repl/repl_coordinator_global.h"
@@ -117,31 +117,31 @@ namespace mongo {
long long nDeleted = 0;
- Runner* rawRunner;
+ PlanExecutor* rawExec;
if (_canonicalQuery.get()) {
- uassertStatusOK(getRunner(_request->getOpCtx(),
- collection,
- _canonicalQuery.release(),
- &rawRunner));
+ uassertStatusOK(getExecutor(_request->getOpCtx(),
+ collection,
+ _canonicalQuery.release(),
+ &rawExec));
}
else {
- CanonicalQuery* ignored;
- uassertStatusOK(getRunner(_request->getOpCtx(),
- collection,
- ns.ns(),
- _request->getQuery(),
- &rawRunner,
- &ignored));
+ uassertStatusOK(getExecutor(_request->getOpCtx(),
+ collection,
+ ns.ns(),
+ _request->getQuery(),
+ &rawExec));
}
- auto_ptr<Runner> runner(rawRunner);
- ScopedRunnerRegistration safety(runner.get());
+ auto_ptr<PlanExecutor> exec(rawExec);
+
+ // Concurrently mutating state (by us) so we need to register 'exec'.
+ ScopedExecutorRegistration safety(exec.get());
DiskLoc rloc;
Runner::RunnerState state;
CurOp* curOp = _request->getOpCtx()->getCurOp();
int oldYieldCount = curOp->numYields();
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, &rloc))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(NULL, &rloc))) {
if (oldYieldCount != curOp->numYields()) {
uassert(ErrorCodes::NotMaster,
str::stream() << "No longer primary while removing from " << ns.ns(),
@@ -154,10 +154,10 @@ namespace mongo {
// TODO: do we want to buffer docs and delete them in a group rather than
// saving/restoring state repeatedly?
- runner->saveState();
+ exec->saveState();
collection->deleteDocument(
_request->getOpCtx(), rloc, false, false, logop ? &toDelete : NULL);
- runner->restoreState(_request->getOpCtx());
+ exec->restoreState(_request->getOpCtx());
nDeleted++;
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index f872f39a97d..4ca1367465c 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -466,6 +466,9 @@ namespace mongo {
// Create the plan executor and setup all deps.
auto_ptr<PlanExecutor> exec(rawExec);
+ // Register executor with the collection cursor cache.
+ const ScopedExecutorRegistration safety(exec.get());
+
// Get the canonical query which the underlying executor is using. This may be NULL in
// the case of idhack updates.
cq = exec->getCanonicalQuery();
@@ -667,7 +670,7 @@ namespace mongo {
// Restore state after modification
uassert(17278,
"Update could not restore plan executor state after updating a document.",
- exec->restoreState());
+ exec->restoreState(request.getOpCtx()));
// Call logOp if requested.
if (request.shouldCallLogOp() && !logObj.isEmpty()) {
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h
index ca3e93a9ce4..5c34eae6fd5 100644
--- a/src/mongo/db/pipeline/document_source.h
+++ b/src/mongo/db/pipeline/document_source.h
@@ -55,7 +55,7 @@ namespace mongo {
class ExpressionFieldPath;
class ExpressionObject;
class DocumentSourceLimit;
- class Runner;
+ class PlanExecutor;
class DocumentSource : public IntrusiveCounterUnsigned {
public:
@@ -334,7 +334,9 @@ namespace mongo {
/**
- * Constructs and returns Documents from the BSONObj objects produced by a supplied Runner.
+ * Constructs and returns Documents from the BSONObj objects produced by a supplied
+ * PlanExecutor.
+ *
* An object of this type may only be used by one thread, see SERVER-6123.
*/
class DocumentSourceCursor :
@@ -351,14 +353,14 @@ namespace mongo {
virtual void dispose();
/**
- * Create a document source based on a passed-in Runner.
+ * Create a document source based on a passed-in PlanExecutor.
*
* This is usually put at the beginning of a chain of document sources
* in order to fetch data from the database.
*/
static intrusive_ptr<DocumentSourceCursor> create(
const std::string& ns,
- const boost::shared_ptr<Runner>& runner,
+ const boost::shared_ptr<PlanExecutor>& exec,
const intrusive_ptr<ExpressionContext> &pExpCtx);
/*
@@ -402,7 +404,7 @@ namespace mongo {
private:
DocumentSourceCursor(
const std::string& ns,
- const boost::shared_ptr<Runner>& runner,
+ const boost::shared_ptr<PlanExecutor>& exec,
const intrusive_ptr<ExpressionContext> &pExpCtx);
void loadBatch();
@@ -418,7 +420,7 @@ namespace mongo {
long long _docsAddedToBatches; // for _limit enforcement
const std::string _ns;
- boost::shared_ptr<Runner> _runner; // PipelineRunner holds a weak_ptr to this.
+ boost::shared_ptr<PlanExecutor> _exec; // PipelineRunner holds a weak_ptr to this.
};
diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp
index 6c4d8c5d6c0..b037e9b7f06 100644
--- a/src/mongo/db/pipeline/document_source_cursor.cpp
+++ b/src/mongo/db/pipeline/document_source_cursor.cpp
@@ -33,6 +33,7 @@
#include "mongo/db/exec/working_set_common.h"
#include "mongo/db/instance.h"
#include "mongo/db/pipeline/document.h"
+#include "mongo/db/query/explain.h"
#include "mongo/db/query/find_constants.h"
#include "mongo/db/query/type_explain.h"
#include "mongo/db/storage_options.h"
@@ -65,29 +66,29 @@ namespace mongo {
}
void DocumentSourceCursor::dispose() {
- // Can't call in to Runner or ClientCursor registries from this function since it will be
- // called when an agg cursor is killed which would cause a deadlock.
- _runner.reset();
+ // Can't call in to PlanExecutor or ClientCursor registries from this function since it
+ // will be called when an agg cursor is killed which would cause a deadlock.
+ _exec.reset();
_currentBatch.clear();
}
void DocumentSourceCursor::loadBatch() {
- if (!_runner) {
+ if (!_exec) {
dispose();
return;
}
- // We have already validated the sharding version when we constructed the Runner
+ // We have already validated the sharding version when we constructed the PlanExecutor
// so we shouldn't check it again.
Lock::DBRead lk(pExpCtx->opCtx->lockState(), _ns);
Client::Context ctx(pExpCtx->opCtx, _ns, /*doVersion=*/false);
- _runner->restoreState(pExpCtx->opCtx);
+ _exec->restoreState(pExpCtx->opCtx);
int memUsageBytes = 0;
BSONObj obj;
Runner::RunnerState state;
- while ((state = _runner->getNext(&obj, NULL)) == Runner::RUNNER_ADVANCED) {
+ while ((state = _exec->getNext(&obj, NULL)) == Runner::RUNNER_ADVANCED) {
if (_dependencies) {
_currentBatch.push_back(_dependencies->extractFields(obj));
}
@@ -105,15 +106,15 @@ namespace mongo {
memUsageBytes += _currentBatch.back().getApproximateSize();
if (memUsageBytes > MaxBytesToReturnToClientAtOnce) {
- // End this batch and prepare Runner for yielding.
- _runner->saveState();
+ // End this batch and prepare PlanExecutor for yielding.
+ _exec->saveState();
return;
}
}
- // If we got here, there won't be any more documents, so destroy the runner. Can't use
+ // If we got here, there won't be any more documents, so destroy the executor. Can't use
// dispose since we want to keep the _currentBatch.
- _runner.reset();
+ _exec.reset();
uassert(16028, "collection or index disappeared when cursor yielded",
state != Runner::RUNNER_DEAD);
@@ -121,7 +122,7 @@ namespace mongo {
uassert(17285, "cursor encountered an error: " + WorkingSetCommon::toStatusString(obj),
state != Runner::RUNNER_ERROR);
- massert(17286, str::stream() << "Unexpected return from Runner::getNext: " << state,
+ massert(17286, str::stream() << "Unexpected return from PlanExecutor::getNext: " << state,
state == Runner::RUNNER_EOF || state == Runner::RUNNER_ADVANCED);
}
@@ -202,17 +203,17 @@ namespace {
Lock::DBRead lk(pExpCtx->opCtx->lockState(), _ns);
Client::Context ctx(pExpCtx->opCtx, _ns, /*doVersion=*/ false);
- massert(17392, "No _runner. Were we disposed before explained?",
- _runner);
+ massert(17392, "No _exec. Were we disposed before explained?",
+ _exec);
- _runner->restoreState(pExpCtx->opCtx);
+ _exec->restoreState(pExpCtx->opCtx);
TypeExplain* explainRaw;
- explainStatus = _runner->getInfo(&explainRaw, NULL);
+ explainStatus = Explain::legacyExplain(_exec.get(), &explainRaw);
if (explainStatus.isOK())
plan.reset(explainRaw);
- _runner->saveState();
+ _exec->saveState();
}
MutableDocument out;
@@ -237,19 +238,19 @@ namespace {
}
DocumentSourceCursor::DocumentSourceCursor(const string& ns,
- const boost::shared_ptr<Runner>& runner,
+ const boost::shared_ptr<PlanExecutor>& exec,
const intrusive_ptr<ExpressionContext> &pCtx)
: DocumentSource(pCtx)
, _docsAddedToBatches(0)
, _ns(ns)
- , _runner(runner)
+ , _exec(exec)
{}
intrusive_ptr<DocumentSourceCursor> DocumentSourceCursor::create(
const string& ns,
- const boost::shared_ptr<Runner>& runner,
+ const boost::shared_ptr<PlanExecutor>& exec,
const intrusive_ptr<ExpressionContext> &pExpCtx) {
- return new DocumentSourceCursor(ns, runner, pExpCtx);
+ return new DocumentSourceCursor(ns, exec, pExpCtx);
}
void DocumentSourceCursor::setProjection(
diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp
index 9259a2a8072..27dd0bb38c0 100644
--- a/src/mongo/db/pipeline/pipeline_d.cpp
+++ b/src/mongo/db/pipeline/pipeline_d.cpp
@@ -36,7 +36,7 @@
#include "mongo/db/instance.h"
#include "mongo/db/pipeline/document_source.h"
#include "mongo/db/pipeline/pipeline.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/query_planner.h"
#include "mongo/s/d_logic.h"
@@ -74,7 +74,7 @@ namespace {
};
}
- boost::shared_ptr<Runner> PipelineD::prepareCursorSource(
+ boost::shared_ptr<PlanExecutor> PipelineD::prepareCursorSource(
OperationContext* txn,
Collection* collection,
const intrusive_ptr<Pipeline>& pPipeline,
@@ -104,7 +104,7 @@ namespace {
// on secondaries, this is needed.
ShardedConnectionInfo::addHook();
}
- return boost::shared_ptr<Runner>(); // don't need a cursor
+ return boost::shared_ptr<PlanExecutor>(); // don't need a cursor
}
@@ -142,19 +142,19 @@ namespace {
}
}
- // Create the Runner.
+ // Create the PlanExecutor.
//
- // If we try to create a Runner that includes both the match and the
+ // If we try to create a PlanExecutor that includes both the match and the
// sort, and the two are incompatible wrt the available indexes, then
- // we don't get a Runner back.
+ // we don't get a PlanExecutor back.
//
// So we try to use both first. If that fails, try again, without the
// sort.
//
- // If we don't have a sort, jump straight to just creating a Runner
+ // If we don't have a sort, jump straight to just creating a PlanExecutor.
// without the sort.
//
- // If we are able to incorporate the sort into the Runner, remove it
+ // If we are able to incorporate the sort into the PlanExecutor, remove it
// from the head of the pipeline.
//
// LATER - we should be able to find this out before we create the
@@ -164,7 +164,7 @@ namespace {
| QueryPlannerParams::INCLUDE_SHARD_FILTER
| QueryPlannerParams::NO_BLOCKING_SORT
;
- boost::shared_ptr<Runner> runner;
+ boost::shared_ptr<PlanExecutor> exec;
bool sortInRunner = false;
const WhereCallbackReal whereCallback(pExpCtx->opCtx, pExpCtx->ns.db());
@@ -178,10 +178,10 @@ namespace {
projectionForQuery,
&cq,
whereCallback);
- Runner* rawRunner;
- if (status.isOK() && getRunner(txn, collection, cq, &rawRunner, runnerOptions).isOK()) {
- // success: The Runner will handle sorting for us using an index.
- runner.reset(rawRunner);
+ PlanExecutor* rawExec;
+ if (status.isOK() && getExecutor(txn, collection, cq, &rawExec, runnerOptions).isOK()) {
+ // success: The PlanExecutor will handle sorting for us using an index.
+ exec.reset(rawExec);
sortInRunner = true;
sources.pop_front();
@@ -192,7 +192,7 @@ namespace {
}
}
- if (!runner.get()) {
+ if (!exec.get()) {
const BSONObj noSort;
CanonicalQuery* cq;
uassertStatusOK(
@@ -203,18 +203,18 @@ namespace {
&cq,
whereCallback));
- Runner* rawRunner;
- uassertStatusOK(getRunner(txn, collection, cq, &rawRunner, runnerOptions));
- runner.reset(rawRunner);
+ PlanExecutor* rawExec;
+ uassertStatusOK(getExecutor(txn, collection, cq, &rawExec, runnerOptions));
+ exec.reset(rawExec);
}
- // DocumentSourceCursor expects a yielding Runner that has had its state saved.
- runner->saveState();
+ // DocumentSourceCursor expects a yielding PlanExecutor that has had its state saved.
+ exec->saveState();
- // Put the Runner into a DocumentSourceCursor and add it to the front of the pipeline.
+ // Put the PlanExecutor into a DocumentSourceCursor and add it to the front of the pipeline.
intrusive_ptr<DocumentSourceCursor> pSource =
- DocumentSourceCursor::create(fullName, runner, pExpCtx);
+ DocumentSourceCursor::create(fullName, exec, pExpCtx);
// Note the query, sort, and projection for explain.
pSource->setQuery(queryObj);
@@ -229,7 +229,7 @@ namespace {
pPipeline->addInitialSource(pSource);
- return runner;
+ return exec;
}
} // namespace mongo
diff --git a/src/mongo/db/pipeline/pipeline_d.h b/src/mongo/db/pipeline/pipeline_d.h
index b9d85a69dbb..1147755f5b6 100644
--- a/src/mongo/db/pipeline/pipeline_d.h
+++ b/src/mongo/db/pipeline/pipeline_d.h
@@ -36,7 +36,7 @@ namespace mongo {
struct ExpressionContext;
class OperationContext;
class Pipeline;
- class Runner;
+ class PlanExecutor;
/*
PipelineD is an extension of the Pipeline class, but with additional
@@ -65,13 +65,13 @@ namespace mongo {
*
* Must have a ReadContext before entering.
*
- * If the returned Runner is non-null, you are responsible for ensuring
+ * If the returned PlanExecutor is non-null, you are responsible for ensuring
* it receives appropriate invalidate and kill messages.
*
* @param pPipeline the logical "this" for this operation
* @param pExpCtx the expression context for this pipeline
*/
- static boost::shared_ptr<Runner> prepareCursorSource(
+ static boost::shared_ptr<PlanExecutor> prepareCursorSource(
OperationContext* txn,
Collection* collection,
const intrusive_ptr<Pipeline> &pPipeline,
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 510a86fe1c6..f1c8859ec18 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -37,7 +37,6 @@ env.Library(
"get_executor.cpp",
"get_runner.cpp",
"idhack_runner.cpp",
- "internal_runner.cpp",
"new_find.cpp",
"plan_executor.cpp",
"plan_ranker.cpp",
diff --git a/src/mongo/db/query/eof_runner.cpp b/src/mongo/db/query/eof_runner.cpp
index 1438ccd5b6b..e56d380d791 100644
--- a/src/mongo/db/query/eof_runner.cpp
+++ b/src/mongo/db/query/eof_runner.cpp
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#include "mongo/db/query/eof_runner.h"
#include "mongo/db/diskloc.h"
diff --git a/src/mongo/db/query/eof_runner.h b/src/mongo/db/query/eof_runner.h
index 983c4b206a7..a24d83fbbda 100644
--- a/src/mongo/db/query/eof_runner.h
+++ b/src/mongo/db/query/eof_runner.h
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#pragma once
#include <boost/scoped_ptr.hpp>
diff --git a/src/mongo/db/query/explain.cpp b/src/mongo/db/query/explain.cpp
index 98c2d40fe69..b2021abde91 100644
--- a/src/mongo/db/query/explain.cpp
+++ b/src/mongo/db/query/explain.cpp
@@ -31,6 +31,7 @@
#include "mongo/db/query/explain.h"
#include "mongo/db/exec/multi_plan.h"
+#include "mongo/db/query/explain_plan.h"
#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/plan_executor.h"
#include "mongo/db/query/query_planner.h"
@@ -114,6 +115,10 @@ namespace {
const CountStats* spec = static_cast<const CountStats*>(specific);
return spec->keysExamined;
}
+ else if (STAGE_DISTINCT == type) {
+ const DistinctScanStats* spec = static_cast<const DistinctScanStats*>(specific);
+ return spec->keysExamined;
+ }
return 0;
}
@@ -368,7 +373,7 @@ namespace mongo {
size_t totalKeysExamined = 0;
size_t totalDocsExamined = 0;
for (size_t i = 0; i < statsNodes.size(); ++i) {
-
+
totalKeysExamined += getKeysExamined(statsNodes[i]->stageType,
statsNodes[i]->specific.get());
totalDocsExamined += getDocsExamined(statsNodes[i]->stageType,
@@ -546,4 +551,89 @@ namespace mongo {
statsOut->summaryStr = ss;
}
+ // TODO: This is temporary and should get deleted. There are a few small ways in which
+ // this differs from 2.6 explain, but I'm not too worried because this entire format is
+ // going away soon:
+ // 1) 'indexBounds' field excluded from idhack explain.
+ // 2) 'filterSet' field (for index filters) excluded.
+ Status Explain::legacyExplain(PlanExecutor* exec, TypeExplain** explain) {
+ invariant(exec);
+ invariant(explain);
+
+ scoped_ptr<PlanStageStats> stats(exec->getStats());
+ if (NULL == stats.get()) {
+ return Status(ErrorCodes::InternalError, "no stats available to explain plan");
+ }
+
+ // Special explain format for EOF.
+ if (STAGE_EOF == stats->stageType) {
+ *explain = new TypeExplain();
+
+ // Fill in mandatory fields.
+ (*explain)->setN(0);
+ (*explain)->setNScannedObjects(0);
+ (*explain)->setNScanned(0);
+
+ // Fill in all the main fields that don't have a default in the explain data structure.
+ (*explain)->setCursor("BasicCursor");
+ (*explain)->setScanAndOrder(false);
+ (*explain)->setIsMultiKey(false);
+ (*explain)->setIndexOnly(false);
+ (*explain)->setNYields(0);
+ (*explain)->setNChunkSkips(0);
+
+ TypeExplain* allPlans = new TypeExplain;
+ allPlans->setCursor("BasicCursor");
+ (*explain)->addToAllPlans(allPlans); // ownership xfer
+
+ (*explain)->setNScannedObjectsAllPlans(0);
+ (*explain)->setNScannedAllPlans(0);
+
+ return Status::OK();
+ }
+
+ // Special explain format for idhack.
+ vector<PlanStageStats*> statNodes;
+ flattenStatsTree(stats.get(), &statNodes);
+ PlanStageStats* idhack = NULL;
+ for (size_t i = 0; i < statNodes.size(); i++) {
+ if (STAGE_IDHACK == statNodes[i]->stageType) {
+ idhack = statNodes[i];
+ break;
+ }
+ }
+
+ if (NULL != idhack) {
+ // Explain format does not match 2.4 and is intended
+ // to indicate clearly that the ID hack has been applied.
+ *explain = new TypeExplain();
+
+ IDHackStats* idhackStats = static_cast<IDHackStats*>(idhack->specific.get());
+
+ (*explain)->setCursor("IDCursor");
+ (*explain)->setIDHack(true);
+ (*explain)->setN(stats->common.advanced);
+ (*explain)->setNScanned(idhackStats->keysExamined);
+ (*explain)->setNScannedObjects(idhackStats->docsExamined);
+
+ return Status::OK();
+ }
+
+ Status status = explainPlan(*stats, explain, true /* full details */);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ // Fill in explain fields that are accounted by on the runner level.
+ TypeExplain* chosenPlan = NULL;
+ explainPlan(*stats, &chosenPlan, false /* no full details */);
+ if (chosenPlan) {
+ (*explain)->addToAllPlans(chosenPlan);
+ }
+ (*explain)->setNScannedObjectsAllPlans((*explain)->getNScannedObjects());
+ (*explain)->setNScannedAllPlans((*explain)->getNScanned());
+
+ return Status::OK();
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/query/explain.h b/src/mongo/db/query/explain.h
index ea57c48eef3..da9d3daff21 100644
--- a/src/mongo/db/query/explain.h
+++ b/src/mongo/db/query/explain.h
@@ -34,6 +34,7 @@
#include "mongo/db/query/plan_executor.h"
#include "mongo/db/query/query_planner_params.h"
#include "mongo/db/query/query_solution.h"
+#include "mongo/db/query/type_explain.h"
namespace mongo {
@@ -146,6 +147,16 @@ namespace mongo {
*/
static void explainCountEmptyQuery(BSONObjBuilder* out);
+ /**
+ * Generate the legacy explain format from a PlanExecutor.
+ *
+ * On success, the caller owns 'explain'.
+ *
+ * TODO: THIS IS TEMPORARY. Once the legacy explain code is deleted, we won't
+ * need this anymore.
+ */
+ static Status legacyExplain(PlanExecutor* exec, TypeExplain** explain);
+
private:
/**
* Converts the stats tree 'stats' into a corresponding BSON object containing
diff --git a/src/mongo/db/query/explain_plan.cpp b/src/mongo/db/query/explain_plan.cpp
index ccc662e0c7e..db9f7b82f40 100644
--- a/src/mongo/db/query/explain_plan.cpp
+++ b/src/mongo/db/query/explain_plan.cpp
@@ -436,7 +436,7 @@ namespace mongo {
}
// Common details.
- bob->append("type", stageTypeString(stats.stageType));
+ bob->append("type", stats.common.stageTypeStr);
bob->appendNumber("works", stats.common.works);
bob->appendNumber("yields", stats.common.yields);
bob->appendNumber("unyields", stats.common.unyields);
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 4b56863eeaa..6a3a5bfffde 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -93,7 +93,7 @@ namespace mongo {
}
namespace {
- // The body is below in the "count hack" section but getRunner calls it.
+ // The body is below in the "count hack" section but getExecutor calls it.
bool turnIxscanIntoCount(QuerySolution* soln);
} // namespace
@@ -174,7 +174,7 @@ namespace mongo {
<< " Using EOF stage: " << unparsedQuery.toString();
EOFStage* eofStage = new EOFStage();
WorkingSet* ws = new WorkingSet();
- *out = new PlanExecutor(ws, eofStage, collection);
+ *out = new PlanExecutor(ws, eofStage, ns);
return Status::OK();
}
diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h
index a1abfaaf4e0..f5ae4a4ef97 100644
--- a/src/mongo/db/query/get_executor.h
+++ b/src/mongo/db/query/get_executor.h
@@ -39,7 +39,7 @@ namespace mongo {
/**
* Filter indexes retrieved from index catalog by
* allowed indices in query settings.
- * Used by getRunner().
+ * Used by getExecutor().
* This function is public to facilitate testing.
*/
void filterAllowedIndexEntries(const AllowedIndices& allowedIndices,
diff --git a/src/mongo/db/query/get_runner.cpp b/src/mongo/db/query/get_runner.cpp
index e93d670a898..dcaca93dc7d 100644
--- a/src/mongo/db/query/get_runner.cpp
+++ b/src/mongo/db/query/get_runner.cpp
@@ -685,16 +685,4 @@ namespace mongo {
return getRunner(txn, collection, cq, out);
}
- ScopedRunnerRegistration::ScopedRunnerRegistration(Runner* runner)
- : _runner(runner) {
- // Collection can be null for EOFRunner, or other places where registration is not needed
- if ( _runner->collection() )
- _runner->collection()->cursorCache()->registerRunner( runner );
- }
-
- ScopedRunnerRegistration::~ScopedRunnerRegistration() {
- if ( _runner->collection() )
- _runner->collection()->cursorCache()->deregisterRunner( _runner );
- }
-
} // namespace mongo
diff --git a/src/mongo/db/query/get_runner.h b/src/mongo/db/query/get_runner.h
index 2d9dd75c88e..4740e2d65ef 100644
--- a/src/mongo/db/query/get_runner.h
+++ b/src/mongo/db/query/get_runner.h
@@ -107,22 +107,4 @@ namespace mongo {
const QueryPlannerParams& plannerParams,
Runner** out);
- /**
- * RAII approach to ensuring that runners are deregistered in newRunQuery.
- *
- * While retrieving the first batch of results, newRunQuery manually registers the runner with
- * ClientCursor. Certain query execution paths, namely $where, can throw an exception. If we
- * fail to deregister the runner, we will call invalidate/kill on the
- * still-registered-yet-deleted runner.
- *
- * For any subsequent calls to getMore, the runner is already registered with ClientCursor
- * by virtue of being cached, so this exception-proofing is not required.
- */
- struct ScopedRunnerRegistration {
- ScopedRunnerRegistration(Runner* runner);
- ~ScopedRunnerRegistration();
-
- Runner* const _runner;
- };
-
} // namespace mongo
diff --git a/src/mongo/db/query/idhack_runner.cpp b/src/mongo/db/query/idhack_runner.cpp
index cf8f8dc78f5..814cc1bf9c8 100644
--- a/src/mongo/db/query/idhack_runner.cpp
+++ b/src/mongo/db/query/idhack_runner.cpp
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#include "mongo/db/query/idhack_runner.h"
#include "mongo/client/dbclientinterface.h"
diff --git a/src/mongo/db/query/idhack_runner.h b/src/mongo/db/query/idhack_runner.h
index a6747a6d83b..3024bc6b2b7 100644
--- a/src/mongo/db/query/idhack_runner.h
+++ b/src/mongo/db/query/idhack_runner.h
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#pragma once
#include <boost/scoped_ptr.hpp>
diff --git a/src/mongo/db/query/internal_plans.h b/src/mongo/db/query/internal_plans.h
index dae7af1c521..9cfff406b8f 100644
--- a/src/mongo/db/query/internal_plans.h
+++ b/src/mongo/db/query/internal_plans.h
@@ -31,10 +31,10 @@
#include "mongo/db/catalog/database.h"
#include "mongo/db/client.h"
#include "mongo/db/exec/collection_scan.h"
+#include "mongo/db/exec/eof.h"
#include "mongo/db/exec/fetch.h"
#include "mongo/db/exec/index_scan.h"
-#include "mongo/db/query/eof_runner.h"
-#include "mongo/db/query/internal_runner.h"
+#include "mongo/db/query/plan_executor.h"
namespace mongo {
@@ -64,13 +64,16 @@ namespace mongo {
/**
* Return a collection scan. Caller owns pointer.
*/
- static Runner* collectionScan(OperationContext* txn,
- const StringData& ns,
- Collection* collection,
- const Direction direction = FORWARD,
- const DiskLoc startLoc = DiskLoc()) {
+ static PlanExecutor* collectionScan(OperationContext* txn,
+ const StringData& ns,
+ Collection* collection,
+ const Direction direction = FORWARD,
+ const DiskLoc startLoc = DiskLoc()) {
+ WorkingSet* ws = new WorkingSet();
+
if (NULL == collection) {
- return new EOFRunner(NULL, ns.toString());
+ EOFStage* eof = new EOFStage();
+ return new PlanExecutor(ws, eof, ns.toString());
}
dassert( ns == collection->ns().ns() );
@@ -86,20 +89,22 @@ namespace mongo {
params.direction = CollectionScanParams::BACKWARD;
}
- WorkingSet* ws = new WorkingSet();
CollectionScan* cs = new CollectionScan(txn, params, ws, NULL);
- return new InternalRunner(collection, cs, ws);
+ PlanExecutor* exec = new PlanExecutor(ws, cs, collection);
+ // 'exec' will be registered until it is destroyed.
+ exec->registerExecInternalPlan();
+ return exec;
}
/**
* Return an index scan. Caller owns returned pointer.
*/
- static Runner* indexScan(OperationContext* txn,
- const Collection* collection,
- const IndexDescriptor* descriptor,
- const BSONObj& startKey, const BSONObj& endKey,
- bool endKeyInclusive, Direction direction = FORWARD,
- int options = 0) {
+ static PlanExecutor* indexScan(OperationContext* txn,
+ const Collection* collection,
+ const IndexDescriptor* descriptor,
+ const BSONObj& startKey, const BSONObj& endKey,
+ bool endKeyInclusive, Direction direction = FORWARD,
+ int options = 0) {
invariant(collection);
invariant(descriptor);
@@ -114,13 +119,16 @@ namespace mongo {
WorkingSet* ws = new WorkingSet();
IndexScan* ix = new IndexScan(txn, params, ws, NULL);
+ PlanStage* root = ix;
+
if (IXSCAN_FETCH & options) {
- return new InternalRunner(
- collection, new FetchStage(ws, ix, NULL, collection), ws);
- }
- else {
- return new InternalRunner(collection, ix, ws);
+ root = new FetchStage(ws, root, NULL, collection);
}
+
+ PlanExecutor* exec = new PlanExecutor(ws, root, collection);
+ // 'exec' will be registered until it is destroyed.
+ exec->registerExecInternalPlan();
+ return exec;
}
};
diff --git a/src/mongo/db/query/internal_runner.cpp b/src/mongo/db/query/internal_runner.cpp
deleted file mode 100644
index f68b82c5080..00000000000
--- a/src/mongo/db/query/internal_runner.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * Copyright (C) 2013 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/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/db/query/internal_runner.h"
-
-#include "mongo/db/catalog/collection.h"
-#include "mongo/db/diskloc.h"
-#include "mongo/db/exec/plan_stage.h"
-#include "mongo/db/exec/working_set.h"
-#include "mongo/db/jsobj.h"
-#include "mongo/db/query/canonical_query.h"
-#include "mongo/db/query/explain_plan.h"
-#include "mongo/db/query/plan_executor.h"
-#include "mongo/db/query/type_explain.h"
-
-namespace mongo {
-
- InternalRunner::InternalRunner(const Collection* collection, PlanStage* root, WorkingSet* ws)
- : _collection(collection),
- _exec(new PlanExecutor(ws, root, collection)) {
-
- _collection->cursorCache()->registerRunner(this);
- invariant( collection );
- }
-
- InternalRunner::~InternalRunner() {
- if (_collection) {
- _collection->cursorCache()->deregisterRunner(this);
- }
- }
-
- Runner::RunnerState InternalRunner::getNext(BSONObj* objOut, DiskLoc* dlOut) {
- return _exec->getNext(objOut, dlOut);
- }
-
- bool InternalRunner::isEOF() {
- return _exec->isEOF();
- }
-
- void InternalRunner::saveState() {
- _exec->saveState();
- }
-
- bool InternalRunner::restoreState(OperationContext* opCtx) {
- return _exec->restoreState();
- }
-
- const std::string& InternalRunner::ns() {
- return _collection->ns().ns();
- }
-
- void InternalRunner::invalidate(const DiskLoc& dl, InvalidationType type) {
- _exec->invalidate(dl, type);
- }
-
- void InternalRunner::kill() {
- _exec->kill();
- _collection = NULL;
- }
-
- Status InternalRunner::getInfo(TypeExplain** explain,
- PlanInfo** planInfo) const {
- if (NULL != explain) {
- verify(_exec.get());
-
- scoped_ptr<PlanStageStats> stats(_exec->getStats());
- if (NULL == stats.get()) {
- return Status(ErrorCodes::InternalError, "no stats available to explain plan");
- }
-
- Status status = explainPlan(*stats, explain, true /* full details */);
- if (!status.isOK()) {
- return status;
- }
-
- // Fill in explain fields that are accounted by on the runner level.
- TypeExplain* chosenPlan = NULL;
- explainPlan(*stats, &chosenPlan, false /* no full details */);
- if (chosenPlan) {
- (*explain)->addToAllPlans(chosenPlan);
- }
- (*explain)->setNScannedObjectsAllPlans((*explain)->getNScannedObjects());
- (*explain)->setNScannedAllPlans((*explain)->getNScanned());
- }
- else if (NULL != planInfo) {
- *planInfo = new PlanInfo();
- (*planInfo)->planSummary = "INTERNAL";
- }
-
- return Status::OK();
- }
-
-} // namespace mongo
diff --git a/src/mongo/db/query/internal_runner.h b/src/mongo/db/query/internal_runner.h
deleted file mode 100644
index d01a39606f6..00000000000
--- a/src/mongo/db/query/internal_runner.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * Copyright (C) 2013-2014 MongoDB 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/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <boost/scoped_ptr.hpp>
-#include <string>
-
-#include "mongo/base/status.h"
-#include "mongo/db/query/runner.h"
-
-namespace mongo {
-
- class BSONObj;
- class CanonicalQuery;
- class DiskLoc;
- class OperationContext;
- class PlanExecutor;
- struct PlanInfo;
- class PlanStage;
- struct QuerySolution;
- class TypeExplain;
- class WorkingSet;
-
- /**
- * This is a runner that was requested by an internal client of the query system, as opposed to
- * runners that are built in response to a query entering the system. It is only used by
- * internal clients of the query systems (e.g., chunk migration, index building, commands that
- * traverse data such as md5, ... )
- *
- * The salient feature of this Runner is that it does not interact with the cache at all.
- */
- class InternalRunner : public Runner {
- public:
-
- /** Takes ownership of root and ws. */
- InternalRunner(const Collection* collection, PlanStage* root, WorkingSet* ws);
-
- virtual ~InternalRunner();
-
- Runner::RunnerState getNext(BSONObj* objOut, DiskLoc* dlOut);
-
- virtual bool isEOF();
-
- virtual void saveState();
-
- virtual bool restoreState(OperationContext* opCtx);
-
- virtual const std::string& ns();
-
- virtual void invalidate(const DiskLoc& dl, InvalidationType type);
-
- virtual void kill();
-
- virtual const Collection* collection() { return _collection; }
-
- /**
- * Returns OK, allocating and filling in '*explain' with details of the plan used by
- * this runner. Caller takes ownership of '*explain'. Similarly fills in '*planInfo',
- * which the caller takes ownership of. Otherwise, return a status describing the
- * error.
- *
- * Strictly speaking, an InternalRunner's explain is never exposed, simply because an
- * InternalRunner itself is not exposed. But we implement the explain here anyway so
- * to help in debugging situations.
- */
- virtual Status getInfo(TypeExplain** explain,
- PlanInfo** planInfo) const;
-
- private:
- const Collection* _collection;
-
- boost::scoped_ptr<PlanExecutor> _exec;
- };
-
-} // namespace mongo
diff --git a/src/mongo/db/query/new_find.cpp b/src/mongo/db/query/new_find.cpp
index 3cc4a035a6e..4e627517910 100644
--- a/src/mongo/db/query/new_find.cpp
+++ b/src/mongo/db/query/new_find.cpp
@@ -38,14 +38,12 @@
#include "mongo/db/exec/working_set_common.h"
#include "mongo/db/keypattern.h"
#include "mongo/db/query/explain.h"
+#include "mongo/db/query/explain_plan.h"
#include "mongo/db/query/find_constants.h"
#include "mongo/db/query/get_executor.h"
-#include "mongo/db/query/get_runner.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/query/qlog.h"
#include "mongo/db/query/query_planner_params.h"
-#include "mongo/db/query/single_solution_runner.h"
-#include "mongo/db/query/type_explain.h"
#include "mongo/db/repl/repl_coordinator_global.h"
#include "mongo/db/server_options.h"
#include "mongo/db/server_parameters.h"
@@ -237,15 +235,15 @@ namespace mongo {
startingResult = cc->pos();
// What gives us results.
- Runner* runner = cc->getRunner();
+ PlanExecutor* exec = cc->getExecutor();
const int queryOptions = cc->queryOptions();
- // Get results out of the runner.
- runner->restoreState(txn);
+ // Get results out of the executor.
+ exec->restoreState(txn);
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
// Add result to output buffer.
bb.appendBuf((void*)obj.objdata(), obj.objsize());
@@ -275,7 +273,7 @@ namespace mongo {
}
// We save the client cursor when there might be more results, and hence we may receive
- // another getmore. If we receive a EOF or an error, or the runner is dead, then we know
+ // another getmore. If we receive a EOF or an error, or 'exec' is dead, then we know
// that we will not be producing more results. We indicate that the cursor is closed by
// sending a cursorId of 0 back to the client.
//
@@ -288,16 +286,10 @@ namespace mongo {
if (Runner::RUNNER_DEAD == state || Runner::RUNNER_ERROR == state) {
// Propagate this error to caller.
if (Runner::RUNNER_ERROR == state) {
- // Stats are helpful when errors occur.
- TypeExplain* bareExplain;
- Status res = runner->getInfo(&bareExplain, NULL);
- if (res.isOK()) {
- boost::scoped_ptr<TypeExplain> errorExplain(bareExplain);
- error() << "Runner error, stats:\n"
- << errorExplain->stats.jsonString(Strict, true);
- }
-
- uasserted(17406, "getMore runner error: " +
+ scoped_ptr<PlanStageStats> stats(exec->getStats());
+ error() << "Runner error, stats: "
+ << statsToBSON(*stats);
+ uasserted(17406, "getMore executor error: " +
WorkingSetCommon::toStatusString(obj));
}
@@ -307,7 +299,7 @@ namespace mongo {
// In the old system tailable capped cursors would be killed off at the
// cursorid level. If a tailable capped cursor is nuked the cursorid
// would vanish.
- //
+ //
// In the new system they die and are cleaned up later (or time out).
// So this is where we get to remove the cursorid.
if (0 == numResults) {
@@ -325,7 +317,7 @@ namespace mongo {
if (!saveClientCursor) {
ccPin.deleteUnderlying();
- // cc is now invalid, as is the runner
+ // cc is now invalid, as is the executor
cursorid = 0;
cc = NULL;
QLOG() << "getMore NOT saving client cursor, ended with state "
@@ -335,7 +327,7 @@ namespace mongo {
else {
// Continue caching the ClientCursor.
cc->incPos(numResults);
- runner->saveState();
+ exec->saveState();
QLOG() << "getMore saving client cursor ended with state "
<< Runner::statestr(state)
<< endl;
@@ -368,7 +360,10 @@ namespace mongo {
Status getOplogStartHack(OperationContext* txn,
Collection* collection,
CanonicalQuery* cq,
- Runner** runnerOut) {
+ PlanExecutor** execOut) {
+ invariant(cq);
+ auto_ptr<CanonicalQuery> autoCq(cq);
+
if ( collection == NULL )
return Status(ErrorCodes::InternalError,
"getOplogStartHack called with a NULL collection" );
@@ -404,14 +399,17 @@ namespace mongo {
OplogStart* stage = new OplogStart(txn, collection, tsExpr, oplogws);
// Takes ownership of ws and stage.
- auto_ptr<InternalRunner> runner(new InternalRunner(collection, stage, oplogws));
+ auto_ptr<PlanExecutor> exec(new PlanExecutor(oplogws, stage, collection));
+ exec->registerExecInternalPlan();
// The stage returns a DiskLoc of where to start.
DiskLoc startLoc;
- Runner::RunnerState state = runner->getNext(NULL, &startLoc);
+ Runner::RunnerState state = exec->getNext(NULL, &startLoc);
// This is normal. The start of the oplog is the beginning of the collection.
- if (Runner::RUNNER_EOF == state) { return getRunner(txn, collection, cq, runnerOut); }
+ if (Runner::RUNNER_EOF == state) {
+ return getExecutor(txn, collection, autoCq.release(), execOut);
+ }
// This is not normal. An error was encountered.
if (Runner::RUNNER_ADVANCED != state) {
@@ -430,8 +428,8 @@ namespace mongo {
WorkingSet* ws = new WorkingSet();
CollectionScan* cs = new CollectionScan(txn, params, ws, cq->root());
- // Takes ownership of cq, cs, ws.
- *runnerOut = new SingleSolutionRunner(collection, cq, NULL, cs, ws);
+ // Takes ownership of 'ws', 'cs', and 'cq'.
+ *execOut = new PlanExecutor(ws, cs, autoCq.release(), collection);
return Status::OK();
}
@@ -505,8 +503,8 @@ namespace mongo {
QLOG() << "Running query:\n" << cq->toString();
LOG(2) << "Running query: " << cq->toStringShort();
- // Parse, canonicalize, plan, transcribe, and get a runner.
- Runner* rawRunner = NULL;
+ // Parse, canonicalize, plan, transcribe, and get a plan executor.
+ PlanExecutor* rawExec = NULL;
// We use this a lot below.
const LiteParsedQuery& pq = cq->getParsed();
@@ -565,42 +563,46 @@ namespace mongo {
return "";
}
- // We'll now try to get the query runner that will execute this query for us. There
- // are a few cases in which we know upfront which runner we should get and, therefore,
+ // We'll now try to get the query executor that will execute this query for us. There
+ // are a few cases in which we know upfront which executor we should get and, therefore,
// we shortcut the selection process here.
//
- // (a) If the query is over a collection that doesn't exist, we get a special runner
- // that's is so (a runner) which doesn't return results, the EOFRunner.
+ // (a) If the query is over a collection that doesn't exist, we use an EOFStage.
//
- // (b) if the query is a replication's initial sync one, we get a SingleSolutinRunner
- // that uses a specifically designed stage that skips extents faster (see details in
- // exec/oplogstart.h)
+ // (b) if the query is a replication's initial sync one, we use a specifically designed
+ // stage that skips extents faster (see details in exec/oplogstart.h).
//
- // Otherwise we go through the selection of which runner is most suited to the
+ // Otherwise we go through the selection of which executor is most suited to the
// query + run-time context at hand.
Status status = Status::OK();
if (collection == NULL) {
- rawRunner = new EOFRunner(cq, cq->ns());
+ LOG(2) << "Collection " << ns << " does not exist."
+ << " Using EOF stage: " << cq->toStringShort();
+ EOFStage* eofStage = new EOFStage();
+ WorkingSet* ws = new WorkingSet();
+ // Takes ownership of 'cq'.
+ rawExec = new PlanExecutor(ws, eofStage, cq, NULL);
}
else if (pq.hasOption(QueryOption_OplogReplay)) {
- status = getOplogStartHack(txn, collection, cq, &rawRunner);
+ // Takes ownership of 'cq'.
+ status = getOplogStartHack(txn, collection, cq, &rawExec);
}
else {
- // Takes ownership of cq.
size_t options = QueryPlannerParams::DEFAULT;
if (shardingState.needCollectionMetadata(pq.ns())) {
options |= QueryPlannerParams::INCLUDE_SHARD_FILTER;
}
- status = getRunner(txn, collection, cq, &rawRunner, options);
+ // Takes ownership of 'cq'.
+ status = getExecutor(txn, collection, cq, &rawExec, options);
}
if (!status.isOK()) {
- // NOTE: Do not access cq as getRunner has deleted it.
+ // NOTE: Do not access cq as getExecutor has deleted it.
uasserted(17007, "Unable to execute query: " + status.reason());
}
- verify(NULL != rawRunner);
- auto_ptr<Runner> runner(rawRunner);
+ verify(NULL != rawExec);
+ auto_ptr<PlanExecutor> exec(rawExec);
// We freak out later if this changes before we're done with the query.
const ChunkVersion shardingVersionAtStart = shardingState.getVersion(cq->ns());
@@ -635,30 +637,28 @@ namespace mongo {
BufBuilder bb(32768);
bb.skip(sizeof(QueryResult));
- // How many results have we obtained from the runner?
+ // How many results have we obtained from the executor?
int numResults = 0;
// If we're replaying the oplog, we save the last time that we read.
OpTime slaveReadTill;
- // Do we save the Runner in a ClientCursor for getMore calls later?
+ // Do we save the PlanExecutor in a ClientCursor for getMore calls later?
bool saveClientCursor = false;
- // We turn on auto-yielding for the runner here. The runner registers itself with the
- // active runners list in ClientCursor.
- auto_ptr<ScopedRunnerRegistration> safety(new ScopedRunnerRegistration(runner.get()));
+ // The executor registers itself with the active executors list in ClientCursor.
+ auto_ptr<ScopedExecutorRegistration> safety(new ScopedExecutorRegistration(exec.get()));
BSONObj obj;
Runner::RunnerState state;
// uint64_t numMisplacedDocs = 0;
- // Have we retrieved info about which plan the runner will
- // use to execute the query yet?
- bool gotPlanInfo = false;
- PlanInfo* rawInfo;
- boost::scoped_ptr<PlanInfo> planInfo;
+ // Get summary info about which plan the executor is using.
+ PlanSummaryStats stats;
+ Explain::getSummaryStats(exec.get(), &stats);
+ curop.debug().planSummary = stats.summaryStr.c_str();
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
// Add result to output buffer. This is unnecessary if explain info is requested
if (!isExplain) {
bb.appendBuf((void*)obj.objdata(), obj.objsize());
@@ -667,24 +667,6 @@ namespace mongo {
// Count the result.
++numResults;
- // In the case of the multi plan runner, we may not be able to
- // successfully retrieve plan info until after the query starts
- // to run. This is because the multi plan runner doesn't know what
- // plan it will end up using until it runs candidates and selects
- // the best.
- //
- // TODO: Do we ever want to output what the MPR is comparing?
- if (!gotPlanInfo) {
- Status infoStatus = runner->getInfo(NULL, &rawInfo);
- if (infoStatus.isOK()) {
- gotPlanInfo = true;
- planInfo.reset(rawInfo);
- // planSummary is really a ThreadSafeString which copies the data from
- // the provided pointer.
- curop.debug().planSummary = planInfo->planSummary.c_str();
- }
- }
-
// Possibly note slave's position in the oplog.
if (pq.hasOption(QueryOption_OplogReplay)) {
BSONElement e = obj["ts"];
@@ -712,47 +694,30 @@ namespace mongo {
<< endl;
// If only one result requested assume it's a findOne() and don't save the cursor.
if (pq.wantMore() && 1 != pq.getNumToReturn()) {
- QLOG() << " runner EOF=" << runner->isEOF() << endl;
- saveClientCursor = !runner->isEOF();
+ QLOG() << " executor EOF=" << exec->isEOF() << endl;
+ saveClientCursor = !exec->isEOF();
}
break;
}
}
- // Try to get information about the plan which the runner
- // will use to execute the query, it we don't have it already.
- if (!gotPlanInfo) {
- Status infoStatus = runner->getInfo(NULL, &rawInfo);
- if (infoStatus.isOK()) {
- gotPlanInfo = true;
- planInfo.reset(rawInfo);
- // planSummary is really a ThreadSafeString which copies the data from
- // the provided pointer.
- curop.debug().planSummary = planInfo->planSummary.c_str();
- }
- }
-
- // If we cache the runner later, we want to deregister it as it receives notifications
+ // If we cache the executor later, we want to deregister it as it receives notifications
// anyway by virtue of being cached.
//
- // If we don't cache the runner later, we are deleting it, so it must be deregistered.
+ // If we don't cache the executor later, we are deleting it, so it must be deregistered.
//
- // So, no matter what, deregister the runner.
+ // So, no matter what, deregister the executor.
safety.reset();
// Caller expects exceptions thrown in certain cases.
if (Runner::RUNNER_ERROR == state) {
- TypeExplain* bareExplain;
- Status res = runner->getInfo(&bareExplain, NULL);
- if (res.isOK()) {
- boost::scoped_ptr<TypeExplain> errorExplain(bareExplain);
- error() << "Runner error, stats:\n"
- << errorExplain->stats.jsonString(Strict, true);
- }
- uasserted(17144, "Runner error: " + WorkingSetCommon::toStatusString(obj));
+ scoped_ptr<PlanStageStats> stats(exec->getStats());
+ error() << "Runner error, stats: "
+ << statsToBSON(*stats);
+ uasserted(17144, "Executor error: " + WorkingSetCommon::toStatusString(obj));
}
- // Why save a dead runner?
+ // Why save a dead executor?
if (Runner::RUNNER_DEAD == state) {
saveClientCursor = false;
}
@@ -788,9 +753,9 @@ namespace mongo {
if (isExplain ||
ctx.ctx().db()->getProfilingLevel() > 0 ||
elapsedMillis > serverGlobalParams.slowMS) {
- // Ask the runner to produce explain information.
+ // Ask the executor to produce explain information.
TypeExplain* bareExplain;
- Status res = runner->getInfo(&bareExplain, NULL);
+ Status res = Explain::legacyExplain(exec.get(), &bareExplain);
if (res.isOK()) {
explain.reset(bareExplain);
}
@@ -830,21 +795,21 @@ namespace mongo {
long long ccId = 0;
if (saveClientCursor) {
- // We won't use the runner until it's getMore'd.
- runner->saveState();
+ // We won't use the executor until it's getMore'd.
+ exec->saveState();
// Allocate a new ClientCursor. We don't have to worry about leaking it as it's
// inserted into a global map by its ctor.
- ClientCursor* cc = new ClientCursor(collection, runner.get(),
+ ClientCursor* cc = new ClientCursor(collection, exec.get(),
cq->getParsed().getOptions(),
cq->getParsed().getFilter());
ccId = cc->cursorid();
- QLOG() << "caching runner with cursorid " << ccId
+ QLOG() << "caching executor with cursorid " << ccId
<< " after returning " << numResults << " results" << endl;
- // ClientCursor takes ownership of runner. Release to make sure it's not deleted.
- runner.release();
+ // ClientCursor takes ownership of executor. Release to make sure it's not deleted.
+ exec.release();
// TODO document
if (pq.hasOption(QueryOption_OplogReplay) && !slaveReadTill.isNull()) {
@@ -865,7 +830,7 @@ namespace mongo {
cc->setLeftoverMaxTimeMicros(curop.getRemainingMaxTimeMicros());
}
else {
- QLOG() << "Not caching runner but returning " << numResults << " results.\n";
+ QLOG() << "Not caching executor but returning " << numResults << " results.\n";
}
// Add the results from the query into the output buffer.
diff --git a/src/mongo/db/query/plan_executor.cpp b/src/mongo/db/query/plan_executor.cpp
index df809af0e68..f1f7c676b74 100644
--- a/src/mongo/db/query/plan_executor.cpp
+++ b/src/mongo/db/query/plan_executor.cpp
@@ -28,6 +28,7 @@
#include "mongo/db/query/plan_executor.h"
+#include "mongo/db/catalog/collection.h"
#include "mongo/db/exec/plan_stage.h"
#include "mongo/db/exec/plan_stats.h"
#include "mongo/db/exec/working_set.h"
@@ -41,6 +42,17 @@ namespace mongo {
_workingSet(ws),
_qs(NULL),
_root(rt),
+ _killed(false) {
+ initNs();
+ }
+
+ PlanExecutor::PlanExecutor(WorkingSet* ws, PlanStage* rt, std::string ns)
+ : _collection(NULL),
+ _cq(NULL),
+ _workingSet(ws),
+ _qs(NULL),
+ _root(rt),
+ _ns(ns),
_killed(false) { }
PlanExecutor::PlanExecutor(WorkingSet* ws, PlanStage* rt, CanonicalQuery* cq,
@@ -50,7 +62,9 @@ namespace mongo {
_workingSet(ws),
_qs(NULL),
_root(rt),
- _killed(false) { }
+ _killed(false) {
+ initNs();
+ }
PlanExecutor::PlanExecutor(WorkingSet* ws, PlanStage* rt, QuerySolution* qs,
CanonicalQuery* cq, const Collection* collection)
@@ -59,7 +73,19 @@ namespace mongo {
_workingSet(ws),
_qs(qs),
_root(rt),
- _killed(false) { }
+ _killed(false) {
+ initNs();
+ }
+
+ void PlanExecutor::initNs() {
+ if (NULL != _collection) {
+ _ns = _collection->ns().ns();
+ }
+ else {
+ invariant(NULL != _cq.get());
+ _ns = _cq->getParsed().ns();
+ }
+ }
PlanExecutor::~PlanExecutor() { }
@@ -79,13 +105,17 @@ namespace mongo {
return _root->getStats();
}
+ const Collection* PlanExecutor::collection() const {
+ return _collection;
+ }
+
void PlanExecutor::saveState() {
if (!_killed) { _root->prepareToYield(); }
}
- bool PlanExecutor::restoreState() {
+ bool PlanExecutor::restoreState(OperationContext* opCtx) {
if (!_killed) {
- _root->recoverFromYield();
+ _root->recoverFromYield(opCtx);
}
return !_killed;
}
@@ -170,8 +200,13 @@ namespace mongo {
return _killed || _root->isEOF();
}
+ void PlanExecutor::registerExecInternalPlan() {
+ _safety.reset(new ScopedExecutorRegistration(this));
+ }
+
void PlanExecutor::kill() {
_killed = true;
+ _collection = NULL;
}
Status PlanExecutor::executePlan() {
@@ -191,4 +226,24 @@ namespace mongo {
return Status::OK();
}
+ const string& PlanExecutor::ns() {
+ return _ns;
+ }
+
+ //
+ // ScopedExecutorRegistration
+ //
+
+ ScopedExecutorRegistration::ScopedExecutorRegistration(PlanExecutor* exec)
+ : _exec(exec) {
+ // Collection can be null for EOFRunner, or other places where registration is not needed
+ if ( _exec->collection() )
+ _exec->collection()->cursorCache()->registerExecutor( exec );
+ }
+
+ ScopedExecutorRegistration::~ScopedExecutorRegistration() {
+ if ( _exec->collection() )
+ _exec->collection()->cursorCache()->deregisterExecutor( _exec );
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/query/plan_executor.h b/src/mongo/db/query/plan_executor.h
index 99043d9c4f4..87c8aaa285f 100644
--- a/src/mongo/db/query/plan_executor.h
+++ b/src/mongo/db/query/plan_executor.h
@@ -41,6 +41,25 @@ namespace mongo {
class PlanStage;
struct PlanStageStats;
class WorkingSet;
+ class PlanExecutor;
+
+ /**
+ * RAII approach to ensuring that plan executors are deregistered.
+ *
+ * While retrieving the first batch of results, newRunQuery manually registers the executor with
+ * ClientCursor. Certain query execution paths, namely $where, can throw an exception. If we
+ * fail to deregister the executor, we will call invalidate/kill on the
+ * still-registered-yet-deleted executor.
+ *
+ * For any subsequent calls to getMore, the executor is already registered with ClientCursor
+ * by virtue of being cached, so this exception-proofing is not required.
+ */
+ struct ScopedExecutorRegistration {
+ ScopedExecutorRegistration(PlanExecutor* exec);
+ ~ScopedExecutorRegistration();
+
+ PlanExecutor* const _exec;
+ };
/**
* A PlanExecutor is the abstraction that knows how to crank a tree of stages into execution.
@@ -61,6 +80,12 @@ namespace mongo {
PlanExecutor(WorkingSet* ws, PlanStage* rt, const Collection* collection);
/**
+ * Used when we have a NULL collection and no canonical query. In this case,
+ * we need to explicitly pass a namespace to the plan executor.
+ */
+ PlanExecutor(WorkingSet* ws, PlanStage* rt, std::string ns);
+
+ /**
* Used when there is a canonical query but no query solution (e.g. idhack
* queries, queries against a NULL collection, queries using the subplan stage).
*/
@@ -96,6 +121,11 @@ namespace mongo {
CanonicalQuery* getCanonicalQuery() const;
/**
+ * The collection in which this executor is working.
+ */
+ const Collection* collection() const;
+
+ /**
* Generates a tree of stats objects with a separate lifetime from the execution
* stage tree wrapped by this PlanExecutor. The caller owns the returned pointer.
*
@@ -111,7 +141,7 @@ namespace mongo {
void saveState();
/** TODO document me */
- bool restoreState();
+ bool restoreState(OperationContext* opCtx);
/** TODO document me */
void invalidate(const DiskLoc& dl, InvalidationType type);
@@ -127,6 +157,22 @@ namespace mongo {
bool isEOF();
/**
+ * Register this plan executor with the collection cursor cache so that it
+ * receives event notifications.
+ *
+ * Deregistration happens automatically when this plan executor is destroyed.
+ *
+ * Used just for internal plans:
+ * -- InternalPlanner::collectionScan(...) (see internal_plans.h)
+ * -- InternalPlanner::indexScan(...) (see internal_plans.h)
+ * -- getOplogStartHack(...) (see new_find.cpp)
+ * -- storeCurrentLocs(...) (see d_migrate.cpp)
+ *
+ * TODO: we probably don't need this for 2.8.
+ */
+ void registerExecInternalPlan();
+
+ /**
* During the yield, the database we're operating over or any collection we're relying on
* may be dropped. When this happens all cursors and runners on that database and
* collection are killed or deleted in some fashion. (This is how the _killed gets set.)
@@ -140,7 +186,17 @@ namespace mongo {
*/
Status executePlan();
+ /**
+ * Return the NS that the query is running over.
+ */
+ const std::string& ns();
+
private:
+ /**
+ * Initialize the namespace using either the canonical query or the collection.
+ */
+ void initNs();
+
// Collection over which this plan executor runs. Used to resolve record ids retrieved by
// the plan stages. The collection must not be destroyed while there are active plans.
const Collection* _collection;
@@ -150,6 +206,11 @@ namespace mongo {
boost::scoped_ptr<QuerySolution> _qs;
std::auto_ptr<PlanStage> _root;
+ // Deregisters this executor when it is destroyed.
+ boost::scoped_ptr<ScopedExecutorRegistration> _safety;
+
+ std::string _ns;
+
// Did somebody drop an index we care about or the namespace we're looking at? If so,
// we'll be killed.
bool _killed;
diff --git a/src/mongo/db/query/runner.h b/src/mongo/db/query/runner.h
index 9d915f4f8ae..db7a642552f 100644
--- a/src/mongo/db/query/runner.h
+++ b/src/mongo/db/query/runner.h
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#pragma once
#include "mongo/base/status.h"
diff --git a/src/mongo/db/query/single_solution_runner.cpp b/src/mongo/db/query/single_solution_runner.cpp
index a2f4327ccc1..e7d3ce652a7 100644
--- a/src/mongo/db/query/single_solution_runner.cpp
+++ b/src/mongo/db/query/single_solution_runner.cpp
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#include "mongo/db/query/single_solution_runner.h"
#include "mongo/db/diskloc.h"
@@ -69,7 +71,7 @@ namespace mongo {
}
bool SingleSolutionRunner::restoreState(OperationContext* opCtx) {
- return _exec->restoreState();
+ return _exec->restoreState(opCtx);
}
void SingleSolutionRunner::invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/db/query/single_solution_runner.h b/src/mongo/db/query/single_solution_runner.h
index 116faa51000..c48e16086cd 100644
--- a/src/mongo/db/query/single_solution_runner.h
+++ b/src/mongo/db/query/single_solution_runner.h
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#pragma once
#include <boost/scoped_ptr.hpp>
diff --git a/src/mongo/db/query/stage_types.h b/src/mongo/db/query/stage_types.h
index d258bd08f2d..6b841645ffb 100644
--- a/src/mongo/db/query/stage_types.h
+++ b/src/mongo/db/query/stage_types.h
@@ -48,6 +48,9 @@ namespace mongo {
// stage is an ixscan with some key-skipping behvaior that only distinct uses.
STAGE_DISTINCT,
+ // Dummy stage used for receiving notifications of deletions during chunk migration.
+ STAGE_NOTIFY_DELETE,
+
STAGE_EOF,
// This is more of an "internal-only" stage where we try to keep docs that were mutated
@@ -64,10 +67,18 @@ namespace mongo {
STAGE_IXSCAN,
STAGE_LIMIT,
STAGE_MOCK,
+
+ // Implements parallelCollectionScan.
+ STAGE_MULTI_ITERATOR,
+
STAGE_MULTI_PLAN,
STAGE_OPLOG_START,
STAGE_OR,
STAGE_PROJECTION,
+
+ // Stage for running aggregation pipelines.
+ STAGE_PIPELINE_PROXY,
+
STAGE_SHARDING_FILTER,
STAGE_SKIP,
STAGE_SORT,
diff --git a/src/mongo/db/query/subplan_runner.cpp b/src/mongo/db/query/subplan_runner.cpp
index 4682c29b2b4..fdd212db36a 100644
--- a/src/mongo/db/query/subplan_runner.cpp
+++ b/src/mongo/db/query/subplan_runner.cpp
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#include "mongo/db/query/subplan_runner.h"
#include "mongo/client/dbclientinterface.h"
diff --git a/src/mongo/db/query/subplan_runner.h b/src/mongo/db/query/subplan_runner.h
index 896772450ad..64f0b29aecb 100644
--- a/src/mongo/db/query/subplan_runner.h
+++ b/src/mongo/db/query/subplan_runner.h
@@ -26,6 +26,8 @@
* it in the license file.
*/
+// THIS FILE IS DEPRECATED -- Runner to be replaced with PlanExecutor.
+
#pragma once
#include <boost/scoped_ptr.hpp>
diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp
index 3ecf77b607a..27e446765bb 100644
--- a/src/mongo/db/repl/master_slave.cpp
+++ b/src/mongo/db/repl/master_slave.cpp
@@ -253,13 +253,13 @@ namespace repl {
// check that no items are in sources other than that
// add if missing
int n = 0;
- auto_ptr<Runner> runner(
+ auto_ptr<PlanExecutor> exec(
InternalPlanner::collectionScan(txn,
localSources,
ctx.db()->getCollection(txn, localSources)));
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
n++;
ReplSource tmp(txn, obj);
if (tmp.hostName != replSettings.source) {
@@ -298,13 +298,13 @@ namespace repl {
}
}
- auto_ptr<Runner> runner(
+ auto_ptr<PlanExecutor> exec(
InternalPlanner::collectionScan(txn,
localSources,
ctx.db()->getCollection(txn, localSources)));
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
ReplSource tmp(txn, obj);
if ( tmp.syncedTo.isNull() ) {
DBDirectClient c(txn);
diff --git a/src/mongo/db/repl/repl_info.cpp b/src/mongo/db/repl/repl_info.cpp
index c05de79df5d..9d3b1e02436 100644
--- a/src/mongo/db/repl/repl_info.cpp
+++ b/src/mongo/db/repl/repl_info.cpp
@@ -83,14 +83,14 @@ namespace repl {
{
const char* localSources = "local.sources";
Client::ReadContext ctx(txn, localSources);
- auto_ptr<Runner> runner(
+ auto_ptr<PlanExecutor> exec(
InternalPlanner::collectionScan(txn,
localSources,
ctx.ctx().db()->getCollection(txn,
localSources)));
BSONObj obj;
Runner::RunnerState state;
- while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
+ while (Runner::RUNNER_ADVANCED == (state = exec->getNext(&obj, NULL))) {
src.push_back(obj);
}
}
diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp
index b65dbb324bb..1ca35ae1e83 100644
--- a/src/mongo/db/repl/rs_rollback.cpp
+++ b/src/mongo/db/repl/rs_rollback.cpp
@@ -234,7 +234,7 @@ namespace repl {
static void syncRollbackFindCommonPoint(OperationContext* txn, DBClientConnection* them, FixUpInfo& fixUpInfo) {
Client::Context ctx(txn, rsoplog);
- boost::scoped_ptr<Runner> runner(
+ boost::scoped_ptr<PlanExecutor> exec(
InternalPlanner::collectionScan(txn,
rsoplog,
ctx.db()->getCollection(txn, rsoplog),
@@ -243,7 +243,7 @@ namespace repl {
BSONObj ourObj;
DiskLoc ourLoc;
- if (Runner::RUNNER_ADVANCED != runner->getNext(&ourObj, &ourLoc)) {
+ if (Runner::RUNNER_ADVANCED != exec->getNext(&ourObj, &ourLoc)) {
throw RSFatalException("our oplog empty or unreadable");
}
@@ -304,7 +304,7 @@ namespace repl {
theirObj = oplogCursor->nextSafe();
theirTime = theirObj["ts"]._opTime();
- if (Runner::RUNNER_ADVANCED != runner->getNext(&ourObj, &ourLoc)) {
+ if (Runner::RUNNER_ADVANCED != exec->getNext(&ourObj, &ourLoc)) {
log() << "replSet rollback error RS101 reached beginning of local oplog"
<< rsLog;
log() << "replSet them: " << them->toString() << " scanned: "
@@ -331,7 +331,7 @@ namespace repl {
else {
// theirTime < ourTime
refetch(fixUpInfo, ourObj);
- if (Runner::RUNNER_ADVANCED != runner->getNext(&ourObj, &ourLoc)) {
+ if (Runner::RUNNER_ADVANCED != exec->getNext(&ourObj, &ourLoc)) {
log() << "replSet rollback error RS101 reached beginning of local oplog"
<< rsLog;
log() << "replSet them: " << them->toString() << " scanned: "
diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp
index 1c37fa6db4c..363925b0719 100644
--- a/src/mongo/dbtests/documentsourcetests.cpp
+++ b/src/mongo/dbtests/documentsourcetests.cpp
@@ -38,7 +38,7 @@
#include "mongo/db/pipeline/dependencies.h"
#include "mongo/db/pipeline/document_source.h"
#include "mongo/db/pipeline/expression_context.h"
-#include "mongo/db/query/get_runner.h"
+#include "mongo/db/query/get_executor.h"
#include "mongo/db/storage_options.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/dbtests/dbtests.h"
@@ -172,27 +172,28 @@ namespace DocumentSourceTests {
// clean up first if this was called before
_source.reset();
_registration.reset();
- _runner.reset();
+ _exec.reset();
Client::WriteContext ctx(&_opCtx, ns);
CanonicalQuery* cq;
uassertStatusOK(CanonicalQuery::canonicalize(ns, /*query=*/BSONObj(), &cq));
- Runner* runnerBare;
- uassertStatusOK(getRunner(&_opCtx, ctx.ctx().db()->getCollection(&_opCtx, ns), cq, &runnerBare));
+ PlanExecutor* execBare;
+ uassertStatusOK(getExecutor(&_opCtx, ctx.ctx().db()->getCollection(&_opCtx, ns),
+ cq, &execBare));
- _runner.reset(runnerBare);
- _runner->saveState();
- _registration.reset(new ScopedRunnerRegistration(_runner.get()));
+ _exec.reset(execBare);
+ _exec->saveState();
+ _registration.reset(new ScopedExecutorRegistration(_exec.get()));
- _source = DocumentSourceCursor::create(ns, _runner, _ctx);
+ _source = DocumentSourceCursor::create(ns, _exec, _ctx);
}
intrusive_ptr<ExpressionContext> ctx() { return _ctx; }
DocumentSourceCursor* source() { return _source.get(); }
private:
// It is important that these are ordered to ensure correct destruction order.
- boost::shared_ptr<Runner> _runner;
- boost::scoped_ptr<ScopedRunnerRegistration> _registration;
+ boost::shared_ptr<PlanExecutor> _exec;
+ boost::scoped_ptr<ScopedExecutorRegistration> _registration;
intrusive_ptr<ExpressionContext> _ctx;
intrusive_ptr<DocumentSourceCursor> _source;
};
diff --git a/src/mongo/dbtests/runner_registry.cpp b/src/mongo/dbtests/executor_registry.cpp
index 970027d9450..d122e356b74 100644
--- a/src/mongo/dbtests/runner_registry.cpp
+++ b/src/mongo/dbtests/executor_registry.cpp
@@ -27,8 +27,8 @@
*/
/**
- * This file tests Runner forced yielding, ClientCursor::registerRunner, and
- * ClientCursor::deregisterRunner.
+ * This file tests PlanExecutor forced yielding, ClientCursor::registerExecutor, and
+ * ClientCursor::deregisterExecutor.
*/
#include "mongo/client/dbclientcursor.h"
@@ -45,11 +45,11 @@
#include "mongo/dbtests/dbtests.h"
-namespace RunnerRegistry {
+namespace ExecutorRegistry {
- class RunnerRegistryBase {
+ class ExecutorRegistryBase {
public:
- RunnerRegistryBase()
+ ExecutorRegistryBase()
: _client(&_opCtx)
{
_ctx.reset(new Client::WriteContext(&_opCtx, ns()));
@@ -60,16 +60,16 @@ namespace RunnerRegistry {
}
}
- ~RunnerRegistryBase() {
+ ~ExecutorRegistryBase() {
if (_ctx.get()) {
_ctx->commit();
}
}
/**
- * Return a runner that is going over the collection in ns().
+ * Return a plan executor that is going over the collection in ns().
*/
- Runner* getCollscan() {
+ PlanExecutor* getCollscan() {
auto_ptr<WorkingSet> ws(new WorkingSet());
CollectionScanParams params;
params.collection = collection();
@@ -77,22 +77,20 @@ namespace RunnerRegistry {
params.tailable = false;
auto_ptr<CollectionScan> scan(new CollectionScan(&_opCtx, params, ws.get(), NULL));
- // Create a runner to hold it
+ // Create a plan executor to hold it
CanonicalQuery* cq;
ASSERT(CanonicalQuery::canonicalize(ns(), BSONObj(), &cq).isOK());
// Owns all args
- auto_ptr<Runner> run(new SingleSolutionRunner(_ctx->ctx().db()->getCollection( &_opCtx,
- ns() ),
- cq, NULL, scan.release(), ws.release()));
- return run.release();
+ return new PlanExecutor(ws.release(), scan.release(), cq,
+ _ctx->ctx().db()->getCollection( &_opCtx, ns() ));
}
- void registerRunner( Runner* runner ) {
- _ctx->ctx().db()->getOrCreateCollection( &_opCtx, ns() )->cursorCache()->registerRunner( runner );
+ void registerExecutor( PlanExecutor* exec ) {
+ _ctx->ctx().db()->getOrCreateCollection( &_opCtx, ns() )->cursorCache()->registerExecutor( exec );
}
- void deregisterRunner( Runner* runner ) {
- _ctx->ctx().db()->getOrCreateCollection( &_opCtx, ns() )->cursorCache()->deregisterRunner( runner );
+ void deregisterExecutor( PlanExecutor* exec ) {
+ _ctx->ctx().db()->getOrCreateCollection( &_opCtx, ns() )->cursorCache()->deregisterExecutor( exec );
}
int N() { return 50; }
@@ -101,7 +99,7 @@ namespace RunnerRegistry {
return _ctx->ctx().db()->getCollection( &_opCtx, ns() );
}
- static const char* ns() { return "unittests.RunnerRegistryDiskLocInvalidation"; }
+ static const char* ns() { return "unittests.ExecutorRegistryDiskLocInvalidation"; }
// Order of these is important for initialization
OperationContextImpl _opCtx;
@@ -111,10 +109,10 @@ namespace RunnerRegistry {
// Test that a registered runner receives invalidation notifications.
- class RunnerRegistryDiskLocInvalid : public RunnerRegistryBase {
+ class ExecutorRegistryDiskLocInvalid : public ExecutorRegistryBase {
public:
void run() {
- auto_ptr<Runner> run(getCollscan());
+ auto_ptr<PlanExecutor> run(getCollscan());
BSONObj obj;
// Read some of it.
@@ -125,7 +123,7 @@ namespace RunnerRegistry {
// Register it.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// At this point it's safe to yield. forceYield would do that. Let's now simulate some
// stuff going on in the yield.
@@ -136,7 +134,7 @@ namespace RunnerRegistry {
// At this point, we're done yielding. We recover our lock.
// Unregister the runner.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
// And clean up anything that happened before.
run->restoreState(&_opCtx);
@@ -153,10 +151,10 @@ namespace RunnerRegistry {
};
// Test that registered runners are killed when their collection is dropped.
- class RunnerRegistryDropCollection : public RunnerRegistryBase {
+ class ExecutorRegistryDropCollection : public ExecutorRegistryBase {
public:
void run() {
- auto_ptr<Runner> run(getCollscan());
+ auto_ptr<PlanExecutor> run(getCollscan());
BSONObj obj;
// Read some of it.
@@ -167,13 +165,13 @@ namespace RunnerRegistry {
// Save state and register.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// Drop a collection that's not ours.
_client.dropCollection("unittests.someboguscollection");
// Unregister and restore state.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
run->restoreState(&_opCtx);
ASSERT_EQUALS(Runner::RUNNER_ADVANCED, run->getNext(&obj, NULL));
@@ -181,25 +179,25 @@ namespace RunnerRegistry {
// Save state and register.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// Drop our collection.
_client.dropCollection(ns());
// Unregister and restore state.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
run->restoreState(&_opCtx);
- // Runner was killed.
+ // PlanExecutor was killed.
ASSERT_EQUALS(Runner::RUNNER_DEAD, run->getNext(&obj, NULL));
}
};
// Test that registered runners are killed when all indices are dropped on the collection.
- class RunnerRegistryDropAllIndices : public RunnerRegistryBase {
+ class ExecutorRegistryDropAllIndices : public ExecutorRegistryBase {
public:
void run() {
- auto_ptr<Runner> run(getCollscan());
+ auto_ptr<PlanExecutor> run(getCollscan());
BSONObj obj;
_client.ensureIndex(ns(), BSON("foo" << 1));
@@ -212,25 +210,25 @@ namespace RunnerRegistry {
// Save state and register.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// Drop all indices.
_client.dropIndexes(ns());
// Unregister and restore state.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
run->restoreState(&_opCtx);
- // Runner was killed.
+ // PlanExecutor was killed.
ASSERT_EQUALS(Runner::RUNNER_DEAD, run->getNext(&obj, NULL));
}
};
// Test that registered runners are killed when an index is dropped on the collection.
- class RunnerRegistryDropOneIndex : public RunnerRegistryBase {
+ class ExecutorRegistryDropOneIndex : public ExecutorRegistryBase {
public:
void run() {
- auto_ptr<Runner> run(getCollscan());
+ auto_ptr<PlanExecutor> run(getCollscan());
BSONObj obj;
_client.ensureIndex(ns(), BSON("foo" << 1));
@@ -243,25 +241,25 @@ namespace RunnerRegistry {
// Save state and register.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// Drop a specific index.
_client.dropIndex(ns(), BSON("foo" << 1));
// Unregister and restore state.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
run->restoreState(&_opCtx);
- // Runner was killed.
+ // PlanExecutor was killed.
ASSERT_EQUALS(Runner::RUNNER_DEAD, run->getNext(&obj, NULL));
}
};
// Test that registered runners are killed when their database is dropped.
- class RunnerRegistryDropDatabase : public RunnerRegistryBase {
+ class ExecutorRegistryDropDatabase : public ExecutorRegistryBase {
public:
void run() {
- auto_ptr<Runner> run(getCollscan());
+ auto_ptr<PlanExecutor> run(getCollscan());
BSONObj obj;
// Read some of it.
@@ -272,7 +270,7 @@ namespace RunnerRegistry {
// Save state and register.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// Drop a DB that's not ours. We can't have a lock at all to do this as dropping a DB
// requires a "global write lock."
@@ -282,7 +280,7 @@ namespace RunnerRegistry {
_ctx.reset(new Client::WriteContext(&_opCtx, ns()));
// Unregister and restore state.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
run->restoreState(&_opCtx);
ASSERT_EQUALS(Runner::RUNNER_ADVANCED, run->getNext(&obj, NULL));
@@ -290,7 +288,7 @@ namespace RunnerRegistry {
// Save state and register.
run->saveState();
- registerRunner(run.get());
+ registerExecutor(run.get());
// Drop our DB. Once again, must give up the lock.
_ctx->commit();
@@ -299,12 +297,12 @@ namespace RunnerRegistry {
_ctx.reset(new Client::WriteContext(&_opCtx, ns()));
// Unregister and restore state.
- deregisterRunner(run.get());
+ deregisterExecutor(run.get());
run->restoreState(&_opCtx);
_ctx->commit();
_ctx.reset();
- // Runner was killed.
+ // PlanExecutor was killed.
ASSERT_EQUALS(Runner::RUNNER_DEAD, run->getNext(&obj, NULL));
}
};
@@ -313,15 +311,15 @@ namespace RunnerRegistry {
class All : public Suite {
public:
- All() : Suite( "runner_registry" ) { }
+ All() : Suite( "executor_registry" ) { }
void setupTests() {
- add<RunnerRegistryDiskLocInvalid>();
- add<RunnerRegistryDropCollection>();
- add<RunnerRegistryDropAllIndices>();
- add<RunnerRegistryDropOneIndex>();
- add<RunnerRegistryDropDatabase>();
+ add<ExecutorRegistryDiskLocInvalid>();
+ add<ExecutorRegistryDropCollection>();
+ add<ExecutorRegistryDropAllIndices>();
+ add<ExecutorRegistryDropOneIndex>();
+ add<ExecutorRegistryDropDatabase>();
}
- } runnerRegistryAll;
+ } executorRegistryAll;
-} // namespace RunnerRegistry
+} // namespace ExecutorRegistry
diff --git a/src/mongo/dbtests/oplogstarttests.cpp b/src/mongo/dbtests/oplogstarttests.cpp
index 0c6b5c0f20b..7a8995aba0c 100644
--- a/src/mongo/dbtests/oplogstarttests.cpp
+++ b/src/mongo/dbtests/oplogstarttests.cpp
@@ -15,10 +15,9 @@
*/
/**
- * This file tests db/exec/oplogstart.{h,cpp}. OplogStart is a planner stage
- * used by an InternalRunner. It is responsible for walking the oplog
- * backwards in order to find where the oplog should be replayed from for
- * replication.
+ * This file tests db/exec/oplogstart.{h,cpp}. OplogStart is an execution stage
+ * responsible for walking the oplog backwards in order to find where the oplog should
+ * be replayed from for replication.
*/
#include "mongo/dbtests/dbtests.h"
@@ -27,7 +26,6 @@
#include "mongo/db/exec/oplogstart.h"
#include "mongo/db/exec/working_set.h"
#include "mongo/db/query/canonical_query.h"
-#include "mongo/db/query/internal_runner.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/repl_settings.h"
#include "mongo/db/operation_context_impl.h"
diff --git a/src/mongo/dbtests/query_single_solution_runner.cpp b/src/mongo/dbtests/query_plan_executor.cpp
index 4f4ddd09570..477f5db80f6 100644
--- a/src/mongo/dbtests/query_single_solution_runner.cpp
+++ b/src/mongo/dbtests/query_plan_executor.cpp
@@ -37,19 +37,19 @@
#include "mongo/db/json.h"
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/query/plan_executor.h"
#include "mongo/db/query/query_solution.h"
-#include "mongo/db/query/single_solution_runner.h"
#include "mongo/dbtests/dbtests.h"
-namespace QuerySingleSolutionRunner {
+namespace QueryPlanExecutor {
- class SingleSolutionRunnerBase {
+ class PlanExecutorBase {
public:
- SingleSolutionRunnerBase() : _client(&_txn) {
-
+ PlanExecutorBase() : _client(&_txn) {
+
}
- virtual ~SingleSolutionRunnerBase() {
+ virtual ~PlanExecutorBase() {
_client.dropCollection(ns());
}
@@ -75,13 +75,12 @@ namespace QuerySingleSolutionRunner {
/**
* Given a match expression, represented as the BSON object 'filterObj',
- * create a SingleSolutionRunner capable of executing a simple collection
+ * create a PlanExecutor capable of executing a simple collection
* scan.
*
- * The caller takes ownership of the returned SingleSolutionRunner*.
+ * The caller takes ownership of the returned PlanExecutor*.
*/
- SingleSolutionRunner* makeCollScanRunner(Client::Context& ctx,
- BSONObj& filterObj) {
+ PlanExecutor* makeCollScanExec(Client::Context& ctx, BSONObj& filterObj) {
CollectionScanParams csparams;
csparams.collection = ctx.db()->getCollection( &_txn, ns() );
csparams.direction = CollectionScanParams::FORWARD;
@@ -97,13 +96,10 @@ namespace QuerySingleSolutionRunner {
verify(CanonicalQuery::canonicalize(ns(), filterObj, &cq).isOK());
verify(NULL != cq);
- // Hand the plan off to the single solution runner.
- SingleSolutionRunner* ssr = new SingleSolutionRunner(ctx.db()->getCollection(&_txn, ns()),
- cq,
- new QuerySolution(),
- root.release(),
- ws.release());
- return ssr;
+ // Hand the plan off to the executor.
+ PlanExecutor* exec = new PlanExecutor(ws.release(), root.release(), cq,
+ ctx.db()->getCollection(&_txn, ns()));
+ return exec;
}
/**
@@ -114,13 +110,13 @@ namespace QuerySingleSolutionRunner {
* @param end -- the lower bound (inclusive) at which to end the
* index scan
*
- * Returns a SingleSolutionRunner capable of executing an index scan
+ * Returns a PlanExecutor capable of executing an index scan
* over the specified index with the specified bounds.
*
- * The caller takes ownership of the returned SingleSolutionRunner*.
+ * The caller takes ownership of the returned PlanExecutor*.
*/
- SingleSolutionRunner* makeIndexScanRunner(Client::Context& context,
- BSONObj& indexSpec, int start, int end) {
+ PlanExecutor* makeIndexScanExec(Client::Context& context,
+ BSONObj& indexSpec, int start, int end) {
// Build the index scan stage.
IndexScanParams ixparams;
ixparams.descriptor = getIndex(context.db(), indexSpec);
@@ -140,13 +136,11 @@ namespace QuerySingleSolutionRunner {
verify(CanonicalQuery::canonicalize(ns(), BSONObj(), &cq).isOK());
verify(NULL != cq);
- // Hand the plan off to the single solution runner.
- return new SingleSolutionRunner(coll,
- cq, new QuerySolution(),
- root.release(), ws.release());
+ // Hand the plan off to the executor.
+ return new PlanExecutor(ws.release(), root.release(), cq, coll);
}
- static const char* ns() { return "unittests.QueryStageSingleSolutionRunner"; }
+ static const char* ns() { return "unittests.QueryPlanExecutor"; }
size_t numCursors() {
Client::ReadContext ctx(&_txn, ns() );
@@ -156,16 +150,16 @@ namespace QuerySingleSolutionRunner {
return collection->cursorCache()->numCursors();
}
- void registerRunner( Runner* runner ) {
+ void registerExec( PlanExecutor* exec ) {
Client::ReadContext ctx(&_txn, ns());
Collection* collection = ctx.ctx().db()->getOrCreateCollection( &_txn, ns() );
- return collection->cursorCache()->registerRunner( runner );
+ collection->cursorCache()->registerExecutor( exec );
}
- void deregisterRunner( Runner* runner ) {
+ void deregisterExec( PlanExecutor* exec ) {
Client::ReadContext ctx(&_txn, ns());
Collection* collection = ctx.ctx().db()->getOrCreateCollection( &_txn, ns() );
- return collection->cursorCache()->deregisterRunner( runner );
+ collection->cursorCache()->deregisterExecutor( exec );
}
protected:
@@ -182,9 +176,9 @@ namespace QuerySingleSolutionRunner {
/**
* Test dropping the collection while the
- * SingleSolutionRunner is doing a collection scan.
+ * PlanExecutor is doing a collection scan.
*/
- class DropCollScan : public SingleSolutionRunnerBase {
+ class DropCollScan : public PlanExecutorBase {
public:
void run() {
Client::WriteContext ctx(&_txn, ns());
@@ -192,19 +186,19 @@ namespace QuerySingleSolutionRunner {
insert(BSON("_id" << 2));
BSONObj filterObj = fromjson("{_id: {$gt: 0}}");
- scoped_ptr<SingleSolutionRunner> ssr(makeCollScanRunner(ctx.ctx(),filterObj));
- registerRunner(ssr.get());
+ scoped_ptr<PlanExecutor> exec(makeCollScanExec(ctx.ctx(),filterObj));
+ registerExec(exec.get());
BSONObj objOut;
- ASSERT_EQUALS(Runner::RUNNER_ADVANCED, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_ADVANCED, exec->getNext(&objOut, NULL));
ASSERT_EQUALS(1, objOut["_id"].numberInt());
// After dropping the collection, the runner
// should be dead.
dropCollection();
- ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_DEAD, exec->getNext(&objOut, NULL));
- deregisterRunner(ssr.get());
+ deregisterExec(exec.get());
ctx.commit();
}
};
@@ -213,7 +207,7 @@ namespace QuerySingleSolutionRunner {
* Test dropping the collection while the
* SingleSolutionRunner is doing an index scan.
*/
- class DropIndexScan : public SingleSolutionRunnerBase {
+ class DropIndexScan : public PlanExecutorBase {
public:
void run() {
Client::WriteContext ctx(&_txn, ns());
@@ -223,24 +217,24 @@ namespace QuerySingleSolutionRunner {
BSONObj indexSpec = BSON("a" << 1);
addIndex(indexSpec);
- scoped_ptr<SingleSolutionRunner> ssr(makeIndexScanRunner(ctx.ctx(), indexSpec, 7, 10));
- registerRunner(ssr.get());
+ scoped_ptr<PlanExecutor> exec(makeIndexScanExec(ctx.ctx(), indexSpec, 7, 10));
+ registerExec(exec.get());
BSONObj objOut;
- ASSERT_EQUALS(Runner::RUNNER_ADVANCED, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_ADVANCED, exec->getNext(&objOut, NULL));
ASSERT_EQUALS(7, objOut["a"].numberInt());
// After dropping the collection, the runner
// should be dead.
dropCollection();
- ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_DEAD, exec->getNext(&objOut, NULL));
- deregisterRunner(ssr.get());
+ deregisterExec(exec.get());
ctx.commit();
}
};
- class SnapshotBase : public SingleSolutionRunnerBase {
+ class SnapshotBase : public PlanExecutorBase {
protected:
void setupCollection() {
insert(BSON("_id" << 1 << "a" << 1));
@@ -265,15 +259,15 @@ namespace QuerySingleSolutionRunner {
}
/**
- * Given an array of ints, 'expectedIds', and a SingleSolutionRunner,
- * 'ssr', uses the runner to iterate through the collection. While
+ * Given an array of ints, 'expectedIds', and a PlanExecutor,
+ * 'exec', uses the executor to iterate through the collection. While
* iterating, asserts that the _id of each successive document equals
* the respective integer in 'expectedIds'.
*/
- void checkIds(int* expectedIds, SingleSolutionRunner* ssr) {
+ void checkIds(int* expectedIds, PlanExecutor* exec) {
BSONObj objOut;
int idcount = 0;
- while (Runner::RUNNER_ADVANCED == ssr->getNext(&objOut, NULL)) {
+ while (Runner::RUNNER_ADVANCED == exec->getNext(&objOut, NULL)) {
ASSERT_EQUALS(expectedIds[idcount], objOut["_id"].numberInt());
++idcount;
}
@@ -292,16 +286,16 @@ namespace QuerySingleSolutionRunner {
setupCollection();
BSONObj filterObj = fromjson("{a: {$gte: 2}}");
- scoped_ptr<SingleSolutionRunner> ssr(makeCollScanRunner(ctx.ctx(),filterObj));
+ scoped_ptr<PlanExecutor> exec(makeCollScanExec(ctx.ctx(),filterObj));
BSONObj objOut;
- ASSERT_EQUALS(Runner::RUNNER_ADVANCED, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_ADVANCED, exec->getNext(&objOut, NULL));
ASSERT_EQUALS(2, objOut["a"].numberInt());
forceDocumentMove();
int ids[] = {3, 4, 2};
- checkIds(ids, ssr.get());
+ checkIds(ids, exec.get());
ctx.commit();
}
};
@@ -320,10 +314,10 @@ namespace QuerySingleSolutionRunner {
addIndex(indexSpec);
BSONObj filterObj = fromjson("{a: {$gte: 2}}");
- scoped_ptr<SingleSolutionRunner> ssr(makeIndexScanRunner(ctx.ctx(), indexSpec, 2, 5));
+ scoped_ptr<PlanExecutor> exec(makeIndexScanExec(ctx.ctx(), indexSpec, 2, 5));
BSONObj objOut;
- ASSERT_EQUALS(Runner::RUNNER_ADVANCED, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_ADVANCED, exec->getNext(&objOut, NULL));
ASSERT_EQUALS(2, objOut["a"].numberInt());
forceDocumentMove();
@@ -331,7 +325,7 @@ namespace QuerySingleSolutionRunner {
// Since this time we're scanning the _id index,
// we should not see the moved document again.
int ids[] = {3, 4};
- checkIds(ids, ssr.get());
+ checkIds(ids, exec.get());
ctx.commit();
}
};
@@ -343,18 +337,18 @@ namespace QuerySingleSolutionRunner {
/**
* Test invalidation of ClientCursor.
*/
- class Invalidate : public SingleSolutionRunnerBase {
+ class Invalidate : public PlanExecutorBase {
public:
void run() {
Client::WriteContext ctx(&_txn, ns());
insert(BSON("a" << 1 << "b" << 1));
BSONObj filterObj = fromjson("{_id: {$gt: 0}, b: {$gt: 0}}");
- SingleSolutionRunner* ssr = makeCollScanRunner(ctx.ctx(),filterObj);
+ PlanExecutor* exec = makeCollScanExec(ctx.ctx(),filterObj);
// Make a client cursor from the runner.
new ClientCursor(ctx.ctx().db()->getCollection(&_txn, ns()),
- ssr, 0, BSONObj());
+ exec, 0, BSONObj());
// There should be one cursor before invalidation,
// and zero cursors after invalidation.
@@ -369,7 +363,7 @@ namespace QuerySingleSolutionRunner {
* Test that pinned client cursors persist even after
* invalidation.
*/
- class InvalidatePinned : public SingleSolutionRunnerBase {
+ class InvalidatePinned : public PlanExecutorBase {
public:
void run() {
Client::WriteContext ctx(&_txn, ns());
@@ -378,11 +372,11 @@ namespace QuerySingleSolutionRunner {
Collection* collection = ctx.ctx().db()->getCollection(&_txn, ns());
BSONObj filterObj = fromjson("{_id: {$gt: 0}, b: {$gt: 0}}");
- SingleSolutionRunner* ssr = makeCollScanRunner(ctx.ctx(),filterObj);
+ PlanExecutor* exec = makeCollScanExec(ctx.ctx(),filterObj);
// Make a client cursor from the runner.
ClientCursor* cc = new ClientCursor(collection,
- ssr, 0, BSONObj());
+ exec, 0, BSONObj());
ClientCursorPin ccPin(collection,cc->cursorid());
// If the cursor is pinned, it sticks around,
@@ -393,7 +387,7 @@ namespace QuerySingleSolutionRunner {
// The invalidation should have killed the runner.
BSONObj objOut;
- ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL));
+ ASSERT_EQUALS(Runner::RUNNER_DEAD, exec->getNext(&objOut, NULL));
// Deleting the underlying cursor should cause the
// number of cursors to return to 0.
@@ -407,7 +401,7 @@ namespace QuerySingleSolutionRunner {
* Test that client cursors time out and get
* deleted.
*/
- class Timeout : public SingleSolutionRunnerBase {
+ class Timeout : public PlanExecutorBase {
public:
void run() {
{
@@ -421,10 +415,10 @@ namespace QuerySingleSolutionRunner {
Collection* collection = ctx.ctx().db()->getCollection(&_txn, ns());
BSONObj filterObj = fromjson("{_id: {$gt: 0}, b: {$gt: 0}}");
- SingleSolutionRunner* ssr = makeCollScanRunner(ctx.ctx(),filterObj);
+ PlanExecutor* exec = makeCollScanExec(ctx.ctx(),filterObj);
// Make a client cursor from the runner.
- new ClientCursor(collection, ssr, 0, BSONObj());
+ new ClientCursor(collection, exec, 0, BSONObj());
}
// There should be one cursor before timeout,
@@ -439,7 +433,7 @@ namespace QuerySingleSolutionRunner {
class All : public Suite {
public:
- All() : Suite( "query_single_solution_runner" ) { }
+ All() : Suite( "query_plan_executor" ) { }
void setupTests() {
add<DropCollScan>();
@@ -450,6 +444,6 @@ namespace QuerySingleSolutionRunner {
add<ClientCursor::InvalidatePinned>();
add<ClientCursor::Timeout>();
}
- } queryMultiPlanRunnerAll;
+ } queryPlanExecutorAll;
-} // namespace QuerySingleSolutionRunner
+} // namespace QueryPlanExecutor
diff --git a/src/mongo/dbtests/query_stage_and.cpp b/src/mongo/dbtests/query_stage_and.cpp
index 2f7fa19bea5..36e292b8c4f 100644
--- a/src/mongo/dbtests/query_stage_and.cpp
+++ b/src/mongo/dbtests/query_stage_and.cpp
@@ -186,7 +186,7 @@ namespace QueryStageAnd {
}
}
size_t memUsageAfter = ah->getMemUsage();
- ah->recoverFromYield();
+ ah->recoverFromYield(&_txn);
// Invalidating a read object should decrease memory usage.
ASSERT_LESS_THAN(memUsageAfter, memUsageBefore);
@@ -291,7 +291,7 @@ namespace QueryStageAnd {
// Look ahead results do not count towards memory usage.
ASSERT_EQUALS(memUsageBefore, memUsageAfter);
- ah->recoverFromYield();
+ ah->recoverFromYield(&_txn);
// The deleted obj should show up in flagged.
ASSERT_EQUALS(size_t(1), flagged.size());
@@ -802,7 +802,7 @@ namespace QueryStageAnd {
ah->prepareToYield();
ah->invalidate(*data.begin(), INVALIDATION_DELETION);
remove(coll->docFor(*data.begin()));
- ah->recoverFromYield();
+ ah->recoverFromYield(&_txn);
// Make sure the nuked obj is actually in the flagged data.
ASSERT_EQUALS(ws.getFlagged().size(), size_t(1));
@@ -841,7 +841,7 @@ namespace QueryStageAnd {
ah->prepareToYield();
ah->invalidate(*it, INVALIDATION_DELETION);
remove(coll->docFor(*it));
- ah->recoverFromYield();
+ ah->recoverFromYield(&_txn);
// Get all results aside from the two we killed.
while (!ah->isEOF()) {
diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp
index 06428a98900..797d0af3d28 100644
--- a/src/mongo/dbtests/query_stage_collscan.cpp
+++ b/src/mongo/dbtests/query_stage_collscan.cpp
@@ -281,7 +281,7 @@ namespace QueryStageCollectionScan {
scan->prepareToYield();
scan->invalidate(locs[count], INVALIDATION_DELETION);
remove(coll->docFor(locs[count]));
- scan->recoverFromYield();
+ scan->recoverFromYield(&_txn);
// Skip over locs[count].
++count;
@@ -343,7 +343,7 @@ namespace QueryStageCollectionScan {
scan->prepareToYield();
scan->invalidate(locs[count], INVALIDATION_DELETION);
remove(coll->docFor(locs[count]));
- scan->recoverFromYield();
+ scan->recoverFromYield(&_txn);
// Skip over locs[count].
++count;
diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp
index 6a7a039008e..d457342c12f 100644
--- a/src/mongo/dbtests/query_stage_count.cpp
+++ b/src/mongo/dbtests/query_stage_count.cpp
@@ -333,7 +333,7 @@ namespace QueryStageCount {
count.prepareToYield();
// Recover from yield
- count.recoverFromYield();
+ count.recoverFromYield(&_txn);
// finish counting
while (PlanStage::IS_EOF != countState) {
@@ -388,7 +388,7 @@ namespace QueryStageCount {
remove(BSON("a" << GTE << 5));
// Recover from yield
- count.recoverFromYield();
+ count.recoverFromYield(&_txn);
// finish counting
while (PlanStage::IS_EOF != countState) {
@@ -446,7 +446,7 @@ namespace QueryStageCount {
insert(BSON("a" << 6.5));
// Recover from yield
- count.recoverFromYield();
+ count.recoverFromYield(&_txn);
// finish counting
while (PlanStage::IS_EOF != countState) {
@@ -501,7 +501,7 @@ namespace QueryStageCount {
insert(BSON("a" << BSON_ARRAY(10 << 11)));
// Recover from yield
- count.recoverFromYield();
+ count.recoverFromYield(&_txn);
// finish counting
while (PlanStage::IS_EOF != countState) {
@@ -625,7 +625,7 @@ namespace QueryStageCount {
remove(BSON("a" << 1 << "b" << 5));
// Recover from yield
- count.recoverFromYield();
+ count.recoverFromYield(&_txn);
// finish counting
while (PlanStage::IS_EOF != countState) {
diff --git a/src/mongo/dbtests/query_stage_merge_sort.cpp b/src/mongo/dbtests/query_stage_merge_sort.cpp
index 0a1492c4b0d..1358315a5ca 100644
--- a/src/mongo/dbtests/query_stage_merge_sort.cpp
+++ b/src/mongo/dbtests/query_stage_merge_sort.cpp
@@ -547,7 +547,7 @@ namespace QueryStageMergeSortTests {
// Invalidate locs[11]. Should force a fetch. We don't get it back.
ms->prepareToYield();
ms->invalidate(*it, INVALIDATION_DELETION);
- ms->recoverFromYield();
+ ms->recoverFromYield(&_txn);
// Make sure locs[11] was fetched for us.
{
diff --git a/src/mongo/dbtests/query_stage_near.cpp b/src/mongo/dbtests/query_stage_near.cpp
index c4939d16e75..ae31c1e6249 100644
--- a/src/mongo/dbtests/query_stage_near.cpp
+++ b/src/mongo/dbtests/query_stage_near.cpp
@@ -85,7 +85,7 @@ namespace {
virtual void prepareToYield() {
}
- virtual void recoverFromYield() {
+ virtual void recoverFromYield(OperationContext* opCtx) {
}
virtual void invalidate(const DiskLoc& dl, InvalidationType type) {
diff --git a/src/mongo/dbtests/query_stage_sort.cpp b/src/mongo/dbtests/query_stage_sort.cpp
index 81e500cb238..fe04b977f16 100644
--- a/src/mongo/dbtests/query_stage_sort.cpp
+++ b/src/mongo/dbtests/query_stage_sort.cpp
@@ -289,7 +289,7 @@ namespace QueryStageSortTests {
ss->prepareToYield();
set<DiskLoc>::iterator it = locs.begin();
ss->invalidate(*it++, INVALIDATION_DELETION);
- ss->recoverFromYield();
+ ss->recoverFromYield(&_txn);
// Read the rest of the data from the mock stage.
while (!ms->isEOF()) {
@@ -305,7 +305,7 @@ namespace QueryStageSortTests {
while (it != locs.end()) {
ss->invalidate(*it++, INVALIDATION_DELETION);
}
- ss->recoverFromYield();
+ ss->recoverFromYield(&_txn);
// Invalidation of data in the sort stage fetches it but passes it through.
int count = 0;
diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp
index 591cb3162fd..5c7e1061dbe 100644
--- a/src/mongo/s/d_migrate.cpp
+++ b/src/mongo/s/d_migrate.cpp
@@ -53,6 +53,7 @@
#include "mongo/db/clientcursor.h"
#include "mongo/db/commands.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/exec/plan_stage.h"
#include "mongo/db/storage/mmap_v1/dur.h"
#include "mongo/db/field_parser.h"
#include "mongo/db/hasher.h"
@@ -263,7 +264,7 @@ namespace mongo {
"section" << endl;
- _dummyRunner.reset( NULL );
+ _deleteNotifyExec.reset( NULL );
Lock::GlobalWrite lk(txn->lockState());
log() << "MigrateFromStatus::done Global lock acquired" << endl;
@@ -423,8 +424,13 @@ namespace mongo {
return false;
}
- invariant( _dummyRunner.get() == NULL );
- _dummyRunner.reset(new DummyRunner(txn, _ns, collection));
+ invariant( _deleteNotifyExec.get() == NULL );
+ WorkingSet* ws = new WorkingSet();
+ DeleteNotificationStage* dns = new DeleteNotificationStage();
+ // Takes ownership of 'ws' and 'dns'.
+ PlanExecutor* deleteNotifyExec = new PlanExecutor(ws, dns, collection);
+ deleteNotifyExec->registerExecInternalPlan();
+ _deleteNotifyExec.reset(deleteNotifyExec);
// Allow multiKey based on the invariant that shard keys must be single-valued.
// Therefore, any multi-key index prefixed by shard key cannot be multikey over
@@ -442,7 +448,8 @@ namespace mongo {
BSONObj min = Helpers::toKeyFormat( kp.extendRangeBound( _min, false ) );
BSONObj max = Helpers::toKeyFormat( kp.extendRangeBound( _max, false ) );
- auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max, false));
+ auto_ptr<PlanExecutor> exec(
+ InternalPlanner::indexScan(txn, collection, idx, min, max, false));
// use the average object size to estimate how many objects a full chunk would carry
// do that while traversing the chunk's range using the sharding index, below
@@ -465,7 +472,7 @@ namespace mongo {
bool isLargeChunk = false;
unsigned long long recCount = 0;;
DiskLoc dl;
- while (Runner::RUNNER_ADVANCED == runner->getNext(NULL, &dl)) {
+ while (Runner::RUNNER_ADVANCED == exec->getNext(NULL, &dl)) {
if ( ! isLargeChunk ) {
scoped_spinlock lk( _trackerLocks );
_cloneLocs.insert( dl );
@@ -475,7 +482,7 @@ namespace mongo {
isLargeChunk = true;
}
}
- runner.reset();
+ exec.reset();
if ( isLargeChunk ) {
warning() << "cannot move chunk: the maximum number of documents for a chunk is "
@@ -628,26 +635,16 @@ namespace mongo {
bool _getActive() const { scoped_lock l(_mutex); return _active; }
void _setActive( bool b ) { scoped_lock l(_mutex); _active = b; }
-
- class DummyRunner : public Runner {
+ /**
+ * Used to receive invalidation notifications.
+ *
+ * XXX: move to the exec/ directory.
+ */
+ class DeleteNotificationStage : public PlanStage {
public:
- DummyRunner(OperationContext* txn,
- const StringData& ns,
- Collection* collection ) {
- _ns = ns.toString();
- _txn = txn;
- _collection = collection;
- _collection->cursorCache()->registerRunner( this );
- }
- ~DummyRunner() {
- if ( !_collection )
- return;
- Client::ReadContext ctx(_txn, _ns);
- Collection* collection = ctx.ctx().db()->getCollection( _txn, _ns );
- invariant( _collection == collection );
- _collection->cursorCache()->deregisterRunner( this );
- }
- virtual RunnerState getNext(BSONObj* objOut, DiskLoc* dlOut) {
+ virtual void invalidate(const DiskLoc& dl, InvalidationType type);
+
+ virtual StageState work(WorkingSetID* out) {
invariant( false );
}
virtual bool isEOF() {
@@ -655,38 +652,42 @@ namespace mongo {
return false;
}
virtual void kill() {
- _collection = NULL;
}
- virtual void saveState() {
+ virtual void prepareToYield() {
invariant( false );
}
- virtual bool restoreState(OperationContext* opCtx) {
+ virtual void recoverFromYield(OperationContext* opCtx) {
invariant( false );
}
- virtual const string& ns() {
+ virtual PlanStageStats* getStats() {
invariant( false );
- return _ns;
+ return NULL;
}
- virtual void invalidate(const DiskLoc& dl, InvalidationType type);
- virtual const Collection* collection() {
- return _collection;
+ virtual CommonStats* getCommonStats() {
+ invariant( false );
+ return NULL;
}
- virtual Status getInfo(TypeExplain** explain, PlanInfo** planInfo) const {
- return Status( ErrorCodes::InternalError, "no" );
+ virtual SpecificStats* getSpecificStats() {
+ invariant( false );
+ return NULL;
+ }
+ virtual std::vector<PlanStage*> getChildren() const {
+ invariant( false );
+ vector<PlanStage*> empty;
+ return empty;
+ }
+ virtual StageType stageType() const {
+ invariant( false );
+ return STAGE_NOTIFY_DELETE;
}
-
- private:
- string _ns;
- OperationContext* _txn;
- Collection* _collection;
};
- scoped_ptr<DummyRunner> _dummyRunner;
+ scoped_ptr<PlanExecutor> _deleteNotifyExec;
} migrateFromStatus;
- void MigrateFromStatus::DummyRunner::invalidate(const DiskLoc& dl,
- InvalidationType type) {
+ void MigrateFromStatus::DeleteNotificationStage::invalidate(const DiskLoc& dl,
+ InvalidationType type) {
if ( type == INVALIDATION_DELETION ) {
migrateFromStatus.aboutToDelete( dl );
}
diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp
index 3841c25b177..3c7a79a207c 100644
--- a/src/mongo/s/d_split.cpp
+++ b/src/mongo/s/d_split.cpp
@@ -146,8 +146,9 @@ namespace mongo {
max = Helpers::toKeyFormat( kp.extendRangeBound( max, false ) );
}
- auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max,
- false, InternalPlanner::FORWARD));
+ auto_ptr<PlanExecutor> exec(InternalPlanner::indexScan(txn, collection, idx,
+ min, max, false,
+ InternalPlanner::FORWARD));
// Find the 'missingField' value used to represent a missing document field in a key of
// this index.
@@ -163,7 +164,7 @@ namespace mongo {
DiskLoc loc;
BSONObj currKey;
- while (Runner::RUNNER_ADVANCED == runner->getNext(&currKey, &loc)) {
+ while (Runner::RUNNER_ADVANCED == exec->getNext(&currKey, &loc)) {
//check that current key contains non missing elements for all fields in keyPattern
BSONObjIterator i( currKey );
for( int k = 0; k < keyPatternLength ; k++ ) {
@@ -377,11 +378,12 @@ namespace mongo {
long long currCount = 0;
long long numChunks = 0;
- auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max,
+ auto_ptr<PlanExecutor> exec(
+ InternalPlanner::indexScan(txn, collection, idx, min, max,
false, InternalPlanner::FORWARD));
BSONObj currKey;
- Runner::RunnerState state = runner->getNext(&currKey, NULL);
+ Runner::RunnerState state = exec->getNext(&currKey, NULL);
if (Runner::RUNNER_ADVANCED != state) {
errmsg = "can't open a cursor for splitting (desired range is possibly empty)";
return false;
@@ -419,7 +421,7 @@ namespace mongo {
break;
}
- state = runner->getNext(&currKey, NULL);
+ state = exec->getNext(&currKey, NULL);
}
if ( ! forceMedianSplit )
@@ -435,10 +437,10 @@ namespace mongo {
currCount = 0;
log() << "splitVector doing another cycle because of force, keyCount now: " << keyCount << endl;
- runner.reset(InternalPlanner::indexScan(txn, collection, idx, min, max,
+ exec.reset(InternalPlanner::indexScan(txn, collection, idx, min, max,
false, InternalPlanner::FORWARD));
- state = runner->getNext(&currKey, NULL);
+ state = exec->getNext(&currKey, NULL);
}
//
@@ -879,12 +881,12 @@ namespace mongo {
BSONObj newmin = Helpers::toKeyFormat( kp.extendRangeBound( chunk.min, false) );
BSONObj newmax = Helpers::toKeyFormat( kp.extendRangeBound( chunk.max, false) );
- auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx,
- newmin, newmax, false));
+ auto_ptr<PlanExecutor> exec(InternalPlanner::indexScan(txn, collection, idx,
+ newmin, newmax, false));
// check if exactly one document found
- if (Runner::RUNNER_ADVANCED == runner->getNext(NULL, NULL)) {
- if (Runner::RUNNER_EOF == runner->getNext(NULL, NULL)) {
+ if (Runner::RUNNER_ADVANCED == exec->getNext(NULL, NULL)) {
+ if (Runner::RUNNER_EOF == exec->getNext(NULL, NULL)) {
result.append( "shouldMigrate",
BSON("min" << chunk.min << "max" << chunk.max) );
break;