lhs << "SnapTrimEvent("
<< "pgid=" << pg->get_pgid()
<< " snapid=" << snapid
+ << " needs_pause=" << needs_pause
<< ")";
}
wait_subop
).then_interruptible([this] {
logger().debug("{}: awaiting completion", *this);
- return subop_blocker.wait_completion().then([this] {
- logger().debug("{}: all completed", *this);
- return interruptor::make_ready_future<seastar::stop_iteration>(
- seastar::stop_iteration::no);
+ return subop_blocker.wait_completion();
+ }).then_interruptible([this] {
+ if (!needs_pause) {
+ return interruptor::now();
+ }
+ // let's know operators we're waiting
+ return enter_stage<interruptor>(
+ wait_trim_timer
+ ).then_interruptible([this] {
+ using crimson::common::local_conf;
+ const auto time_to_sleep =
+ local_conf().template get_val<double>("osd_snap_trim_sleep");
+ logger().debug("{}: time_to_sleep {}", *this, time_to_sleep);
+ // TODO: this logic should be more sophisticated and distinguish
+ // between SSDs, HDDs and the hybrid case
+ return seastar::sleep(
+ std::chrono::milliseconds(std::lround(time_to_sleep * 1000)));
});
+ }).then_interruptible([this] {
+ logger().debug("{}: all completed", *this);
+ return interruptor::make_ready_future<seastar::stop_iteration>(
+ seastar::stop_iteration::no);
});
});
});
public:
static constexpr OperationTypeCode type = OperationTypeCode::snaptrim_event;
- SnapTrimEvent(Ref<PG> pg, SnapMapper& snap_mapper, snapid_t snapid)
+ SnapTrimEvent(Ref<PG> pg,
+ SnapMapper& snap_mapper,
+ const snapid_t snapid,
+ const bool needs_pause)
: pg(std::move(pg)),
snap_mapper(snap_mapper),
- snapid(snapid) {}
+ snapid(snapid),
+ needs_pause(needs_pause) {}
void print(std::ostream &) const final;
void dump_detail(ceph::Formatter* f) const final;
static constexpr auto type_name = "SnapTrimEvent::wait_subop";
} wait_subop;
+ // an instantiator can instruct us to go over this stage and then
+ // wait for the future to implement throttling. It is implemented
+ // that way to for the sake of tracking ops.
+ struct WaitTrimTimer : OrderedExclusivePhaseT<WaitTrimTimer> {
+ static constexpr auto type_name = "SnapTrimEvent::wait_trim_timer";
+ } wait_trim_timer;
+
PipelineHandle handle;
Ref<PG> pg;
SnapMapper& snap_mapper;
const snapid_t snapid;
+ const bool needs_pause;
public:
PipelineHandle& get_handle() { return handle; }
CommonPGPipeline::GetOBC::BlockingEvent,
CommonPGPipeline::Process::BlockingEvent,
WaitSubop::BlockingEvent,
+ WaitTrimTimer::BlockingEvent,
CompletionEvent
> tracking_events;
};
[this] {
const auto to_trim = snap_trimq.range_start();
snap_trimq.erase(to_trim);
- return seastar::repeat([to_trim, this] {
+ const auto needs_pause = !snap_trimq.empty();
+ return seastar::repeat([to_trim, needs_pause, this] {
logger().debug("{}: going to start SnapTrimEvent, to_trim={}",
*this, to_trim);
return shard_services.start_operation<SnapTrimEvent>(
this,
snap_mapper,
- to_trim).second;
+ to_trim,
+ needs_pause).second;
}).then([this, trimmed=to_trim] {
logger().debug("{}: trimmed snap={}", *this, trimmed);
});