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() && { ...@@ -870,7 +870,7 @@ SemiFuture<Unit> SemiFuture<T>::unit() && {
} }
template <typename T> 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)) return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.toUnsafeFuture() .toUnsafeFuture()
.thenValue([](std::tuple<Try<T>, Try<Unit>> tup) { .thenValue([](std::tuple<Try<T>, Try<Unit>> tup) {
...@@ -1228,7 +1228,8 @@ Future<T> Future<T>::ensure(F&& func) && { ...@@ -1228,7 +1228,8 @@ Future<T> Future<T>::ensure(F&& func) && {
template <class T> template <class T>
template <class F> 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( return std::move(*this).within(dur, tk).thenError(
tag_t<FutureTimeout>{}, tag_t<FutureTimeout>{},
[funcw = std::forward<F>(func)](auto const&) mutable { [funcw = std::forward<F>(func)](auto const&) mutable {
...@@ -1999,13 +2000,13 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) { ...@@ -1999,13 +2000,13 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) {
// within // within
template <class T> 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); return std::move(*this).within(dur, FutureTimeout(), tk);
} }
template <class T> template <class T>
template <class E> 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()) { if (this->isReady()) {
return std::move(*this); return std::move(*this);
} }
...@@ -2018,7 +2019,8 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && { ...@@ -2018,7 +2019,8 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && {
template <class T> template <class T>
template <typename E> 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()) { if (this->isReady()) {
return std::move(*this); return std::move(*this);
} }
...@@ -2103,7 +2105,7 @@ SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && { ...@@ -2103,7 +2105,7 @@ SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && {
// delayed // delayed
template <class T> 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(); auto e = this->getExecutor();
return collectAllSemiFuture(*this, futures::sleep(dur, tk)) return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.via(e ? e : &InlineExecutor::instance()) .via(e ? e : &InlineExecutor::instance())
...@@ -2153,7 +2155,7 @@ SemiFuture<T> convertFuture(SemiFuture<T>&& sf, const SemiFuture<T>&) { ...@@ -2153,7 +2155,7 @@ SemiFuture<T> convertFuture(SemiFuture<T>&& sf, const SemiFuture<T>&) {
} }
template <class FutureType, typename T = typename FutureType::value_type> 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) { if (std::is_base_of<Future<T>, FutureType>::value) {
f = std::move(f).via(&InlineExecutor::instance()); f = std::move(f).via(&InlineExecutor::instance());
} }
...@@ -2252,7 +2254,7 @@ SemiFuture<T>&& SemiFuture<T>::wait() && { ...@@ -2252,7 +2254,7 @@ SemiFuture<T>&& SemiFuture<T>::wait() && {
} }
template <class T> template <class T>
SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & { SemiFuture<T>& SemiFuture<T>::wait(HighResDuration dur) & {
if (auto deferredExecutor = this->getDeferredExecutor()) { if (auto deferredExecutor = this->getDeferredExecutor()) {
// Make sure that the last callback in the future chain will be run on the // Make sure that the last callback in the future chain will be run on the
// WaitExecutor. // WaitExecutor.
...@@ -2280,7 +2282,7 @@ SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & { ...@@ -2280,7 +2282,7 @@ SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & {
} }
template <class T> template <class T>
bool SemiFuture<T>::wait(Duration dur) && { bool SemiFuture<T>::wait(HighResDuration dur) && {
auto future = std::move(*this); auto future = std::move(*this);
future.wait(dur); future.wait(dur);
return future.isReady(); return future.isReady();
...@@ -2292,7 +2294,7 @@ T SemiFuture<T>::get() && { ...@@ -2292,7 +2294,7 @@ T SemiFuture<T>::get() && {
} }
template <class T> template <class T>
T SemiFuture<T>::get(Duration dur) && { T SemiFuture<T>::get(HighResDuration dur) && {
return std::move(*this).getTry(dur).value(); return std::move(*this).getTry(dur).value();
} }
...@@ -2305,7 +2307,7 @@ Try<T> SemiFuture<T>::getTry() && { ...@@ -2305,7 +2307,7 @@ Try<T> SemiFuture<T>::getTry() && {
} }
template <class T> template <class T>
Try<T> SemiFuture<T>::getTry(Duration dur) && { Try<T> SemiFuture<T>::getTry(HighResDuration dur) && {
wait(dur); wait(dur);
auto future = folly::Future<T>(this->core_); auto future = folly::Future<T>(this->core_);
this->core_ = nullptr; this->core_ = nullptr;
...@@ -2329,13 +2331,13 @@ Future<T>&& Future<T>::wait() && { ...@@ -2329,13 +2331,13 @@ Future<T>&& Future<T>::wait() && {
} }
template <class T> template <class T>
Future<T>& Future<T>::wait(Duration dur) & { Future<T>& Future<T>::wait(HighResDuration dur) & {
futures::detail::waitImpl(*this, dur); futures::detail::waitImpl(*this, dur);
return *this; return *this;
} }
template <class T> template <class T>
Future<T>&& Future<T>::wait(Duration dur) && { Future<T>&& Future<T>::wait(HighResDuration dur) && {
futures::detail::waitImpl(*this, dur); futures::detail::waitImpl(*this, dur);
return std::move(*this); return std::move(*this);
} }
...@@ -2353,13 +2355,15 @@ Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && { ...@@ -2353,13 +2355,15 @@ Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
} }
template <class T> 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); futures::detail::waitViaImpl(*this, e, dur);
return *this; return *this;
} }
template <class T> 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); futures::detail::waitViaImpl(*this, e, dur);
return std::move(*this); return std::move(*this);
} }
...@@ -2371,7 +2375,7 @@ T Future<T>::get() && { ...@@ -2371,7 +2375,7 @@ T Future<T>::get() && {
} }
template <class T> template <class T>
T Future<T>::get(Duration dur) && { T Future<T>::get(HighResDuration dur) && {
wait(dur); wait(dur);
auto future = copy(std::move(*this)); auto future = copy(std::move(*this));
if (!future.isReady()) { if (!future.isReady()) {
...@@ -2391,7 +2395,7 @@ T Future<T>::getVia(DrivableExecutor* e) { ...@@ -2391,7 +2395,7 @@ T Future<T>::getVia(DrivableExecutor* e) {
} }
template <class T> template <class T>
T Future<T>::getVia(TimedDrivableExecutor* e, Duration dur) { T Future<T>::getVia(TimedDrivableExecutor* e, HighResDuration dur) {
waitVia(e, dur); waitVia(e, dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<FutureTimeout>(); throw_exception<FutureTimeout>();
...@@ -2405,7 +2409,7 @@ Try<T>& Future<T>::getTryVia(DrivableExecutor* e) { ...@@ -2405,7 +2409,7 @@ Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
} }
template <class T> template <class T>
Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, Duration dur) { Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, HighResDuration dur) {
waitVia(e, dur); waitVia(e, dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<FutureTimeout>(); throw_exception<FutureTimeout>();
...@@ -2557,7 +2561,7 @@ SemiFuture<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) { ...@@ -2557,7 +2561,7 @@ SemiFuture<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) {
return makeSemiFuture(); return makeSemiFuture();
} }
return after(std::chrono::duration_cast<Duration>(when - now)); return after(std::chrono::duration_cast<HighResDuration>(when - now));
} }
} // namespace folly } // namespace folly
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
namespace folly { namespace folly {
namespace futures { namespace futures {
SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) { SemiFuture<Unit> sleep(HighResDuration dur, Timekeeper* tk) {
std::shared_ptr<Timekeeper> tks; std::shared_ptr<Timekeeper> tks;
if (LIKELY(!tk)) { if (LIKELY(!tk)) {
tks = folly::detail::getTimekeeperSingleton(); tks = folly::detail::getTimekeeperSingleton();
...@@ -36,7 +36,7 @@ SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) { ...@@ -36,7 +36,7 @@ SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) {
return tk->after(dur); return tk->after(dur);
} }
Future<Unit> sleepUnsafe(Duration dur, Timekeeper* tk) { Future<Unit> sleepUnsafe(HighResDuration dur, Timekeeper* tk) {
return sleep(dur, tk).toUnsafeFuture(); return sleep(dur, tk).toUnsafeFuture();
} }
......
This diff is collapsed.
...@@ -20,7 +20,7 @@ namespace folly { ...@@ -20,7 +20,7 @@ namespace folly {
ManualTimekeeper::ManualTimekeeper() : now_{std::chrono::steady_clock::now()} {} 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>(); auto contract = folly::makePromiseContract<Unit>();
if (dur.count() == 0) { if (dur.count() == 0) {
contract.first.setValue(folly::unit); contract.first.setValue(folly::unit);
......
...@@ -35,7 +35,7 @@ class ManualTimekeeper : public folly::Timekeeper { ...@@ -35,7 +35,7 @@ class ManualTimekeeper : public folly::Timekeeper {
/// The returned future is completed when someone calls advance and pushes the /// 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) /// 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 /// 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 /// time points less than or equal to (now() + dur) are fulfilled after the
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <folly/futures/ThreadWheelTimekeeper.h> #include <folly/futures/ThreadWheelTimekeeper.h>
#include <folly/Chrono.h>
#include <folly/Singleton.h> #include <folly/Singleton.h>
#include <folly/futures/Future.h> #include <folly/futures/Future.h>
#include <future> #include <future>
...@@ -121,7 +122,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() { ...@@ -121,7 +122,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
thread_.join(); thread_.join();
} }
SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) { SemiFuture<Unit> ThreadWheelTimekeeper::after(HighResDuration dur) {
auto cob = WTCallback::create(&eventBase_); auto cob = WTCallback::create(&eventBase_);
auto f = cob->getSemiFuture(); auto f = cob->getSemiFuture();
// //
...@@ -138,8 +139,9 @@ SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) { ...@@ -138,8 +139,9 @@ SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) {
// callback has either been executed, or will never be executed. So we are // callback has either been executed, or will never be executed. So we are
// fine here. // fine here.
// //
eventBase_.runInEventBaseThread( eventBase_.runInEventBaseThread([this, cob, dur] {
[this, cob, dur] { wheelTimer_->scheduleTimeout(cob.get(), dur); }); wheelTimer_->scheduleTimeout(cob.get(), folly::chrono::ceil<Duration>(dur));
});
return f; return f;
} }
......
...@@ -33,7 +33,7 @@ class ThreadWheelTimekeeper : public Timekeeper { ...@@ -33,7 +33,7 @@ class ThreadWheelTimekeeper : public Timekeeper {
~ThreadWheelTimekeeper() override; ~ThreadWheelTimekeeper() override;
/// Implement the Timekeeper interface /// Implement the Timekeeper interface
SemiFuture<Unit> after(Duration) override; SemiFuture<Unit> after(HighResDuration) override;
protected: protected:
folly::EventBase eventBase_; folly::EventBase eventBase_;
......
...@@ -34,6 +34,7 @@ namespace folly { ...@@ -34,6 +34,7 @@ namespace folly {
/// ///
/// futures::sleep(std::chrono::seconds(1)); /// futures::sleep(std::chrono::seconds(1));
using Duration = std::chrono::milliseconds; using Duration = std::chrono::milliseconds;
using HighResDuration = std::chrono::microseconds;
namespace futures { namespace futures {
namespace detail { namespace detail {
......
...@@ -136,7 +136,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) { ...@@ -136,7 +136,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) {
}); });
} }
SemiFuture<Unit> after(Duration) override { SemiFuture<Unit> after(HighResDuration) override {
return p_.getSemiFuture(); return p_.getSemiFuture();
} }
...@@ -155,7 +155,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) { ...@@ -155,7 +155,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) {
TEST(Timekeeper, semiFutureWithinInlineAfter) { TEST(Timekeeper, semiFutureWithinInlineAfter) {
struct MockTimekeeper : Timekeeper { struct MockTimekeeper : Timekeeper {
SemiFuture<Unit> after(Duration) override { SemiFuture<Unit> after(HighResDuration) override {
return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper()); return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper());
} }
}; };
...@@ -169,7 +169,7 @@ TEST(Timekeeper, semiFutureWithinInlineAfter) { ...@@ -169,7 +169,7 @@ TEST(Timekeeper, semiFutureWithinInlineAfter) {
TEST(Timekeeper, semiFutureWithinReady) { TEST(Timekeeper, semiFutureWithinReady) {
struct MockTimekeeper : Timekeeper { struct MockTimekeeper : Timekeeper {
SemiFuture<Unit> after(Duration) override { SemiFuture<Unit> after(HighResDuration) override {
called_ = true; called_ = true;
return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper()); 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