]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/osd/osd_operation: introduce PhasedOperationT::enter_stage_sync()
authorYingxin Cheng <yingxin.cheng@intel.com>
Mon, 22 Apr 2024 07:29:28 +0000 (15:29 +0800)
committerMatan Breizman <mbreizma@redhat.com>
Thu, 13 Jun 2024 12:18:56 +0000 (15:18 +0300)
Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
(cherry picked from commit 22847658944408446b1acbaa3be80e2aa99df5c6)

src/crimson/common/operation.h
src/crimson/osd/osd_operation.h

index 938db0c87c8eea2edd8b6a15f252e46f24e0924c..1cdc672805fbf464ab8125d806123ef54bd62384 100644 (file)
@@ -502,15 +502,43 @@ class PipelineHandle {
   }
 
   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:
@@ -530,18 +558,29 @@ 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.
    */
@@ -607,6 +646,8 @@ class OrderedExclusivePhaseT : public PipelineStageIT<T> {
   }
 
 public:
+  static constexpr bool is_enter_sync = false;
+
   template <class TriggerT>
   seastar::future<PipelineExitBarrierI::Ref> enter(TriggerT& t) {
     waiting++;
@@ -709,10 +750,11 @@ private:
   };
 
 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:
@@ -742,10 +784,11 @@ class UnorderedStageT : public PipelineStageIT<T> {
   };
 
 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>();
   }
 };
 
index 6c420f2cc2f96459aba093fcca6254b8aafff851..1064a5c8e03e1cfef1a19691b64d08378527708b 100644 (file)
@@ -153,11 +153,15 @@ protected:
     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 {
@@ -196,6 +200,12 @@ protected:
     });
   }
 
+  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;