summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2016-11-30 18:11:36 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-06-16 15:33:16 -0400
commitee82d192505ef5e062bb770ce87b6741e70e99fb (patch)
tree8ee8e4bb7a840df80dfe436ff4adb93a60e57056
parent065672a9ee574ba1c2c0dab132848a8bfe7a53f8 (diff)
downloadmongo-ee82d192505ef5e062bb770ce87b6741e70e99fb.tar.gz
SERVER-26355 Implement the interruptible form of Notification::get().
(cherry picked from commit ac3c2daf34f06e3b35faaa8a524d52bff9d182c7)
-rw-r--r--src/mongo/db/range_deleter_test.cpp79
-rw-r--r--src/mongo/util/concurrency/notification.h7
2 files changed, 53 insertions, 33 deletions
diff --git a/src/mongo/db/range_deleter_test.cpp b/src/mongo/db/range_deleter_test.cpp
index 0a625507b61..f723cfa42e1 100644
--- a/src/mongo/db/range_deleter_test.cpp
+++ b/src/mongo/db/range_deleter_test.cpp
@@ -30,15 +30,14 @@
#include <string>
-#include "mongo/db/field_parser.h"
#include "mongo/db/range_deleter.h"
#include "mongo/db/range_deleter_mock_env.h"
#include "mongo/db/repl/repl_settings.h"
#include "mongo/db/repl/replication_coordinator_mock.h"
-#include "mongo/db/service_context.h"
-#include "mongo/db/write_concern_options.h"
+#include "mongo/db/service_context_noop.h"
#include "mongo/stdx/functional.h"
#include "mongo/stdx/future.h"
+#include "mongo/stdx/memory.h"
#include "mongo/stdx/thread.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/scopeguard.h"
@@ -48,8 +47,6 @@ namespace {
using std::string;
-OperationContext* const noTxn = NULL; // MockEnv doesn't need txn XXX SERVER-13931
-
// The range deleter cursor close wait interval increases exponentially from 5 milliseconds to an
// upper bound of 500 msec. Three seconds should be enough time for changes in the cursors set to be
// noticed.
@@ -57,8 +54,27 @@ const Seconds MAX_IMMEDIATE_DELETE_WAIT(3);
const mongo::repl::ReplSettings replSettings = {};
+class RangeDeleterTestFixture : public unittest::Test {
+public:
+ RangeDeleterTestFixture()
+ : _client(_serviceContext.makeClient("TestClient")),
+ _opCtx(_client->makeOperationContext()) {}
+
+protected:
+ OperationContext* opCtx() const {
+ return _opCtx.get();
+ }
+
+private:
+ ServiceContextNoop _serviceContext;
+ ServiceContext::UniqueClient _client;
+ ServiceContext::UniqueOperationContext _opCtx;
+};
+
+using QueuedDelete = RangeDeleterTestFixture;
+
// Should not be able to queue deletes if deleter workers were not started.
-TEST(QueueDelete, CantAfterStop) {
+TEST_F(QueuedDelete, CantAfterStop) {
RangeDeleterMockEnv* env = new RangeDeleterMockEnv();
RangeDeleter deleter(env);
@@ -72,7 +88,7 @@ TEST(QueueDelete, CantAfterStop) {
string errMsg;
ASSERT_FALSE(
- deleter.queueDelete(noTxn,
+ deleter.queueDelete(opCtx(),
RangeDeleterOptions(KeyRange(
"test.user", BSON("x" << 120), BSON("x" << 200), BSON("x" << 1))),
NULL /* notifier not needed */,
@@ -83,7 +99,7 @@ TEST(QueueDelete, CantAfterStop) {
// Should not start delete if the set of cursors that were open when the
// delete was queued is still open.
-TEST(QueuedDelete, ShouldWaitCursor) {
+TEST_F(QueuedDelete, ShouldWaitCursor) {
const string ns("test.user");
RangeDeleterMockEnv* env = new RangeDeleterMockEnv();
@@ -104,7 +120,7 @@ TEST(QueuedDelete, ShouldWaitCursor) {
deleterOptions.waitForOpenCursors = true;
ASSERT_TRUE(
- deleter.queueDelete(noTxn, deleterOptions, &doneSignal, NULL /* errMsg not needed */));
+ deleter.queueDelete(opCtx(), deleterOptions, &doneSignal, NULL /* errMsg not needed */));
env->waitForNthGetCursor(1u);
@@ -115,7 +131,7 @@ TEST(QueuedDelete, ShouldWaitCursor) {
env->addCursorId(ns, 200);
env->removeCursorId(ns, 345);
- doneSignal.get(noTxn);
+ doneSignal.get(opCtx());
ASSERT_TRUE(env->deleteOccured());
const DeletedRange deletedChunk(env->getLastDelete());
@@ -128,7 +144,7 @@ TEST(QueuedDelete, ShouldWaitCursor) {
}
// Should terminate when stop is requested.
-TEST(QueuedDelete, StopWhileWaitingCursor) {
+TEST_F(QueuedDelete, StopWhileWaitingCursor) {
const string ns("test.user");
RangeDeleterMockEnv* env = new RangeDeleterMockEnv();
@@ -148,7 +164,7 @@ TEST(QueuedDelete, StopWhileWaitingCursor) {
KeyRange(ns, BSON("x" << 0), BSON("x" << 10), BSON("x" << 1)));
deleterOptions.waitForOpenCursors = true;
ASSERT_TRUE(
- deleter.queueDelete(noTxn, deleterOptions, &doneSignal, NULL /* errMsg not needed */));
+ deleter.queueDelete(opCtx(), deleterOptions, &doneSignal, NULL /* errMsg not needed */));
env->waitForNthGetCursor(1u);
@@ -157,9 +173,11 @@ TEST(QueuedDelete, StopWhileWaitingCursor) {
ASSERT_FALSE(env->deleteOccured());
}
-// Should not start delete if the set of cursors that were open when the
-// deleteNow method is called is still open.
-TEST(ImmediateDelete, ShouldWaitCursor) {
+using ImmediateDelete = RangeDeleterTestFixture;
+
+// Should not start delete if the set of cursors that were open when the deleteNow method is called
+// is still open.
+TEST_F(ImmediateDelete, ShouldWaitCursor) {
const string ns("test.user");
RangeDeleterMockEnv* env = new RangeDeleterMockEnv();
@@ -180,7 +198,7 @@ TEST(ImmediateDelete, ShouldWaitCursor) {
deleterOption.waitForOpenCursors = true;
stdx::packaged_task<bool()> deleterTask(
- [&] { return deleter.deleteNow(noTxn, deleterOption, &errMsg); });
+ [&] { return deleter.deleteNow(opCtx(), deleterOption, &errMsg); });
stdx::future<bool> deleterFuture = deleterTask.get_future();
stdx::thread deleterThread(std::move(deleterTask));
@@ -215,7 +233,7 @@ TEST(ImmediateDelete, ShouldWaitCursor) {
}
// Should terminate when stop is requested.
-TEST(ImmediateDelete, StopWhileWaitingCursor) {
+TEST_F(ImmediateDelete, StopWhileWaitingCursor) {
const string ns("test.user");
RangeDeleterMockEnv* env = new RangeDeleterMockEnv();
@@ -236,7 +254,7 @@ TEST(ImmediateDelete, StopWhileWaitingCursor) {
deleterOption.waitForOpenCursors = true;
stdx::packaged_task<bool()> deleterTask(
- [&] { return deleter.deleteNow(noTxn, deleterOption, &errMsg); });
+ [&] { return deleter.deleteNow(opCtx(), deleterOption, &errMsg); });
stdx::future<bool> deleterFuture = deleterTask.get_future();
stdx::thread deleterThread(std::move(deleterTask));
@@ -259,12 +277,13 @@ TEST(ImmediateDelete, StopWhileWaitingCursor) {
ASSERT_FALSE(env->deleteOccured());
}
-// Tests the interaction of multiple deletes queued with different states.
-// Starts by adding a new delete task, waits for the worker to work on it,
-// and then adds 2 more task, one of which is ready to be deleted, while the
-// other one is waiting for an open cursor. The test then makes sure that the
-// deletes are performed in the right order.
-TEST(MixedDeletes, MultipleDeletes) {
+using MixedDeletes = RangeDeleterTestFixture;
+
+// Tests the interaction of multiple deletes queued with different states. Starts by adding a new
+// delete task, waits for the worker to work on it, and then adds 2 more task, one of which is ready
+// to be deleted, while the other one is waiting for an open cursor. The test then makes sure that
+// the deletes are performed in the right order.
+TEST_F(MixedDeletes, MultipleDeletes) {
const string blockedNS("foo.bar");
const string ns("test.user");
@@ -286,7 +305,7 @@ TEST(MixedDeletes, MultipleDeletes) {
KeyRange(ns, BSON("x" << 10), BSON("x" << 20), BSON("x" << 1)));
deleterOption1.waitForOpenCursors = true;
ASSERT_TRUE(
- deleter.queueDelete(noTxn, deleterOption1, &doneSignal1, NULL /* don't care errMsg */));
+ deleter.queueDelete(opCtx(), deleterOption1, &doneSignal1, NULL /* don't care errMsg */));
env->waitForNthPausedDelete(1u);
@@ -298,14 +317,14 @@ TEST(MixedDeletes, MultipleDeletes) {
KeyRange(blockedNS, BSON("x" << 20), BSON("x" << 30), BSON("x" << 1)));
deleterOption2.waitForOpenCursors = true;
ASSERT_TRUE(
- deleter.queueDelete(noTxn, deleterOption2, &doneSignal2, NULL /* don't care errMsg */));
+ deleter.queueDelete(opCtx(), deleterOption2, &doneSignal2, NULL /* don't care errMsg */));
Notification<void> doneSignal3;
RangeDeleterOptions deleterOption3(
KeyRange(ns, BSON("x" << 30), BSON("x" << 40), BSON("x" << 1)));
deleterOption3.waitForOpenCursors = true;
ASSERT_TRUE(
- deleter.queueDelete(noTxn, deleterOption3, &doneSignal3, NULL /* don't care errMsg */));
+ deleter.queueDelete(opCtx(), deleterOption3, &doneSignal3, NULL /* don't care errMsg */));
// Now, the setup is:
// { x: 10 } => { x: 20 } in progress.
@@ -319,7 +338,7 @@ TEST(MixedDeletes, MultipleDeletes) {
// Let the first delete proceed.
env->resumeOneDelete();
- doneSignal1.get(noTxn);
+ doneSignal1.get(opCtx());
ASSERT_TRUE(env->deleteOccured());
@@ -334,7 +353,7 @@ TEST(MixedDeletes, MultipleDeletes) {
// Let the second delete proceed.
env->resumeOneDelete();
- doneSignal3.get(noTxn);
+ doneSignal3.get(opCtx());
DeletedRange deleted2(env->getLastDelete());
@@ -349,7 +368,7 @@ TEST(MixedDeletes, MultipleDeletes) {
env->removeCursorId(blockedNS, 345);
// Let the last delete proceed.
env->resumeOneDelete();
- doneSignal2.get(noTxn);
+ doneSignal2.get(opCtx());
DeletedRange deleted3(env->getLastDelete());
diff --git a/src/mongo/util/concurrency/notification.h b/src/mongo/util/concurrency/notification.h
index 538012cb257..32ce9caa068 100644
--- a/src/mongo/util/concurrency/notification.h
+++ b/src/mongo/util/concurrency/notification.h
@@ -30,6 +30,7 @@
#include <boost/optional.hpp>
+#include "mongo/db/operation_context.h"
#include "mongo/stdx/condition_variable.h"
#include "mongo/stdx/mutex.h"
#include "mongo/util/assert_util.h"
@@ -38,8 +39,6 @@
namespace mongo {
-class OperationContext;
-
/**
* Allows waiting for a result returned from an asynchronous operation.
*/
@@ -68,7 +67,9 @@ public:
* If the wait is interrupted, throws an exception.
*/
T& get(OperationContext* txn) {
- return get();
+ stdx::unique_lock<stdx::mutex> lock(_mutex);
+ txn->waitForConditionOrInterrupt(_condVar, lock, [this]() -> bool { return !!_value; });
+ return _value.get();
}
/**