summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2018-03-28 20:25:07 -0400
committerMathias Stearn <mathias@10gen.com>2018-03-30 10:45:26 -0400
commit028d3ff3e5fed549c42761f4595a73ed40d34e9f (patch)
tree04db5dbf38a943479db37f653b0187a08b7ddae8 /src/mongo/util
parentd32066522d16341e7eba3a752c8697db8b824d7a (diff)
downloadmongo-028d3ff3e5fed549c42761f4595a73ed40d34e9f.tar.gz
SERVER-34186 add Future::isReady()
Diffstat (limited to 'src/mongo/util')
-rw-r--r--src/mongo/util/future.h23
-rw-r--r--src/mongo/util/future_test.cpp77
2 files changed, 100 insertions, 0 deletions
diff --git a/src/mongo/util/future.h b/src/mongo/util/future.h
index bc670372d90..9fa51d173b4 100644
--- a/src/mongo/util/future.h
+++ b/src/mongo/util/future.h
@@ -683,6 +683,25 @@ public:
}
/**
+ * If this returns true, get() is guaranteed not to block and callbacks will be immediately
+ * invoked. You can't assume anything if this returns false since it may be completed
+ * immediately after checking (unless you have independent knowledge that this Future can't
+ * complete in the background).
+ *
+ * Callers must still call get() or similar, even on Future<void>, to ensure that they are
+ * correctly sequenced with the completing task, and to be informed about whether the Promise
+ * completed successfully.
+ *
+ * This is generally only useful as an optimization to avoid prep work, such as setting up
+ * timeouts, that is unnecessary if the Future is ready already.
+ */
+ bool isReady() const {
+ // This can be a relaxed load because callers are not allowed to use it to establish
+ // ordering.
+ return immediate || shared->state.load(std::memory_order_relaxed) == SSBState::kFinished;
+ }
+
+ /**
* Gets the value out of this Future, blocking until it is ready.
*
* get() methods throw on error, while getNoThrow() returns a !OK status.
@@ -1137,6 +1156,10 @@ public:
return Future<FakeVoid>::makeReady(std::move(status));
}
+ bool isReady() const {
+ return inner.isReady();
+ }
+
void get() const {
inner.get();
}
diff --git a/src/mongo/util/future_test.cpp b/src/mongo/util/future_test.cpp
index da3481c8f38..a5cbebd9ada 100644
--- a/src/mongo/util/future_test.cpp
+++ b/src/mongo/util/future_test.cpp
@@ -245,6 +245,46 @@ TEST(Future, Fail_getAsync) {
});
}
+TEST(Future, Success_isReady) {
+ FUTURE_SUCCESS_TEST([] { return 1; },
+ [](Future<int>&& fut) {
+ const auto id = stdx::this_thread::get_id();
+ while (!fut.isReady()) {
+ }
+ std::move(fut).getAsync([&](StatusWith<int> status) {
+ ASSERT_EQ(stdx::this_thread::get_id(), id);
+ ASSERT_EQ(status, 1);
+ });
+
+ });
+}
+
+TEST(Future, Fail_isReady) {
+ FUTURE_FAIL_TEST<int>([](Future<int>&& fut) {
+ const auto id = stdx::this_thread::get_id();
+ while (!fut.isReady()) {
+ }
+ std::move(fut).getAsync([&](StatusWith<int> status) {
+ ASSERT_EQ(stdx::this_thread::get_id(), id);
+ ASSERT_NOT_OK(status);
+ });
+
+ });
+}
+
+TEST(Future, isReady_TSAN_OK) {
+ bool done = false;
+ auto fut = async([&] {
+ done = true;
+ return 1;
+ });
+ while (!fut.isReady()) {
+ }
+ // ASSERT(done); // Data Race! Uncomment to make sure TSAN is working.
+ (void)fut.get();
+ ASSERT(done);
+}
+
TEST(Future, Success_thenSimple) {
FUTURE_SUCCESS_TEST([] { return 1; },
[](Future<int>&& fut) {
@@ -696,6 +736,43 @@ TEST(Future_Void, Fail_getAsync) {
});
}
+TEST(Future_Void, Success_isReady) {
+ FUTURE_SUCCESS_TEST([] {},
+ [](Future<void>&& fut) {
+ const auto id = stdx::this_thread::get_id();
+ while (!fut.isReady()) {
+ }
+ std::move(fut).getAsync([&](Status status) {
+ ASSERT_EQ(stdx::this_thread::get_id(), id);
+ ASSERT_OK(status);
+ });
+
+ });
+}
+
+TEST(Future_Void, Fail_isReady) {
+ FUTURE_FAIL_TEST<void>([](Future<void>&& fut) {
+ const auto id = stdx::this_thread::get_id();
+ while (!fut.isReady()) {
+ }
+ std::move(fut).getAsync([&](Status status) {
+ ASSERT_EQ(stdx::this_thread::get_id(), id);
+ ASSERT_NOT_OK(status);
+ });
+
+ });
+}
+
+TEST(Future_Void, isReady_TSAN_OK) {
+ bool done = false;
+ auto fut = async([&] { done = true; });
+ while (!fut.isReady()) {
+ }
+ // ASSERT(done); // Data Race! Uncomment to make sure TSAN is working.
+ fut.get();
+ ASSERT(done);
+}
+
TEST(Future_Void, Success_thenSimple) {
FUTURE_SUCCESS_TEST(
[] {},