}
template <typename OpT, typename T>
- seastar::future<>
- do_enter(T &stage, typename T::BlockingEvent::template Trigger<OpT>&& t) {
- auto fut = t.maybe_record_blocking(stage.enter(t), stage);
- return std::move(fut).then(
- [this, t=std::move(t)](auto &&barrier_ref) mutable {
+ std::optional<seastar::future<>>
+ do_enter_maybe_sync(T &stage, typename T::BlockingEvent::template Trigger<OpT>&& t) {
+ if constexpr (!T::is_enter_sync) {
+ auto fut = t.maybe_record_blocking(stage.enter(t), stage);
+ return std::move(fut).then(
+ [this, t=std::move(t)](auto &&barrier_ref) {
+ exit();
+ barrier = std::move(barrier_ref);
+ return seastar::now();
+ });
+ } else {
+ auto barrier_ref = stage.enter(t);
exit();
barrier = std::move(barrier_ref);
- return seastar::now();
- });
+ return std::nullopt;
+ }
+ }
+
+ template <typename OpT, typename T>
+ std::optional<seastar::future<>>
+ enter_maybe_sync(T &stage, typename T::BlockingEvent::template Trigger<OpT>&& t) {
+ assert(stage.core == seastar::this_shard_id());
+ auto wait_fut = wait_barrier();
+ if (wait_fut.has_value()) {
+ return wait_fut.value(
+ ).then([this, &stage, t=std::move(t)]() mutable {
+ auto ret = do_enter_maybe_sync<OpT, T>(stage, std::move(t));
+ if constexpr (!T::is_enter_sync) {
+ return std::move(ret.value());
+ } else {
+ assert(ret == std::nullopt);
+ return seastar::now();
+ }
+ });
+ } else {
+ return do_enter_maybe_sync<OpT, T>(stage, std::move(t));
+ }
}
public:
template <typename OpT, typename T>
seastar::future<>
enter(T &stage, typename T::BlockingEvent::template Trigger<OpT>&& t) {
- assert(stage.core == seastar::this_shard_id());
- auto wait_fut = wait_barrier();
- if (wait_fut.has_value()) {
- return wait_fut.value(
- ).then([this, &stage, t=std::move(t)]() mutable {
- return do_enter<OpT, T>(stage, std::move(t));
- });
+ auto ret = enter_maybe_sync<OpT, T>(stage, std::move(t));
+ if (ret.has_value()) {
+ return std::move(ret.value());
} else {
- return do_enter<OpT, T>(stage, std::move(t));
+ return seastar::now();
}
}
+ /**
+ * Synchronously leaves the previous stage and enters the next stage.
+ * Required for the use case which needs ordering upon entering an
+ * ordered concurrent phase.
+ */
+ template <typename OpT, typename T>
+ void
+ enter_sync(T &stage, typename T::BlockingEvent::template Trigger<OpT>&& t) {
+ static_assert(T::is_enter_sync);
+ auto ret = enter_maybe_sync<OpT, T>(stage, std::move(t));
+ // Expect that barrier->wait() (leaving the previous stage)
+ // also returns nullopt, see enter_maybe_sync() above
+ ceph_assert(!ret.has_value());
+ }
+
/**
* Completes pending exit barrier without entering a new one.
*/
}
public:
+ static constexpr bool is_enter_sync = false;
+
template <class TriggerT>
seastar::future<PipelineExitBarrierI::Ref> enter(TriggerT& t) {
waiting++;
};
public:
+ static constexpr bool is_enter_sync = true;
+
template <class TriggerT>
- seastar::future<PipelineExitBarrierI::Ref> enter(TriggerT& t) {
- return seastar::make_ready_future<PipelineExitBarrierI::Ref>(
- new ExitBarrier<TriggerT>{*this, mutex.lock(), t});
+ PipelineExitBarrierI::Ref enter(TriggerT& t) {
+ return std::make_unique<ExitBarrier<TriggerT>>(*this, mutex.lock(), t);
}
private:
};
public:
- template <class... IgnoreArgs>
- seastar::future<PipelineExitBarrierI::Ref> enter(IgnoreArgs&&...) {
- return seastar::make_ready_future<PipelineExitBarrierI::Ref>(
- new ExitBarrier);
+ static constexpr bool is_enter_sync = true;
+
+ template <class TriggerT>
+ PipelineExitBarrierI::Ref enter(TriggerT&) {
+ return std::make_unique<ExitBarrier>();
}
};
get_event<EventT>().trigger(*that(), std::forward<Args>(args)...);
}
+ template <class BlockingEventT>
+ typename BlockingEventT::template Trigger<T>
+ get_trigger() {
+ return {get_event<BlockingEventT>(), *that()};
+ }
+
template <class BlockingEventT, class InterruptorT=void, class F>
auto with_blocking_event(F&& f) {
- auto ret = std::forward<F>(f)(typename BlockingEventT::template Trigger<T>{
- get_event<BlockingEventT>(), *that()
- });
+ auto ret = std::forward<F>(f)(get_trigger<BlockingEventT>());
if constexpr (std::is_same_v<InterruptorT, void>) {
return ret;
} else {
});
}
+ template <class StageT>
+ void enter_stage_sync(StageT& stage) {
+ that()->get_handle().template enter_sync<T>(
+ stage, this->template get_trigger<typename StageT::BlockingEvent>());
+ }
+
template <class OpT>
friend class crimson::os::seastore::OperationProxyT;