diff options
author | Scott Hernandez <scotthernandez@gmail.com> | 2015-10-02 17:19:59 -0400 |
---|---|---|
committer | Scott Hernandez <scotthernandez@gmail.com> | 2015-10-05 12:53:28 -0400 |
commit | 849505ebc395d15c6f777d96436447f1f98f7285 (patch) | |
tree | 876032c3644aca38afd0d2e4c2d198c9bea5dca8 /src/mongo/db/query/find.cpp | |
parent | 1fd64cee88562e77883db5b75ee666a55b15e748 (diff) | |
download | mongo-849505ebc395d15c6f777d96436447f1f98f7285.tar.gz |
SERVER-20749: Race during getmore batch creation and cappedInsertNotification::wait
Diffstat (limited to 'src/mongo/db/query/find.cpp')
-rw-r--r-- | src/mongo/db/query/find.cpp | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index 0156112283c..4b3bdb5b50b 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -366,10 +366,24 @@ QueryResult::View getMore(OperationContext* txn, // What number result are we starting at? Used to fill out the reply. startingResult = cc->pos(); + uint64_t notifierVersion = 0; + std::shared_ptr<CappedInsertNotifier> notifier; + if (isCursorAwaitData(cc)) { + invariant(ctx->getCollection()->isCapped()); + // Retrieve the notifier which we will wait on until new data arrives. We make sure + // to do this in the lock because once we drop the lock it is possible for the + // collection to become invalid. The notifier itself will outlive the collection if + // the collection is dropped, as we keep a shared_ptr to it. + notifier = ctx->getCollection()->getCappedInsertNotifier(); + + // Must get the version before we call generateBatch in case a write comes in after + // that call and before we call wait on the notifier. + notifierVersion = notifier->getVersion(); + } + PlanExecutor* exec = cc->getExecutor(); exec->reattachToOperationContext(txn); exec->restoreState(); - PlanExecutor::ExecState state; generateBatch(ntoreturn, cc, &bb, &numResults, &slaveReadTill, &state); @@ -377,19 +391,13 @@ QueryResult::View getMore(OperationContext* txn, // If this is an await data cursor, and we hit EOF without generating any results, then // we block waiting for new data to arrive. if (isCursorAwaitData(cc) && state == PlanExecutor::IS_EOF && numResults == 0) { - // Retrieve the notifier which we will wait on until new data arrives. We make sure - // to do this in the lock because once we drop the lock it is possible for the - // collection to become invalid. The notifier itself will outlive the collection if - // the collection is dropped, as we keep a shared_ptr to it. - auto notifier = ctx->getCollection()->getCappedInsertNotifier(); - // Save the PlanExecutor and drop our locks. exec->saveState(); ctx.reset(); // Block waiting for data for up to 1 second. Seconds timeout(1); - notifier->wait(timeout); + notifier->wait(notifierVersion, timeout); notifier.reset(); // Set expected latency to match wait time. This makes sure the logs aren't spammed |