]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/osd/osd_operation.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / crimson / osd / osd_operation.h
CommitLineData
9f95a23c
TL
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
20effc67
TL
6#include "crimson/common/operation.h"
7#include "crimson/osd/pg_interval_interrupt_condition.h"
f67539c2 8#include "crimson/osd/scheduler/scheduler.h"
20effc67 9#include "osd/osd_types.h"
9f95a23c 10
1e59de90
TL
11namespace crimson::os::seastore {
12 template<class OpT>
13 class OperationProxyT;
14}
15
9f95a23c
TL
16namespace crimson::osd {
17
1e59de90
TL
18/// Ordering stages for a class of operations ordered by PG.
19struct ConnectionPipeline {
20 struct AwaitActive : OrderedExclusivePhaseT<AwaitActive> {
21 static constexpr auto type_name =
22 "ConnectionPipeline::await_active";
23 } await_active;
24
25 struct AwaitMap : OrderedExclusivePhaseT<AwaitMap> {
26 static constexpr auto type_name =
27 "ConnectionPipeline::await_map";
28 } await_map;
29
30 struct GetPG : OrderedExclusivePhaseT<GetPG> {
31 static constexpr auto type_name =
32 "ConnectionPipeline::get_pg";
33 } get_pg;
34};
35
9f95a23c
TL
36enum class OperationTypeCode {
37 client_request = 0,
f67539c2 38 peering_event,
f67539c2
TL
39 pg_advance_map,
40 pg_creation,
41 replicated_request,
42 background_recovery,
43 background_recovery_sub,
20effc67 44 internal_client_request,
1e59de90
TL
45 historic_client_request,
46 logmissing_request,
47 logmissing_request_reply,
48 snaptrim_event,
49 snaptrimobj_subevent,
f67539c2 50 last_op
9f95a23c
TL
51};
52
53static constexpr const char* const OP_NAMES[] = {
54 "client_request",
55 "peering_event",
9f95a23c
TL
56 "pg_advance_map",
57 "pg_creation",
58 "replicated_request",
f67539c2
TL
59 "background_recovery",
60 "background_recovery_sub",
20effc67 61 "internal_client_request",
1e59de90
TL
62 "historic_client_request",
63 "logmissing_request",
64 "logmissing_request_reply",
65 "snaptrim_event",
66 "snaptrimobj_subevent",
9f95a23c
TL
67};
68
69// prevent the addition of OperationTypeCode-s with no matching OP_NAMES entry:
70static_assert(
71 (sizeof(OP_NAMES)/sizeof(OP_NAMES[0])) ==
72 static_cast<int>(OperationTypeCode::last_op));
73
20effc67
TL
74struct InterruptibleOperation : Operation {
75 template <typename ValuesT = void>
76 using interruptible_future =
77 ::crimson::interruptible::interruptible_future<
78 ::crimson::osd::IOInterruptCondition, ValuesT>;
79 using interruptor =
80 ::crimson::interruptible::interruptor<
81 ::crimson::osd::IOInterruptCondition>;
9f95a23c 82};
9f95a23c
TL
83
84template <typename T>
1e59de90 85struct OperationT : InterruptibleOperation {
9f95a23c
TL
86 static constexpr const char *type_name = OP_NAMES[static_cast<int>(T::type)];
87 using IRef = boost::intrusive_ptr<T>;
1e59de90 88 using ICRef = boost::intrusive_ptr<const T>;
9f95a23c 89
20effc67
TL
90 unsigned get_type() const final {
91 return static_cast<unsigned>(T::type);
9f95a23c
TL
92 }
93
94 const char *get_type_name() const final {
95 return T::type_name;
96 }
97
98 virtual ~OperationT() = default;
f67539c2
TL
99
100private:
101 virtual void dump_detail(ceph::Formatter *f) const = 0;
9f95a23c
TL
102};
103
1e59de90
TL
104template <class T>
105class TrackableOperationT : public OperationT<T> {
106 T* that() {
107 return static_cast<T*>(this);
108 }
109 const T* that() const {
110 return static_cast<const T*>(this);
111 }
112
113protected:
114 template<class EventT>
115 decltype(auto) get_event() {
116 // all out derivates are supposed to define the list of tracking
117 // events accessible via `std::get`. This will usually boil down
118 // into an instance of `std::tuple`.
119 return std::get<EventT>(that()->tracking_events);
120 }
121
122 template<class EventT>
123 decltype(auto) get_event() const {
124 return std::get<EventT>(that()->tracking_events);
125 }
126
127 using OperationT<T>::OperationT;
128
129 struct StartEvent : TimeEvent<StartEvent> {};
130 struct CompletionEvent : TimeEvent<CompletionEvent> {};
131
132 template <class EventT, class... Args>
133 void track_event(Args&&... args) {
134 // the idea is to have a visitor-like interface that allows to double
135 // dispatch (backend, blocker type)
136 get_event<EventT>().trigger(*that(), std::forward<Args>(args)...);
137 }
138
139 template <class BlockingEventT, class InterruptorT=void, class F>
140 auto with_blocking_event(F&& f) {
141 auto ret = std::forward<F>(f)(typename BlockingEventT::template Trigger<T>{
142 get_event<BlockingEventT>(), *that()
143 });
144 if constexpr (std::is_same_v<InterruptorT, void>) {
145 return ret;
146 } else {
147 using ret_t = decltype(ret);
148 return typename InterruptorT::template futurize_t<ret_t>{std::move(ret)};
149 }
150 }
151
152public:
153 static constexpr bool is_trackable = true;
154};
155
156template <class T>
157class PhasedOperationT : public TrackableOperationT<T> {
158 using base_t = TrackableOperationT<T>;
159
160 T* that() {
161 return static_cast<T*>(this);
162 }
163 const T* that() const {
164 return static_cast<const T*>(this);
165 }
166
167protected:
168 using TrackableOperationT<T>::TrackableOperationT;
169
170 template <class InterruptorT=void, class StageT>
171 auto enter_stage(StageT& stage) {
172 return this->template with_blocking_event<typename StageT::BlockingEvent,
173 InterruptorT>(
174 [&stage, this] (auto&& trigger) {
175 // delegated storing the pipeline handle to let childs to match
176 // the lifetime of pipeline with e.g. ConnectedSocket (important
177 // for ConnectionPipeline).
178 return that()->get_handle().template enter<T>(stage, std::move(trigger));
179 });
180 }
181
182 template <class OpT>
183 friend class crimson::os::seastore::OperationProxyT;
184
185 // PGShardManager::start_pg_operation needs access to enter_stage, we can make this
186 // more sophisticated later on
187 friend class PGShardManager;
188};
189
9f95a23c
TL
190/**
191 * Maintains a set of lists of all active ops.
192 */
1e59de90 193struct OSDOperationRegistry : OperationRegistryT<
20effc67 194 static_cast<size_t>(OperationTypeCode::last_op)
1e59de90
TL
195> {
196 OSDOperationRegistry();
f67539c2 197
1e59de90
TL
198 void do_stop() override;
199
200 void put_historic(const class ClientRequest& op);
201
202 size_t dump_historic_client_requests(ceph::Formatter* f) const;
203 size_t dump_slowest_historic_client_requests(ceph::Formatter* f) const;
204
205private:
206 op_list::const_iterator last_of_recents;
207 size_t num_recent_ops = 0;
208 size_t num_slow_ops = 0;
209};
f67539c2
TL
210/**
211 * Throttles set of currently running operations
212 *
213 * Very primitive currently, assumes all ops are equally
214 * expensive and simply limits the number that can be
215 * concurrently active.
216 */
1e59de90 217class OperationThrottler : public BlockerT<OperationThrottler>,
f67539c2 218 private md_config_obs_t {
1e59de90
TL
219 friend BlockerT<OperationThrottler>;
220 static constexpr const char* type_name = "OperationThrottler";
f67539c2 221
1e59de90 222 template <typename OperationT, typename F>
f67539c2 223 auto with_throttle(
1e59de90 224 OperationT* op,
f67539c2
TL
225 crimson::osd::scheduler::params_t params,
226 F &&f) {
227 if (!max_in_progress) return f();
1e59de90 228 return acquire_throttle(params)
f67539c2
TL
229 .then(std::forward<F>(f))
230 .then([this](auto x) {
231 release_throttle();
232 return x;
233 });
234 }
235
1e59de90 236 template <typename OperationT, typename F>
f67539c2 237 seastar::future<> with_throttle_while(
1e59de90 238 OperationT* op,
f67539c2
TL
239 crimson::osd::scheduler::params_t params,
240 F &&f) {
241 return with_throttle(op, params, f).then([this, params, op, f](bool cont) {
1e59de90 242 return cont ? with_throttle_while(op, params, f) : seastar::now();
f67539c2
TL
243 });
244 }
245
1e59de90
TL
246
247public:
248 OperationThrottler(ConfigProxy &conf);
249
250 const char** get_tracked_conf_keys() const final;
251 void handle_conf_change(const ConfigProxy& conf,
252 const std::set<std::string> &changed) final;
253 void update_from_config(const ConfigProxy &conf);
254
255 template <class OpT, class... Args>
256 seastar::future<> with_throttle_while(
257 BlockingEvent::Trigger<OpT>&& trigger,
258 Args&&... args) {
259 return trigger.maybe_record_blocking(
260 with_throttle_while(std::forward<Args>(args)...), *this);
f67539c2
TL
261 }
262
263private:
1e59de90
TL
264 void dump_detail(Formatter *f) const final;
265
f67539c2
TL
266 crimson::osd::scheduler::SchedulerRef scheduler;
267
268 uint64_t max_in_progress = 0;
269 uint64_t in_progress = 0;
270
271 uint64_t pending = 0;
272
273 void wake();
274
1e59de90 275 seastar::future<> acquire_throttle(
f67539c2
TL
276 crimson::osd::scheduler::params_t params);
277
278 void release_throttle();
9f95a23c
TL
279};
280
9f95a23c 281}