You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2017/09/01 00:48:28 UTC
mesos git commit: Added an undiscardable() helper that blocks
discards from propagating.
Repository: mesos
Updated Branches:
refs/heads/master c50637c5b -> 8da1f0e61
Added an undiscardable() helper that blocks discards from propagating.
This can be useful in circumstances where you don't want some
asynchronous operation to be canceled.
Review: https://reviews.apache.org/r/61987
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/8da1f0e6
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/8da1f0e6
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/8da1f0e6
Branch: refs/heads/master
Commit: 8da1f0e6126f903f4d4371be95da96de7adaa633
Parents: c50637c
Author: Benjamin Hindman <be...@gmail.com>
Authored: Tue Aug 29 23:23:36 2017 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Thu Aug 31 17:48:09 2017 -0700
----------------------------------------------------------------------
3rdparty/libprocess/include/process/future.hpp | 91 +++++++++++++++++++++
3rdparty/libprocess/src/tests/future_tests.cpp | 41 ++++++++++
2 files changed, 132 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/8da1f0e6/3rdparty/libprocess/include/process/future.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/future.hpp b/3rdparty/libprocess/include/process/future.hpp
index 2f5f0a2..a11a588 100644
--- a/3rdparty/libprocess/include/process/future.hpp
+++ b/3rdparty/libprocess/include/process/future.hpp
@@ -1624,6 +1624,97 @@ void discardPromises(std::set<Promise<T>*>* promises, const Future<T>& future)
}
}
+
+// Returns a future that will not propagate a discard through to the
+// future passed in as an argument. This can be very valuable if you
+// want to block some future from getting discarded.
+//
+// Example:
+//
+// Promise<int> promise;
+// Future<int> future = undiscardable(promise.future());
+// future.discard();
+// assert(!promise.future().hasDiscard());
+//
+// Or another example, when chaining futures:
+//
+// Future<int> future = undiscardable(
+// foo()
+// .then([]() { ...; })
+// .then([]() { ...; }));
+//
+// This will guarantee that a discard _will not_ propagate to `foo()`
+// or any of the futures returned from the invocations of `.then()`.
+template <typename T>
+Future<T> undiscardable(const Future<T>& future)
+{
+ std::shared_ptr<Promise<T>> promise(new Promise<T>());
+ future.onAny([promise](const Future<T>& future) {
+ promise->associate(future);
+ });
+ return promise->future();
+}
+
+
+// Decorator that for some callable `f` invokes
+// `undiscardable(f(args))` for some `args`. This is used by the
+// overload of `undiscardable()` that takes callables instead of a
+// specialization of `Future`.
+//
+// TODO(benh): Factor out a generic decorator pattern to be used in
+// other circumstances, e.g., to replace `_Deferred`.
+template <typename F>
+struct UndiscardableDecorator
+{
+ template <
+ typename G,
+ typename std::enable_if<
+ std::is_constructible<F, G>::value, int>::type = 0>
+ UndiscardableDecorator(G&& g) : f(std::forward<G>(g)) {}
+
+ template <typename... Args>
+ auto operator()(Args&&... args)
+ -> decltype(std::declval<F&>()(std::forward<Args>(args)...))
+ {
+ using Result =
+ typename std::decay<decltype(f(std::forward<Args>(args)...))>::type;
+
+ static_assert(
+ is_specialization_of<Future, Result>::value,
+ "Expecting Future<T> to be returned from undiscarded(...)");
+
+ return undiscardable(f(std::forward<Args>(args)...));
+ }
+
+ F f;
+};
+
+
+// An overload of `undiscardable()` above that takes and returns a
+// callable. The returned callable has decorated the provided callable
+// `f` such that when the returned callable is invoked it will in turn
+// invoke `undiscardable(f(args))` for some `args`. See
+// `UndiscardableDecorator` above for more details.
+//
+// Example:
+//
+// Future<int> future = foo()
+// .then(undiscardable([]() { ...; }));
+//
+// This guarantees that even if `future` is discarded the discard will
+// not propagate into the lambda passed into `.then()`.
+template <
+ typename F,
+ typename std::enable_if<
+ !is_specialization_of<
+ Future,
+ typename std::decay<F>::type>::value, int>::type = 0>
+UndiscardableDecorator<typename std::decay<F>::type> undiscardable(F&& f)
+{
+ return UndiscardableDecorator<
+ typename std::decay<F>::type>(std::forward<F>(f));
+}
+
} // namespace process {
#endif // __PROCESS_FUTURE_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/8da1f0e6/3rdparty/libprocess/src/tests/future_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/future_tests.cpp b/3rdparty/libprocess/src/tests/future_tests.cpp
index 0c8725b..76a32bd 100644
--- a/3rdparty/libprocess/src/tests/future_tests.cpp
+++ b/3rdparty/libprocess/src/tests/future_tests.cpp
@@ -26,6 +26,7 @@ using process::Clock;
using process::Failure;
using process::Future;
using process::Promise;
+using process::undiscardable;
using std::string;
@@ -545,3 +546,43 @@ TEST(FutureTest, ArrowOperator)
Future<string> s = string("hello");
EXPECT_EQ(5u, s->size());
}
+
+
+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);
+}