}
for (const auto& object : to_trim) {
logger().debug("{}: trimming {}", *this, object);
- auto [op, fut] = shard_services.start_operation<SnapTrimObjSubEvent>(
+ auto [op, fut] = shard_services.start_operation_may_interrupt<
+ interruptor, SnapTrimObjSubEvent>(
pg,
object,
snapid);
return std::make_pair(std::move(op), std::move(fut));
}
+ template <typename InterruptorT, typename T, typename... Args>
+ auto start_operation_may_interrupt(Args&&... args) {
+ assert_core();
+ if (__builtin_expect(stopping, false)) {
+ throw crimson::common::system_shutdown_exception();
+ }
+ auto op = registry.create_operation<T>(std::forward<Args>(args)...);
+ crimson::get_logger(ceph_subsys_osd).info(
+ "PerShardState::{}, {}", __func__, *op);
+ auto fut = InterruptorT::make_interruptible(
+ seastar::yield()
+ ).then_interruptible([op] {
+ return op->start().finally([op /* by copy */] {
+ // ensure the op's lifetime is appropriate. It is not enough to
+ // guarantee it's alive at the scheduling stages (i.e. `then()`
+ // calling) but also during the actual execution (i.e. when passed
+ // lambdas are actually run).
+ });
+ });
+ return std::make_pair(std::move(op), std::move(fut));
+ }
+
// tids for ops i issue, prefixed with core id to ensure uniqueness
ceph_tid_t next_tid;
ceph_tid_t get_tid() {
return local_state.start_operation<T>(std::forward<Args>(args)...);
}
+ template <typename InterruptorT, typename T, typename... Args>
+ auto start_operation_may_interrupt(Args&&... args) {
+ return local_state.start_operation_may_interrupt<
+ InterruptorT, T>(std::forward<Args>(args)...);
+ }
+
auto &get_registry() { return local_state.registry; }
// Loggers