diff options
author | Mathias Stearn <mathias@10gen.com> | 2018-03-28 20:25:07 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2018-03-30 10:45:26 -0400 |
commit | 028d3ff3e5fed549c42761f4595a73ed40d34e9f (patch) | |
tree | 04db5dbf38a943479db37f653b0187a08b7ddae8 /src/mongo/util | |
parent | d32066522d16341e7eba3a752c8697db8b824d7a (diff) | |
download | mongo-028d3ff3e5fed549c42761f4595a73ed40d34e9f.tar.gz |
SERVER-34186 add Future::isReady()
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/future.h | 23 | ||||
-rw-r--r-- | src/mongo/util/future_test.cpp | 77 |
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( [] {}, |