return out;
}
-// returns false if the message should be discarded. Handles the notification of interval
-// change, if not done already. called only for active scrub? not sure.
-
-// let's first make this a Primary-only function
+/*
+ * if the incoming message is from a previous interval, it must mean
+ * PrimaryLogPG::on_change() was called when that interval ended. We can safely discard
+ * the stale message.
+ */
bool PgScrubber::check_interval(epoch_t epoch_to_verify)
{
- const auto current_interval = m_pg->get_same_interval_since();
-
- if (epoch_to_verify < current_interval) {
- // the event will not be delivered. If we have already noticed and handled
- // the change of seasons, it will be silently discarded. Otherwise - we
- // reset the scrubber and its FSM.
- dout(10) << __func__ << " stale message. epoch: " << epoch_to_verify << " vs. "
- << current_interval << " (handled: " << m_last_dead_interval << ")" << dendl;
-
- if (epoch_to_verify > m_last_dead_interval) {
-
- // we have not seen this interval change yet.
- // The remote reservations are no longer relevant.
-
- m_last_dead_interval = current_interval;
-
- // clear the remote reservations. No need to send messages.
- if (m_reservations) {
- m_reservations->discard_all();
- }
-
- // stop the scrub and send a reset message to the FSM
- scrub_clear_state();
- }
- return false;
- }
-
- return true;
-}
-
-bool PgScrubber::check_interval_replica(epoch_t epoch_to_verify)
-{
- const auto current_interval = m_pg->get_same_interval_since();
-
- if (epoch_to_verify < current_interval) {
- // the event will not be delivered. If we have already noticed and handled
- // the change of seasons, it will be silently discarded. Otherwise - we
- // reset the scrubber and its FSM.
- dout(10) << __func__ << " stale message. epoch: " << epoch_to_verify << " vs. "
- << current_interval << " (handled: " << m_last_dead_interval << ")" << dendl;
-
- if (epoch_to_verify > m_last_dead_interval) {
-
- // we have not seen this interval change yet.
- // The remote reservations are no longer relevant.
-
- m_last_dead_interval = current_interval;
-
- // clear the remote reservations. No need to send messages
- m_remote_osd_resource.reset();
-
- // stop the scrub and send a reset message to the FSM
- // replica_handling_done();
- send_interval_changed();
- }
- return false;
- }
-
- // verify that we are reserved by the primary
- // not true anymore (see rapair scrubs) ceph_assert(m_remote_osd_resource &&
- // m_remote_osd_resource->is_reserved());
-
- return true;
+ return epoch_to_verify >= m_pg->get_same_interval_since();
}
bool PgScrubber::is_message_relevant(epoch_t epoch_to_verify)
return false;
}
- // check for reasons to abort this scrub
-
// has a new interval started?
if (!check_interval(epoch_to_verify)) {
- // if this is a new interval, check_interval() just discarded
- // remote resources and then killed the scrub
+ // if this is a new interval, on_change() has already terminated that
+ // old scrub.
return false;
}
return verify_against_abort(epoch_to_verify);
}
-
-// false if the message was discarded because of an abort flag.
-// Reset everything if the abort was not handled before.
bool PgScrubber::verify_against_abort(epoch_t epoch_to_verify)
{
if (!should_abort()) {
return false;
}
-// sending (processing) state-machine events --------------------------------
+// initiating state-machine events --------------------------------
/*
* a note re the checks performed before sending scrub-initiating messages:
* The check_interval() catches all major changes to the PG. As for the other conditions
* we may check (and see is_message_relevant() above):
*
- * - we are not 'active' yet, so must check against is_active(), andL
+ * - we are not 'active' yet, so must not check against is_active(), and:
*
* - the 'abort' flags were just verified (when the triggering message was queued). As
* those are only modified in human speeds - they need not be queried again.
* ('StartReplica' & 'StartReplicaNoWait').
*/
-
-void PgScrubber::send_start_scrub(epoch_t epoch_queued)
+void PgScrubber::initiate_regular_scrub(epoch_t epoch_queued)
{
- dout(10) << "scrubber event -->> " << __func__ << " epoch: " << epoch_queued << dendl;
+ dout(15) << __func__ << " epoch: " << epoch_queued << dendl;
+ // we may have lost our Primary status while the message languished in the queue
if (check_interval(epoch_queued)) {
+ dout(10) << "scrubber event -->> StartScrub epoch: " << epoch_queued << dendl;
+ reset_epoch(epoch_queued);
m_fsm->my_states();
m_fsm->process_event(StartScrub{});
+ dout(10) << "scrubber event --<< StartScrub" << dendl;
}
- dout(10) << "scrubber event --<< " << __func__ << dendl;
}
-void PgScrubber::send_start_after_repair(epoch_t epoch_queued)
+void PgScrubber::initiate_scrub_after_repair(epoch_t epoch_queued)
{
- dout(10) << "scrubber event -->> " << __func__ << " epoch: " << epoch_queued << dendl;
+ dout(15) << __func__ << " epoch: " << epoch_queued << dendl;
+ // we may have lost our Primary status while the message languished in the queue
if (check_interval(epoch_queued)) {
+ dout(10) << "scrubber event -->> AfterRepairScrub epoch: " << epoch_queued << dendl;
+ reset_epoch(epoch_queued);
m_fsm->my_states();
m_fsm->process_event(AfterRepairScrub{});
+ dout(10) << "scrubber event --<< AfterRepairScrub" << dendl;
}
- dout(10) << "scrubber event --<< " << __func__ << dendl;
}
void PgScrubber::send_scrub_unblock(epoch_t epoch_queued)
m_fsm->my_states();
m_fsm->process_event(InternalSchedScrub{});
}
+ dout(10) << "scrubber event --<< " << __func__ << dendl;
}
void PgScrubber::send_start_replica(epoch_t epoch_queued)
dout(1) << "got a replica scrub request while Primary!" << dendl;
return;
}
- if (check_interval_replica(epoch_queued)) {
+ if (check_interval(epoch_queued)) {
m_fsm->my_states();
- // buy us some time by not waiting for updates if there are none
+ // save us some time by not waiting for updates if there are none
// to wait for. Affects the transition from NotActive into either
// ReplicaWaitUpdates or ActiveReplica.
if (pending_active_pushes())
void PgScrubber::send_sched_replica(epoch_t epoch_queued)
{
dout(10) << "scrubber event -->> " << __func__ << " epoch: " << epoch_queued << dendl;
- if (check_interval_replica(epoch_queued)) {
+ if (check_interval(epoch_queued)) {
m_fsm->my_states();
m_fsm->process_event(SchedReplica{}); // retest for map availability
}
dout(10) << "scrubber event --<< " << __func__ << dendl;
}
-// no checks should be performed here
-void PgScrubber::send_interval_changed()
-{
- dout(10) << "scrubber event -->> " << __func__ << dendl;
- m_fsm->my_states();
- m_fsm->process_event(IntervalChanged{});
- dout(10) << "scrubber event --<< " << __func__ << dendl;
-}
-
void PgScrubber::send_replica_maps_ready(epoch_t epoch_queued)
{
dout(10) << "scrubber event -->> " << __func__ << " epoch: " << epoch_queued << dendl;
void PgScrubber::send_replica_pushes_upd(epoch_t epoch_queued)
{
dout(10) << "scrubber event -->> " << __func__ << " epoch: " << epoch_queued << dendl;
- if (check_interval_replica(epoch_queued)) {
+ if (check_interval(epoch_queued)) {
m_fsm->my_states();
m_fsm->process_event(ReplicaPushesUpd{});
}
preemption_data.reset();
m_pg->publish_stats_to_osd();
m_interval_start = m_pg->get_history().same_interval_since;
- // m_epoch_started = m_pg->get_osdmap_epoch();
dout(10) << __func__ << " start same_interval:" << m_interval_start << dendl;
}
m_start = m_pg->info.pgid.pgid.get_hobj_start();
- m_last_dead_interval = get_osdmap_epoch();
m_active = true;
}
{
ceph_assert(!m_active);
m_active = true;
- m_last_dead_interval = get_osdmap_epoch(); // so that check_interval_replica() won't
- // kill a scrub for stale messages
}
void PgScrubber::_scan_snaps(ScrubMap& smap)
m_remote_osd_resource.reset();
}
+void PgScrubber::discard_replica_reservations()
+{
+ dout(10) << __func__ << dendl;
+ if (m_reservations.has_value()) {
+ m_reservations->discard_all();
+ }
+}
+
void PgScrubber::clear_scrub_reservations()
{
dout(10) << __func__ << dendl;
state_clear(PG_STATE_DEEP_SCRUB);
m_pg->publish_stats_to_osd();
- m_reservations.reset();
- m_local_osd_resource.reset();
+ clear_scrub_reservations();
+ m_pg->publish_stats_to_osd();
requeue_waiting();
reset_internal_state();
+ m_flags = scrub_flags_t{};
+
// type-specific state clear
_scrub_clear_state();
}
requeue_waiting();
reset_internal_state();
+ m_flags = scrub_flags_t{};
// type-specific state clear
_scrub_clear_state();
state_clear(PG_STATE_SCRUBBING);
state_clear(PG_STATE_DEEP_SCRUB);
- preemption_data.reset();
- m_maps_status.reset();
- m_received_maps.clear();
-
- m_start = hobject_t{};
- m_end = hobject_t{};
- m_max_end = hobject_t{};
- m_subset_last_update = eversion_t{};
- m_shallow_errors = 0;
- m_deep_errors = 0;
- m_fixed_count = 0;
- m_omap_stats = (const struct omap_stat_t){0};
-
- run_callbacks();
- m_inconsistent.clear();
- m_missing.clear();
- m_authoritative.clear();
- num_digest_updates_pending = 0;
- replica_scrubmap = ScrubMap{};
- replica_scrubmap_pos.reset();
-
- m_cleaned_meta_map = ScrubMap{};
- m_needs_sleep = true;
- m_sleep_started_at = utime_t{};
+ reset_internal_state();
- m_active = false;
m_pg->publish_stats_to_osd();
}
m_needs_sleep = true;
m_sleep_started_at = utime_t{};
- m_flags = scrub_flags_t{};
-
m_active = false;
}
/// are we waiting for resource reservation grants form our replicas?
[[nodiscard]] bool is_reserving() const final;
- void send_start_scrub(epoch_t epoch_queued) final;
+ void initiate_regular_scrub(epoch_t epoch_queued) final;
- void send_start_after_repair(epoch_t epoch_queued) final;
+ void initiate_scrub_after_repair(epoch_t epoch_queued) final;
void send_scrub_resched(epoch_t epoch_queued) final;
void send_replica_pushes_upd(epoch_t epoch_queued) final;
- void reset_epoch(epoch_t epoch_queued) final;
-
/**
* we allow some number of preemptions of the scrub, which mean we do
* not block. Then we start to block. Once we start blocking, we do
void handle_scrub_reserve_grant(OpRequestRef op, pg_shard_t from) final;
void handle_scrub_reserve_reject(OpRequestRef op, pg_shard_t from) final;
void handle_scrub_reserve_release(OpRequestRef op) final;
+ void discard_replica_reservations() final;
void clear_scrub_reservations() final; // PG::clear... fwds to here
void unreserve_replicas() final;
ScrubMap clean_meta_map();
- void run_callbacks();
+ /**
+ * mark down some parameters of the initiated scrub:
+ * - the epoch when started;
+ * - the depth of the scrub requested (from the PG_STATE variable)
+ */
+ void reset_epoch(epoch_t epoch_queued);
- void send_interval_changed();
+ void run_callbacks();
// ----- methods used to verify the relevance of incoming events:
* check the 'no scrub' configuration options.
*/
[[nodiscard]] bool should_abort() const;
+
+ /**
+ * Check the 'no scrub' configuration flags.
+ *
+ * Reset everything if the abort was not handled before.
+ * @returns false if the message was discarded due to abort flag.
+ */
[[nodiscard]] bool verify_against_abort(epoch_t epoch_to_verify);
- bool check_interval(epoch_t epoch_to_verify);
- bool check_interval_replica(epoch_t epoch_to_verify);
+ [[nodiscard]] bool check_interval(epoch_t epoch_to_verify);
- epoch_t m_last_dead_interval{};
epoch_t m_last_aborted{}; // last time we've noticed a request to abort
MEV(RemotesReserved) ///< all replicas have granted our reserve request
MEV(ReservationFailure) ///< a reservation request has failed
-MEV(IntervalChanged) ///< ... from what it was when this chunk started
-
MEV(StartScrub) ///< initiate a new scrubbing session (relevant if we are a Primary)
MEV(AfterRepairScrub) ///< initiate a new scrubbing session. Only triggered at Recovery
///< completion.
struct NotActive : sc::state<NotActive, ScrubMachine> {
explicit NotActive(my_context ctx);
- using reactions = mpl::list<sc::custom_reaction<IntervalChanged>,
- sc::transition<StartScrub, ReservingReplicas>,
+ using reactions = mpl::list<sc::transition<StartScrub, ReservingReplicas>,
// a scrubbing that was initiated at recovery completion,
// and requires no resource reservations:
sc::transition<AfterRepairScrub, ActiveScrubbing>,
sc::transition<StartReplica, ReplicaWaitUpdates>,
sc::transition<StartReplicaNoWait, ActiveReplica>>;
-
- sc::result react(const IntervalChanged&);
};
struct ReservingReplicas : sc::state<ReservingReplicas, ScrubMachine> {
*/
struct ReplicaWaitUpdates : sc::state<ReplicaWaitUpdates, ScrubMachine> {
explicit ReplicaWaitUpdates(my_context ctx);
- using reactions = mpl::list<sc::custom_reaction<ReplicaPushesUpd>,
- sc::custom_reaction<FullReset>,
- sc::custom_reaction<IntervalChanged>>;
+ using reactions =
+ mpl::list<sc::custom_reaction<ReplicaPushesUpd>, sc::custom_reaction<FullReset>>;
sc::result react(const ReplicaPushesUpd&);
- sc::result react(const IntervalChanged&);
sc::result react(const FullReset&);
};
struct ActiveReplica : sc::state<ActiveReplica, ScrubMachine> {
explicit ActiveReplica(my_context ctx);
- using reactions = mpl::list<sc::custom_reaction<IntervalChanged>,
- sc::custom_reaction<SchedReplica>,
- sc::custom_reaction<FullReset>>;
+ using reactions =
+ mpl::list<sc::custom_reaction<SchedReplica>, sc::custom_reaction<FullReset>>;
sc::result react(const SchedReplica&);
- sc::result react(const IntervalChanged&);
sc::result react(const FullReset&);
};