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);
+}