]>
Commit | Line | Data |
---|---|---|
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 TL |
10 | |
11 | namespace crimson::osd { | |
12 | ||
13 | enum class OperationTypeCode { | |
14 | client_request = 0, | |
f67539c2 TL |
15 | peering_event, |
16 | compound_peering_request, | |
17 | pg_advance_map, | |
18 | pg_creation, | |
19 | replicated_request, | |
20 | background_recovery, | |
21 | background_recovery_sub, | |
20effc67 | 22 | internal_client_request, |
f67539c2 | 23 | last_op |
9f95a23c TL |
24 | }; |
25 | ||
26 | static constexpr const char* const OP_NAMES[] = { | |
27 | "client_request", | |
28 | "peering_event", | |
29 | "compound_peering_request", | |
30 | "pg_advance_map", | |
31 | "pg_creation", | |
32 | "replicated_request", | |
f67539c2 TL |
33 | "background_recovery", |
34 | "background_recovery_sub", | |
20effc67 | 35 | "internal_client_request", |
9f95a23c TL |
36 | }; |
37 | ||
38 | // prevent the addition of OperationTypeCode-s with no matching OP_NAMES entry: | |
39 | static_assert( | |
40 | (sizeof(OP_NAMES)/sizeof(OP_NAMES[0])) == | |
41 | static_cast<int>(OperationTypeCode::last_op)); | |
42 | ||
20effc67 TL |
43 | struct InterruptibleOperation : Operation { |
44 | template <typename ValuesT = void> | |
45 | using interruptible_future = | |
46 | ::crimson::interruptible::interruptible_future< | |
47 | ::crimson::osd::IOInterruptCondition, ValuesT>; | |
48 | using interruptor = | |
49 | ::crimson::interruptible::interruptor< | |
50 | ::crimson::osd::IOInterruptCondition>; | |
9f95a23c | 51 | }; |
9f95a23c TL |
52 | |
53 | template <typename T> | |
20effc67 | 54 | class OperationT : public InterruptibleOperation { |
9f95a23c TL |
55 | public: |
56 | static constexpr const char *type_name = OP_NAMES[static_cast<int>(T::type)]; | |
57 | using IRef = boost::intrusive_ptr<T>; | |
58 | ||
20effc67 TL |
59 | unsigned get_type() const final { |
60 | return static_cast<unsigned>(T::type); | |
9f95a23c TL |
61 | } |
62 | ||
63 | const char *get_type_name() const final { | |
64 | return T::type_name; | |
65 | } | |
66 | ||
67 | virtual ~OperationT() = default; | |
f67539c2 TL |
68 | |
69 | private: | |
70 | virtual void dump_detail(ceph::Formatter *f) const = 0; | |
9f95a23c TL |
71 | }; |
72 | ||
73 | /** | |
74 | * Maintains a set of lists of all active ops. | |
75 | */ | |
20effc67 TL |
76 | using OSDOperationRegistry = OperationRegistryT< |
77 | static_cast<size_t>(OperationTypeCode::last_op) | |
78 | >; | |
f67539c2 TL |
79 | |
80 | /** | |
81 | * Throttles set of currently running operations | |
82 | * | |
83 | * Very primitive currently, assumes all ops are equally | |
84 | * expensive and simply limits the number that can be | |
85 | * concurrently active. | |
86 | */ | |
87 | class OperationThrottler : public Blocker, | |
88 | private md_config_obs_t { | |
89 | public: | |
90 | OperationThrottler(ConfigProxy &conf); | |
91 | ||
92 | const char** get_tracked_conf_keys() const final; | |
93 | void handle_conf_change(const ConfigProxy& conf, | |
94 | const std::set<std::string> &changed) final; | |
95 | void update_from_config(const ConfigProxy &conf); | |
96 | ||
97 | template <typename F> | |
98 | auto with_throttle( | |
99 | OperationRef op, | |
100 | crimson::osd::scheduler::params_t params, | |
101 | F &&f) { | |
102 | if (!max_in_progress) return f(); | |
103 | auto fut = acquire_throttle(params); | |
104 | return op->with_blocking_future(std::move(fut)) | |
105 | .then(std::forward<F>(f)) | |
106 | .then([this](auto x) { | |
107 | release_throttle(); | |
108 | return x; | |
109 | }); | |
110 | } | |
111 | ||
112 | template <typename F> | |
113 | seastar::future<> with_throttle_while( | |
114 | OperationRef op, | |
115 | crimson::osd::scheduler::params_t params, | |
116 | F &&f) { | |
117 | return with_throttle(op, params, f).then([this, params, op, f](bool cont) { | |
118 | if (cont) | |
119 | return with_throttle_while(op, params, f); | |
120 | else | |
121 | return seastar::make_ready_future<>(); | |
122 | }); | |
123 | } | |
124 | ||
125 | private: | |
126 | void dump_detail(Formatter *f) const final; | |
127 | const char *get_type_name() const final { | |
128 | return "OperationThrottler"; | |
129 | } | |
130 | ||
131 | private: | |
132 | crimson::osd::scheduler::SchedulerRef scheduler; | |
133 | ||
134 | uint64_t max_in_progress = 0; | |
135 | uint64_t in_progress = 0; | |
136 | ||
137 | uint64_t pending = 0; | |
138 | ||
139 | void wake(); | |
140 | ||
141 | blocking_future<> acquire_throttle( | |
142 | crimson::osd::scheduler::params_t params); | |
143 | ||
144 | void release_throttle(); | |
9f95a23c TL |
145 | }; |
146 | ||
9f95a23c | 147 | } |