// max number of parallel snap trims/pg
OPTION(osd_pg_max_concurrent_snap_trims, OPT_U64, 2)
+// max number of trimming pgs
+OPTION(osd_max_trimming_pgs, OPT_U64, 2)
// minimum number of peers that must be reachable to mark ourselves
// back up after being wrongly marked down.
remote_reserver(&reserver_finisher, cct->_conf->osd_max_backfills,
cct->_conf->osd_min_recovery_priority),
pg_temp_lock("OSDService::pg_temp_lock"),
+ snap_reserver(&reserver_finisher,
+ cct->_conf->osd_max_trimming_pgs),
map_cache_lock("OSDService::map_lock"),
map_cache(cct, cct->_conf->osd_map_cache_size),
map_bl_cache(cct->_conf->osd_map_cache_size),
service.local_reserver.set_min_priority(cct->_conf->osd_min_recovery_priority);
service.remote_reserver.set_min_priority(cct->_conf->osd_min_recovery_priority);
}
+ if (changed.count("osd_max_trimming_pgs")) {
+ service.snap_reserver.set_max(cct->_conf->osd_max_trimming_pgs);
+ }
if (changed.count("osd_op_complaint_time") ||
changed.count("osd_op_log_threshold")) {
op_tracker.set_complaint_and_threshold(cct->_conf->osd_op_complaint_time,
ceph_clock_now(cct),
entity_inst_t())));
}
+ AsyncReserver<spg_t> snap_reserver;
+
void queue_for_scrub(PG *pg) {
op_wq.queue(
make_pair(
<< pg->snap_trimq.range_start()
<< dendl;
post_event(SnapTrim());
- return transit<TrimmingObjects>();
+ return transit<Trimming>();
}
}
+boost::statechart::result ReplicatedPG::WaitReservation::react(const SnapTrimReserved&)
+{
+ ReplicatedPG *pg = context< SnapTrimmer >().pg;
+ ldout(pg->cct, 10) << "WaitReservation react SnapTrimReserved" << dendl;
+
+ pending = nullptr;
+ if (!pg->is_primary() || !pg->is_active() || !pg->is_clean() ||
+ pg->scrubber.active) {
+ post_event(SnapTrim());
+ return transit< NotTrimming >();
+ }
+
+ context<SnapTrimmer>().snap_to_trim = pg->snap_trimq.range_start();
+ ldout(pg->cct, 10) << "NotTrimming: trimming "
+ << pg->snap_trimq.range_start()
+ << dendl;
+ pg->queue_snap_trim();
+ return transit< TrimmingObjects >();
+}
+
/* TrimmingObjects */
ReplicatedPG::TrimmingObjects::TrimmingObjects(my_context ctx)
: my_base(ctx),
NamedState(context< SnapTrimmer >().pg->cct, "Trimming/TrimmingObjects")
+{
+ auto *pg = context< SnapTrimmer >().pg;
+ context< SnapTrimmer >().log_enter(state_name);
+ pg->state_set(PG_STATE_SNAPTRIM);
+ pg->publish_stats_to_osd();
+}
+
+ReplicatedPG::Trimming::Trimming(my_context ctx)
+ : my_base(ctx),
+ NamedState(context< SnapTrimmer >().pg->cct, "Trimming")
{
context< SnapTrimmer >().log_enter(state_name);
}
-void ReplicatedPG::TrimmingObjects::exit()
+void ReplicatedPG::Trimming::exit()
{
context< SnapTrimmer >().log_exit(state_name, enter_time);
+ auto *pg = context< SnapTrimmer >().pg;
+ pg->osd->snap_reserver.cancel_reservation(pg->get_pgid());
+ pg->state_clear(PG_STATE_SNAPTRIM);
+ pg->publish_stats_to_osd();
context<SnapTrimmer>().in_flight.clear();
}
}
private:
struct NotTrimming;
+ struct WaitReservation;
struct SnapTrim : boost::statechart::event< SnapTrim > {
SnapTrim() : boost::statechart::event < SnapTrim >() {}
};
struct Reset : boost::statechart::event< Reset > {
Reset() : boost::statechart::event< Reset >() {}
};
+ struct SnapTrimReserved : boost::statechart::event< SnapTrimReserved > {
+ SnapTrimReserved() : boost::statechart::event< SnapTrimReserved >() {}
+ };
struct SnapTrimmer : public boost::statechart::state_machine< SnapTrimmer, NotTrimming > {
ReplicatedPG *pg;
set<hobject_t, hobject_t::BitwiseComparator> in_flight;
} snap_trimmer_machine;
/* SnapTrimmerStates */
- struct TrimmingObjects : boost::statechart::state< TrimmingObjects, SnapTrimmer >, NamedState {
+ struct Trimming : boost::statechart::state< Trimming,
+ SnapTrimmer,
+ WaitReservation >,
+ NamedState {
+ typedef boost::mpl::list <
+ boost::statechart::custom_reaction< SnapTrim >,
+ boost::statechart::transition< Reset, NotTrimming >
+ > reactions;
+ explicit Trimming(my_context ctx);
+ void exit();
+ boost::statechart::result react(const SnapTrim&) { return discard_event(); }
+ };
+
+ struct TrimmingObjects : boost::statechart::state<TrimmingObjects, Trimming>, NamedState {
typedef boost::mpl::list <
boost::statechart::custom_reaction< SnapTrim >,
boost::statechart::transition< Reset, NotTrimming >
> reactions;
hobject_t pos;
explicit TrimmingObjects(my_context ctx);
- void exit();
+ void exit() { context< SnapTrimmer >().log_exit(state_name, enter_time); }
boost::statechart::result react(const SnapTrim&);
};
- struct WaitingOnReplicas : boost::statechart::state< WaitingOnReplicas, SnapTrimmer >, NamedState {
+ struct WaitReservation : boost::statechart::state< WaitReservation, Trimming >, NamedState {
+ /* WaitReservation is a sub-state of trimming simply so that exiting Trimming
+ * always cancels the reservation */
+ typedef boost::mpl::list <
+ boost::statechart::custom_reaction< SnapTrimReserved >
+ > reactions;
+ struct ReservationCB : public Context {
+ ReplicatedPGRef pg;
+ bool canceled;
+ ReservationCB(ReplicatedPG *pg) : pg(pg), canceled(false) {}
+ void finish(int) override {
+ pg->lock();
+ if (!canceled)
+ pg->snap_trimmer_machine.process_event(SnapTrimReserved());
+ pg->unlock();
+ }
+ void cancel() {
+ assert(pg->is_locked());
+ assert(!canceled);
+ canceled = true;
+ }
+ };
+ ReservationCB *pending = nullptr;
+
+ explicit WaitReservation(my_context ctx)
+ : my_base(ctx),
+ NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitReservation") {
+ context< SnapTrimmer >().log_enter(state_name);
+ auto *pg = context< SnapTrimmer >().pg;
+ pending = new ReservationCB(pg);
+ pg->osd->snap_reserver.request_reservation(pg->get_pgid(), pending, 0);
+ pg->state_set(PG_STATE_SNAPTRIM_WAIT);
+ pg->publish_stats_to_osd();
+ }
+ boost::statechart::result react(const SnapTrimReserved&);
+ void exit() {
+ context< SnapTrimmer >().log_exit(state_name, enter_time);
+ if (pending)
+ pending->cancel();
+ pending = nullptr;
+ auto *pg = context< SnapTrimmer >().pg;
+ pg->state_clear(PG_STATE_SNAPTRIM_WAIT);
+ pg->publish_stats_to_osd();
+ }
+ boost::statechart::result react(const SnapTrim&) {
+ return discard_event();
+ }
+ };
+
+ struct WaitingOnReplicas : boost::statechart::state< WaitingOnReplicas, Trimming >, NamedState {
typedef boost::mpl::list <
boost::statechart::custom_reaction< SnapTrim >,
boost::statechart::transition< Reset, NotTrimming >
oss << "incomplete+";
if (state & PG_STATE_PEERED)
oss << "peered+";
+ if (state & PG_STATE_SNAPTRIM)
+ oss << "snaptrim+";
+ if (state & PG_STATE_SNAPTRIM_WAIT)
+ oss << "snaptrim_wait+";
string ret(oss.str());
if (ret.length() > 0)
ret.resize(ret.length() - 1);
type = PG_STATE_ACTIVATING;
else if (state == "peered")
type = PG_STATE_PEERED;
+ else if (state == "snaptrim")
+ type = PG_STATE_SNAPTRIM;
+ else if (state == "snaptrim_wait")
+ type = PG_STATE_SNAPTRIM_WAIT;
else
type = -1;
return type;
#define PG_STATE_UNDERSIZED (1<<23) // pg acting < pool size
#define PG_STATE_ACTIVATING (1<<24) // pg is peered but not yet active
#define PG_STATE_PEERED (1<<25) // peered, cannot go active, can recover
+#define PG_STATE_SNAPTRIM (1<<26) // trimming snaps
+#define PG_STATE_SNAPTRIM_WAIT (1<<27) // queued to trim snaps
std::string pg_state_string(int state);
std::string pg_vector_string(const vector<int32_t> &a);