]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2016 Red Hat Inc. | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #pragma once | |
16 | ||
17 | #include <ostream> | |
18 | ||
19 | #include "include/types.h" | |
20 | #include "include/utime.h" | |
21 | #include "osd/OpRequest.h" | |
22 | #include "osd/PG.h" | |
23 | #include "PGPeeringEvent.h" | |
24 | ||
25 | class OSD; | |
26 | class OSDShard; | |
27 | ||
28 | class OpQueueItem { | |
29 | public: | |
30 | class OrderLocker { | |
31 | public: | |
32 | using Ref = unique_ptr<OrderLocker>; | |
33 | virtual void lock() = 0; | |
34 | virtual void unlock() = 0; | |
35 | virtual ~OrderLocker() {} | |
36 | }; | |
37 | // Abstraction for operations queueable in the op queue | |
38 | class OpQueueable { | |
39 | public: | |
40 | enum class op_type_t { | |
41 | client_op, | |
42 | peering_event, | |
43 | bg_snaptrim, | |
44 | bg_recovery, | |
45 | bg_scrub, | |
46 | bg_pg_delete | |
47 | }; | |
48 | using Ref = std::unique_ptr<OpQueueable>; | |
49 | ||
50 | /// Items with the same queue token will end up in the same shard | |
51 | virtual uint32_t get_queue_token() const = 0; | |
52 | ||
53 | /* Items will be dequeued and locked atomically w.r.t. other items with the | |
54 | * same ordering token */ | |
55 | virtual const spg_t& get_ordering_token() const = 0; | |
56 | virtual OrderLocker::Ref get_order_locker(PGRef pg) = 0; | |
57 | virtual op_type_t get_op_type() const = 0; | |
58 | virtual boost::optional<OpRequestRef> maybe_get_op() const { | |
59 | return boost::none; | |
60 | } | |
61 | ||
62 | virtual uint64_t get_reserved_pushes() const { | |
63 | return 0; | |
64 | } | |
65 | ||
66 | virtual bool is_peering() const { | |
67 | return false; | |
68 | } | |
69 | virtual bool peering_requires_pg() const { | |
70 | ceph_abort(); | |
71 | } | |
72 | virtual const PGCreateInfo *creates_pg() const { | |
73 | return nullptr; | |
74 | } | |
75 | ||
76 | virtual ostream &print(ostream &rhs) const = 0; | |
77 | ||
78 | virtual void run(OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) = 0; | |
79 | virtual ~OpQueueable() {} | |
80 | friend ostream& operator<<(ostream& out, const OpQueueable& q) { | |
81 | return q.print(out); | |
82 | } | |
83 | ||
84 | }; | |
85 | ||
86 | private: | |
87 | OpQueueable::Ref qitem; | |
88 | int cost; | |
89 | unsigned priority; | |
90 | utime_t start_time; | |
91 | uint64_t owner; ///< global id (e.g., client.XXX) | |
92 | epoch_t map_epoch; ///< an epoch we expect the PG to exist in | |
93 | ||
94 | public: | |
95 | OpQueueItem( | |
96 | OpQueueable::Ref &&item, | |
97 | int cost, | |
98 | unsigned priority, | |
99 | utime_t start_time, | |
100 | uint64_t owner, | |
101 | epoch_t e) | |
102 | : qitem(std::move(item)), | |
103 | cost(cost), | |
104 | priority(priority), | |
105 | start_time(start_time), | |
106 | owner(owner), | |
107 | map_epoch(e) | |
108 | {} | |
109 | OpQueueItem(OpQueueItem &&) = default; | |
110 | OpQueueItem(const OpQueueItem &) = delete; | |
111 | OpQueueItem &operator=(OpQueueItem &&) = default; | |
112 | OpQueueItem &operator=(const OpQueueItem &) = delete; | |
113 | ||
114 | OrderLocker::Ref get_order_locker(PGRef pg) { | |
115 | return qitem->get_order_locker(pg); | |
116 | } | |
117 | uint32_t get_queue_token() const { | |
118 | return qitem->get_queue_token(); | |
119 | } | |
120 | const spg_t& get_ordering_token() const { | |
121 | return qitem->get_ordering_token(); | |
122 | } | |
123 | using op_type_t = OpQueueable::op_type_t; | |
124 | OpQueueable::op_type_t get_op_type() const { | |
125 | return qitem->get_op_type(); | |
126 | } | |
127 | boost::optional<OpRequestRef> maybe_get_op() const { | |
128 | return qitem->maybe_get_op(); | |
129 | } | |
130 | uint64_t get_reserved_pushes() const { | |
131 | return qitem->get_reserved_pushes(); | |
132 | } | |
133 | void run(OSD *osd, OSDShard *sdata,PGRef& pg, ThreadPool::TPHandle &handle) { | |
134 | qitem->run(osd, sdata, pg, handle); | |
135 | } | |
136 | unsigned get_priority() const { return priority; } | |
137 | int get_cost() const { return cost; } | |
138 | utime_t get_start_time() const { return start_time; } | |
139 | uint64_t get_owner() const { return owner; } | |
140 | epoch_t get_map_epoch() const { return map_epoch; } | |
141 | ||
142 | bool is_peering() const { | |
143 | return qitem->is_peering(); | |
144 | } | |
145 | ||
146 | const PGCreateInfo *creates_pg() const { | |
147 | return qitem->creates_pg(); | |
148 | } | |
149 | ||
150 | bool peering_requires_pg() const { | |
151 | return qitem->peering_requires_pg(); | |
152 | } | |
153 | ||
154 | friend ostream& operator<<(ostream& out, const OpQueueItem& item) { | |
155 | out << "OpQueueItem(" | |
156 | << item.get_ordering_token() << " " << *item.qitem | |
157 | << " prio " << item.get_priority() | |
158 | << " cost " << item.get_cost() | |
159 | << " e" << item.get_map_epoch(); | |
160 | if (item.get_reserved_pushes()) { | |
161 | out << " reserved_pushes " << item.get_reserved_pushes(); | |
162 | } | |
163 | return out << ")"; | |
164 | } | |
165 | }; // class OpQueueItem | |
166 | ||
167 | /// Implements boilerplate for operations queued for the pg lock | |
168 | class PGOpQueueable : public OpQueueItem::OpQueueable { | |
169 | spg_t pgid; | |
170 | protected: | |
171 | const spg_t& get_pgid() const { | |
172 | return pgid; | |
173 | } | |
174 | public: | |
175 | explicit PGOpQueueable(spg_t pg) : pgid(pg) {} | |
176 | uint32_t get_queue_token() const override final { | |
177 | return get_pgid().ps(); | |
178 | } | |
179 | ||
180 | const spg_t& get_ordering_token() const override final { | |
181 | return get_pgid(); | |
182 | } | |
183 | ||
184 | OpQueueItem::OrderLocker::Ref get_order_locker(PGRef pg) override final { | |
185 | class Locker : public OpQueueItem::OrderLocker { | |
186 | PGRef pg; | |
187 | public: | |
188 | explicit Locker(PGRef pg) : pg(pg) {} | |
189 | void lock() override final { | |
190 | pg->lock(); | |
191 | } | |
192 | void unlock() override final { | |
193 | pg->unlock(); | |
194 | } | |
195 | }; | |
196 | return OpQueueItem::OrderLocker::Ref( | |
197 | new Locker(pg)); | |
198 | } | |
199 | }; | |
200 | ||
201 | class PGOpItem : public PGOpQueueable { | |
202 | OpRequestRef op; | |
203 | public: | |
204 | PGOpItem(spg_t pg, OpRequestRef op) : PGOpQueueable(pg), op(std::move(op)) {} | |
205 | op_type_t get_op_type() const override final { | |
206 | return op_type_t::client_op; | |
207 | } | |
208 | ostream &print(ostream &rhs) const override final { | |
209 | return rhs << "PGOpItem(op=" << *(op->get_req()) << ")"; | |
210 | } | |
211 | boost::optional<OpRequestRef> maybe_get_op() const override final { | |
212 | return op; | |
213 | } | |
214 | void run(OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
215 | }; | |
216 | ||
217 | class PGPeeringItem : public PGOpQueueable { | |
218 | PGPeeringEventRef evt; | |
219 | public: | |
220 | PGPeeringItem(spg_t pg, PGPeeringEventRef e) : PGOpQueueable(pg), evt(e) {} | |
221 | op_type_t get_op_type() const override final { | |
222 | return op_type_t::peering_event; | |
223 | } | |
224 | ostream &print(ostream &rhs) const override final { | |
225 | return rhs << "PGPeeringEvent(" << evt->get_desc() << ")"; | |
226 | } | |
227 | void run(OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
228 | bool is_peering() const override { | |
229 | return true; | |
230 | } | |
231 | bool peering_requires_pg() const override { | |
232 | return evt->requires_pg; | |
233 | } | |
234 | const PGCreateInfo *creates_pg() const override { | |
235 | return evt->create_info.get(); | |
236 | } | |
237 | }; | |
238 | ||
239 | class PGSnapTrim : public PGOpQueueable { | |
240 | epoch_t epoch_queued; | |
241 | public: | |
242 | PGSnapTrim( | |
243 | spg_t pg, | |
244 | epoch_t epoch_queued) | |
245 | : PGOpQueueable(pg), epoch_queued(epoch_queued) {} | |
246 | op_type_t get_op_type() const override final { | |
247 | return op_type_t::bg_snaptrim; | |
248 | } | |
249 | ostream &print(ostream &rhs) const override final { | |
250 | return rhs << "PGSnapTrim(pgid=" << get_pgid() | |
251 | << "epoch_queued=" << epoch_queued | |
252 | << ")"; | |
253 | } | |
254 | void run( | |
255 | OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
256 | }; | |
257 | ||
258 | class PGScrub : public PGOpQueueable { | |
259 | epoch_t epoch_queued; | |
260 | public: | |
261 | PGScrub( | |
262 | spg_t pg, | |
263 | epoch_t epoch_queued) | |
264 | : PGOpQueueable(pg), epoch_queued(epoch_queued) {} | |
265 | op_type_t get_op_type() const override final { | |
266 | return op_type_t::bg_scrub; | |
267 | } | |
268 | ostream &print(ostream &rhs) const override final { | |
269 | return rhs << "PGScrub(pgid=" << get_pgid() | |
270 | << "epoch_queued=" << epoch_queued | |
271 | << ")"; | |
272 | } | |
273 | void run( | |
274 | OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
275 | }; | |
276 | ||
277 | class PGRecovery : public PGOpQueueable { | |
278 | epoch_t epoch_queued; | |
279 | uint64_t reserved_pushes; | |
280 | public: | |
281 | PGRecovery( | |
282 | spg_t pg, | |
283 | epoch_t epoch_queued, | |
284 | uint64_t reserved_pushes) | |
285 | : PGOpQueueable(pg), | |
286 | epoch_queued(epoch_queued), | |
287 | reserved_pushes(reserved_pushes) {} | |
288 | op_type_t get_op_type() const override final { | |
289 | return op_type_t::bg_recovery; | |
290 | } | |
291 | virtual ostream &print(ostream &rhs) const override final { | |
292 | return rhs << "PGRecovery(pgid=" << get_pgid() | |
293 | << "epoch_queued=" << epoch_queued | |
294 | << "reserved_pushes=" << reserved_pushes | |
295 | << ")"; | |
296 | } | |
297 | virtual uint64_t get_reserved_pushes() const override final { | |
298 | return reserved_pushes; | |
299 | } | |
300 | virtual void run( | |
301 | OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
302 | }; | |
303 | ||
304 | class PGRecoveryContext : public PGOpQueueable { | |
305 | unique_ptr<GenContext<ThreadPool::TPHandle&>> c; | |
306 | epoch_t epoch; | |
307 | public: | |
308 | PGRecoveryContext(spg_t pgid, | |
309 | GenContext<ThreadPool::TPHandle&> *c, epoch_t epoch) | |
310 | : PGOpQueueable(pgid), | |
311 | c(c), epoch(epoch) {} | |
312 | op_type_t get_op_type() const override final { | |
313 | return op_type_t::bg_recovery; | |
314 | } | |
315 | ostream &print(ostream &rhs) const override final { | |
316 | return rhs << "PGRecoveryContext(pgid=" << get_pgid() | |
317 | << " c=" << c.get() << " epoch=" << epoch | |
318 | << ")"; | |
319 | } | |
320 | void run( | |
321 | OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
322 | }; | |
323 | ||
324 | class PGDelete : public PGOpQueueable { | |
325 | epoch_t epoch_queued; | |
326 | public: | |
327 | PGDelete( | |
328 | spg_t pg, | |
329 | epoch_t epoch_queued) | |
330 | : PGOpQueueable(pg), | |
331 | epoch_queued(epoch_queued) {} | |
332 | op_type_t get_op_type() const override final { | |
333 | return op_type_t::bg_pg_delete; | |
334 | } | |
335 | ostream &print(ostream &rhs) const override final { | |
336 | return rhs << "PGDelete(" << get_pgid() | |
337 | << " e" << epoch_queued | |
338 | << ")"; | |
339 | } | |
340 | void run( | |
341 | OSD *osd, OSDShard *sdata, PGRef& pg, ThreadPool::TPHandle &handle) override final; | |
342 | }; |