From 2c5e2f82028ab2b3ce8544c18b6a60a7c18f2a0e Mon Sep 17 00:00:00 2001 From: Radoslaw Zarzynski Date: Mon, 2 Sep 2019 16:38:32 +0200 Subject: [PATCH] crimson/osd: extend OpsExecuter to carry about op effects. This commit brings a new infrastructural piece that will be needed by e.g. the watch/notify mechanism. Signed-off-by: Radoslaw Zarzynski --- src/crimson/osd/ops_executer.h | 70 ++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/crimson/osd/ops_executer.h b/src/crimson/osd/ops_executer.h index 3e8564570dfc..f1ea36713f0d 100644 --- a/src/crimson/osd/ops_executer.h +++ b/src/crimson/osd/ops_executer.h @@ -5,9 +5,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -31,6 +33,17 @@ class OSDOp; namespace ceph::osd { class OpsExecuter { + // an operation can be divided into two stages: main and effect-exposing + // one. The former is performed immediately on call to `do_osd_op()` while + // the later on `submit_changes()` – after successfully processing main + // stages of all involved operations. When any stage fails, none of all + // scheduled effect-exposing stages will be executed. + // when operation requires this division, `with_effect()` should be used. + struct effect_t { + virtual seastar::future<> execute() = 0; + virtual ~effect_t() = default; + }; + PGBackend::cached_os_t os; PG& pg; PGBackend& backend; @@ -39,6 +52,14 @@ class OpsExecuter { size_t num_read = 0; ///< count read ops size_t num_write = 0; ///< count update ops + // this gizmo could be wrapped in std::optional for the sake of lazy + // initialization. we don't need it for ops that doesn't have effect + // TODO: verify the init overhead of chunked_fifo + seastar::chunked_fifo> op_effects; + + template + auto with_effect(Context&& ctx, MainFunc&& main_func, EffectFunc&& effect_func); + seastar::future<> do_op_call(class OSDOp& osd_op); template @@ -74,9 +95,52 @@ public: seastar::future<> do_osd_op(class OSDOp& osd_op); - template seastar::future<> submit_changes(Func&& f) && { - return std::forward(f)(std::move(txn), std::move(os)); - } + template + seastar::future<> submit_changes(Func&& f) &&; }; +template +auto OpsExecuter::with_effect( + Context&& ctx, + MainFunc&& main_func, + EffectFunc&& effect_func) +{ + using context_t = std::decay_t; + // the language offers implicit conversion to pointer-to-function for + // lambda only when it's closureless + static_assert(std::is_convertible_v (*)(context_t&&)>, + "with_effect function is not allowed to capture"); + struct task_t final : effect_t { + context_t ctx; + EffectFunc effect_func; + + task_t(Context&& ctx, EffectFunc&& effect_func) + : ctx(std::move(ctx)), effect_func(std::move(effect_func)) {} + seastar::future<> execute() final { + return std::move(effect_func)(std::move(ctx)); + } + }; + auto task = + std::make_unique(std::move(ctx), std::move(effect_func)); + auto& ctx_ref = task->ctx; + op_effects.emplace_back(std::move(task)); + return std::forward(main_func)(ctx_ref); +} + +template +seastar::future<> OpsExecuter::submit_changes(Func&& f) && { + return std::forward(f)(std::move(txn), std::move(os)).then( + // NOTE: this lambda could be scheduled conditionally (if_then?) + [this] { + return seastar::do_until( + [this] { return op_effects.empty(); }, + [this] { + auto fut = op_effects.front()->execute(); + op_effects.pop_front(); + return fut; + }); + }); +} + } // namespace ceph::osd -- 2.47.3