diff options
20 files changed, 238 insertions, 327 deletions
diff --git a/src/mongo/db/exec/SConscript b/src/mongo/db/exec/SConscript index e54f69b82d7..931ea2abbd1 100644 --- a/src/mongo/db/exec/SConscript +++ b/src/mongo/db/exec/SConscript @@ -112,7 +112,6 @@ env.CppUnitTest( "exec", "$BUILD_DIR/mongo/db/serveronly", "$BUILD_DIR/mongo/dbtests/mocklib", - "$BUILD_DIR/mongo/util/clock_source_mock", "$BUILD_DIR/mongo/util/ntservice_mock", ], NO_CRUTCH = True, @@ -128,7 +127,6 @@ env.CppUnitTest( "$BUILD_DIR/mongo/db/serveronly", "$BUILD_DIR/mongo/dbtests/mocklib", "$BUILD_DIR/mongo/db/query/collation/collator_interface_mock", - "$BUILD_DIR/mongo/util/clock_source_mock", "$BUILD_DIR/mongo/util/ntservice_mock", ], NO_CRUTCH = True, diff --git a/src/mongo/db/exec/cached_plan.cpp b/src/mongo/db/exec/cached_plan.cpp index 3425a2562b5..7604d5ce465 100644 --- a/src/mongo/db/exec/cached_plan.cpp +++ b/src/mongo/db/exec/cached_plan.cpp @@ -74,7 +74,7 @@ Status CachedPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { // Adds the amount of time taken by pickBestPlan() to executionTimeMillis. There's lots of // execution work that happens here, so this is needed for the time accounting to // make sense. - ScopedTimer timer(getClock(), &_commonStats.executionTimeMillis); + ScopedTimer timer(&_commonStats.executionTimeMillis); // If we work this many times during the trial period, then we will replan the // query from scratch. diff --git a/src/mongo/db/exec/multi_plan.cpp b/src/mongo/db/exec/multi_plan.cpp index c57e0a5f02f..95c70b47ce0 100644 --- a/src/mongo/db/exec/multi_plan.cpp +++ b/src/mongo/db/exec/multi_plan.cpp @@ -203,7 +203,7 @@ Status MultiPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { // Adds the amount of time taken by pickBestPlan() to executionTimeMillis. There's lots of // execution work that happens here, so this is needed for the time accounting to // make sense. - ScopedTimer timer(getClock(), &_commonStats.executionTimeMillis); + ScopedTimer timer(&_commonStats.executionTimeMillis); size_t numWorks = getTrialPeriodWorks(getOpCtx(), _collection); size_t numResults = getTrialPeriodNumToReturn(*_query); diff --git a/src/mongo/db/exec/plan_stage.cpp b/src/mongo/db/exec/plan_stage.cpp index 13062fa919f..c81679bd8cb 100644 --- a/src/mongo/db/exec/plan_stage.cpp +++ b/src/mongo/db/exec/plan_stage.cpp @@ -33,14 +33,11 @@ #include "mongo/db/exec/plan_stage.h" #include "mongo/db/exec/scoped_timer.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" namespace mongo { PlanStage::StageState PlanStage::work(WorkingSetID* out) { - invariant(_opCtx); - ScopedTimer timer(getClock(), &_commonStats.executionTimeMillis); + ScopedTimer timer(&_commonStats.executionTimeMillis); ++_commonStats.works; StageState workResult = doWork(out); @@ -105,8 +102,4 @@ void PlanStage::reattachToOperationContext(OperationContext* opCtx) { doReattachToOperationContext(); } -ClockSource* PlanStage::getClock() const { - return _opCtx->getServiceContext()->getFastClockSource(); -} - } // namespace mongo diff --git a/src/mongo/db/exec/plan_stage.h b/src/mongo/db/exec/plan_stage.h index c0afd992e72..3ad007c8430 100644 --- a/src/mongo/db/exec/plan_stage.h +++ b/src/mongo/db/exec/plan_stage.h @@ -37,10 +37,9 @@ namespace mongo { -class ClockSource; class Collection; -class OperationContext; class RecordId; +class OperationContext; /** * A PlanStage ("stage") is the basic building block of a "Query Execution Plan." A stage is @@ -358,8 +357,6 @@ protected: */ virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) {} - ClockSource* getClock() const; - OperationContext* getOpCtx() const { return _opCtx; } diff --git a/src/mongo/db/exec/queued_data_stage_test.cpp b/src/mongo/db/exec/queued_data_stage_test.cpp index 26f41ca4c8c..e26d303a833 100644 --- a/src/mongo/db/exec/queued_data_stage_test.cpp +++ b/src/mongo/db/exec/queued_data_stage_test.cpp @@ -32,12 +32,8 @@ #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/exec/working_set.h" -#include "mongo/db/operation_context_noop.h" -#include "mongo/db/service_context.h" -#include "mongo/db/service_context_noop.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" -#include "mongo/util/clock_source_mock.h" using namespace mongo; @@ -46,38 +42,12 @@ namespace { using std::unique_ptr; using stdx::make_unique; -class QueuedDataStageTest : public unittest::Test { -public: - QueuedDataStageTest() { - _service = stdx::make_unique<ServiceContextNoop>(); - _client = _service.get()->makeClient("test"); - _opCtxNoop.reset(new OperationContextNoop(_client.get(), 0)); - _opCtx = _opCtxNoop.get(); - } - -protected: - OperationContext* getOpCtx() { - return _opCtx; - } - -private: - OperationContext* _opCtx; - std::unique_ptr<OperationContextNoop> _opCtxNoop; - - std::unique_ptr<ServiceContextNoop> _service; - - // UniqueClient is declared after ServiceContextNoop because - // members of a class are destroyed in reverse order of declaration and - // UniqueClient must be destroyed before the ServiceContextNoop is destroyed. - ServiceContext::UniqueClient _client; -}; - // // Basic test that we get out valid stats objects. // -TEST_F(QueuedDataStageTest, getValidStats) { +TEST(QueuedDataStageTest, getValidStats) { WorkingSet ws; - auto mock = make_unique<QueuedDataStage>(getOpCtx(), &ws); + auto mock = make_unique<QueuedDataStage>(nullptr, &ws); const CommonStats* commonStats = mock->getCommonStats(); ASSERT_EQUALS(commonStats->works, static_cast<size_t>(0)); const SpecificStats* specificStats = mock->getSpecificStats(); @@ -89,10 +59,10 @@ TEST_F(QueuedDataStageTest, getValidStats) { // // Test that our stats are updated as we perform operations. // -TEST_F(QueuedDataStageTest, validateStats) { +TEST(QueuedDataStageTest, validateStats) { WorkingSet ws; WorkingSetID wsID; - auto mock = make_unique<QueuedDataStage>(getOpCtx(), &ws); + auto mock = make_unique<QueuedDataStage>(nullptr, &ws); // make sure that we're at all zero const CommonStats* stats = mock->getCommonStats(); diff --git a/src/mongo/db/exec/scoped_timer.cpp b/src/mongo/db/exec/scoped_timer.cpp index 8493db68116..e1db4a44ff8 100644 --- a/src/mongo/db/exec/scoped_timer.cpp +++ b/src/mongo/db/exec/scoped_timer.cpp @@ -29,15 +29,16 @@ #include "mongo/platform/basic.h" #include "mongo/db/exec/scoped_timer.h" -#include "mongo/util/clock_source.h" + +#include "mongo/util/net/listen.h" namespace mongo { -ScopedTimer::ScopedTimer(ClockSource* cs, long long* counter) - : _clock(cs), _counter(counter), _start(cs->now()) {} +ScopedTimer::ScopedTimer(long long* counter) + : _counter(counter), _start(Listener::getElapsedTimeMillis()) {} ScopedTimer::~ScopedTimer() { - long long elapsed = durationCount<Milliseconds>(_clock->now() - _start); + long long elapsed = Listener::getElapsedTimeMillis() - _start; *_counter += elapsed; } diff --git a/src/mongo/db/exec/scoped_timer.h b/src/mongo/db/exec/scoped_timer.h index da0a484fabf..3e1c29fe719 100644 --- a/src/mongo/db/exec/scoped_timer.h +++ b/src/mongo/db/exec/scoped_timer.h @@ -30,12 +30,8 @@ #include "mongo/base/disallow_copying.h" -#include "mongo/util/time_support.h" - namespace mongo { -class ClockSource; - /** * This class increments a counter by a rough estimate of the time elapsed since its * construction when it goes out of scope. @@ -44,17 +40,19 @@ class ScopedTimer { MONGO_DISALLOW_COPYING(ScopedTimer); public: - ScopedTimer(ClockSource* cs, long long* counter); + ScopedTimer(long long* counter); ~ScopedTimer(); private: - ClockSource* const _clock; + // Default constructor disallowed. + ScopedTimer(); + // Reference to the counter that we are incrementing with the elapsed time. long long* _counter; // Time at which the timer was constructed. - const Date_t _start; + long long _start; }; } // namespace mongo diff --git a/src/mongo/db/exec/sort_test.cpp b/src/mongo/db/exec/sort_test.cpp index f0cc0d01062..6a45fa27022 100644 --- a/src/mongo/db/exec/sort_test.cpp +++ b/src/mongo/db/exec/sort_test.cpp @@ -34,145 +34,23 @@ #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/json.h" -#include "mongo/db/operation_context_noop.h" #include "mongo/db/query/collation/collator_interface_mock.h" -#include "mongo/db/service_context.h" -#include "mongo/db/service_context_noop.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" -#include "mongo/util/clock_source_mock.h" using namespace mongo; namespace { -class SortStageTest : public unittest::Test { -public: - SortStageTest() { - _service = stdx::make_unique<ServiceContextNoop>(); - _client = _service.get()->makeClient("test"); - _opCtxNoop.reset(new OperationContextNoop(_client.get(), 0)); - _opCtx = _opCtxNoop.get(); - } - - /** - * Test function to verify sort stage. - * SortStageParams will be initialized using patternStr, collator, queryStr and limit. - * inputStr represents the input data set in a BSONObj. - * {input: [doc1, doc2, doc3, ...]} - * expectedStr represents the expected sorted data set. - * {output: [docA, docB, docC, ...]} - */ - void testWork(const char* patternStr, - CollatorInterface* collator, - const char* queryStr, - int limit, - const char* inputStr, - const char* expectedStr) { - // WorkingSet is not owned by stages - // so it's fine to declare - WorkingSet ws; - - // QueuedDataStage will be owned by SortStage. - auto queuedDataStage = stdx::make_unique<QueuedDataStage>(getOpCtx(), &ws); - BSONObj inputObj = fromjson(inputStr); - BSONElement inputElt = inputObj.getField("input"); - ASSERT(inputElt.isABSONObj()); - BSONObjIterator inputIt(inputElt.embeddedObject()); - while (inputIt.more()) { - BSONElement elt = inputIt.next(); - ASSERT(elt.isABSONObj()); - BSONObj obj = elt.embeddedObject().getOwned(); - - // Insert obj from input array into working set. - WorkingSetID id = ws.allocate(); - WorkingSetMember* wsm = ws.get(id); - wsm->obj = Snapshotted<BSONObj>(SnapshotId(), obj); - wsm->transitionToOwnedObj(); - queuedDataStage->pushBack(id); - } - - // Initialize SortStageParams - // Setting limit to 0 means no limit - SortStageParams params; - params.pattern = fromjson(patternStr); - params.collator = collator; - params.limit = limit; - - auto sortKeyGen = stdx::make_unique<SortKeyGeneratorStage>( - getOpCtx(), queuedDataStage.release(), &ws, params.pattern, fromjson(queryStr)); - - SortStage sort(getOpCtx(), params, &ws, sortKeyGen.release()); - - WorkingSetID id = WorkingSet::INVALID_ID; - PlanStage::StageState state = PlanStage::NEED_TIME; - - // Keep working sort stage until data is available. - while (state == PlanStage::NEED_TIME) { - state = sort.work(&id); - } - - // QueuedDataStage's state should be EOF when sort is ready to advance. - ASSERT_TRUE(sort.child()->child()->isEOF()); - - // While there's data to be retrieved, state should be equal to ADVANCED. - // Insert documents into BSON document in this format: - // {output: [docA, docB, docC, ...]} - BSONObjBuilder bob; - BSONArrayBuilder arr(bob.subarrayStart("output")); - while (state == PlanStage::ADVANCED) { - WorkingSetMember* member = ws.get(id); - const BSONObj& obj = member->obj.value(); - arr.append(obj); - state = sort.work(&id); - } - arr.doneFast(); - BSONObj outputObj = bob.obj(); - - // Sort stage should be EOF after data is retrieved. - ASSERT_EQUALS(state, PlanStage::IS_EOF); - ASSERT_TRUE(sort.isEOF()); - - // Finally, we get to compare the sorted results against what we expect. - BSONObj expectedObj = fromjson(expectedStr); - if (outputObj != expectedObj) { - mongoutils::str::stream ss; - // Even though we have the original string representation of the expected output, - // we invoke BSONObj::toString() to get a format consistent with outputObj. - ss << "Unexpected sort result with query=" << queryStr << "; pattern=" << patternStr - << "; limit=" << limit << ":\n" - << "Expected: " << expectedObj.toString() << "\n" - << "Actual: " << outputObj.toString() << "\n"; - FAIL(ss); - } - } - -protected: - OperationContext* getOpCtx() { - return _opCtx; - } - -private: - OperationContext* _opCtx; - std::unique_ptr<OperationContextNoop> _opCtxNoop; - - std::unique_ptr<ServiceContextNoop> _service; - - // UniqueClient is declared after ServiceContextNoop because - // members of a class are destroyed in reverse order of declaration and - // UniqueClient must be destroyed before the ServiceContextNoop is destroyed. - ServiceContext::UniqueClient _client; -}; - -TEST_F(SortStageTest, SortEmptyWorkingSet) { +TEST(SortStageTest, SortEmptyWorkingSet) { WorkingSet ws; // QueuedDataStage will be owned by SortStage. - auto queuedDataStage = stdx::make_unique<QueuedDataStage>(getOpCtx(), &ws); + auto queuedDataStage = stdx::make_unique<QueuedDataStage>(nullptr, &ws); auto sortKeyGen = stdx::make_unique<SortKeyGeneratorStage>( - getOpCtx(), queuedDataStage.release(), &ws, BSONObj(), BSONObj()); + nullptr, queuedDataStage.release(), &ws, BSONObj(), BSONObj()); SortStageParams params; - SortStage sort(getOpCtx(), params, &ws, sortKeyGen.release()); + SortStage sort(nullptr, params, &ws, sortKeyGen.release()); // Check initial EOF state. ASSERT_FALSE(sort.isEOF()); @@ -193,6 +71,98 @@ TEST_F(SortStageTest, SortEmptyWorkingSet) { ASSERT_TRUE(sort.isEOF()); } +/** + * Test function to verify sort stage. + * SortStageParams will be initialized using patternStr, collator, queryStr and limit. + * inputStr represents the input data set in a BSONObj. + * {input: [doc1, doc2, doc3, ...]} + * expectedStr represents the expected sorted data set. + * {output: [docA, docB, docC, ...]} + */ +void testWork(const char* patternStr, + CollatorInterface* collator, + const char* queryStr, + int limit, + const char* inputStr, + const char* expectedStr) { + // WorkingSet is not owned by stages + // so it's fine to declare + WorkingSet ws; + + // QueuedDataStage will be owned by SortStage. + auto queuedDataStage = stdx::make_unique<QueuedDataStage>(nullptr, &ws); + BSONObj inputObj = fromjson(inputStr); + BSONElement inputElt = inputObj.getField("input"); + ASSERT(inputElt.isABSONObj()); + BSONObjIterator inputIt(inputElt.embeddedObject()); + while (inputIt.more()) { + BSONElement elt = inputIt.next(); + ASSERT(elt.isABSONObj()); + BSONObj obj = elt.embeddedObject().getOwned(); + + // Insert obj from input array into working set. + WorkingSetID id = ws.allocate(); + WorkingSetMember* wsm = ws.get(id); + wsm->obj = Snapshotted<BSONObj>(SnapshotId(), obj); + wsm->transitionToOwnedObj(); + queuedDataStage->pushBack(id); + } + + // Initialize SortStageParams + // Setting limit to 0 means no limit + SortStageParams params; + params.pattern = fromjson(patternStr); + params.collator = collator; + params.limit = limit; + + auto sortKeyGen = stdx::make_unique<SortKeyGeneratorStage>( + nullptr, queuedDataStage.release(), &ws, params.pattern, fromjson(queryStr)); + + SortStage sort(nullptr, params, &ws, sortKeyGen.release()); + + WorkingSetID id = WorkingSet::INVALID_ID; + PlanStage::StageState state = PlanStage::NEED_TIME; + + // Keep working sort stage until data is available. + while (state == PlanStage::NEED_TIME) { + state = sort.work(&id); + } + + // QueuedDataStage's state should be EOF when sort is ready to advance. + ASSERT_TRUE(sort.child()->child()->isEOF()); + + // While there's data to be retrieved, state should be equal to ADVANCED. + // Insert documents into BSON document in this format: + // {output: [docA, docB, docC, ...]} + BSONObjBuilder bob; + BSONArrayBuilder arr(bob.subarrayStart("output")); + while (state == PlanStage::ADVANCED) { + WorkingSetMember* member = ws.get(id); + const BSONObj& obj = member->obj.value(); + arr.append(obj); + state = sort.work(&id); + } + arr.doneFast(); + BSONObj outputObj = bob.obj(); + + // Sort stage should be EOF after data is retrieved. + ASSERT_EQUALS(state, PlanStage::IS_EOF); + ASSERT_TRUE(sort.isEOF()); + + // Finally, we get to compare the sorted results against what we expect. + BSONObj expectedObj = fromjson(expectedStr); + if (outputObj != expectedObj) { + mongoutils::str::stream ss; + // Even though we have the original string representation of the expected output, + // we invoke BSONObj::toString() to get a format consistent with outputObj. + ss << "Unexpected sort result with query=" << queryStr << "; pattern=" << patternStr + << "; limit=" << limit << ":\n" + << "Expected: " << expectedObj.toString() << "\n" + << "Actual: " << outputObj.toString() << "\n"; + FAIL(ss); + } +} + // // Limit values // The server interprets limit values from the user as follows: @@ -206,7 +176,7 @@ TEST_F(SortStageTest, SortEmptyWorkingSet) { // Implementation should keep all items fetched from child. // -TEST_F(SortStageTest, SortAscending) { +TEST(SortStageTest, SortAscending) { testWork("{a: 1}", nullptr, "{}", @@ -215,7 +185,7 @@ TEST_F(SortStageTest, SortAscending) { "{output: [{a: 1}, {a: 2}, {a: 3}]}"); } -TEST_F(SortStageTest, SortDescending) { +TEST(SortStageTest, SortDescending) { testWork("{a: -1}", nullptr, "{}", @@ -224,7 +194,7 @@ TEST_F(SortStageTest, SortDescending) { "{output: [{a: 3}, {a: 2}, {a: 1}]}"); } -TEST_F(SortStageTest, SortIrrelevantSortKey) { +TEST(SortStageTest, SortIrrelevantSortKey) { testWork("{b: 1}", nullptr, "{}", @@ -239,7 +209,7 @@ TEST_F(SortStageTest, SortIrrelevantSortKey) { // and discard the rest. // -TEST_F(SortStageTest, SortAscendingWithLimit) { +TEST(SortStageTest, SortAscendingWithLimit) { testWork("{a: 1}", nullptr, "{}", @@ -248,7 +218,7 @@ TEST_F(SortStageTest, SortAscendingWithLimit) { "{output: [{a: 1}, {a: 2}]}"); } -TEST_F(SortStageTest, SortDescendingWithLimit) { +TEST(SortStageTest, SortDescendingWithLimit) { testWork("{a: -1}", nullptr, "{}", @@ -263,7 +233,7 @@ TEST_F(SortStageTest, SortDescendingWithLimit) { // and discard the rest. // -TEST_F(SortStageTest, SortAscendingWithLimitGreaterThanInputSize) { +TEST(SortStageTest, SortAscendingWithLimitGreaterThanInputSize) { testWork("{a: 1}", nullptr, "{}", @@ -272,7 +242,7 @@ TEST_F(SortStageTest, SortAscendingWithLimitGreaterThanInputSize) { "{output: [{a: 1}, {a: 2}, {a: 3}]}"); } -TEST_F(SortStageTest, SortDescendingWithLimitGreaterThanInputSize) { +TEST(SortStageTest, SortDescendingWithLimitGreaterThanInputSize) { testWork("{a: -1}", nullptr, "{}", @@ -286,16 +256,16 @@ TEST_F(SortStageTest, SortDescendingWithLimitGreaterThanInputSize) { // Implementation should optimize this into a running maximum. // -TEST_F(SortStageTest, SortAscendingWithLimitOfOne) { +TEST(SortStageTest, SortAscendingWithLimitOfOne) { testWork("{a: 1}", nullptr, "{}", 1, "{input: [{a: 2}, {a: 1}, {a: 3}]}", "{output: [{a: 1}]}"); } -TEST_F(SortStageTest, SortDescendingWithLimitOfOne) { +TEST(SortStageTest, SortDescendingWithLimitOfOne) { testWork( "{a: -1}", nullptr, "{}", 1, "{input: [{a: 2}, {a: 1}, {a: 3}]}", "{output: [{a: 3}]}"); } -TEST_F(SortStageTest, SortAscendingWithCollation) { +TEST(SortStageTest, SortAscendingWithCollation) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); testWork("{a: 1}", &collator, @@ -305,7 +275,7 @@ TEST_F(SortStageTest, SortAscendingWithCollation) { "{output: [{a: 'aa'}, {a: 'ba'}, {a: 'ab'}]}"); } -TEST_F(SortStageTest, SortDescendingWithCollation) { +TEST(SortStageTest, SortDescendingWithCollation) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); testWork("{a: -1}", &collator, diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index 8be5da178dc..b694a4cc902 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -494,7 +494,7 @@ Status SubplanStage::choosePlanWholeQuery(PlanYieldPolicy* yieldPolicy) { Status SubplanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { // Adds the amount of time taken by pickBestPlan() to executionTimeMillis. There's lots of // work that happens here, so this is needed for the time accounting to make sense. - ScopedTimer timer(getClock(), &_commonStats.executionTimeMillis); + ScopedTimer timer(&_commonStats.executionTimeMillis); // Plan each branch of the $or. Status subplanningStatus = planSubqueries(); diff --git a/src/mongo/db/pipeline/document_source_test.cpp b/src/mongo/db/pipeline/document_source_test.cpp index c7fcdab4675..bf4a2ad32e9 100644 --- a/src/mongo/db/pipeline/document_source_test.cpp +++ b/src/mongo/db/pipeline/document_source_test.cpp @@ -37,9 +37,9 @@ #include "mongo/db/pipeline/pipeline.h" #include "mongo/db/service_context.h" #include "mongo/db/service_context_noop.h" +#include "mongo/stdx/memory.h" #include "mongo/db/storage/storage_options.h" #include "mongo/dbtests/dbtests.h" -#include "mongo/stdx/memory.h" #include "mongo/util/clock_source_mock.h" #include "mongo/unittest/temp_dir.h" diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp index 542c61dc8ce..79517b5b193 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp @@ -88,8 +88,8 @@ BSONObj createRecvChunkCommitRequest(const NamespaceString& nss, */ class DeleteNotificationStage final : public PlanStage { public: - DeleteNotificationStage(MigrationChunkClonerSourceLegacy* cloner, OperationContext* txn) - : PlanStage("SHARDING_NOTIFY_DELETE", txn), _cloner(cloner) {} + DeleteNotificationStage(MigrationChunkClonerSourceLegacy* cloner) + : PlanStage("SHARDING_NOTIFY_DELETE", nullptr), _cloner(cloner) {} void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) override { if (type == INVALIDATION_DELETION) { @@ -527,7 +527,7 @@ Status MigrationChunkClonerSourceLegacy::_storeCurrentLocs(OperationContext* txn auto statusWithPlanExecutor = PlanExecutor::make(txn, stdx::make_unique<WorkingSet>(), - stdx::make_unique<DeleteNotificationStage>(this, txn), + stdx::make_unique<DeleteNotificationStage>(this), collection, PlanExecutor::YIELD_MANUAL); invariant(statusWithPlanExecutor.isOK()); diff --git a/src/mongo/db/storage/mmap_v1/dur_journal.cpp b/src/mongo/db/storage/mmap_v1/dur_journal.cpp index 524085a87e9..ea3b02d9476 100644 --- a/src/mongo/db/storage/mmap_v1/dur_journal.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_journal.cpp @@ -58,6 +58,7 @@ #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" +#include "mongo/util/net/listen.h" // getelapsedtimemillis #include "mongo/util/progress_meter.h" #include "mongo/util/timer.h" diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index 970f7d02ac9..8871e17a5bf 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -51,9 +51,12 @@ #include "mongo/db/query/stage_builder.h" #include "mongo/dbtests/dbtests.h" #include "mongo/stdx/memory.h" +#include "mongo/util/clock_source_mock.h" namespace mongo { +const std::unique_ptr<ClockSource> clockSource = stdx::make_unique<ClockSourceMock>(); + // How we access the external setParameter testing bool. extern std::atomic<bool> internalQueryForceIntersectionPlans; // NOLINT @@ -129,8 +132,7 @@ public: _mps->addPlan(solutions[i], root, ws.get()); } // This is what sets a backup plan, should we test for it. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, - _txn.getServiceContext()->getFastClockSource()); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); _mps->pickBestPlan(&yieldPolicy); ASSERT(_mps->bestPlanChosen()); diff --git a/src/mongo/dbtests/query_stage_cached_plan.cpp b/src/mongo/dbtests/query_stage_cached_plan.cpp index f090e61f8c4..1d41db88d93 100644 --- a/src/mongo/dbtests/query_stage_cached_plan.cpp +++ b/src/mongo/dbtests/query_stage_cached_plan.cpp @@ -47,9 +47,11 @@ #include "mongo/db/query/query_planner_params.h" #include "mongo/dbtests/dbtests.h" #include "mongo/stdx/memory.h" +#include "mongo/util/clock_source_mock.h" namespace QueryStageCachedPlan { +const std::unique_ptr<ClockSource> clockSource = stdx::make_unique<ClockSourceMock>(); static const NamespaceString nss("unittests.QueryStageCachedPlan"); class QueryStageCachedPlanBase { @@ -147,8 +149,7 @@ public: &_txn, collection, &_ws, cq.get(), plannerParams, decisionWorks, mockChild.release()); // This should succeed after triggering a replan. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, - _txn.getServiceContext()->getFastClockSource()); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(cachedPlanStage.pickBestPlan(&yieldPolicy)); // Make sure that we get 2 legit results back. @@ -219,8 +220,7 @@ public: &_txn, collection, &_ws, cq.get(), plannerParams, decisionWorks, mockChild.release()); // This should succeed after triggering a replan. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, - _txn.getServiceContext()->getFastClockSource()); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(cachedPlanStage.pickBestPlan(&yieldPolicy)); // Make sure that we get 2 legit results back. diff --git a/src/mongo/dbtests/query_stage_ensure_sorted.cpp b/src/mongo/dbtests/query_stage_ensure_sorted.cpp index f89bbd42ea5..8ba3b552eeb 100644 --- a/src/mongo/dbtests/query_stage_ensure_sorted.cpp +++ b/src/mongo/dbtests/query_stage_ensure_sorted.cpp @@ -28,7 +28,6 @@ #include "mongo/platform/basic.h" -#include "mongo/db/client.h" #include "mongo/db/exec/ensure_sorted.h" #include "mongo/db/exec/sort_key_generator.h" #include "mongo/db/exec/queued_data_stage.h" @@ -41,81 +40,12 @@ namespace mongo { namespace { -class QueryStageEnsureSortedTest : public unittest::Test { -public: - /** - * Test function to verify the EnsureSortedStage. - * patternStr is the JSON representation of the sort pattern BSONObj. - * inputStr represents the input data set in a BSONObj. - * {input: [doc1, doc2, doc3, ...]} - * expectedStr represents the expected output data set. - * {output: [docA, docB, docC, ...]} - * collator is passed to EnsureSortedStage() for string comparisons. - */ - void testWork(const char* patternStr, - const char* inputStr, - const char* expectedStr, - CollatorInterface* collator = nullptr) { - WorkingSet ws; - auto queuedDataStage = stdx::make_unique<QueuedDataStage>(_opCtx, &ws); - BSONObj inputObj = fromjson(inputStr); - BSONElement inputElt = inputObj["input"]; - ASSERT(inputElt.isABSONObj()); - - for (auto&& elt : inputElt.embeddedObject()) { - ASSERT(elt.isABSONObj()); - BSONObj obj = elt.embeddedObject().getOwned(); - - // Insert obj from input array into working set. - WorkingSetID id = ws.allocate(); - WorkingSetMember* wsm = ws.get(id); - wsm->obj = Snapshotted<BSONObj>(SnapshotId(), obj); - wsm->transitionToOwnedObj(); - queuedDataStage->pushBack(id); - } - - // Initialization. - BSONObj pattern = fromjson(patternStr); - auto sortKeyGen = stdx::make_unique<SortKeyGeneratorStage>( - _opCtx, queuedDataStage.release(), &ws, pattern, BSONObj()); - EnsureSortedStage ess(_opCtx, pattern, collator, &ws, sortKeyGen.release()); - WorkingSetID id = WorkingSet::INVALID_ID; - PlanStage::StageState state = PlanStage::NEED_TIME; - - // Documents are inserted into BSON document in this format: - // {output: [docA, docB, docC, ...]} - BSONObjBuilder bob; - BSONArrayBuilder arr(bob.subarrayStart("output")); - while (state != PlanStage::IS_EOF) { - state = ess.work(&id); - ASSERT_NE(state, PlanStage::DEAD); - ASSERT_NE(state, PlanStage::FAILURE); - if (state == PlanStage::ADVANCED) { - WorkingSetMember* member = ws.get(id); - const BSONObj& obj = member->obj.value(); - arr.append(obj); - } - } - ASSERT_TRUE(ess.isEOF()); - arr.doneFast(); - BSONObj outputObj = bob.obj(); - - // Compare the results against what we expect. - BSONObj expectedObj = fromjson(expectedStr); - ASSERT_EQ(outputObj, expectedObj); - } - -protected: - const ServiceContext::UniqueOperationContext _uniqOpCtx = cc().makeOperationContext(); - OperationContext* const _opCtx = _uniqOpCtx.get(); -}; - -TEST_F(QueryStageEnsureSortedTest, EnsureSortedEmptyWorkingSet) { +TEST(QueryStageEnsureSorted, EnsureSortedEmptyWorkingSet) { WorkingSet ws; - auto queuedDataStage = stdx::make_unique<QueuedDataStage>(_opCtx, &ws); + auto queuedDataStage = stdx::make_unique<QueuedDataStage>(nullptr, &ws); auto sortKeyGen = stdx::make_unique<SortKeyGeneratorStage>( - _opCtx, queuedDataStage.release(), &ws, BSONObj(), BSONObj()); - EnsureSortedStage ess(_opCtx, BSONObj(), nullptr, &ws, sortKeyGen.release()); + nullptr, queuedDataStage.release(), &ws, BSONObj(), BSONObj()); + EnsureSortedStage ess(nullptr, BSONObj(), nullptr, &ws, sortKeyGen.release()); WorkingSetID id = WorkingSet::INVALID_ID; PlanStage::StageState state = PlanStage::NEED_TIME; @@ -126,19 +56,81 @@ TEST_F(QueryStageEnsureSortedTest, EnsureSortedEmptyWorkingSet) { ASSERT_EQ(state, PlanStage::IS_EOF); } +/** + * Test function to verify the EnsureSortedStage. + * patternStr is the JSON representation of the sort pattern BSONObj. + * inputStr represents the input data set in a BSONObj. + * {input: [doc1, doc2, doc3, ...]} + * expectedStr represents the expected output data set. + * {output: [docA, docB, docC, ...]} + * collator is passed to EnsureSortedStage() for string comparisons. + */ +void testWork(const char* patternStr, + const char* inputStr, + const char* expectedStr, + const CollatorInterface* collator = nullptr) { + WorkingSet ws; + auto queuedDataStage = stdx::make_unique<QueuedDataStage>(nullptr, &ws); + BSONObj inputObj = fromjson(inputStr); + BSONElement inputElt = inputObj["input"]; + ASSERT(inputElt.isABSONObj()); + + for (auto&& elt : inputElt.embeddedObject()) { + ASSERT(elt.isABSONObj()); + BSONObj obj = elt.embeddedObject().getOwned(); + + // Insert obj from input array into working set. + WorkingSetID id = ws.allocate(); + WorkingSetMember* wsm = ws.get(id); + wsm->obj = Snapshotted<BSONObj>(SnapshotId(), obj); + wsm->transitionToOwnedObj(); + queuedDataStage->pushBack(id); + } + + // Initialization. + BSONObj pattern = fromjson(patternStr); + auto sortKeyGen = stdx::make_unique<SortKeyGeneratorStage>( + nullptr, queuedDataStage.release(), &ws, pattern, BSONObj()); + EnsureSortedStage ess(nullptr, pattern, collator, &ws, sortKeyGen.release()); + WorkingSetID id = WorkingSet::INVALID_ID; + PlanStage::StageState state = PlanStage::NEED_TIME; + + // Documents are inserted into BSON document in this format: + // {output: [docA, docB, docC, ...]} + BSONObjBuilder bob; + BSONArrayBuilder arr(bob.subarrayStart("output")); + while (state != PlanStage::IS_EOF) { + state = ess.work(&id); + ASSERT_NE(state, PlanStage::DEAD); + ASSERT_NE(state, PlanStage::FAILURE); + if (state == PlanStage::ADVANCED) { + WorkingSetMember* member = ws.get(id); + const BSONObj& obj = member->obj.value(); + arr.append(obj); + } + } + ASSERT_TRUE(ess.isEOF()); + arr.doneFast(); + BSONObj outputObj = bob.obj(); + + // Compare the results against what we expect. + BSONObj expectedObj = fromjson(expectedStr); + ASSERT_EQ(outputObj, expectedObj); +} + // // EnsureSorted on already sorted order should make no change. // -TEST_F(QueryStageEnsureSortedTest, EnsureAlreadySortedAscending) { +TEST(QueryStageEnsureSorted, EnsureAlreadySortedAscending) { testWork("{a: 1}", "{input: [{a: 1}, {a: 2}, {a: 3}]}", "{output: [{a: 1}, {a: 2}, {a: 3}]}"); } -TEST_F(QueryStageEnsureSortedTest, EnsureAlreadySortedDescending) { +TEST(QueryStageEnsureSorted, EnsureAlreadySortedDescending) { testWork("{a: -1}", "{input: [{a: 3}, {a: 2}, {a: 1}]}", "{output: [{a: 3}, {a: 2}, {a: 1}]}"); } -TEST_F(QueryStageEnsureSortedTest, EnsureIrrelevantSortKey) { +TEST(QueryStageEnsureSorted, EnsureIrrelevantSortKey) { testWork("{b: 1}", "{input: [{a: 2}, {a: 1}, {a: 3}]}", "{output: [{a: 2}, {a: 1}, {a: 3}]}"); } @@ -146,29 +138,33 @@ TEST_F(QueryStageEnsureSortedTest, EnsureIrrelevantSortKey) { // EnsureSorted should drop unsorted results. // -TEST_F(QueryStageEnsureSortedTest, EnsureSortedOnAscending) { +TEST(QueryStageEnsureSorted, EnsureSortedOnAscending) { testWork("{a: 1}", "{input: [{a: 1}, {a: 2}, {a: 0}, {a: 4}, {a: 6}]}", "{output: [{a: 1}, {a: 2}, {a: 4}, {a: 6}]}"); } -TEST_F(QueryStageEnsureSortedTest, EnsureSortedOnDescending) { +TEST(QueryStageEnsureSorted, EnsureSortedOnDescending) { testWork("{a: -1}", "{input: [{a: 6}, {a: 4}, {a: 3}, {a: 9}, {a: 8}]}", "{output: [{a: 6}, {a: 4}, {a: 3}]}"); } -TEST_F(QueryStageEnsureSortedTest, EnsureSortedCompoundKey) { +TEST(QueryStageEnsureSorted, EnsureSortedCompoundKey) { testWork("{a: -1, b: 1}", "{input: [{a: 6, b: 10}, {a: 6, b: 8}, {a: 6, b: 12}, {a: 9, b: 13}, {a: 5, b: 1}]}", "{output: [{a: 6, b: 10}, {a: 6, b: 12}, {a: 5, b: 1}]}"); } -TEST_F(QueryStageEnsureSortedTest, EnsureSortedStringsNullCollator) { - testWork("{a: 1}", "{input: [{a: 'abc'}, {a: 'cba'}]}", "{output: [{a: 'abc'}, {a: 'cba'}]}"); +TEST(QueryStageEnsureSorted, EnsureSortedStringsNullCollator) { + const CollatorInterface* collator = nullptr; + testWork("{a: 1}", + "{input: [{a: 'abc'}, {a: 'cba'}]}", + "{output: [{a: 'abc'}, {a: 'cba'}]}", + collator); } -TEST_F(QueryStageEnsureSortedTest, EnsureSortedStringsCollator) { +TEST(QueryStageEnsureSorted, EnsureSortedStringsCollator) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); testWork("{a: 1}", "{input: [{a: 'abc'}, {a: 'cba'}]}", "{output: [{a: 'abc'}]}", &collator); } diff --git a/src/mongo/dbtests/query_stage_limit_skip.cpp b/src/mongo/dbtests/query_stage_limit_skip.cpp index 0009f32ea8c..2bb8e3b1faf 100644 --- a/src/mongo/dbtests/query_stage_limit_skip.cpp +++ b/src/mongo/dbtests/query_stage_limit_skip.cpp @@ -34,7 +34,6 @@ #include "mongo/platform/basic.h" #include "mongo/client/dbclientcursor.h" -#include "mongo/db/client.h" #include "mongo/db/exec/limit.h" #include "mongo/db/exec/plan_stage.h" #include "mongo/db/exec/queued_data_stage.h" @@ -56,8 +55,8 @@ using stdx::make_unique; static const int N = 50; /* Populate a QueuedDataStage and return it. Caller owns it. */ -QueuedDataStage* getMS(OperationContext* opCtx, WorkingSet* ws) { - auto ms = make_unique<QueuedDataStage>(opCtx, ws); +QueuedDataStage* getMS(WorkingSet* ws) { + auto ms = make_unique<QueuedDataStage>(nullptr, ws); // Put N ADVANCED results into the mock stage, and some other stalling results (YIELD/TIME). for (int i = 0; i < N; ++i) { @@ -97,18 +96,13 @@ public: for (int i = 0; i < 2 * N; ++i) { WorkingSet ws; - unique_ptr<PlanStage> skip = make_unique<SkipStage>(_opCtx, i, &ws, getMS(_opCtx, &ws)); + unique_ptr<PlanStage> skip = make_unique<SkipStage>(nullptr, i, &ws, getMS(&ws)); ASSERT_EQUALS(max(0, N - i), countResults(skip.get())); - unique_ptr<PlanStage> limit = - make_unique<LimitStage>(_opCtx, i, &ws, getMS(_opCtx, &ws)); + unique_ptr<PlanStage> limit = make_unique<LimitStage>(nullptr, i, &ws, getMS(&ws)); ASSERT_EQUALS(min(N, i), countResults(limit.get())); } } - -protected: - const ServiceContext::UniqueOperationContext _uniqOpCtx = cc().makeOperationContext(); - OperationContext* const _opCtx = _uniqOpCtx.get(); }; class All : public Suite { diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp index a76bfbe22c1..1ea517f1253 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -114,8 +114,6 @@ public: protected: const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); OperationContext& _txn = *_txnPtr; - ClockSource* const _clock = _txn.getServiceContext()->getFastClockSource(); - DBDirectClient _client; }; @@ -182,7 +180,7 @@ public: mps->addPlan(createQuerySolution(), secondRoot.release(), sharedWs.get()); // Plan 0 aka the first plan aka the index scan should be the best. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); mps->pickBestPlan(&yieldPolicy); ASSERT(mps->bestPlanChosen()); ASSERT_EQUALS(0, mps->bestPlanIdx()); @@ -266,7 +264,7 @@ public: } // This sets a backup plan. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); mps->pickBestPlan(&yieldPolicy); ASSERT(mps->bestPlanChosen()); ASSERT(mps->hasBackupPlan()); diff --git a/src/mongo/dbtests/query_stage_near.cpp b/src/mongo/dbtests/query_stage_near.cpp index d973779e7ed..58833e6a2bf 100644 --- a/src/mongo/dbtests/query_stage_near.cpp +++ b/src/mongo/dbtests/query_stage_near.cpp @@ -34,7 +34,6 @@ #include "mongo/platform/basic.h" #include "mongo/base/owned_pointer_vector.h" -#include "mongo/db/client.h" #include "mongo/db/exec/near.h" #include "mongo/db/exec/queued_data_stage.h" #include "mongo/db/exec/working_set_common.h" @@ -49,12 +48,6 @@ using std::unique_ptr; using std::vector; using stdx::make_unique; -class QueryStageNearTest : public unittest::Test { -protected: - const ServiceContext::UniqueOperationContext _uniqOpCtx = cc().makeOperationContext(); - OperationContext* const _opCtx = _uniqOpCtx.get(); -}; - /** * Stage which implements a basic distance search, and interprets the "distance" field of * fetched documents as the distance. @@ -70,9 +63,8 @@ public: double max; }; - MockNearStage(OperationContext* opCtx, WorkingSet* workingSet) - : NearStage(opCtx, "MOCK_DISTANCE_SEARCH_STAGE", STAGE_UNKNOWN, workingSet, NULL), - _pos(0) {} + MockNearStage(WorkingSet* workingSet) + : NearStage(NULL, "MOCK_DISTANCE_SEARCH_STAGE", STAGE_UNKNOWN, workingSet, NULL), _pos(0) {} void addInterval(vector<BSONObj> data, double min, double max) { _intervals.mutableVector().push_back(new MockInterval(data, min, max)); @@ -147,11 +139,11 @@ static void assertAscendingAndValid(const vector<BSONObj>& results) { } } -TEST_F(QueryStageNearTest, Basic) { +TEST(query_stage_near, Basic) { vector<BSONObj> mockData; WorkingSet workingSet; - MockNearStage nearStage(_opCtx, &workingSet); + MockNearStage nearStage(&workingSet); // First set of results mockData.clear(); @@ -182,11 +174,11 @@ TEST_F(QueryStageNearTest, Basic) { assertAscendingAndValid(results); } -TEST_F(QueryStageNearTest, EmptyResults) { +TEST(query_stage_near, EmptyResults) { vector<BSONObj> mockData; WorkingSet workingSet; - MockNearStage nearStage(_opCtx, &workingSet); + MockNearStage nearStage(&workingSet); // Empty set of results mockData.clear(); diff --git a/src/mongo/dbtests/query_stage_subplan.cpp b/src/mongo/dbtests/query_stage_subplan.cpp index 825152c4007..419cd04d08d 100644 --- a/src/mongo/dbtests/query_stage_subplan.cpp +++ b/src/mongo/dbtests/query_stage_subplan.cpp @@ -43,9 +43,11 @@ #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/get_executor.h" #include "mongo/dbtests/dbtests.h" +#include "mongo/util/clock_source_mock.h" namespace QueryStageSubplan { +const std::unique_ptr<ClockSource> clockSource = stdx::make_unique<ClockSourceMock>(); static const NamespaceString nss("unittests.QueryStageSubplan"); class QueryStageSubplanBase { @@ -87,7 +89,6 @@ protected: const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); OperationContext& _txn = *_txnPtr; - ClockSource* _clock = _txn.getServiceContext()->getFastClockSource(); private: DBDirectClient _client; @@ -131,7 +132,7 @@ public: new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get())); // Plan selection should succeed due to falling back on regular planning. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); } }; @@ -174,7 +175,7 @@ public: std::unique_ptr<SubplanStage> subplan( new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get())); - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Nothing is in the cache yet, so neither branch should have been planned from @@ -232,7 +233,7 @@ public: std::unique_ptr<SubplanStage> subplan( new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get())); - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Nothing is in the cache yet, so neither branch should have been planned from @@ -291,7 +292,7 @@ public: std::unique_ptr<SubplanStage> subplan( new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get())); - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Nothing is in the cache yet, so neither branch should have been planned from @@ -548,7 +549,7 @@ public: new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get())); // Plan selection should succeed due to falling back on regular planning. - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); // Work the stage until it produces all results. @@ -606,7 +607,7 @@ public: std::unique_ptr<SubplanStage> subplan( new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get())); - PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock); + PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, clockSource.get()); ASSERT_OK(subplan->pickBestPlan(&yieldPolicy)); size_t numResults = 0; |