summaryrefslogtreecommitdiffstats
path: root/src/osd/scrubber/scrub_queue_entry.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/scrubber/scrub_queue_entry.h')
-rw-r--r--src/osd/scrubber/scrub_queue_entry.h222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/osd/scrubber/scrub_queue_entry.h b/src/osd/scrubber/scrub_queue_entry.h
new file mode 100644
index 00000000000..aeb76c104fe
--- /dev/null
+++ b/src/osd/scrubber/scrub_queue_entry.h
@@ -0,0 +1,222 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#pragma once
+
+#include <compare>
+#include <string_view>
+
+#include "include/utime.h"
+#include "osd/osd_types.h"
+#include "osd/scrubber_common.h"
+
+namespace Scrub {
+
+/**
+ * Possible urgency levels for a specific scheduling target (shallow or deep):
+ *
+ * (note: the 'urgency' attribute conveys both the relative priority for
+ * scheduling and the behavior of the scrub). The urgency levels are:
+ * ^^^^^^^^^^^^^^^^^^^^^
+ *
+ * periodic scrubs:
+ * ---------------
+ *
+ * 'periodic_regular' - the "standard" shallow/deep scrub performed
+ * periodically on each PG.
+ *
+ *
+ * priority scrubs (termed 'required' or 'must' in the legacy code):
+ * ---------------------------------------------------------------
+ * In order of ascending priority:
+ *
+ * 'must_scrub' - the PG info is not valid (i.e. we do not have a valid
+ * 'last-scrub' stamp). A high-priority shallow scrub is required.
+ *
+ * 'after_repair' - triggered immediately after a recovery process
+ * ('m_after_repair_scrub_required' was set).
+ * This type of scrub is always deep.
+ * (note: this urgency level is not implemented in this commit)
+ *
+ * 'repairing' - the target is currently being deep-scrubbed with the repair
+ * flag set. Triggered by a previous shallow scrub that ended with errors.
+ *
+ * 'operator_requested' - the target was manually requested for scrubbing by
+ * an administrator.
+ *
+ * 'must_repair' - the target is required to be deep-scrubbed with the
+ * repair flag set, initiated by a message specifying 'do_repair'.
+ */
+enum class urgency_t {
+ periodic_regular,
+ must_scrub,
+ after_repair,
+ repairing,
+ operator_requested,
+ must_repair,
+};
+
+/**
+ * SchedEntry holds the scheduling details for scrubbing a specific PG at
+ * a specific scrub level. Namely - it identifies the [pg,level] combination,
+ * the 'urgency' attribute of the scheduled scrub (which determines most of
+ * its behavior and scheduling decisions) and the actual time attributes
+ * for scheduling (target, deadline, not_before).
+ *
+ * In this commit - the 'urgency' attribute is not fully used yet, and some
+ * of the scrub behavior is still controlled by the 'planned scrub' flags.
+ */
+struct SchedEntry {
+ constexpr SchedEntry(spg_t pgid, scrub_level_t level)
+ : pgid{pgid}
+ , level{level}
+ {}
+
+ SchedEntry(const SchedEntry&) = default;
+ SchedEntry(SchedEntry&&) = default;
+ SchedEntry& operator=(const SchedEntry&) = default;
+ SchedEntry& operator=(SchedEntry&&) = default;
+
+ spg_t pgid;
+ scrub_level_t level;
+
+ urgency_t urgency{urgency_t::periodic_regular};
+
+ /// scheduled_at, not-before & the deadline times
+ Scrub::scrub_schedule_t schedule;
+
+ /// either 'none', or the reason for the latest failure/delay (for
+ /// logging/reporting purposes)
+ delay_cause_t last_issue{delay_cause_t::none};
+};
+
+
+static inline std::weak_ordering cmp_ripe_entries(
+ const Scrub::SchedEntry& l,
+ const Scrub::SchedEntry& r) noexcept
+{
+ // for 'higher is better' sub elements - the 'r.' is on the left
+ if (auto cmp = r.urgency <=> l.urgency; cmp != 0) {
+ return cmp;
+ }
+ // the 'utime_t' operator<=> is 'partial_ordering', it seems.
+ if (auto cmp = std::weak_order(
+ double(l.schedule.scheduled_at), double(r.schedule.scheduled_at));
+ cmp != 0) {
+ return cmp;
+ }
+ if (r.level < l.level) {
+ return std::weak_ordering::less;
+ }
+ if (auto cmp = std::weak_order(
+ double(l.schedule.not_before), double(r.schedule.not_before));
+ cmp != 0) {
+ return cmp;
+ }
+ return std::weak_ordering::greater;
+}
+
+static inline std::weak_ordering cmp_future_entries(
+ const Scrub::SchedEntry& l,
+ const Scrub::SchedEntry& r) noexcept
+{
+ if (auto cmp = std::weak_order(
+ double(l.schedule.not_before), double(r.schedule.not_before));
+ cmp != 0) {
+ return cmp;
+ }
+ // for 'higher is better' sub elements - the 'r.' is on the left
+ if (auto cmp = r.urgency <=> l.urgency; cmp != 0) {
+ return cmp;
+ }
+ if (auto cmp = std::weak_order(
+ double(l.schedule.scheduled_at), double(r.schedule.scheduled_at));
+ cmp != 0) {
+ return cmp;
+ }
+ if (r.level < l.level) {
+ return std::weak_ordering::less;
+ }
+ return std::weak_ordering::greater;
+}
+
+static inline std::weak_ordering cmp_entries(
+ utime_t t,
+ const Scrub::SchedEntry& l,
+ const Scrub::SchedEntry& r) noexcept
+{
+ bool l_ripe = l.schedule.not_before <= t;
+ bool r_ripe = r.schedule.not_before <= t;
+ if (l_ripe) {
+ if (r_ripe) {
+ return cmp_ripe_entries(l, r);
+ }
+ return std::weak_ordering::less;
+ }
+ if (r_ripe) {
+ return std::weak_ordering::greater;
+ }
+ return cmp_future_entries(l, r);
+}
+
+// --- the interface required by 'not_before_queue_t':
+
+static inline const utime_t& project_not_before(const Scrub::SchedEntry& e)
+{
+ return e.schedule.not_before;
+}
+
+static inline const spg_t& project_removal_class(const Scrub::SchedEntry& e)
+{
+ return e.pgid;
+}
+
+
+/// 'not_before_queue_t' requires a '<' operator, to be used for
+/// eligible entries:
+static inline bool operator<(
+ const Scrub::SchedEntry& lhs,
+ const Scrub::SchedEntry& rhs)
+{
+ return cmp_ripe_entries(lhs, rhs) == std::weak_ordering::less;
+}
+
+} // namespace Scrub
+
+
+namespace fmt {
+
+// clang-format off
+template <>
+struct formatter<Scrub::urgency_t> : formatter<std::string_view> {
+ template <typename FormatContext>
+ auto format(Scrub::urgency_t urg, FormatContext& ctx) const
+ {
+ using enum Scrub::urgency_t;
+ std::string_view desc;
+ switch (urg) {
+ case periodic_regular: desc = "periodic-regular"; break;
+ case must_scrub: desc = "must-scrub"; break;
+ case after_repair: desc = "after-repair"; break;
+ case repairing: desc = "repairing"; break;
+ case operator_requested: desc = "operator-requested"; break;
+ case must_repair: desc = "must-repair"; break;
+ // better to not have a default case, so that the compiler will warn
+ }
+ return formatter<string_view>::format(desc, ctx);
+ }
+};
+// clang-format on
+
+template <>
+struct formatter<Scrub::SchedEntry> {
+ constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
+ template <typename FormatContext>
+ auto format(const Scrub::SchedEntry& st, FormatContext& ctx) const
+ {
+ return fmt::format_to(
+ ctx.out(), "{}/{},nb:{:s},({},tr:{:s},dl:{:s})", st.pgid,
+ (st.level == scrub_level_t::deep ? "dp" : "sh"), st.schedule.not_before,
+ st.urgency, st.schedule.scheduled_at, st.schedule.deadline);
+ }
+};
+} // namespace fmt