// Verifies that a a future does not leak memory after calling // `after()`. This behavior occurred because a future indirectly // kept a reference counted pointer to itself. TEST(FutureTest, After3) { Future<Nothing> future; process::WeakFuture<Nothing> weak_future(future); EXPECT_SOME(weak_future.get()); { Clock::pause(); // The original future disappears here. After this call the // original future goes out of scope and should not be reachable // anymore. future = future .after(Milliseconds(1), [](Future<Nothing> f) { f.discard(); return Nothing(); }); Clock::advance(Milliseconds(1)); Clock::settle(); AWAIT_READY(future); } EXPECT_NONE(weak_future.get()); EXPECT_FALSE(future.hasDiscard()); }
/* * Class: org_apache_mesos_state_AbstractState * Method: __expunge_is_done * Signature: (J)Z */ JNIEXPORT jboolean JNICALL Java_org_apache_mesos_state_AbstractState__1_1expunge_1is_1done (JNIEnv* env, jobject thiz, jlong jfuture) { Future<bool>* future = (Future<bool>*) jfuture; return (jboolean) !future->isPending() || future->hasDiscard(); }
TEST(FutureTest, UndiscardableFuture) { Promise<int> promise; Future<int> f = undiscardable(promise.future()); f.discard(); EXPECT_TRUE(f.hasDiscard()); EXPECT_FALSE(promise.future().hasDiscard()); promise.set(42); AWAIT_ASSERT_EQ(42, f); }
TEST(FutureTest, UndiscardableLambda) { Promise<int> promise; Future<int> f = Future<int>(2) .then(undiscardable([&](int multiplier) { return promise.future() .then([=](int i) { return i * multiplier; }); })); f.discard(); EXPECT_TRUE(f.hasDiscard()); EXPECT_FALSE(promise.future().hasDiscard()); promise.set(42); AWAIT_ASSERT_EQ(84, f); }
// Tests that Future::discard does not complete the future and // Promise::set can still be invoked to complete the future. TEST(FutureTest, Discard2) { Promise<bool> promise1; Promise<int> promise2; std::atomic_bool executed(false); Future<int> future = Future<string>("hello world") .then(lambda::bind(&inner1, promise1.future())) .then(lambda::bind(&inner2, &executed, promise2.future())); ASSERT_TRUE(future.isPending()); future.discard(); // The future should remain pending, even though we discarded it. ASSERT_TRUE(future.hasDiscard()); ASSERT_TRUE(future.isPending()); // The future associated with the lambda already executed in the // first 'then' should have the discard propagated to it. ASSERT_TRUE(promise1.future().hasDiscard()); // But the future assocaited with the lambda that hasn't yet been // executed should not have the discard propagated to it. ASSERT_FALSE(promise2.future().hasDiscard()); // Now setting the promise should cause the outer future to be // discarded rather than executing the last lambda because the // implementation of Future::then does not continue the chain once a // discard occurs. ASSERT_TRUE(promise1.set(true)); AWAIT_DISCARDED(future); // And the final lambda should never have executed. ASSERT_FALSE(executed.load()); ASSERT_TRUE(promise2.future().isPending()); }
// Tests that Future::discard does not complete the future and // Promise::fail can still be invoked to complete the future. TEST(FutureTest, Discard3) { Promise<bool> promise1; Promise<int> promise2; std::atomic_bool executed(false); Future<int> future = Future<string>("hello world") .then(lambda::bind(&inner1, promise1.future())) .then(lambda::bind(&inner2, &executed, promise2.future())); ASSERT_TRUE(future.isPending()); future.discard(); // The future should remain pending, even though we discarded it. ASSERT_TRUE(future.hasDiscard()); ASSERT_TRUE(future.isPending()); // The future associated with the lambda already executed in the // first 'then' should have the discard propagated to it. ASSERT_TRUE(promise1.future().hasDiscard()); // But the future assocaited with the lambda that hasn't yet been // executed should not have the discard propagated to it. ASSERT_FALSE(promise2.future().hasDiscard()); // Now failing the promise should cause the outer future to be // failed also. ASSERT_TRUE(promise1.fail("failure message")); AWAIT_FAILED(future); // And the final lambda should never have executed. ASSERT_FALSE(executed.load()); ASSERT_TRUE(promise2.future().isPending()); }
Future<Nothing> after(std::atomic_bool* executed, const Future<Nothing>& future) { EXPECT_TRUE(future.hasDiscard()); executed->store(true); return Failure("Failure"); }