From: Ronen Friedman Date: Sun, 20 Mar 2022 13:20:59 +0000 (+0000) Subject: osd/scrub: modify scrub behaviour under no-scrub X-Git-Tag: v18.0.0~275^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F46891%2Fhead;p=ceph.git osd/scrub: modify scrub behaviour under no-scrub Fix no-scrub & nodeep-scrub related code to match requirements: - deep scrubs should be allowed to execute when no-scrub is set; - some initiated scrubs (i.e. not periodic ones) might be changed from the requested 'deep' to 'shallow'. Signed-off-by: Ronen Friedman --- diff --git a/qa/standalone/scrub/osd-scrub-test.sh b/qa/standalone/scrub/osd-scrub-test.sh index e5c6de31d59e7..73f165380f456 100755 --- a/qa/standalone/scrub/osd-scrub-test.sh +++ b/qa/standalone/scrub/osd-scrub-test.sh @@ -466,10 +466,11 @@ function TEST_just_deep_scrubs() { done rm -f $TESTDATA - # set 'no scrub', then request a deep-scrub. + # set both 'no scrub' & 'no deep-scrub', then request a deep-scrub. # we do not expect to see the scrub scheduled. ceph osd set noscrub || return 1 + ceph osd set nodeep-scrub || return 1 sleep 6 # the 'noscrub' command takes a long time to reach the OSDs local now_is=`date -I"ns"` declare -A sched_data @@ -492,8 +493,8 @@ function TEST_just_deep_scrubs() { (( ${sc_data_2['dmp_last_duration']} == 0)) || return 1 (( ${sc_data_2['query_scrub_seq']} == $dbg_counter_at_start)) || return 1 - # unset the 'no scrub'. Deep scrubbing should start now. - ceph osd unset noscrub || return 1 + # unset the 'no deep-scrub'. Deep scrubbing should start now. + ceph osd unset nodeep-scrub || return 1 sleep 5 declare -A expct_qry_duration=( ['query_last_duration']="0" ['query_last_duration_neg']="not0" ) sc_data_2=() diff --git a/src/osd/PG.cc b/src/osd/PG.cc index 9723a4aa63ffe..0aaf33946cc07 100644 --- a/src/osd/PG.cc +++ b/src/osd/PG.cc @@ -431,6 +431,7 @@ void PG::queue_scrub_after_repair() m_planned_scrub.must_deep_scrub = true; m_planned_scrub.check_repair = true; m_planned_scrub.must_scrub = true; + m_planned_scrub.calculated_to_deep = true; if (is_scrub_queued_or_active()) { dout(10) << __func__ << ": scrubbing already (" @@ -1352,7 +1353,7 @@ Scrub::schedule_result_t PG::sched_scrub() // analyse the combination of the requested scrub flags, the osd/pool configuration // and the PG status to determine whether we should scrub now, and what type of scrub // should that be. - auto updated_flags = verify_scrub_mode(); + auto updated_flags = validate_scrub_mode(); if (!updated_flags) { // the stars do not align for starting a scrub for this PG at this time // (due to configuration or priority issues) @@ -1393,12 +1394,20 @@ double PG::next_deepscrub_interval() const } bool PG::is_time_for_deep(bool allow_deep_scrub, - bool allow_scrub, + bool allow_shallow_scrub, bool has_deep_errors, const requested_scrub_t& planned) const { - dout(10) << __func__ << ": need_auto?" << planned.need_auto << " allow_deep_scrub? " - << allow_deep_scrub << dendl; + dout(10) << fmt::format( + "{}: need-auto? {} allowed? {}/{} deep-errors? {} " + "last_deep_scrub_stamp {}", + __func__, + planned.need_auto, + allow_shallow_scrub, + allow_deep_scrub, + has_deep_errors, + info.history.last_deep_scrub_stamp) + << dendl; if (!allow_deep_scrub) return false; @@ -1409,21 +1418,24 @@ bool PG::is_time_for_deep(bool allow_deep_scrub, } if (ceph_clock_now() >= next_deepscrub_interval()) { - dout(20) << __func__ << ": now (" << ceph_clock_now() << ") >= time for deep (" - << next_deepscrub_interval() << ")" << dendl; + dout(20) << __func__ << ": now (" << ceph_clock_now() + << ") >= time for deep (" << next_deepscrub_interval() << ")" + << dendl; return true; } if (has_deep_errors) { + // note: the text below is matched by 'standalone' tests osd->clog->info() << "osd." << osd->whoami << " pg " << info.pgid - << " Deep scrub errors, upgrading scrub to deep-scrub"; + << " Deep scrub errors, upgrading scrub to deep-scrub"; return true; } - // we only flip coins if 'allow_scrub' is asserted. Otherwise - as this function is - // called often, we will probably be deep-scrubbing most of the time. - if (allow_scrub) { - bool deep_coin_flip = + // we only flip coins if 'allow_shallow_scrub' is asserted. Otherwise - as + // this function is called often, we will probably be deep-scrubbing most of + // the time. + if (allow_shallow_scrub) { + const bool deep_coin_flip = (rand() % 100) < cct->_conf->osd_deep_scrub_randomize_ratio * 100; dout(15) << __func__ << ": time_for_deep=" << planned.time_for_deep @@ -1436,110 +1448,233 @@ bool PG::is_time_for_deep(bool allow_deep_scrub, return false; } -bool PG::verify_periodic_scrub_mode(bool allow_deep_scrub, - bool try_to_auto_repair, - bool allow_regular_scrub, - bool has_deep_errors, - requested_scrub_t& planned) const +/* + clang-format off + + Request details | none | no-scrub | no-scrub+no-deep | no-deep + ------------------------------------------------------------------------ + ------------------------------------------------------------------------ + initiated | shallow | shallow | shallow | shallow + ------------------------------------------------------------------------ + init. + t.f.deep | deep | deep | shallow | shallow + ------------------------------------------------------------------------ + initiated deep | deep | deep | deep | deep + ------------------------------------------------------------------------ + + clang-format on +*/ +std::optional PG::validate_initiated_scrub( + bool allow_deep_scrub, + bool try_to_auto_repair, + bool time_for_deep, + bool has_deep_errors, + const requested_scrub_t& planned) const +{ + requested_scrub_t upd_flags{planned}; + + upd_flags.time_for_deep = time_for_deep; + upd_flags.deep_scrub_on_error = false; + upd_flags.auto_repair = false; // will only be considered for periodic scrubs + + if (upd_flags.must_deep_scrub) { + upd_flags.calculated_to_deep = true; + } else if (upd_flags.time_for_deep && allow_deep_scrub) { + upd_flags.calculated_to_deep = true; + } else { + upd_flags.calculated_to_deep = false; + if (has_deep_errors) { + osd->clog->error() << fmt::format( + "osd.{} pg {} Regular scrub request, deep-scrub details will be lost", + osd->whoami, + info.pgid); + } + } + + return upd_flags; +} + +/* + clang-format off + + for periodic scrubs: + + Periodic type | none | no-scrub | no-scrub+no-deep | no-deep + ------------------------------------------------------------------------ + ------------------------------------------------------------------------ + periodic | shallow | x | x | shallow + ------------------------------------------------------------------------ + periodic + t.f.deep| deep | deep | x | shallow + ------------------------------------------------------------------------ + + clang-format on +*/ +std::optional PG::validate_periodic_mode( + bool allow_deep_scrub, + bool try_to_auto_repair, + bool allow_shallow_scrub, + bool time_for_deep, + bool has_deep_errors, + const requested_scrub_t& planned) const { ceph_assert(!planned.must_deep_scrub && !planned.must_repair); if (!allow_deep_scrub && has_deep_errors) { - osd->clog->error() - << "osd." << osd->whoami << " pg " << info.pgid - << " Regular scrub skipped due to deep-scrub errors and nodeep-scrub set"; - return false; + osd->clog->error() + << "osd." << osd->whoami << " pg " << info.pgid + << " Regular scrub skipped due to deep-scrub errors and nodeep-scrub set"; + return std::nullopt; // no scrubbing } - if (allow_deep_scrub) { - // Initial entry and scheduled scrubs without nodeep_scrub set get here + requested_scrub_t upd_flags{planned}; - planned.time_for_deep = - is_time_for_deep(allow_deep_scrub, allow_regular_scrub, has_deep_errors, planned); + upd_flags.time_for_deep = time_for_deep; + upd_flags.deep_scrub_on_error = false; + upd_flags.auto_repair = false; + upd_flags.calculated_to_deep = false; + + dout(20) << fmt::format("{}: allowed:{}/{} t.f.d:{} req:{}", + __func__, + allow_shallow_scrub, + allow_deep_scrub, + upd_flags.time_for_deep, + planned) + << dendl; - if (try_to_auto_repair) { - if (planned.time_for_deep) { - dout(20) << __func__ << ": auto repair with deep scrubbing" << dendl; - planned.auto_repair = true; - } else if (allow_regular_scrub) { - dout(20) << __func__ << ": auto repair with scrubbing, rescrub if errors found" + // should we perform a shallow scrub? + if (allow_shallow_scrub) { + if (!upd_flags.time_for_deep || !allow_deep_scrub) { + if (try_to_auto_repair) { + dout(10) << __func__ + << ": auto repair with scrubbing, rescrub if errors found" << dendl; - planned.deep_scrub_on_error = true; + upd_flags.deep_scrub_on_error = true; } + dout(20) << __func__ << " will do shallow scrub (time_for_deep = " + << upd_flags.time_for_deep << ")" << dendl; + return upd_flags; } + // else - either deep-scrub or nothing } - dout(20) << __func__ << " updated flags: " << planned - << " allow_regular_scrub: " << allow_regular_scrub << dendl; - - // NOSCRUB so skip regular scrubs - if (!allow_regular_scrub && !planned.time_for_deep) { - return false; + if (upd_flags.time_for_deep) { + if (allow_deep_scrub) { + if (try_to_auto_repair) { + dout(20) << __func__ << ": auto repair with deep scrubbing" << dendl; + upd_flags.auto_repair = true; + } + upd_flags.calculated_to_deep = true; + dout(20) << fmt::format("{}: final: {}", __func__, upd_flags) << dendl; + return upd_flags; + } + if (allow_shallow_scrub) { + dout(20) << fmt::format("{}: final:{}", __func__, upd_flags) << dendl; + return upd_flags; + } + return std::nullopt; } - return true; + return std::nullopt; // no scrubbing } -std::optional PG::verify_scrub_mode() const + +/* + From docs.ceph.com (osd-internals/scrub): + + clang-format off + + Desired no-scrub flags & scrub type interactions: + + Periodic type | none | no-scrub | no-scrub+no-deep | no-deep + ------------------------------------------------------------------------ + ------------------------------------------------------------------------ + periodic | shallow | x | x | shallow + ------------------------------------------------------------------------ + periodic + t.f.deep| deep | deep | x | shallow + ------------------------------------------------------------------------ + initiated | shallow | shallow | shallow | shallow + ------------------------------------------------------------------------ + init. + t.f.deep | deep | deep | shallow | shallow + ------------------------------------------------------------------------ + initiated deep | deep | deep | deep | deep + ------------------------------------------------------------------------ + + "periodic" - if !must_scrub && !must_deep_scrub; + "initiated deep" - if must_scrub && must_deep_scrub; + "initiated" - if must_scrub && !must_deep_scrub; + + clang-format on +*/ +/* + * The returned flags collection (requested_scrub_t) is based on + * m_planned_scrub with the following modifications: + * + * - calculated_to_deep will be set to shallow or deep, depending on the + * scrub type (according to the decision table above); + * - deep_scrub_on_error will be determined; + * - same for auto_repair; + * - time_for_deep will be set to true if the scrub is periodic and the + * time for a deep scrub has been reached (+ some other conditions); + * and + * - need_auto is cleared + */ +std::optional PG::validate_scrub_mode() const { - const bool allow_regular_scrub = + const bool allow_shallow_scrub = !(get_osdmap()->test_flag(CEPH_OSDMAP_NOSCRUB) || pool.info.has_flag(pg_pool_t::FLAG_NOSCRUB)); const bool allow_deep_scrub = - allow_regular_scrub && !(get_osdmap()->test_flag(CEPH_OSDMAP_NODEEP_SCRUB) || pool.info.has_flag(pg_pool_t::FLAG_NODEEP_SCRUB)); const bool has_deep_errors = (info.stats.stats.sum.num_deep_scrub_errors > 0); const bool try_to_auto_repair = (cct->_conf->osd_scrub_auto_repair && - get_pgbackend()->auto_repair_supported()); + get_pgbackend()->auto_repair_supported()); dout(10) << __func__ << " pg: " << info.pgid - << " allow: " << allow_regular_scrub << "/" << allow_deep_scrub - << " deep errs: " << has_deep_errors - << " auto-repair: " << try_to_auto_repair << " (" - << cct->_conf->osd_scrub_auto_repair << ")" << dendl; - - auto upd_flags = m_planned_scrub; + << " allow: " << allow_shallow_scrub << "/" << allow_deep_scrub + << " deep errs: " << has_deep_errors + << " auto-repair: " << try_to_auto_repair << " (" + << cct->_conf->osd_scrub_auto_repair << ")" << dendl; - upd_flags.time_for_deep = false; - // Clear these in case user issues the scrub/repair command during - // the scheduling of the scrub/repair (e.g. request reservation) - upd_flags.deep_scrub_on_error = false; - upd_flags.auto_repair = false; + // scrubbing while recovering? + const bool prevented_by_recovery = + osd->is_recovery_active() && !cct->_conf->osd_scrub_during_recovery && + (!cct->_conf->osd_repair_during_recovery || !m_planned_scrub.must_repair); - if (upd_flags.must_scrub && !upd_flags.must_deep_scrub && has_deep_errors) { - osd->clog->error() - << "osd." << osd->whoami << " pg " << info.pgid - << " Regular scrub request, deep-scrub details will be lost"; + if (prevented_by_recovery) { + dout(20) << __func__ << ": scrubbing prevented during recovery" << dendl; + return std::nullopt; } - if (!upd_flags.must_scrub) { - // All periodic scrub handling goes here because must_scrub is - // always set for must_deep_scrub and must_repair. + const bool time_for_deep = is_time_for_deep(allow_deep_scrub, + allow_shallow_scrub, + has_deep_errors, + m_planned_scrub); + std::optional upd_flags; - const bool can_start_periodic = verify_periodic_scrub_mode( - allow_deep_scrub, try_to_auto_repair, allow_regular_scrub, - has_deep_errors, upd_flags); - if (!can_start_periodic) { - // "I don't want no scrub" + if (m_planned_scrub.must_scrub) { + upd_flags = validate_initiated_scrub(allow_deep_scrub, + try_to_auto_repair, + time_for_deep, + has_deep_errors, + m_planned_scrub); + } else { + ceph_assert(!m_planned_scrub.must_deep_scrub); + upd_flags = validate_periodic_mode(allow_deep_scrub, + try_to_auto_repair, + allow_shallow_scrub, + time_for_deep, + has_deep_errors, + m_planned_scrub); + if (!upd_flags) { dout(20) << __func__ << ": no periodic scrubs allowed" << dendl; return std::nullopt; } } - // scrubbing while recovering? - - bool prevented_by_recovery = - osd->is_recovery_active() && !cct->_conf->osd_scrub_during_recovery && - (!cct->_conf->osd_repair_during_recovery || !upd_flags.must_repair); - - if (prevented_by_recovery) { - dout(20) << __func__ << ": scrubbing prevented during recovery" << dendl; - return std::nullopt; - } - - upd_flags.need_auto = false; + dout(10) << fmt::format("{}: next scrub flags: {}", __func__, *upd_flags) + << dendl; + upd_flags->need_auto = false; return upd_flags; } diff --git a/src/osd/PG.h b/src/osd/PG.h index 11850ada6bc97..7d013ec4d9d9a 100644 --- a/src/osd/PG.h +++ b/src/osd/PG.h @@ -717,23 +717,32 @@ private: /// should we perform deep scrub? bool is_time_for_deep(bool allow_deep_scrub, - bool allow_scrub, - bool has_deep_errors, - const requested_scrub_t& planned) const; + bool allow_shallow_scrub, + bool has_deep_errors, + const requested_scrub_t& planned) const; /** - * Verify the various 'next scrub' flags in m_planned_scrub against configuration + * Validate the various 'next scrub' flags in m_planned_scrub against configuration * and scrub-related timestamps. * * @returns an updated copy of the m_planned_flags (or nothing if no scrubbing) */ - std::optional verify_scrub_mode() const; - - bool verify_periodic_scrub_mode(bool allow_deep_scrub, - bool try_to_auto_repair, - bool allow_regular_scrub, - bool has_deep_errors, - requested_scrub_t& planned) const; + std::optional validate_scrub_mode() const; + + std::optional validate_periodic_mode( + bool allow_deep_scrub, + bool try_to_auto_repair, + bool allow_shallow_scrub, + bool time_for_deep, + bool has_deep_errors, + const requested_scrub_t& planned) const; + + std::optional validate_initiated_scrub( + bool allow_deep_scrub, + bool try_to_auto_repair, + bool time_for_deep, + bool has_deep_errors, + const requested_scrub_t& planned) const; using ScrubAPI = void (ScrubPgIF::*)(epoch_t epoch_queued); void forward_scrub_event(ScrubAPI fn, epoch_t epoch_queued, std::string_view desc); diff --git a/src/osd/scrubber/pg_scrubber.cc b/src/osd/scrubber/pg_scrubber.cc index a7572019a2eae..7158553fdaa36 100644 --- a/src/osd/scrubber/pg_scrubber.cc +++ b/src/osd/scrubber/pg_scrubber.cc @@ -137,10 +137,15 @@ bool PgScrubber::verify_against_abort(epoch_t epoch_to_verify) bool PgScrubber::should_abort() const { + // note that set_op_parameters() guarantees that we would never have + // must_scrub set (i.e. possibly have started a scrub even though noscrub + // was set), without having 'required' also set. if (m_flags.required) { return false; // not stopping 'required' scrubs for configuration changes } + // note: deep scrubs are allowed even if 'no-scrub' is set (but not + // 'no-deepscrub') if (m_is_deep) { if (get_osdmap()->test_flag(CEPH_OSDMAP_NODEEP_SCRUB) || m_pg->pool.info.has_flag(pg_pool_t::FLAG_NODEEP_SCRUB)) { @@ -148,7 +153,7 @@ bool PgScrubber::should_abort() const return true; } } else if (get_osdmap()->test_flag(CEPH_OSDMAP_NOSCRUB) || - m_pg->pool.info.has_flag(pg_pool_t::FLAG_NOSCRUB)) { + m_pg->pool.info.has_flag(pg_pool_t::FLAG_NOSCRUB)) { dout(10) << "noscrub set, aborting" << dendl; return true; } @@ -426,7 +431,7 @@ void PgScrubber::reset_epoch(epoch_t epoch_queued) m_epoch_start = epoch_queued; m_needs_sleep = true; - m_is_deep = state_test(PG_STATE_DEEP_SCRUB); + ceph_assert(m_is_deep == state_test(PG_STATE_DEEP_SCRUB)); update_op_mode_text(); } @@ -1424,9 +1429,9 @@ void PgScrubber::replica_scrub_op(OpRequestRef op) m_current_token); } -void PgScrubber::set_op_parameters(requested_scrub_t& request) +void PgScrubber::set_op_parameters(const requested_scrub_t& request) { - dout(10) << __func__ << " input: " << request << dendl; + dout(10) << fmt::format("{}: @ input: {}", __func__, request) << dendl; set_queued_or_active(); // we are fully committed now. @@ -1445,8 +1450,15 @@ void PgScrubber::set_op_parameters(requested_scrub_t& request) state_set(PG_STATE_SCRUBBING); // will we be deep-scrubbing? - if (request.must_deep_scrub || request.need_auto || request.time_for_deep) { + if (request.calculated_to_deep) { state_set(PG_STATE_DEEP_SCRUB); + m_is_deep = true; + } else { + m_is_deep = false; + + // make sure we got the 'calculated_to_deep' flag right + ceph_assert(!request.must_deep_scrub); + ceph_assert(!request.need_auto); } // m_is_repair is set for either 'must_repair' or 'repair-on-the-go' (i.e. @@ -1458,7 +1470,7 @@ void PgScrubber::set_op_parameters(requested_scrub_t& request) m_is_repair = request.must_repair || m_flags.auto_repair; if (request.must_repair) { state_set(PG_STATE_REPAIR); - // not calling update_op_mode_text() yet, as m_is_deep not set yet + update_op_mode_text(); } // the publishing here is required for tests synchronization @@ -1556,6 +1568,11 @@ void PgScrubber::handle_scrub_reserve_request(OpRequestRef op) dout(10) << __func__ << " " << *op->get_req() << dendl; op->mark_started(); auto request_ep = op->get_req()->get_map_epoch(); + dout(20) << fmt::format("{}: request_ep:{} recovery:{}", + __func__, + request_ep, + m_osds->is_recovery_active()) + << dendl; /* * if we are currently holding a reservation, then: @@ -1583,13 +1600,18 @@ void PgScrubber::handle_scrub_reserve_request(OpRequestRef op) if (request_ep < m_pg->get_same_interval_since()) { // will not ack stale requests + dout(10) << fmt::format("{}: stale reservation (request ep{} < {}) denied", + __func__, + request_ep, + m_pg->get_same_interval_since()) + << dendl; return; } bool granted{false}; if (m_remote_osd_resource.has_value()) { - dout(10) << __func__ << " already reserved." << dendl; + dout(10) << __func__ << " already reserved. Reassigned." << dendl; /* * it might well be that we did not yet finish handling the latest scrub-op @@ -1612,6 +1634,8 @@ void PgScrubber::handle_scrub_reserve_request(OpRequestRef op) m_remote_osd_resource.reset(); dout(20) << __func__ << ": failed to reserve remotely" << dendl; } + } else { + dout(10) << __func__ << ": recovery is active; not granting" << dendl; } dout(10) << __func__ << " reserved? " << (granted ? "yes" : "no") << dendl; diff --git a/src/osd/scrubber/pg_scrubber.h b/src/osd/scrubber/pg_scrubber.h index 2f28b3281fbe0..baa78eebcb768 100644 --- a/src/osd/scrubber/pg_scrubber.h +++ b/src/osd/scrubber/pg_scrubber.h @@ -431,7 +431,7 @@ class PgScrubber : public ScrubPgIF, * flag-set; PG_STATE_SCRUBBING, and possibly PG_STATE_DEEP_SCRUB & * PG_STATE_REPAIR are set. */ - void set_op_parameters(requested_scrub_t& request) final; + void set_op_parameters(const requested_scrub_t& request) final; void cleanup_store(ObjectStore::Transaction* t) final; diff --git a/src/osd/scrubber_common.h b/src/osd/scrubber_common.h index 4a63cdf18161f..f643c08a00139 100644 --- a/src/osd/scrubber_common.h +++ b/src/osd/scrubber_common.h @@ -2,6 +2,8 @@ // vim: ts=8 sw=2 smarttab #pragma once +#include + #include "common/scrub_types.h" #include "include/types.h" #include "os/ObjectStore.h" @@ -128,7 +130,7 @@ struct requested_scrub_t { bool deep_scrub_on_error{false}; /** - * If set, we should see must_deep_scrub and must_repair set, too + * If set, we should see must_deep_scrub & must_scrub, too * * - 'must_repair' is checked by the OSD when scheduling the scrubs. * - also checked & cleared at pg::queue_scrub() @@ -149,10 +151,38 @@ struct requested_scrub_t { * Otherwise - PG_STATE_FAILED_REPAIR will be asserted. */ bool check_repair{false}; + + /** + * Used to indicate, both in client-facing listings and internally, that + * the planned scrub will be a deep one. + */ + bool calculated_to_deep{false}; }; std::ostream& operator<<(std::ostream& out, const requested_scrub_t& sf); +template <> +struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + + template + auto format(const requested_scrub_t& rs, FormatContext& ctx) + { + return fmt::format_to(ctx.out(), + "(plnd:{}{}{}{}{}{}{}{}{}{})", + rs.must_repair ? " must_repair" : "", + rs.auto_repair ? " auto_repair" : "", + rs.check_repair ? " check_repair" : "", + rs.deep_scrub_on_error ? " deep_scrub_on_error" : "", + rs.must_deep_scrub ? " must_deep_scrub" : "", + rs.must_scrub ? " must_scrub" : "", + rs.time_for_deep ? " time_for_deep" : "", + rs.need_auto ? " need_auto" : "", + rs.req_scrub ? " req_scrub" : "", + rs.calculated_to_deep ? " deep" : ""); + } +}; + /** * The interface used by the PG when requesting scrub-related info or services */ @@ -250,7 +280,7 @@ struct ScrubPgIF { virtual void replica_scrub_op(OpRequestRef op) = 0; - virtual void set_op_parameters(requested_scrub_t&) = 0; + virtual void set_op_parameters(const requested_scrub_t&) = 0; virtual void scrub_clear_state() = 0;