]>
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.h"
29 #include "crimson/osd/pg_backend.h"
30 #include "crimson/osd/exceptions.h"
32 #include "messages/MOSDOp.h"
37 namespace crimson::osd
{
39 using call_errorator
= crimson::errorator
<
41 crimson::ct_error::enoent
,
42 crimson::ct_error::invarg
,
43 crimson::ct_error::permission_denied
,
44 crimson::ct_error::operation_not_supported
,
45 crimson::ct_error::input_output_error
>;
46 using read_errorator
= PGBackend::read_errorator
;
47 using get_attr_errorator
= PGBackend::get_attr_errorator
;
48 using watch_errorator
= crimson::errorator
<
49 crimson::ct_error::enoent
,
50 crimson::ct_error::invarg
,
51 crimson::ct_error::not_connected
,
52 crimson::ct_error::timed_out
>;
55 // because OpsExecuter is pretty heavy-weight object we want to ensure
56 // it's not copied nor even moved by accident. Performance is the sole
57 // reason for prohibiting that.
58 OpsExecuter(OpsExecuter
&&) = delete;
59 OpsExecuter(const OpsExecuter
&) = delete;
61 using osd_op_errorator
= crimson::compound_errorator_t
<
66 PGBackend::stat_errorator
>;
69 // an operation can be divided into two stages: main and effect-exposing
70 // one. The former is performed immediately on call to `do_osd_op()` while
71 // the later on `submit_changes()` – after successfully processing main
72 // stages of all involved operations. When any stage fails, none of all
73 // scheduled effect-exposing stages will be executed.
74 // when operation requires this division, some variant of `with_effect()`
77 virtual osd_op_errorator::future
<> execute() = 0;
78 virtual ~effect_t() = default;
85 ceph::os::Transaction txn
;
87 size_t num_read
= 0; ///< count read ops
88 size_t num_write
= 0; ///< count update ops
90 // this gizmo could be wrapped in std::optional for the sake of lazy
91 // initialization. we don't need it for ops that doesn't have effect
92 // TODO: verify the init overhead of chunked_fifo
93 seastar::chunked_fifo
<std::unique_ptr
<effect_t
>> op_effects
;
95 template <class Context
, class MainFunc
, class EffectFunc
>
96 auto with_effect_on_obc(
99 EffectFunc
&& effect_func
);
101 call_errorator::future
<> do_op_call(class OSDOp
& osd_op
);
102 watch_errorator::future
<> do_op_watch(
104 class ObjectState
& os
,
105 ceph::os::Transaction
& txn
);
106 watch_errorator::future
<> do_op_watch_subop_watch(
108 class ObjectState
& os
,
109 ceph::os::Transaction
& txn
);
110 watch_errorator::future
<> do_op_watch_subop_reconnect(
112 class ObjectState
& os
,
113 ceph::os::Transaction
& txn
);
114 watch_errorator::future
<> do_op_watch_subop_unwatch(
116 class ObjectState
& os
,
117 ceph::os::Transaction
& txn
);
118 watch_errorator::future
<> do_op_watch_subop_ping(
120 class ObjectState
& os
,
121 ceph::os::Transaction
& txn
);
122 watch_errorator::future
<> do_op_notify(
124 const class ObjectState
& os
);
125 watch_errorator::future
<> do_op_notify_ack(
127 const class ObjectState
& os
);
129 hobject_t
&get_target() const {
130 return obc
->obs
.oi
.soid
;
133 template <class Func
>
134 auto do_const_op(Func
&& f
) {
135 // TODO: pass backend as read-only
136 return std::forward
<Func
>(f
)(backend
, std::as_const(obc
->obs
));
139 template <class Func
>
140 auto do_read_op(Func
&& f
) {
142 // TODO: pass backend as read-only
143 return do_const_op(std::forward
<Func
>(f
));
146 template <class Func
>
147 auto do_write_op(Func
&& f
) {
149 return std::forward
<Func
>(f
)(backend
, obc
->obs
, txn
);
152 // PG operations are being provided with pg instead of os.
153 template <class Func
>
154 auto do_pg_op(Func
&& f
) {
155 return std::forward
<Func
>(f
)(std::as_const(pg
),
156 std::as_const(msg
->get_hobj().nspace
));
159 decltype(auto) dont_do_legacy_op() {
160 return crimson::ct_error::operation_not_supported::make();
164 OpsExecuter(ObjectContextRef obc
, PG
& pg
, Ref
<MOSDOp
> msg
)
165 : obc(std::move(obc
)),
167 backend(pg
.get_backend()),
168 msg(std::move(msg
)) {
170 OpsExecuter(PG
& pg
, Ref
<MOSDOp
> msg
)
171 : OpsExecuter
{ObjectContextRef(), pg
, std::move(msg
)}
174 osd_op_errorator::future
<> execute_osd_op(class OSDOp
& osd_op
);
175 seastar::future
<> execute_pg_op(class OSDOp
& osd_op
);
177 template <typename Func
>
178 osd_op_errorator::future
<> submit_changes(Func
&& f
) &&;
180 const auto& get_message() const {
185 template <class Context
, class MainFunc
, class EffectFunc
>
186 auto OpsExecuter::with_effect_on_obc(
188 MainFunc
&& main_func
,
189 EffectFunc
&& effect_func
)
191 using context_t
= std::decay_t
<Context
>;
192 // the language offers implicit conversion to pointer-to-function for
193 // lambda only when it's closureless. We enforce this restriction due
194 // the fact that `submit_changes()` std::moves many executer's parts.
195 using allowed_effect_func_t
=
196 seastar::future
<> (*)(context_t
&&, ObjectContextRef
);
197 static_assert(std::is_convertible_v
<EffectFunc
, allowed_effect_func_t
>,
198 "with_effect function is not allowed to capture");
199 struct task_t final
: effect_t
{
201 EffectFunc effect_func
;
202 ObjectContextRef obc
;
204 task_t(Context
&& ctx
, EffectFunc
&& effect_func
, ObjectContextRef obc
)
205 : ctx(std::move(ctx
)),
206 effect_func(std::move(effect_func
)),
207 obc(std::move(obc
)) {
209 osd_op_errorator::future
<> execute() final
{
210 return std::move(effect_func
)(std::move(ctx
), std::move(obc
));
214 std::make_unique
<task_t
>(std::move(ctx
), std::move(effect_func
), obc
);
215 auto& ctx_ref
= task
->ctx
;
216 op_effects
.emplace_back(std::move(task
));
217 return std::forward
<MainFunc
>(main_func
)(ctx_ref
);
220 template <typename Func
>
221 OpsExecuter::osd_op_errorator::future
<> OpsExecuter::submit_changes(Func
&& f
) && {
222 if (__builtin_expect(op_effects
.empty(), true)) {
223 return std::forward
<Func
>(f
)(std::move(txn
), std::move(obc
));
225 return std::forward
<Func
>(f
)(std::move(txn
), std::move(obc
)).safe_then([this] {
226 // let's do the cleaning of `op_effects` in destructor
227 return crimson::do_for_each(op_effects
, [] (auto& op_effect
) {
228 return op_effect
->execute();
233 } // namespace crimson::osd