]>
git.proxmox.com Git - ceph.git/blob - 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
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>
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"
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"
28 #include "crimson/osd/pg_backend.h"
29 #include "crimson/osd/exceptions.h"
31 #include "messages/MOSDOp.h"
37 namespace crimson::osd
{
39 // PgOpsExecuter -- a class for executing ops targeting a certain object.
41 using call_errorator
= crimson::errorator
<
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
>;
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;
65 using osd_op_errorator
= crimson::compound_errorator_t
<
71 PGBackend::stat_errorator
>;
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()`
82 virtual osd_op_errorator::future
<> execute() = 0;
83 virtual ~effect_t() = default;
87 const OpInfo
& op_info
;
88 const pg_pool_t
& pool_info
; // for the sake of the ObjClass API
91 std::optional
<osd_op_params_t
> osd_op_params
;
92 bool user_modify
= false;
93 ceph::os::Transaction txn
;
95 size_t num_read
= 0; ///< count read ops
96 size_t num_write
= 0; ///< count update ops
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
;
103 template <class Context
, class MainFunc
, class EffectFunc
>
104 auto with_effect_on_obc(
106 MainFunc
&& main_func
,
107 EffectFunc
&& effect_func
);
109 call_errorator::future
<> do_op_call(class OSDOp
& osd_op
);
110 watch_errorator::future
<> do_op_watch(
112 class ObjectState
& os
,
113 ceph::os::Transaction
& txn
);
114 watch_errorator::future
<> do_op_watch_subop_watch(
116 class ObjectState
& os
,
117 ceph::os::Transaction
& txn
);
118 watch_errorator::future
<> do_op_watch_subop_reconnect(
120 class ObjectState
& os
,
121 ceph::os::Transaction
& txn
);
122 watch_errorator::future
<> do_op_watch_subop_unwatch(
124 class ObjectState
& os
,
125 ceph::os::Transaction
& txn
);
126 watch_errorator::future
<> do_op_watch_subop_ping(
128 class ObjectState
& os
,
129 ceph::os::Transaction
& txn
);
130 watch_errorator::future
<> do_op_notify(
132 const class ObjectState
& os
);
133 watch_errorator::future
<> do_op_notify_ack(
135 const class ObjectState
& os
);
137 hobject_t
&get_target() const {
138 return obc
->obs
.oi
.soid
;
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
));
147 template <class Func
>
148 auto do_read_op(Func
&& f
) {
150 // TODO: pass backend as read-only
151 return do_const_op(std::forward
<Func
>(f
));
154 template <class Func
>
155 auto do_write_op(Func
&& f
, bool um
) {
157 if (!osd_op_params
) {
158 osd_op_params
.emplace();
161 return std::forward
<Func
>(f
)(backend
, obc
->obs
, txn
);
164 decltype(auto) dont_do_legacy_op() {
165 return crimson::ct_error::operation_not_supported::make();
169 OpsExecuter(ObjectContextRef obc
,
170 const OpInfo
& op_info
,
171 const pg_pool_t
& pool_info
,
174 : obc(std::move(obc
)),
176 pool_info(pool_info
),
181 osd_op_errorator::future
<> execute_op(class OSDOp
& osd_op
);
183 template <typename Func
, typename MutFunc
>
184 osd_op_errorator::future
<> flush_changes(Func
&& func
, MutFunc
&& mut_func
) &&;
186 const auto& get_message() const {
190 size_t get_processed_rw_ops_num() const {
191 return num_read
+ num_write
;
194 uint32_t get_pool_stripe_width() const {
195 return pool_info
.get_stripe_width();
198 bool has_seen_write() const {
199 return num_write
> 0;
203 template <class Context
, class MainFunc
, class EffectFunc
>
204 auto OpsExecuter::with_effect_on_obc(
206 MainFunc
&& main_func
,
207 EffectFunc
&& effect_func
)
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
{
219 EffectFunc effect_func
;
220 ObjectContextRef obc
;
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
)) {
227 osd_op_errorator::future
<> execute() final
{
228 return std::move(effect_func
)(std::move(ctx
), std::move(obc
));
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
);
238 template <typename Func
,
240 OpsExecuter::osd_op_errorator::future
<> OpsExecuter::flush_changes(
242 MutFunc
&& mut_func
) &&
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
);
248 if (__builtin_expect(op_effects
.empty(), true)) {
249 return want_mutate
? std::forward
<MutFunc
>(mut_func
)(std::move(txn
),
251 std::move(*osd_op_params
),
253 : std::forward
<Func
>(func
)(std::move(obc
));
255 return (want_mutate
? std::forward
<MutFunc
>(mut_func
)(std::move(txn
),
257 std::move(*osd_op_params
),
259 : std::forward
<Func
>(func
)(std::move(obc
))
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();
269 // PgOpsExecuter -- a class for executing ops targeting a certain PG.
270 class PgOpsExecuter
{
272 PgOpsExecuter(const PG
& pg
, const MOSDOp
& msg
)
273 : pg(pg
), nspace(msg
.get_hobj().nspace
) {
276 seastar::future
<> execute_op(class OSDOp
& osd_op
);
280 const std::string
& nspace
;
283 } // namespace crimson::osd