1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include <fmt/ranges.h>
7 #include "common/scrub_types.h"
8 #include "include/types.h"
9 #include "os/ObjectStore.h"
11 #include "OpRequest.h"
20 class ReplicaReservations
;
23 /// Facilitating scrub-realated object access to private PG data
24 class ScrubberPasskey
{
26 friend class Scrub::ReplicaReservations
;
27 friend class PrimaryLogScrub
;
28 friend class PgScrubber
;
29 friend class ScrubBackend
;
31 ScrubberPasskey(const ScrubberPasskey
&) = default;
32 ScrubberPasskey
& operator=(const ScrubberPasskey
&) = delete;
37 /// high/low OP priority
38 enum class scrub_prio_t
: bool { low_priority
= false, high_priority
= true };
40 /// Identifies a specific scrub activation within an interval,
41 /// see ScrubPGgIF::m_current_token
42 using act_token_t
= uint32_t;
44 /// "environment" preconditions affecting which PGs are eligible for scrubbing
45 struct ScrubPreconds
{
46 bool allow_requested_repair_only
{false};
47 bool load_is_low
{true};
48 bool time_permit
{true};
49 bool only_deadlined
{false};
52 /// PG services used by the scrubber backend
53 struct PgScrubBeListener
{
54 virtual ~PgScrubBeListener() = default;
56 virtual const PGPool
& get_pgpool() const = 0;
57 virtual pg_shard_t
get_primary() const = 0;
58 virtual void force_object_missing(ScrubberPasskey
,
59 const std::set
<pg_shard_t
>& peer
,
61 eversion_t version
) = 0;
62 virtual const pg_info_t
& get_pg_info(ScrubberPasskey
) const = 0;
64 // query the PG backend for the on-disk size of an object
65 virtual uint64_t logical_to_ondisk_size(uint64_t logical_size
) const = 0;
67 // used to verify our "cleaness" before scrubbing
68 virtual bool is_waiting_for_unreadable_object() const = 0;
75 * Flags affecting the scheduling and behaviour of the *next* scrub.
77 * we hold two of these flag collections: one
78 * for the next scrub, and one frozen at initiation (i.e. in pg::queue_scrub())
80 struct requested_scrub_t
{
82 // flags to indicate explicitly requested scrubs (by admin):
83 // bool must_scrub, must_deep_scrub, must_repair, need_auto;
86 * 'must_scrub' is set by an admin command (or by need_auto).
87 * Affects the priority of the scrubbing, and the sleep periods
90 bool must_scrub
{false};
93 * scrub must not be aborted.
94 * Set for explicitly requested scrubs, and for scrubs originated by the
95 * pairing process with the 'repair' flag set (in the RequestScrub event).
97 * Will be copied into the 'required' scrub flag upon scrub start.
99 bool req_scrub
{false};
103 * - scrub_requested() with need_auto param set, which only happens in
104 * - scrub_finish() - if deep_scrub_on_error is set, and we have errors
106 * If set, will prevent the OSD from casually postponing our scrub. When
107 * scrubbing starts, will cause must_scrub, must_deep_scrub and auto_repair to
110 bool need_auto
{false};
113 * Set for scrub-after-recovery just before we initiate the recovery deep
114 * scrub, or if scrub_requested() was called with either need_auto ot repair.
115 * Affects PG_STATE_DEEP_SCRUB.
117 bool must_deep_scrub
{false};
120 * (An intermediary flag used by pg::sched_scrub() on the first time
121 * a planned scrub has all its resources). Determines whether the next
122 * repair/scrub will be 'deep'.
124 * Note: 'dumped' by PgScrubber::dump() and such. In reality, being a
125 * temporary that is set and reset by the same operation, will never
126 * appear externally to be set
128 bool time_for_deep
{false};
130 bool deep_scrub_on_error
{false};
133 * If set, we should see must_deep_scrub & must_scrub, too
135 * - 'must_repair' is checked by the OSD when scheduling the scrubs.
136 * - also checked & cleared at pg::queue_scrub()
138 bool must_repair
{false};
141 * the value of auto_repair is determined in sched_scrub() (once per scrub.
142 * previous value is not remembered). Set if
143 * - allowed by configuration and backend, and
144 * - must_scrub is not set (i.e. - this is a periodic scrub),
145 * - time_for_deep was just set
147 bool auto_repair
{false};
150 * indicating that we are scrubbing post repair to verify everything is fixed.
151 * Otherwise - PG_STATE_FAILED_REPAIR will be asserted.
153 bool check_repair
{false};
156 * Used to indicate, both in client-facing listings and internally, that
157 * the planned scrub will be a deep one.
159 bool calculated_to_deep
{false};
162 std::ostream
& operator<<(std::ostream
& out
, const requested_scrub_t
& sf
);
165 struct fmt::formatter
<requested_scrub_t
> {
166 constexpr auto parse(format_parse_context
& ctx
) { return ctx
.begin(); }
168 template <typename FormatContext
>
169 auto format(const requested_scrub_t
& rs
, FormatContext
& ctx
)
171 return fmt::format_to(ctx
.out(),
172 "(plnd:{}{}{}{}{}{}{}{}{}{})",
173 rs
.must_repair
? " must_repair" : "",
174 rs
.auto_repair
? " auto_repair" : "",
175 rs
.check_repair
? " check_repair" : "",
176 rs
.deep_scrub_on_error
? " deep_scrub_on_error" : "",
177 rs
.must_deep_scrub
? " must_deep_scrub" : "",
178 rs
.must_scrub
? " must_scrub" : "",
179 rs
.time_for_deep
? " time_for_deep" : "",
180 rs
.need_auto
? " need_auto" : "",
181 rs
.req_scrub
? " req_scrub" : "",
182 rs
.calculated_to_deep
? " deep" : "");
187 * The interface used by the PG when requesting scrub-related info or services
191 virtual ~ScrubPgIF() = default;
193 friend std::ostream
& operator<<(std::ostream
& out
, const ScrubPgIF
& s
)
198 virtual std::ostream
& show(std::ostream
& out
) const = 0;
200 // --------------- triggering state-machine events:
202 virtual void initiate_regular_scrub(epoch_t epoch_queued
) = 0;
204 virtual void initiate_scrub_after_repair(epoch_t epoch_queued
) = 0;
206 virtual void send_scrub_resched(epoch_t epoch_queued
) = 0;
208 virtual void active_pushes_notification(epoch_t epoch_queued
) = 0;
210 virtual void update_applied_notification(epoch_t epoch_queued
) = 0;
212 virtual void digest_update_notification(epoch_t epoch_queued
) = 0;
214 virtual void send_scrub_unblock(epoch_t epoch_queued
) = 0;
216 virtual void send_replica_maps_ready(epoch_t epoch_queued
) = 0;
218 virtual void send_replica_pushes_upd(epoch_t epoch_queued
) = 0;
220 virtual void send_start_replica(epoch_t epoch_queued
,
221 Scrub::act_token_t token
) = 0;
223 virtual void send_sched_replica(epoch_t epoch_queued
,
224 Scrub::act_token_t token
) = 0;
226 virtual void send_full_reset(epoch_t epoch_queued
) = 0;
228 virtual void send_chunk_free(epoch_t epoch_queued
) = 0;
230 virtual void send_chunk_busy(epoch_t epoch_queued
) = 0;
232 virtual void send_local_map_done(epoch_t epoch_queued
) = 0;
234 virtual void send_get_next_chunk(epoch_t epoch_queued
) = 0;
236 virtual void send_scrub_is_finished(epoch_t epoch_queued
) = 0;
238 virtual void on_applied_when_primary(const eversion_t
& applied_version
) = 0;
240 // --------------------------------------------------
242 [[nodiscard
]] virtual bool are_callbacks_pending() const = 0; // currently
248 * the scrubber is marked 'active':
249 * - for the primary: when all replica OSDs grant us the requested resources
250 * - for replicas: upon receiving the scrub request from the primary
252 [[nodiscard
]] virtual bool is_scrub_active() const = 0;
255 * 'true' until after the FSM processes the 'scrub-finished' event,
256 * and scrubbing is completely cleaned-up.
258 * In other words - holds longer than is_scrub_active(), thus preventing
259 * a rescrubbing of the same PG while the previous scrub has not fully
262 [[nodiscard
]] virtual bool is_queued_or_active() const = 0;
265 * Manipulate the 'scrubbing request has been queued, or - we are
266 * actually scrubbing' Scrubber's flag
268 * clear_queued_or_active() will also restart any blocked snaptrimming.
270 virtual void set_queued_or_active() = 0;
271 virtual void clear_queued_or_active() = 0;
273 /// are we waiting for resource reservation grants form our replicas?
274 [[nodiscard
]] virtual bool is_reserving() const = 0;
276 /// handle a message carrying a replica map
277 virtual void map_from_replica(OpRequestRef op
) = 0;
279 virtual void replica_scrub_op(OpRequestRef op
) = 0;
281 virtual void set_op_parameters(const requested_scrub_t
&) = 0;
283 virtual void scrub_clear_state() = 0;
285 virtual void handle_query_state(ceph::Formatter
* f
) = 0;
287 virtual pg_scrubbing_status_t
get_schedule() const = 0;
289 virtual void dump_scrubber(ceph::Formatter
* f
,
290 const requested_scrub_t
& request_flags
) const = 0;
293 * Return true if soid is currently being scrubbed and pending IOs should
294 * block. May have a side effect of preempting an in-progress scrub -- will
295 * return false in that case.
297 * @param soid object to check for ongoing scrub
298 * @return boolean whether a request on soid should block until scrub
301 virtual bool write_blocked_by_scrub(const hobject_t
& soid
) = 0;
303 /// Returns whether any objects in the range [begin, end] are being scrubbed
304 virtual bool range_intersects_scrub(const hobject_t
& start
,
305 const hobject_t
& end
) = 0;
307 /// the op priority, taken from the primary's request message
308 virtual Scrub::scrub_prio_t
replica_op_priority() const = 0;
310 /// the priority of the on-going scrub (used when requeuing events)
311 virtual unsigned int scrub_requeue_priority(
312 Scrub::scrub_prio_t with_priority
) const = 0;
313 virtual unsigned int scrub_requeue_priority(
314 Scrub::scrub_prio_t with_priority
,
315 unsigned int suggested_priority
) const = 0;
317 virtual void add_callback(Context
* context
) = 0;
319 /// add to scrub statistics, but only if the soid is below the scrub start
320 virtual void stats_of_handled_objects(const object_stat_sum_t
& delta_stats
,
321 const hobject_t
& soid
) = 0;
324 * the version of 'scrub_clear_state()' that does not try to invoke FSM
325 * services (thus can be called from FSM reactions)
327 virtual void clear_pgscrub_state() = 0;
330 * triggers the 'RemotesReserved' (all replicas granted scrub resources)
331 * state-machine event
333 virtual void send_remotes_reserved(epoch_t epoch_queued
) = 0;
336 * triggers the 'ReservationFailure' (at least one replica denied us the
337 * requested resources) state-machine event
339 virtual void send_reservation_failure(epoch_t epoch_queued
) = 0;
341 virtual void cleanup_store(ObjectStore::Transaction
* t
) = 0;
343 virtual bool get_store_errors(const scrub_ls_arg_t
& arg
,
344 scrub_ls_result_t
& res_inout
) const = 0;
347 * force a periodic 'publish_stats_to_osd()' call, to update scrub-related
348 * counters and statistics.
350 virtual void update_scrub_stats(
351 ceph::coarse_real_clock::time_point now_is
) = 0;
353 // --------------- reservations -----------------------------------
356 * message all replicas with a request to "unreserve" scrub
358 virtual void unreserve_replicas() = 0;
361 * "forget" all replica reservations. No messages are sent to the
362 * previously-reserved.
364 * Used upon interval change. The replicas' state is guaranteed to
365 * be reset separately by the interval-change event.
367 virtual void discard_replica_reservations() = 0;
370 * clear both local and OSD-managed resource reservation flags
372 virtual void clear_scrub_reservations() = 0;
375 * Reserve local scrub resources (managed by the OSD)
377 * Fails if OSD's local-scrubs budget was exhausted
378 * \returns were local resources reserved?
380 virtual bool reserve_local() = 0;
383 * Register/de-register with the OSD scrub queue
385 * Following our status as Primary or replica.
387 virtual void on_primary_change(
388 std::string_view caller
,
389 const requested_scrub_t
& request_flags
) = 0;
392 * Recalculate the required scrub time.
394 * This function assumes that the queue registration status is up-to-date,
395 * i.e. the OSD "knows our name" if-f we are the Primary.
397 virtual void update_scrub_job(const requested_scrub_t
& request_flags
) = 0;
400 virtual void handle_scrub_reserve_request(OpRequestRef op
) = 0;
401 virtual void handle_scrub_reserve_release(OpRequestRef op
) = 0;
403 // and on the primary:
404 virtual void handle_scrub_reserve_grant(OpRequestRef op
, pg_shard_t from
) = 0;
405 virtual void handle_scrub_reserve_reject(OpRequestRef op
,
406 pg_shard_t from
) = 0;
408 virtual void rm_from_osd_scrubbing() = 0;
410 virtual void scrub_requested(scrub_level_t scrub_level
,
411 scrub_type_t scrub_type
,
412 requested_scrub_t
& req_flags
) = 0;
414 // --------------- debugging via the asok ------------------------------
416 virtual int asok_debug(std::string_view cmd
,
419 std::stringstream
& ss
) = 0;