]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
osd/scrub: decoupling the FSM from the scrubber 62557/head
authorRonen Friedman <rfriedma@redhat.com>
Fri, 28 Mar 2025 16:16:52 +0000 (11:16 -0500)
committerRonen Friedman <rfriedma@redhat.com>
Tue, 1 Apr 2025 04:37:35 +0000 (23:37 -0500)
The scrubber FSM has always been accessing the PgScrubber
object via an abstract interface (ScrubMachineListener).
But the reverse was not true: the PgScrubber owned a unique_ptr
directly to an instance of Scrubber::ScrubMachine.

This PR introduces a new interface, ScrubFsmIf, that is
implemented by the ScrubMachine. This simplifies
unit-testing the PgScrubber, as we can now inject a mock
implementation of the FSM interface.

Signed-off-by: Ronen Friedman <rfriedma@redhat.com>
src/osd/scrubber/pg_scrubber.h
src/osd/scrubber/scrub_machine.h
src/osd/scrubber/scrub_machine_if.h [new file with mode: 0644]

index d6c686e3ac4f58a891a2688db4ac0997cc053bf5..f148101559f5586c7552472d1ce387d39ef41f89 100644 (file)
@@ -84,6 +84,7 @@ Main Scrubber interfaces:
 #include "osd_scrub_sched.h"
 #include "scrub_backend.h"
 #include "scrub_machine_lstnr.h"
+#include "scrub_machine_if.h"
 #include "scrub_reservations.h"
 
 namespace Scrub {
@@ -693,7 +694,7 @@ class PgScrubber : public ScrubPgIF,
                            hobject_t end,
                            bool deep);
 
-  std::unique_ptr<Scrub::ScrubMachine> m_fsm;
+  std::unique_ptr<Scrub::ScrubFsmIf> m_fsm;
   /// the FSM state, as a string for logging
   const char* m_fsm_state_name{nullptr};
   const spg_t m_pg_id; ///< a local copy of m_pg->pg_id
index 5ae895d86df89a73051ab9a685ea664ebca8105e..60a3eea5ab50aebe708f5adaf2c630837f9860a0 100644 (file)
@@ -2,6 +2,7 @@
 // vim: ts=8 sw=2 smarttab
 #pragma once
 
+#include <cassert>
 #include <optional>
 #include <string>
 
@@ -23,6 +24,7 @@
 #include "messages/MOSDRepScrubMap.h"
 #include "osd/scrubber_common.h"
 
+#include "scrub_machine_if.h"
 #include "scrub_machine_lstnr.h"
 #include "scrub_reservations.h"
 
@@ -278,28 +280,34 @@ struct ReplicaWaitUpdates;
 struct ReplicaBuildingMap;
 
 
-class ScrubMachine : public sc::state_machine<ScrubMachine, NotActive> {
+class ScrubMachine : public ScrubFsmIf, public sc::state_machine<ScrubMachine, NotActive> {
  public:
   friend class PgScrubber;
 
  public:
   explicit ScrubMachine(PG* pg, ScrubMachineListener* pg_scrub);
-  ~ScrubMachine();
+  virtual ~ScrubMachine();
 
   spg_t m_pg_id;
   ScrubMachineListener* m_scrbr;
   std::ostream& gen_prefix(std::ostream& out) const;
 
-  void assert_not_in_session() const;
-  [[nodiscard]] bool is_reserving() const;
-  [[nodiscard]] bool is_accepting_updates() const;
-  [[nodiscard]] bool is_primary_idle() const;
+  void assert_not_in_session() const final;
+  [[nodiscard]] bool is_reserving() const final;
+  [[nodiscard]] bool is_accepting_updates() const final;
+  [[nodiscard]] bool is_primary_idle() const final;
 
   /// elapsed time for the currently active scrub.session
-  ceph::timespan get_time_scrubbing() const;
+  ceph::timespan get_time_scrubbing() const final;
 
   /// replica reservation process status
-  std::optional<pg_scrubbing_status_t> get_reservation_status() const;
+  std::optional<pg_scrubbing_status_t> get_reservation_status() const final;
+
+  void initiate() final { sc::state_machine<ScrubMachine, NotActive>::initiate(); }
+
+  void process_event(const boost::statechart::event_base& evt) final {
+    sc::state_machine<ScrubMachine, NotActive>::process_event(evt);
+  }
 
 // ///////////////// aux declarations & functions //////////////////////// //
 
diff --git a/src/osd/scrubber/scrub_machine_if.h b/src/osd/scrubber/scrub_machine_if.h
new file mode 100644 (file)
index 0000000..c49ac3c
--- /dev/null
@@ -0,0 +1,59 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+/**
+ * \file the FSM API used by the scrubber
+ */
+#include <boost/statechart/event.hpp>
+#include <boost/statechart/event_base.hpp>
+#include <boost/statechart/simple_state.hpp>
+#include <boost/statechart/state.hpp>
+#include <boost/statechart/state_machine.hpp>
+
+#include "osd/scrubber_common.h"
+
+namespace Scrub {
+
+namespace sc = ::boost::statechart;
+
+
+/// the FSM API used by the scrubber
+class ScrubFsmIf {
+ public:
+  virtual ~ScrubFsmIf() = default;
+
+  virtual void process_event(const sc::event_base& evt) = 0;
+
+  /// 'true' if the FSM state is PrimaryActive/PrimaryIdle
+  [[nodiscard]] virtual bool is_primary_idle() const = 0;
+
+  /// 'true' if the FSM state is PrimaryActive/Session/ReservingReplicas
+  [[nodiscard]] virtual bool is_reserving() const = 0;
+
+  /// 'true' if the FSM state is PrimaryActive/Session/Act/WaitLastUpdate
+  [[nodiscard]] virtual bool is_accepting_updates() const = 0;
+
+  /// verify state is not any substate of PrimaryActive/Session
+  virtual void assert_not_in_session() const = 0;
+
+  /**
+   * time passed since entering the current scrubbing session.
+   * Specifically - since the Session ctor has completed.
+   */
+  virtual ceph::timespan get_time_scrubbing() const = 0;
+
+  /**
+   * if we are in the ReservingReplicas state - fetch the reservation status.
+   * The returned data names the last request sent to the replicas, and
+   * how many replicas responded / are yet expected to respond.
+   */
+  virtual std::optional<pg_scrubbing_status_t> get_reservation_status()
+      const = 0;
+
+  /// "initiate" the state machine (an internal state_chart function)
+  virtual void initiate() = 0;
+};
+
+}  // namespace Scrub
+