]> git.proxmox.com Git - ceph.git/blob - ceph/src/crimson/osd/ops_executer.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / crimson / osd / ops_executer.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #pragma once
5
6 #include <memory>
7 #include <type_traits>
8 #include <boost/intrusive_ptr.hpp>
9 #include <boost/smart_ptr/intrusive_ref_counter.hpp>
10 #include <boost/smart_ptr/local_shared_ptr.hpp>
11 #include <seastar/core/chunked_fifo.hh>
12 #include <seastar/core/future.hh>
13 #include <seastar/core/shared_future.hh>
14
15 #include "common/dout.h"
16 #include "crimson/net/Fwd.h"
17 #include "os/Transaction.h"
18 #include "osd/osd_types.h"
19 #include "crimson/osd/object_context.h"
20
21 #include "crimson/common/errorator.h"
22 #include "crimson/common/type_helpers.h"
23 #include "crimson/osd/osd_operations/client_request.h"
24 #include "crimson/osd/osd_operations/peering_event.h"
25 #include "crimson/osd/shard_services.h"
26 #include "crimson/osd/osdmap_gate.h"
27
28 #include "crimson/osd/pg_backend.h"
29 #include "crimson/osd/exceptions.h"
30
31 #include "messages/MOSDOp.h"
32
33 class PG;
34 class PGLSFilter;
35 class OSDOp;
36
37 namespace crimson::osd {
38
39 // PgOpsExecuter -- a class for executing ops targeting a certain object.
40 class OpsExecuter {
41 using call_errorator = crimson::errorator<
42 crimson::stateful_ec,
43 crimson::ct_error::enoent,
44 crimson::ct_error::invarg,
45 crimson::ct_error::permission_denied,
46 crimson::ct_error::operation_not_supported,
47 crimson::ct_error::input_output_error,
48 crimson::ct_error::value_too_large>;
49 using read_errorator = PGBackend::read_errorator;
50 using write_ertr = PGBackend::write_ertr;
51 using get_attr_errorator = PGBackend::get_attr_errorator;
52 using watch_errorator = crimson::errorator<
53 crimson::ct_error::enoent,
54 crimson::ct_error::invarg,
55 crimson::ct_error::not_connected,
56 crimson::ct_error::timed_out>;
57
58 public:
59 // because OpsExecuter is pretty heavy-weight object we want to ensure
60 // it's not copied nor even moved by accident. Performance is the sole
61 // reason for prohibiting that.
62 OpsExecuter(OpsExecuter&&) = delete;
63 OpsExecuter(const OpsExecuter&) = delete;
64
65 using osd_op_errorator = crimson::compound_errorator_t<
66 call_errorator,
67 read_errorator,
68 write_ertr,
69 get_attr_errorator,
70 watch_errorator,
71 PGBackend::stat_errorator>;
72
73 private:
74 // an operation can be divided into two stages: main and effect-exposing
75 // one. The former is performed immediately on call to `do_osd_op()` while
76 // the later on `submit_changes()` – after successfully processing main
77 // stages of all involved operations. When any stage fails, none of all
78 // scheduled effect-exposing stages will be executed.
79 // when operation requires this division, some variant of `with_effect()`
80 // should be used.
81 struct effect_t {
82 virtual osd_op_errorator::future<> execute() = 0;
83 virtual ~effect_t() = default;
84 };
85
86 ObjectContextRef obc;
87 const OpInfo& op_info;
88 const pg_pool_t& pool_info; // for the sake of the ObjClass API
89 PGBackend& backend;
90 const MOSDOp& msg;
91 std::optional<osd_op_params_t> osd_op_params;
92 bool user_modify = false;
93 ceph::os::Transaction txn;
94
95 size_t num_read = 0; ///< count read ops
96 size_t num_write = 0; ///< count update ops
97
98 // this gizmo could be wrapped in std::optional for the sake of lazy
99 // initialization. we don't need it for ops that doesn't have effect
100 // TODO: verify the init overhead of chunked_fifo
101 seastar::chunked_fifo<std::unique_ptr<effect_t>> op_effects;
102
103 template <class Context, class MainFunc, class EffectFunc>
104 auto with_effect_on_obc(
105 Context&& ctx,
106 MainFunc&& main_func,
107 EffectFunc&& effect_func);
108
109 call_errorator::future<> do_op_call(class OSDOp& osd_op);
110 watch_errorator::future<> do_op_watch(
111 class OSDOp& osd_op,
112 class ObjectState& os,
113 ceph::os::Transaction& txn);
114 watch_errorator::future<> do_op_watch_subop_watch(
115 class OSDOp& osd_op,
116 class ObjectState& os,
117 ceph::os::Transaction& txn);
118 watch_errorator::future<> do_op_watch_subop_reconnect(
119 class OSDOp& osd_op,
120 class ObjectState& os,
121 ceph::os::Transaction& txn);
122 watch_errorator::future<> do_op_watch_subop_unwatch(
123 class OSDOp& osd_op,
124 class ObjectState& os,
125 ceph::os::Transaction& txn);
126 watch_errorator::future<> do_op_watch_subop_ping(
127 class OSDOp& osd_op,
128 class ObjectState& os,
129 ceph::os::Transaction& txn);
130 watch_errorator::future<> do_op_notify(
131 class OSDOp& osd_op,
132 const class ObjectState& os);
133 watch_errorator::future<> do_op_notify_ack(
134 class OSDOp& osd_op,
135 const class ObjectState& os);
136
137 hobject_t &get_target() const {
138 return obc->obs.oi.soid;
139 }
140
141 template <class Func>
142 auto do_const_op(Func&& f) {
143 // TODO: pass backend as read-only
144 return std::forward<Func>(f)(backend, std::as_const(obc->obs));
145 }
146
147 template <class Func>
148 auto do_read_op(Func&& f) {
149 ++num_read;
150 // TODO: pass backend as read-only
151 return do_const_op(std::forward<Func>(f));
152 }
153
154 template <class Func>
155 auto do_write_op(Func&& f, bool um) {
156 ++num_write;
157 if (!osd_op_params) {
158 osd_op_params.emplace();
159 }
160 user_modify = um;
161 return std::forward<Func>(f)(backend, obc->obs, txn);
162 }
163
164 decltype(auto) dont_do_legacy_op() {
165 return crimson::ct_error::operation_not_supported::make();
166 }
167
168 public:
169 OpsExecuter(ObjectContextRef obc,
170 const OpInfo& op_info,
171 const pg_pool_t& pool_info,
172 PGBackend& backend,
173 const MOSDOp& msg)
174 : obc(std::move(obc)),
175 op_info(op_info),
176 pool_info(pool_info),
177 backend(backend),
178 msg(msg) {
179 }
180
181 osd_op_errorator::future<> execute_op(class OSDOp& osd_op);
182
183 template <typename Func, typename MutFunc>
184 osd_op_errorator::future<> flush_changes(Func&& func, MutFunc&& mut_func) &&;
185
186 const auto& get_message() const {
187 return msg;
188 }
189
190 size_t get_processed_rw_ops_num() const {
191 return num_read + num_write;
192 }
193
194 uint32_t get_pool_stripe_width() const {
195 return pool_info.get_stripe_width();
196 }
197
198 bool has_seen_write() const {
199 return num_write > 0;
200 }
201 };
202
203 template <class Context, class MainFunc, class EffectFunc>
204 auto OpsExecuter::with_effect_on_obc(
205 Context&& ctx,
206 MainFunc&& main_func,
207 EffectFunc&& effect_func)
208 {
209 using context_t = std::decay_t<Context>;
210 // the language offers implicit conversion to pointer-to-function for
211 // lambda only when it's closureless. We enforce this restriction due
212 // the fact that `flush_changes()` std::moves many executer's parts.
213 using allowed_effect_func_t =
214 seastar::future<> (*)(context_t&&, ObjectContextRef);
215 static_assert(std::is_convertible_v<EffectFunc, allowed_effect_func_t>,
216 "with_effect function is not allowed to capture");
217 struct task_t final : effect_t {
218 context_t ctx;
219 EffectFunc effect_func;
220 ObjectContextRef obc;
221
222 task_t(Context&& ctx, EffectFunc&& effect_func, ObjectContextRef obc)
223 : ctx(std::move(ctx)),
224 effect_func(std::move(effect_func)),
225 obc(std::move(obc)) {
226 }
227 osd_op_errorator::future<> execute() final {
228 return std::move(effect_func)(std::move(ctx), std::move(obc));
229 }
230 };
231 auto task =
232 std::make_unique<task_t>(std::move(ctx), std::move(effect_func), obc);
233 auto& ctx_ref = task->ctx;
234 op_effects.emplace_back(std::move(task));
235 return std::forward<MainFunc>(main_func)(ctx_ref);
236 }
237
238 template <typename Func,
239 typename MutFunc>
240 OpsExecuter::osd_op_errorator::future<> OpsExecuter::flush_changes(
241 Func&& func,
242 MutFunc&& mut_func) &&
243 {
244 const bool want_mutate = !txn.empty();
245 // osd_op_params are instantiated by every wr-like operation.
246 assert(osd_op_params || !want_mutate);
247 assert(obc);
248 if (__builtin_expect(op_effects.empty(), true)) {
249 return want_mutate ? std::forward<MutFunc>(mut_func)(std::move(txn),
250 std::move(obc),
251 std::move(*osd_op_params),
252 user_modify)
253 : std::forward<Func>(func)(std::move(obc));
254 } else {
255 return (want_mutate ? std::forward<MutFunc>(mut_func)(std::move(txn),
256 std::move(obc),
257 std::move(*osd_op_params),
258 user_modify)
259 : std::forward<Func>(func)(std::move(obc))
260 ).safe_then([this] {
261 // let's do the cleaning of `op_effects` in destructor
262 return crimson::do_for_each(op_effects, [] (auto& op_effect) {
263 return op_effect->execute();
264 });
265 });
266 }
267 }
268
269 // PgOpsExecuter -- a class for executing ops targeting a certain PG.
270 class PgOpsExecuter {
271 public:
272 PgOpsExecuter(const PG& pg, const MOSDOp& msg)
273 : pg(pg), nspace(msg.get_hobj().nspace) {
274 }
275
276 seastar::future<> execute_op(class OSDOp& osd_op);
277
278 private:
279 const PG& pg;
280 const std::string& nspace;
281 };
282
283 } // namespace crimson::osd