From cd9d6bc2b51e10182fa2cd498d68c1c426646b8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rados=C5=82aw=20Zarzy=C5=84ski?= <rzarzyns@redhat.com>
Date: Wed, 27 Apr 2022 02:12:21 +0200
Subject: [PATCH] crimson: bring the WaitBarrier tracking
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Radosław Zarzyński <rzarzyns@redhat.com>
---
 src/crimson/common/operation.h                | 49 +++++++++++++++----
 .../osd/osd_operation_external_tracking.h     |  5 ++
 2 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/src/crimson/common/operation.h b/src/crimson/common/operation.h
index 3a35af75abe..d55da04b677 100644
--- a/src/crimson/common/operation.h
+++ b/src/crimson/common/operation.h
@@ -343,8 +343,8 @@ template <class T>
 struct AggregateBlockingEvent {
   struct TriggerI {
     template <class FutureT>
-    decltype(auto) maybe_record_blocking(FutureT&& fut,
-		    			 const typename T::Blocker& blocker) {
+    auto maybe_record_blocking(FutureT&& fut,
+			       const typename T::Blocker& blocker) {
       // AggregateBlockingEvent is supposed to be used on relatively cold
       // paths (recovery), so we don't need to worry about the dynamic
       // polymothps / dynamic memory's overhead.
@@ -615,8 +615,7 @@ public:
   seastar::future<>
   enter(T &stage, typename T::BlockingEvent::template Trigger<OpT>&& t) {
     return wait_barrier().then([this, &stage, t=std::move(t)] () mutable {
-      auto fut = stage.enter();
-      t.maybe_record_blocking(fut, stage);
+      auto fut = t.maybe_record_blocking(stage.enter(t), stage);
       exit();
       return std::move(fut).then(
         [this, t=std::move(t)](auto &&barrier_ref) mutable {
@@ -686,7 +685,8 @@ class OrderedExclusivePhaseT : public PipelineStageIT<T> {
   }
 
 public:
-  seastar::future<PipelineExitBarrierI::Ref> enter() {
+  template <class... IgnoreArgs>
+  seastar::future<PipelineExitBarrierI::Ref> enter(IgnoreArgs&&...) {
     return mutex.lock().then([this] {
       return PipelineExitBarrierI::Ref(new ExitBarrier{this});
     });
@@ -709,22 +709,49 @@ struct OrderedExclusivePhase : OrderedExclusivePhaseT<OrderedExclusivePhase> {
  */
 template <class T>
 class OrderedConcurrentPhaseT : public PipelineStageIT<T> {
+  using base_t = PipelineStageIT<T>;
+public:
+  struct BlockingEvent : base_t::BlockingEvent {
+    using base_t::BlockingEvent::BlockingEvent;
+
+    struct ExitBarrierEvent : TimeEvent<ExitBarrierEvent> {};
+
+    template <class OpT>
+    struct Trigger : base_t::BlockingEvent::template Trigger<OpT> {
+      using base_t::BlockingEvent::template Trigger<OpT>::Trigger;
+
+      template <class FutureT>
+      decltype(auto) maybe_record_exit_barrier(FutureT&& fut) {
+        if (!fut.available()) {
+	  exit_barrier_event.trigger(this->op);
+	}
+	return std::forward<FutureT>(fut);
+      }
+
+      ExitBarrierEvent exit_barrier_event;
+    };
+  };
+
+private:
   void dump_detail(ceph::Formatter *f) const final {}
 
+  template <class TriggerT>
   class ExitBarrier final : public PipelineExitBarrierI {
     OrderedConcurrentPhaseT *phase;
     std::optional<seastar::future<>> barrier;
+    TriggerT trigger;
   public:
     ExitBarrier(
       OrderedConcurrentPhaseT *phase,
-      seastar::future<> &&barrier) : phase(phase), barrier(std::move(barrier)) {}
+      seastar::future<> &&barrier,
+      TriggerT& trigger) : phase(phase), barrier(std::move(barrier)), trigger(trigger) {}
 
     seastar::future<> wait() final {
       assert(phase);
       assert(barrier);
       auto ret = std::move(*barrier);
       barrier = std::nullopt;
-      return ret;
+      return trigger.maybe_record_exit_barrier(std::move(ret));
     }
 
     void exit() final {
@@ -750,9 +777,10 @@ class OrderedConcurrentPhaseT : public PipelineStageIT<T> {
   };
 
 public:
-  seastar::future<PipelineExitBarrierI::Ref> enter() {
+  template <class TriggerT>
+  seastar::future<PipelineExitBarrierI::Ref> enter(TriggerT& t) {
     return seastar::make_ready_future<PipelineExitBarrierI::Ref>(
-      new ExitBarrier{this, mutex.lock()});
+      new ExitBarrier<TriggerT>{this, mutex.lock(), t});
   }
 
 private:
@@ -789,7 +817,8 @@ class UnorderedStageT : public PipelineStageIT<T> {
   };
 
 public:
-  seastar::future<PipelineExitBarrierI::Ref> enter() {
+  template <class... IgnoreArgs>
+  seastar::future<PipelineExitBarrierI::Ref> enter(IgnoreArgs&&...) {
     return seastar::make_ready_future<PipelineExitBarrierI::Ref>(
       new ExitBarrier);
   }
diff --git a/src/crimson/osd/osd_operation_external_tracking.h b/src/crimson/osd/osd_operation_external_tracking.h
index 97794aa66b7..5c64721034e 100644
--- a/src/crimson/osd/osd_operation_external_tracking.h
+++ b/src/crimson/osd/osd_operation_external_tracking.h
@@ -31,6 +31,7 @@ struct LttngBackend
     ClientRequest::PGPipeline::GetOBC::BlockingEvent::Backend,
     ClientRequest::PGPipeline::Process::BlockingEvent::Backend,
     ClientRequest::PGPipeline::WaitRepop::BlockingEvent::Backend,
+    ClientRequest::PGPipeline::WaitRepop::BlockingEvent::ExitBarrierEvent::Backend,
     ClientRequest::PGPipeline::SendReply::BlockingEvent::Backend,
     ClientRequest::CompletionEvent::Backend
 {
@@ -97,6 +98,10 @@ struct LttngBackend
               const ClientRequest::PGPipeline::WaitRepop& blocker) override {
   }
 
+  void handle(ClientRequest::PGPipeline::WaitRepop::BlockingEvent::ExitBarrierEvent& ev,
+              const Operation& op) override {
+  }
+
   void handle(ClientRequest::PGPipeline::SendReply::BlockingEvent& ev,
               const Operation& op,
               const ClientRequest::PGPipeline::SendReply& blocker) override {