#undef dout_prefix
#define dout_prefix *_dout << pg->gen_prefix()
-PrimaryLogPG::SnapTrimmer::~SnapTrimmer()
-{
- in_flight.clear();
-}
-
void PrimaryLogPG::SnapTrimmer::log_enter(const char *state_name)
{
dout(20) << "enter " << state_name << dendl;
PrimaryLogPG *pg = context< SnapTrimmer >().pg;
dout(10) << "NotTrimming react KickTrim" << dendl;
- assert(pg->is_primary() && pg->is_active());
+ if (!(pg->is_primary() && pg->is_active())) {
+ ldout(pg->cct, 10) << "NotTrimming not primary or active" << dendl;
+ return discard_event();
+ }
if (!pg->is_clean() ||
pg->snap_trimq.empty()) {
dout(10) << "NotTrimming not clean or nothing to trim" << dendl;
return discard_event();
}
-
if (pg->scrubber.active) {
dout(10) << " scrubbing, will requeue snap_trimmer after" << dendl;
pg->scrubber.queue_snap_trim = true;
return transit< WaitScrub >();
} else {
- context<SnapTrimmer>().snap_to_trim = pg->snap_trimq.range_start();
- dout(10) << "NotTrimming: trimming "
- << pg->snap_trimq.range_start()
- << dendl;
- return transit< AwaitAsyncWork >();
+ return transit< Trimming >();
+ }
+}
+
+boost::statechart::result PrimaryLogPG::WaitReservation::react(const SnapTrimReserved&)
+{
+ PrimaryLogPG *pg = context< SnapTrimmer >().pg;
+ ldout(pg->cct, 10) << "WaitReservation react SnapTrimReserved" << dendl;
+
+ pending = nullptr;
+ if (!context< SnapTrimmer >().can_trim()) {
+ post_event(KickTrim());
+ return transit< NotTrimming >();
}
+
+ context<Trimming>().snap_to_trim = pg->snap_trimq.range_start();
+ ldout(pg->cct, 10) << "NotTrimming: trimming "
+ << pg->snap_trimq.range_start()
+ << dendl;
+ return transit< AwaitAsyncWork >();
}
/* AwaitAsyncWork */
context< SnapTrimmer >().pg);
}
-void PrimaryLogPG::AwaitAsyncWork::exit()
-{
- context< SnapTrimmer >().log_exit(state_name, enter_time);
-}
-
boost::statechart::result PrimaryLogPG::AwaitAsyncWork::react(const DoSnapWork&)
{
dout(10) << "AwaitAsyncWork react" << dendl;
PrimaryLogPGRef pg = context< SnapTrimmer >().pg;
- snapid_t snap_to_trim = context<SnapTrimmer>().snap_to_trim;
- auto &in_flight = context<SnapTrimmer>().in_flight;
+
+ snapid_t snap_to_trim = context<Trimming>().snap_to_trim;
+ auto &in_flight = context<Trimming>().in_flight;
assert(in_flight.empty());
assert(pg->is_primary() && pg->is_active());
- if (!pg->is_clean() ||
- pg->scrubber.active) {
- dout(10) << "something changed, reverting to NotTrimming" << dendl;
+ if (!context< SnapTrimmer >().can_trim()) {
+ ldout(pg->cct, 10) << "something changed, reverting to NotTrimming" << dendl;
post_event(KickTrim());
return transit< NotTrimming >();
}
PG::_init(*t, child, pool);
}
private:
- struct NotTrimming;
+
struct DoSnapWork : boost::statechart::event< DoSnapWork > {
DoSnapWork() : boost::statechart::event < DoSnapWork >() {}
};
struct Reset : boost::statechart::event< Reset > {
Reset() : boost::statechart::event< Reset >() {}
};
+ struct SnapTrimReserved : boost::statechart::event< SnapTrimReserved > {
+ SnapTrimReserved() : boost::statechart::event< SnapTrimReserved >() {}
+ };
+
+ struct NotTrimming;
struct SnapTrimmer : public boost::statechart::state_machine< SnapTrimmer, NotTrimming > {
PrimaryLogPG *pg;
- set<hobject_t, hobject_t::BitwiseComparator> in_flight;
- snapid_t snap_to_trim;
explicit SnapTrimmer(PrimaryLogPG *pg) : pg(pg) {}
- ~SnapTrimmer();
void log_enter(const char *state_name);
void log_exit(const char *state_name, utime_t duration);
+ bool can_trim() {
+ return pg->is_clean() && !pg->scrubber.active && !pg->snap_trimq.empty();
+ }
} snap_trimmer_machine;
- /* SnapTrimmerStates */
- struct AwaitAsyncWork : boost::statechart::state< AwaitAsyncWork, SnapTrimmer >, NamedState {
+ struct WaitReservation;
+ struct Trimming : boost::statechart::state< Trimming, SnapTrimmer, WaitReservation >, NamedState {
typedef boost::mpl::list <
- boost::statechart::custom_reaction< DoSnapWork >,
boost::statechart::custom_reaction< KickTrim >,
boost::statechart::transition< Reset, NotTrimming >
> reactions;
- explicit AwaitAsyncWork(my_context ctx);
- void exit();
- boost::statechart::result react(const DoSnapWork&);
+
+ set<hobject_t, hobject_t::BitwiseComparator> in_flight;
+ snapid_t snap_to_trim;
+
+ explicit Trimming(my_context ctx)
+ : my_base(ctx),
+ NamedState(context< SnapTrimmer >().pg->cct, "Trimming") {
+ context< SnapTrimmer >().log_enter(state_name);
+ assert(context< SnapTrimmer >().can_trim());
+ assert(in_flight.empty());
+ }
+ void exit() {
+ context< SnapTrimmer >().log_exit(state_name, enter_time);
+ auto *pg = context< SnapTrimmer >().pg;
+ pg->osd->snap_reserver.cancel_reservation(pg->get_pgid());
+ }
boost::statechart::result react(const KickTrim&) {
return discard_event();
}
};
- struct WaitRWLock : boost::statechart::state< WaitRWLock, SnapTrimmer >, NamedState {
+ /* SnapTrimmerStates */
+ struct WaitRWLock : boost::statechart::state< WaitRWLock, Trimming >, NamedState {
typedef boost::mpl::list <
- boost::statechart::custom_reaction< TrimWriteUnblocked >,
- boost::statechart::custom_reaction< KickTrim >,
- boost::statechart::transition< Reset, NotTrimming >
+ boost::statechart::custom_reaction< TrimWriteUnblocked >
> reactions;
explicit WaitRWLock(my_context ctx)
: my_base(ctx),
NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitRWLock") {
context< SnapTrimmer >().log_enter(state_name);
- assert(context<SnapTrimmer>().in_flight.empty());
+ assert(context<Trimming>().in_flight.empty());
}
void exit() {
context< SnapTrimmer >().log_exit(state_name, enter_time);
}
boost::statechart::result react(const TrimWriteUnblocked&) {
- post_event(KickTrim());
- return discard_event();
- }
- boost::statechart::result react(const KickTrim&) {
- return discard_event();
+ if (!context< SnapTrimmer >().can_trim()) {
+ post_event(KickTrim());
+ return transit< NotTrimming >();
+ } else {
+ return transit< AwaitAsyncWork >();
+ }
}
};
- struct WaitScrub : boost::statechart::state< WaitScrub, SnapTrimmer >, NamedState {
+ struct WaitRepops : boost::statechart::state< WaitRepops, Trimming >, NamedState {
typedef boost::mpl::list <
- boost::statechart::custom_reaction< ScrubComplete >,
- boost::statechart::custom_reaction< KickTrim >,
- boost::statechart::transition< Reset, NotTrimming >
+ boost::statechart::custom_reaction< RepopsComplete >
> reactions;
- explicit WaitScrub(my_context ctx)
+ explicit WaitRepops(my_context ctx)
: my_base(ctx),
- NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitScrub") {
+ NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitRepops") {
context< SnapTrimmer >().log_enter(state_name);
- assert(context<SnapTrimmer>().in_flight.empty());
+ assert(!context<Trimming>().in_flight.empty());
}
void exit() {
context< SnapTrimmer >().log_exit(state_name, enter_time);
}
- boost::statechart::result react(const ScrubComplete&) {
- post_event(KickTrim());
- return transit< NotTrimming >();
+ boost::statechart::result react(const RepopsComplete&) {
+ if (!context< SnapTrimmer >().can_trim()) {
+ post_event(KickTrim());
+ return transit< NotTrimming >();
+ } else {
+ return transit< AwaitAsyncWork >();
+ }
+ }
+ };
+
+ struct AwaitAsyncWork : boost::statechart::state< AwaitAsyncWork, Trimming >, NamedState {
+ typedef boost::mpl::list <
+ boost::statechart::custom_reaction< DoSnapWork >
+ > reactions;
+ explicit AwaitAsyncWork(my_context ctx);
+ void exit() {
+ context< SnapTrimmer >().log_exit(state_name, enter_time);
+ }
+ boost::statechart::result react(const DoSnapWork&);
+ };
+
+ 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 {
+ PrimaryLogPGRef pg;
+ bool canceled;
+ ReservationCB(PrimaryLogPG *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);
+ assert(context<Trimming>().in_flight.empty());
+ auto *pg = context< SnapTrimmer >().pg;
+ pending = new ReservationCB(pg);
+ pg->osd->snap_reserver.request_reservation(
+ pg->get_pgid(),
+ pending,
+ 0);
+ }
+ boost::statechart::result react(const SnapTrimReserved&);
+ void exit() {
+ context< SnapTrimmer >().log_exit(state_name, enter_time);
+ if (pending)
+ pending->cancel();
+ pending = nullptr;
}
boost::statechart::result react(const KickTrim&) {
return discard_event();
}
};
- struct WaitRepops : boost::statechart::state< WaitRepops, SnapTrimmer >, NamedState {
+ struct WaitScrub : boost::statechart::state< WaitScrub, SnapTrimmer >, NamedState {
typedef boost::mpl::list <
- boost::statechart::custom_reaction< RepopsComplete >,
+ boost::statechart::custom_reaction< ScrubComplete >,
boost::statechart::custom_reaction< KickTrim >,
- boost::statechart::custom_reaction< Reset >
+ boost::statechart::transition< Reset, NotTrimming >
> reactions;
- explicit WaitRepops(my_context ctx)
+ explicit WaitScrub(my_context ctx)
: my_base(ctx),
- NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitRepops") {
+ NamedState(context< SnapTrimmer >().pg->cct, "Trimming/WaitScrub") {
context< SnapTrimmer >().log_enter(state_name);
- assert(!context<SnapTrimmer>().in_flight.empty());
}
void exit() {
context< SnapTrimmer >().log_exit(state_name, enter_time);
- assert(context<SnapTrimmer>().in_flight.empty());
}
- boost::statechart::result react(const RepopsComplete&) {
+ boost::statechart::result react(const ScrubComplete&) {
post_event(KickTrim());
return transit< NotTrimming >();
}
boost::statechart::result react(const KickTrim&) {
return discard_event();
}
- boost::statechart::result react(const Reset&) {
- context<SnapTrimmer>().in_flight.clear();
- return transit< NotTrimming>();
- }
};
struct NotTrimming : boost::statechart::state< NotTrimming, SnapTrimmer >, NamedState {