You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2017/09/01 04:39:48 UTC

[2/2] mesos git commit: Added an undiscardable() helper that blocks discards from propagating.

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/f8b8ab9c
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/f8b8ab9c
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/f8b8ab9c

Branch: refs/heads/1.4.x
Commit: f8b8ab9cfba02d98a68bbaa203627294fa75b9ae
Parents: 9de5503
Author: Benjamin Hindman <be...@gmail.com>
Authored: Tue Aug 29 23:23:36 2017 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Thu Aug 31 19:54:44 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/f8b8ab9c/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/f8b8ab9c/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);
+}