Commit 6c881171 authored by Dan Melnic's avatar Dan Melnic Committed by Facebook Github Bot

Add support for futures folly::HighResDuration

Summary: Add support for futures folly::HighResDuration

Reviewed By: kevin-vigor

Differential Revision: D19981652

fbshipit-source-id: 4a321fda487d5acdee04d138b0e4f0f10a4119f1
parent 581e3369
......@@ -870,7 +870,7 @@ SemiFuture<Unit> SemiFuture<T>::unit() && {
}
template <typename T>
SemiFuture<T> SemiFuture<T>::delayed(Duration dur, Timekeeper* tk) && {
SemiFuture<T> SemiFuture<T>::delayed(HighResDuration dur, Timekeeper* tk) && {
return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.toUnsafeFuture()
.thenValue([](std::tuple<Try<T>, Try<Unit>> tup) {
......@@ -1228,7 +1228,8 @@ Future<T> Future<T>::ensure(F&& func) && {
template <class T>
template <class F>
Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) && {
Future<T>
Future<T>::onTimeout(HighResDuration dur, F&& func, Timekeeper* tk) && {
return std::move(*this).within(dur, tk).thenError(
tag_t<FutureTimeout>{},
[funcw = std::forward<F>(func)](auto const&) mutable {
......@@ -1999,13 +2000,13 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) {
// within
template <class T>
Future<T> Future<T>::within(Duration dur, Timekeeper* tk) && {
Future<T> Future<T>::within(HighResDuration dur, Timekeeper* tk) && {
return std::move(*this).within(dur, FutureTimeout(), tk);
}
template <class T>
template <class E>
Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && {
Future<T> Future<T>::within(HighResDuration dur, E e, Timekeeper* tk) && {
if (this->isReady()) {
return std::move(*this);
}
......@@ -2018,7 +2019,8 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && {
template <class T>
template <typename E>
SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && {
SemiFuture<T>
SemiFuture<T>::within(HighResDuration dur, E e, Timekeeper* tk) && {
if (this->isReady()) {
return std::move(*this);
}
......@@ -2103,7 +2105,7 @@ SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && {
// delayed
template <class T>
Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) && {
Future<T> Future<T>::delayed(HighResDuration dur, Timekeeper* tk) && {
auto e = this->getExecutor();
return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.via(e ? e : &InlineExecutor::instance())
......@@ -2153,7 +2155,7 @@ SemiFuture<T> convertFuture(SemiFuture<T>&& sf, const SemiFuture<T>&) {
}
template <class FutureType, typename T = typename FutureType::value_type>
void waitImpl(FutureType& f, Duration dur) {
void waitImpl(FutureType& f, HighResDuration dur) {
if (std::is_base_of<Future<T>, FutureType>::value) {
f = std::move(f).via(&InlineExecutor::instance());
}
......@@ -2252,7 +2254,7 @@ SemiFuture<T>&& SemiFuture<T>::wait() && {
}
template <class T>
SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & {
SemiFuture<T>& SemiFuture<T>::wait(HighResDuration dur) & {
if (auto deferredExecutor = this->getDeferredExecutor()) {
// Make sure that the last callback in the future chain will be run on the
// WaitExecutor.
......@@ -2280,7 +2282,7 @@ SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & {
}
template <class T>
bool SemiFuture<T>::wait(Duration dur) && {
bool SemiFuture<T>::wait(HighResDuration dur) && {
auto future = std::move(*this);
future.wait(dur);
return future.isReady();
......@@ -2292,7 +2294,7 @@ T SemiFuture<T>::get() && {
}
template <class T>
T SemiFuture<T>::get(Duration dur) && {
T SemiFuture<T>::get(HighResDuration dur) && {
return std::move(*this).getTry(dur).value();
}
......@@ -2305,7 +2307,7 @@ Try<T> SemiFuture<T>::getTry() && {
}
template <class T>
Try<T> SemiFuture<T>::getTry(Duration dur) && {
Try<T> SemiFuture<T>::getTry(HighResDuration dur) && {
wait(dur);
auto future = folly::Future<T>(this->core_);
this->core_ = nullptr;
......@@ -2329,13 +2331,13 @@ Future<T>&& Future<T>::wait() && {
}
template <class T>
Future<T>& Future<T>::wait(Duration dur) & {
Future<T>& Future<T>::wait(HighResDuration dur) & {
futures::detail::waitImpl(*this, dur);
return *this;
}
template <class T>
Future<T>&& Future<T>::wait(Duration dur) && {
Future<T>&& Future<T>::wait(HighResDuration dur) && {
futures::detail::waitImpl(*this, dur);
return std::move(*this);
}
......@@ -2353,13 +2355,15 @@ Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
}
template <class T>
Future<T>& Future<T>::waitVia(TimedDrivableExecutor* e, Duration dur) & {
Future<T>& Future<T>::waitVia(TimedDrivableExecutor* e, HighResDuration dur) & {
futures::detail::waitViaImpl(*this, e, dur);
return *this;
}
template <class T>
Future<T>&& Future<T>::waitVia(TimedDrivableExecutor* e, Duration dur) && {
Future<T>&& Future<T>::waitVia(
TimedDrivableExecutor* e,
HighResDuration dur) && {
futures::detail::waitViaImpl(*this, e, dur);
return std::move(*this);
}
......@@ -2371,7 +2375,7 @@ T Future<T>::get() && {
}
template <class T>
T Future<T>::get(Duration dur) && {
T Future<T>::get(HighResDuration dur) && {
wait(dur);
auto future = copy(std::move(*this));
if (!future.isReady()) {
......@@ -2391,7 +2395,7 @@ T Future<T>::getVia(DrivableExecutor* e) {
}
template <class T>
T Future<T>::getVia(TimedDrivableExecutor* e, Duration dur) {
T Future<T>::getVia(TimedDrivableExecutor* e, HighResDuration dur) {
waitVia(e, dur);
if (!this->isReady()) {
throw_exception<FutureTimeout>();
......@@ -2405,7 +2409,7 @@ Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
}
template <class T>
Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, Duration dur) {
Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, HighResDuration dur) {
waitVia(e, dur);
if (!this->isReady()) {
throw_exception<FutureTimeout>();
......@@ -2557,7 +2561,7 @@ SemiFuture<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) {
return makeSemiFuture();
}
return after(std::chrono::duration_cast<Duration>(when - now));
return after(std::chrono::duration_cast<HighResDuration>(when - now));
}
} // namespace folly
......@@ -22,7 +22,7 @@
namespace folly {
namespace futures {
SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) {
SemiFuture<Unit> sleep(HighResDuration dur, Timekeeper* tk) {
std::shared_ptr<Timekeeper> tks;
if (LIKELY(!tk)) {
tks = folly::detail::getTimekeeperSingleton();
......@@ -36,7 +36,7 @@ SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) {
return tk->after(dur);
}
Future<Unit> sleepUnsafe(Duration dur, Timekeeper* tk) {
Future<Unit> sleepUnsafe(HighResDuration dur, Timekeeper* tk) {
return sleep(dur, tk).toUnsafeFuture();
}
......
......@@ -589,7 +589,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Postconditions:
///
/// - `valid() == false`
T get(Duration dur) &&;
T get(HighResDuration dur) &&;
/// Blocks until the future is fulfilled. Returns the Try of the result
/// (moved-out).
......@@ -614,7 +614,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Postconditions:
///
/// - `valid() == false`
Try<T> getTry(Duration dur) &&;
Try<T> getTry(HighResDuration dur) &&;
/// Blocks the caller's thread until this Future `isReady()`, i.e., until the
/// asynchronous producer has stored a result or exception.
......@@ -655,7 +655,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Postconditions:
///
/// - `valid() == false`
bool wait(Duration dur) &&;
bool wait(HighResDuration dur) &&;
/// Returns a Future which will call back on the other side of executor.
Future<T> via(Executor::KeepAlive<> executor) &&;
......@@ -852,7 +852,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
SemiFuture<T> within(Duration dur, Timekeeper* tk = nullptr) && {
SemiFuture<T> within(HighResDuration dur, Timekeeper* tk = nullptr) && {
return std::move(*this).within(dur, FutureTimeout(), tk);
}
......@@ -871,7 +871,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class E>
SemiFuture<T> within(Duration dur, E e, Timekeeper* tk = nullptr) &&;
SemiFuture<T> within(HighResDuration dur, E e, Timekeeper* tk = nullptr) &&;
/// Delay the completion of this SemiFuture for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep().
......@@ -884,7 +884,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
SemiFuture<T> delayed(Duration dur, Timekeeper* tk = nullptr) &&;
SemiFuture<T> delayed(HighResDuration dur, Timekeeper* tk = nullptr) &&;
/// Returns a future that completes inline, as if the future had no executor.
/// Intended for porting legacy code without behavioral change, and for rare
......@@ -955,7 +955,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// - `valid() == true`
/// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true
SemiFuture<T>& wait(Duration dur) &;
SemiFuture<T>& wait(HighResDuration dur) &;
static void releaseDeferredExecutor(Core* core);
};
......@@ -1122,7 +1122,7 @@ class Future : private futures::detail::FutureBase<T> {
///
/// Returns the fulfilled value (moved-out), throws the fulfilled exception,
/// or on timeout throws FutureTimeout.
T getVia(TimedDrivableExecutor* e, Duration dur);
T getVia(TimedDrivableExecutor* e, HighResDuration dur);
/// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns a
......@@ -1131,7 +1131,7 @@ class Future : private futures::detail::FutureBase<T> {
/// getTryVia but will wait only until `dur` elapses. Returns the
/// Try of the value (moved-out) or may throw a FutureTimeout exception.
Try<T>& getTryVia(TimedDrivableExecutor* e, Duration dur);
Try<T>& getTryVia(TimedDrivableExecutor* e, HighResDuration dur);
/// Unwraps the case of a Future<Future<T>> instance, and returns a simple
/// Future<T> instance.
......@@ -1641,7 +1641,7 @@ class Future : private futures::detail::FutureBase<T> {
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class F>
Future<T> onTimeout(Duration, F&& func, Timekeeper* = nullptr) &&;
Future<T> onTimeout(HighResDuration, F&& func, Timekeeper* = nullptr) &&;
/// If this Future completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout
......@@ -1658,7 +1658,7 @@ class Future : private futures::detail::FutureBase<T> {
/// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
Future<T> within(Duration dur, Timekeeper* tk = nullptr) &&;
Future<T> within(HighResDuration dur, Timekeeper* tk = nullptr) &&;
/// If this SemiFuture completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with exception e.
......@@ -1675,7 +1675,8 @@ class Future : private futures::detail::FutureBase<T> {
/// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true`
template <class E>
Future<T> within(Duration dur, E exception, Timekeeper* tk = nullptr) &&;
Future<T>
within(HighResDuration dur, E exception, Timekeeper* tk = nullptr) &&;
/// Delay the completion of this Future for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep().
......@@ -1688,7 +1689,7 @@ class Future : private futures::detail::FutureBase<T> {
///
/// - `valid() == false`
/// - `RESULT.valid() == true`
Future<T> delayed(Duration, Timekeeper* = nullptr) &&;
Future<T> delayed(HighResDuration, Timekeeper* = nullptr) &&;
/// Blocks until the future is fulfilled. Returns the value (moved-out), or
/// throws the exception. The future must not already have a continuation.
......@@ -1713,7 +1714,7 @@ class Future : private futures::detail::FutureBase<T> {
/// Postconditions:
///
/// - `valid() == false`
T get(Duration dur) &&;
T get(HighResDuration dur) &&;
/// A reference to the Try of the value
///
......@@ -1761,7 +1762,7 @@ class Future : private futures::detail::FutureBase<T> {
/// - `valid() == true` (so you may call `wait(...)` repeatedly)
/// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true
Future<T>& wait(Duration dur) &;
Future<T>& wait(HighResDuration dur) &;
/// Blocks until this Future is complete or until `dur` passes.
///
......@@ -1775,7 +1776,7 @@ class Future : private futures::detail::FutureBase<T> {
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true
Future<T>&& wait(Duration dur) &&;
Future<T>&& wait(HighResDuration dur) &&;
/// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns a
......@@ -1815,7 +1816,7 @@ class Future : private futures::detail::FutureBase<T> {
///
/// - `valid() == true` (does not move-out `*this`)
/// - `&RESULT == this`
Future<T>& waitVia(TimedDrivableExecutor* e, Duration dur) &;
Future<T>& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &;
/// Overload of waitVia() for rvalue Futures
/// As waitVia but may return early after dur passes.
......@@ -1829,7 +1830,7 @@ class Future : private futures::detail::FutureBase<T> {
/// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this`
Future<T>&& waitVia(TimedDrivableExecutor* e, Duration dur) &&;
Future<T>&& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &&;
/// If the value in this Future is equal to the given Future, when they have
/// both completed, the value of the resulting Future<bool> will be true. It
......@@ -1929,8 +1930,8 @@ class Future : private futures::detail::FutureBase<T> {
/// Delays that are used to trigger timeouts of async operations), then you
/// can and should cancel them to reclaim resources.
///
/// Users will typically get one of these via Future::sleep(Duration dur) or
/// use them implicitly behind the scenes by passing a timeout to some Future
/// Users will typically get one of these via Future::sleep(HighResDuration dur)
/// or use them implicitly behind the scenes by passing a timeout to some Future
/// operation.
///
/// Although we don't formally alias Delay = Future<Unit>,
......@@ -1938,14 +1939,14 @@ class Future : private futures::detail::FutureBase<T> {
/// Timeouts, and that's ok I guess, but that term is so overloaded I thought
/// it made sense to introduce a cleaner term.
///
/// Remember that Duration is a std::chrono duration (millisecond resolution
/// at the time of writing). When writing code that uses specific durations,
/// prefer using the explicit std::chrono type, e.g. std::chrono::milliseconds
/// over Duration. This makes the code more legible and means you won't be
/// unpleasantly surprised if we redefine Duration to microseconds, or
/// something.
/// Remember that HighResDuration is a std::chrono duration (millisecond
/// resolution at the time of writing). When writing code that uses specific
/// durations, prefer using the explicit std::chrono type, e.g.
/// std::chrono::milliseconds over HighResDuration. This makes the code more
/// legible and means you won't be unpleasantly surprised if we redefine
/// HighResDuration to microseconds, or something.
///
/// timekeeper.after(std::chrono::duration_cast<Duration>(someNanoseconds))
/// timekeeper.after(std::chrono::duration_cast<HighResDuration>(someNanoseconds))
class Timekeeper {
public:
virtual ~Timekeeper() = default;
......@@ -1955,7 +1956,7 @@ class Timekeeper {
/// exceptional. Use the steady (monotonic) clock.
///
/// The consumer thread may cancel this Future to reclaim resources.
virtual SemiFuture<Unit> after(Duration dur) = 0;
virtual SemiFuture<Unit> after(HighResDuration dur) = 0;
/// Unsafe version of after that returns an inline Future.
/// Any work added to this future will run inline on the Timekeeper's thread.
......@@ -1963,7 +1964,7 @@ class Timekeeper {
///
/// Please migrate to use after + a call to via with a valid, non-inline
/// executor.
Future<Unit> afterUnsafe(Duration dur) {
Future<Unit> afterUnsafe(HighResDuration dur) {
return after(dur).toUnsafeFuture();
}
......@@ -2018,7 +2019,7 @@ auto makeAsyncTask(folly::Executor::KeepAlive<> ka, F&& func) {
/// and "sleep".
namespace futures {
/// Returns a Future that will complete after the specified duration. The
/// Duration typedef of a `std::chrono` duration type indicates the
/// HighResDuration typedef of a `std::chrono` duration type indicates the
/// resolution you can expect to be meaningful (milliseconds at the time of
/// writing). Normally you wouldn't need to specify a Timekeeper, we will
/// use the global futures timekeeper (we run a thread whose job it is to
......@@ -2028,12 +2029,12 @@ namespace futures {
/// The Timekeeper thread will be lazily created the first time it is
/// needed. If your program never uses any timeouts or other time-based
/// Futures you will pay no Timekeeper thread overhead.
SemiFuture<Unit> sleep(Duration, Timekeeper* = nullptr);
SemiFuture<Unit> sleep(HighResDuration, Timekeeper* = nullptr);
[[deprecated(
"futures::sleep now returns a SemiFuture<Unit>. "
"sleepUnsafe is deprecated. "
"Please call futures::sleep and apply an executor with .via")]] Future<Unit>
sleepUnsafe(Duration, Timekeeper* = nullptr);
sleepUnsafe(HighResDuration, Timekeeper* = nullptr);
/**
* Set func as the callback for each input Future and return a vector of
......
......@@ -20,7 +20,7 @@ namespace folly {
ManualTimekeeper::ManualTimekeeper() : now_{std::chrono::steady_clock::now()} {}
SemiFuture<Unit> ManualTimekeeper::after(Duration dur) {
SemiFuture<Unit> ManualTimekeeper::after(HighResDuration dur) {
auto contract = folly::makePromiseContract<Unit>();
if (dur.count() == 0) {
contract.first.setValue(folly::unit);
......
......@@ -35,7 +35,7 @@ class ManualTimekeeper : public folly::Timekeeper {
/// The returned future is completed when someone calls advance and pushes the
/// executor's clock to a value greater than or equal to (now() + dur)
SemiFuture<Unit> after(folly::Duration dur) override;
SemiFuture<Unit> after(folly::HighResDuration dur) override;
/// Advance the timekeeper's clock to (now() + dur). All futures with target
/// time points less than or equal to (now() + dur) are fulfilled after the
......
......@@ -16,6 +16,7 @@
#include <folly/futures/ThreadWheelTimekeeper.h>
#include <folly/Chrono.h>
#include <folly/Singleton.h>
#include <folly/futures/Future.h>
#include <future>
......@@ -121,7 +122,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
thread_.join();
}
SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) {
SemiFuture<Unit> ThreadWheelTimekeeper::after(HighResDuration dur) {
auto cob = WTCallback::create(&eventBase_);
auto f = cob->getSemiFuture();
//
......@@ -138,8 +139,9 @@ SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) {
// callback has either been executed, or will never be executed. So we are
// fine here.
//
eventBase_.runInEventBaseThread(
[this, cob, dur] { wheelTimer_->scheduleTimeout(cob.get(), dur); });
eventBase_.runInEventBaseThread([this, cob, dur] {
wheelTimer_->scheduleTimeout(cob.get(), folly::chrono::ceil<Duration>(dur));
});
return f;
}
......
......@@ -33,7 +33,7 @@ class ThreadWheelTimekeeper : public Timekeeper {
~ThreadWheelTimekeeper() override;
/// Implement the Timekeeper interface
SemiFuture<Unit> after(Duration) override;
SemiFuture<Unit> after(HighResDuration) override;
protected:
folly::EventBase eventBase_;
......
......@@ -34,6 +34,7 @@ namespace folly {
///
/// futures::sleep(std::chrono::seconds(1));
using Duration = std::chrono::milliseconds;
using HighResDuration = std::chrono::microseconds;
namespace futures {
namespace detail {
......
......@@ -136,7 +136,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) {
});
}
SemiFuture<Unit> after(Duration) override {
SemiFuture<Unit> after(HighResDuration) override {
return p_.getSemiFuture();
}
......@@ -155,7 +155,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) {
TEST(Timekeeper, semiFutureWithinInlineAfter) {
struct MockTimekeeper : Timekeeper {
SemiFuture<Unit> after(Duration) override {
SemiFuture<Unit> after(HighResDuration) override {
return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper());
}
};
......@@ -169,7 +169,7 @@ TEST(Timekeeper, semiFutureWithinInlineAfter) {
TEST(Timekeeper, semiFutureWithinReady) {
struct MockTimekeeper : Timekeeper {
SemiFuture<Unit> after(Duration) override {
SemiFuture<Unit> after(HighResDuration) override {
called_ = true;
return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper());
}
......
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