Commit 9af220fa authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

Ensure that SemiFuture executor is correctly chained to deal with deferred work.

Summary: There was previously a bug in that defer used within a continuation would not correctly chain the deferred executor on the executor in the returned (and hence in the original) folly::Future like it would when .via was called on a SemiFuture. This fixes that situation by returning a semifuture from a continuation by correctly chaining it onto the outer future's executor.

Reviewed By: yfeldblum

Differential Revision: D7156241

fbshipit-source-id: ed6db3ad0de7a921b72459fcd2b1228114832853
parent e0d04ed7
main v2022.02.14.00 v2022.02.07.00 v2022.01.31.00 v2022.01.24.00 v2022.01.17.00 v2022.01.10.00 v2022.01.03.00 v2021.12.27.00 v2021.12.20.00 v2021.12.13.00 v2021.12.06.00 v2021.11.29.00 v2021.11.15.00 v2021.11.08.00 v2021.11.01.00 v2021.10.25.00 v2021.10.18.00 v2021.10.11.00 v2021.10.04.00 v2021.09.27.00 v2021.09.20.00 v2021.09.13.00 v2021.09.06.00 v2021.08.30.00 v2021.08.23.00 v2021.08.02.00 v2021.07.22.00 v2021.07.20.01 v2021.07.20.00 v2021.06.28.00 v2021.06.14.00 v2021.06.07.00 v2021.05.31.00 v2021.05.24.00 v2021.05.17.00 v2021.05.10.00 v2021.05.03.00 v2021.04.26.00 v2021.04.19.00 v2021.04.12.00 v2021.04.05.00 v2021.03.29.00 v2021.03.22.00 v2021.03.15.00 v2021.03.08.00 v2021.03.01.00 v2021.02.22.00 v2021.02.15.00 v2021.02.08.00 v2021.02.01.00 v2021.01.25.00 v2021.01.18.01 v2021.01.18.00 v2021.01.11.00 v2021.01.04.00 v2020.12.28.00 v2020.12.21.00 v2020.12.14.00 v2020.12.07.00 v2020.11.30.00 v2020.11.23.00 v2020.11.16.00 v2020.11.09.00 v2020.11.02.00 v2020.10.26.00 v2020.10.19.00 v2020.10.12.00 v2020.10.05.00 v2020.09.28.00 v2020.09.21.00 v2020.09.14.00 v2020.09.07.00 v2020.08.31.00 v2020.08.24.00 v2020.08.17.00 v2020.08.10.00 v2020.08.03.00 v2020.07.27.00 v2020.07.20.00 v2020.07.13.00 v2020.07.06.00 v2020.06.29.00 v2020.06.15.00 v2020.06.08.00 v2020.06.01.00 v2020.05.25.00 v2020.05.18.00 v2020.05.11.00 v2020.05.04.00 v2020.04.27.00 v2020.04.20.00 v2020.04.13.00 v2020.04.06.00 v2020.03.30.00 v2020.03.23.00 v2020.03.16.00 v2020.03.09.00 v2020.03.02.00 v2020.02.24.00 v2020.02.17.00 v2020.02.10.00 v2020.02.03.00 v2020.01.27.00 v2020.01.20.00 v2020.01.13.00 v2020.01.06.00 v2019.12.30.00 v2019.12.23.00 v2019.12.16.00 v2019.12.09.00 v2019.12.06.00 v2019.12.02.00 v2019.11.11.00 v2019.11.04.00 v2019.10.28.00 v2019.10.21.00 v2019.10.14.00 v2019.10.07.00 v2019.09.30.00 v2019.09.23.00 v2019.09.16.00 v2019.09.09.00 v2019.09.02.00 v2019.08.26.00 v2019.08.19.00 v2019.08.12.00 v2019.08.05.00 v2019.07.29.00 v2019.07.22.00 v2019.06.17.00 v2019.06.10.00 v2019.06.03.00 v2019.05.27.00 v2019.05.20.00 v2019.05.13.00 v2019.05.06.00 v2019.04.29.00 v2019.04.22.00 v2019.04.15.00 v2019.04.08.00 v2019.04.01.00 v2019.03.25.00 v2019.03.18.00 v2019.03.04.00 v2019.02.25.00 v2019.02.18.00 v2019.02.11.00 v2019.02.04.00 v2019.01.28.00 v2019.01.21.00 v2019.01.14.00 v2019.01.07.00 v2018.12.31.00 v2018.12.24.00 v2018.12.17.00 v2018.12.10.00 v2018.12.03.00 v2018.11.26.00 v2018.11.19.00 v2018.11.12.00 v2018.11.05.00 v2018.10.29.00 v2018.10.22.00 v2018.10.15.00 v2018.10.08.00 v2018.10.01.00 v2018.09.24.00 v2018.09.17.00 v2018.09.10.01 v2018.09.10.00 v2018.09.03.01 v2018.09.03.00 v2018.08.27.00 v2018.08.20.00 v2018.08.13.00 v2018.08.09.00 v2018.08.06.00 v2018.07.30.00 v2018.07.23.00 v2018.07.16.00 v2018.07.09.00 v2018.07.02.00 v2018.06.25.00 v2018.06.18.00 v2018.06.11.00 v2018.06.04.00 v2018.05.28.00 v2018.05.21.00 v2018.05.14.00 v2018.05.07.00 v2018.04.30.00 v2018.04.23.00 v2018.04.16.00 v2018.04.09.00 v2018.04.02.00 v2018.03.26.00 v2018.03.19.00 v2018.03.12.00
No related merge requests found
...@@ -342,6 +342,21 @@ FutureBase<T>::thenImplementation( ...@@ -342,6 +342,21 @@ FutureBase<T>::thenImplementation(
return f; return f;
} }
// Pass through a simple future as it needs no deferral adaptation
template <class T>
Future<T> chainExecutor(Executor*, Future<T>&& f) {
return std::move(f);
}
// Correctly chain a SemiFuture for deferral
template <class T>
Future<T> chainExecutor(Executor* e, SemiFuture<T>&& f) {
if (!e) {
e = &folly::InlineExecutor::instance();
}
return std::move(f).via(e);
}
// Variant: returns a Future // Variant: returns a Future
// e.g. f.then([](T&& t){ return makeFuture<T>(t); }); // e.g. f.then([](T&& t){ return makeFuture<T>(t); });
template <class T> template <class T>
...@@ -359,26 +374,32 @@ FutureBase<T>::thenImplementation( ...@@ -359,26 +374,32 @@ FutureBase<T>::thenImplementation(
// grab the Future now before we lose our handle on the Promise // grab the Future now before we lose our handle on the Promise
auto sf = p.getSemiFuture(); auto sf = p.getSemiFuture();
sf.core_->setExecutor(this->getExecutor()); auto* e = this->getExecutor();
sf.core_->setExecutor(e);
auto f = Future<B>(sf.core_); auto f = Future<B>(sf.core_);
sf.core_ = nullptr; sf.core_ = nullptr;
this->setCallback_( this->setCallback_([state = futures::detail::makeCoreCallbackState(
[state = futures::detail::makeCoreCallbackState( std::move(p), std::forward<F>(func))](
std::move(p), std::forward<F>(func))](Try<T>&& t) mutable { Try<T>&& t) mutable {
if (!isTry && t.hasException()) { if (!isTry && t.hasException()) {
state.setException(std::move(t.exception())); state.setException(std::move(t.exception()));
} else { } else {
auto tf2 = state.tryInvoke(t.template get<isTry, Args>()...); // Ensure that if function returned a SemiFuture we correctly chain
if (tf2.hasException()) { // potential deferral.
state.setException(std::move(tf2.exception())); auto tf2 = state.tryInvoke(t.template get<isTry, Args>()...);
} else { if (tf2.hasException()) {
tf2->setCallback_([p = state.stealPromise()](Try<B> && b) mutable { state.setException(std::move(tf2.exception()));
p.setTry(std::move(b)); } else {
}); auto statePromise = state.stealPromise();
} auto tf3 =
} chainExecutor(statePromise.core_->getExecutor(), *std::move(tf2));
}); tf3.setCallback_([p2 = std::move(statePromise)](Try<B>&& b) mutable {
p2.setTry(std::move(b));
});
}
}
});
return f; return f;
} }
......
...@@ -517,3 +517,26 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) { ...@@ -517,3 +517,26 @@ TEST(SemiFuture, MakeSemiFutureFromFutureWithTry) {
auto tryResult = std::move(sf).get(); auto tryResult = std::move(sf).get();
ASSERT_EQ(tryResult.value(), "Try"); ASSERT_EQ(tryResult.value(), "Try");
} }
TEST(SemiFuture, DeferWithinContinuation) {
std::atomic<int> innerResult{0};
std::atomic<int> result{0};
EventBase e2;
Promise<int> p;
Promise<int> p2;
auto f = p.getSemiFuture().via(&e2);
auto resultF = std::move(f).then([&, p3 = std::move(p2)](int outer) mutable {
result = outer;
return makeSemiFuture<int>(std::move(outer))
.defer([&, p4 = std::move(p3)](int inner) mutable {
innerResult = inner;
p4.setValue(inner);
return inner;
});
});
p.setValue(7);
auto r = resultF.getVia(&e2);
ASSERT_EQ(r, 7);
ASSERT_EQ(innerResult, 7);
ASSERT_EQ(result, 7);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment