]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab ft=cpp | |
3 | ||
1e59de90 | 4 | #pragma once |
f67539c2 TL |
5 | |
6 | #include <optional> | |
7 | #include <iostream> | |
8 | #include <string> | |
9 | #include <string_view> | |
10 | ||
11 | #include <strings.h> | |
12 | ||
13 | #include <boost/container/flat_map.hpp> | |
14 | #include <boost/system/error_code.hpp> | |
15 | ||
f67539c2 TL |
16 | #include <fmt/format.h> |
17 | ||
18 | #include "include/rados/librados.hpp" | |
19 | #include "include/encoding.h" | |
20 | #include "include/expected.hpp" | |
21 | #include "include/function2.hpp" | |
22 | ||
23 | #include "cls/version/cls_version_types.h" | |
24 | ||
25 | #include "common/async/yield_context.h" | |
26 | #include "common/Formatter.h" | |
27 | #include "common/strtol.h" | |
28 | ||
29 | namespace bc = boost::container; | |
30 | namespace bs = boost::system; | |
31 | ||
32 | #include "cls_fifo_legacy.h" | |
33 | ||
34 | /// Type of log backing, stored in the mark used in the quick check, | |
35 | /// and passed to checking functions. | |
36 | enum class log_type { | |
37 | omap = 0, | |
38 | fifo = 1 | |
39 | }; | |
40 | ||
41 | inline void encode(const log_type& type, ceph::buffer::list& bl) { | |
42 | auto t = static_cast<uint8_t>(type); | |
43 | encode(t, bl); | |
44 | } | |
45 | ||
46 | inline void decode(log_type& type, bufferlist::const_iterator& bl) { | |
47 | uint8_t t; | |
48 | decode(t, bl); | |
49 | type = static_cast<log_type>(t); | |
50 | } | |
51 | ||
52 | inline std::optional<log_type> to_log_type(std::string_view s) { | |
53 | if (strncasecmp(s.data(), "omap", s.length()) == 0) { | |
54 | return log_type::omap; | |
55 | } else if (strncasecmp(s.data(), "fifo", s.length()) == 0) { | |
56 | return log_type::fifo; | |
57 | } else { | |
58 | return std::nullopt; | |
59 | } | |
60 | } | |
61 | inline std::ostream& operator <<(std::ostream& m, const log_type& t) { | |
62 | switch (t) { | |
63 | case log_type::omap: | |
64 | return m << "log_type::omap"; | |
65 | case log_type::fifo: | |
66 | return m << "log_type::fifo"; | |
67 | } | |
68 | ||
69 | return m << "log_type::UNKNOWN=" << static_cast<uint32_t>(t); | |
70 | } | |
71 | ||
72 | /// Look over the shards in a log and determine the type. | |
73 | tl::expected<log_type, bs::error_code> | |
b3b6e05e TL |
74 | log_backing_type(const DoutPrefixProvider *dpp, |
75 | librados::IoCtx& ioctx, | |
f67539c2 TL |
76 | log_type def, |
77 | int shards, //< Total number of shards | |
78 | /// A function taking a shard number and | |
79 | /// returning an oid. | |
80 | const fu2::unique_function<std::string(int) const>& get_oid, | |
81 | optional_yield y); | |
82 | ||
83 | /// Remove all log shards and associated parts of fifos. | |
84 | bs::error_code log_remove(librados::IoCtx& ioctx, | |
85 | int shards, //< Total number of shards | |
86 | /// A function taking a shard number and | |
87 | /// returning an oid. | |
88 | const fu2::unique_function<std::string(int) const>& get_oid, | |
89 | bool leave_zero, | |
90 | optional_yield y); | |
91 | ||
92 | ||
93 | struct logback_generation { | |
94 | uint64_t gen_id = 0; | |
95 | log_type type; | |
96 | std::optional<ceph::real_time> pruned; | |
97 | ||
98 | void encode(ceph::buffer::list& bl) const { | |
99 | ENCODE_START(1, 1, bl); | |
100 | encode(gen_id, bl); | |
101 | encode(type, bl); | |
102 | encode(pruned, bl); | |
103 | ENCODE_FINISH(bl); | |
104 | } | |
105 | ||
106 | void decode(bufferlist::const_iterator& bl) { | |
107 | DECODE_START(1, bl); | |
108 | decode(gen_id, bl); | |
109 | decode(type, bl); | |
110 | decode(pruned, bl); | |
111 | DECODE_FINISH(bl); | |
112 | } | |
113 | }; | |
114 | WRITE_CLASS_ENCODER(logback_generation) | |
b3b6e05e TL |
115 | inline std::ostream& operator <<(std::ostream& m, const logback_generation& g) { |
116 | return m << "[" << g.gen_id << "," << g.type << "," | |
117 | << (g.pruned ? "PRUNED" : "NOT PRUNED") << "]"; | |
118 | } | |
f67539c2 TL |
119 | |
120 | class logback_generations : public librados::WatchCtx2 { | |
121 | public: | |
122 | using entries_t = bc::flat_map<uint64_t, logback_generation>; | |
123 | ||
124 | protected: | |
125 | librados::IoCtx& ioctx; | |
126 | logback_generations(librados::IoCtx& ioctx, | |
127 | std::string oid, | |
128 | fu2::unique_function<std::string( | |
129 | uint64_t, int) const>&& get_oid, | |
130 | int shards) noexcept | |
131 | : ioctx(ioctx), oid(oid), get_oid(std::move(get_oid)), | |
132 | shards(shards) {} | |
133 | ||
134 | uint64_t my_id = ioctx.get_instance_id(); | |
135 | ||
136 | private: | |
137 | const std::string oid; | |
138 | const fu2::unique_function<std::string(uint64_t, int) const> get_oid; | |
139 | ||
140 | protected: | |
141 | const int shards; | |
142 | ||
143 | private: | |
144 | ||
145 | uint64_t watchcookie = 0; | |
146 | ||
147 | obj_version version; | |
148 | std::mutex m; | |
149 | entries_t entries_; | |
150 | ||
151 | tl::expected<std::pair<entries_t, obj_version>, bs::error_code> | |
b3b6e05e TL |
152 | read(const DoutPrefixProvider *dpp, optional_yield y) noexcept; |
153 | bs::error_code write(const DoutPrefixProvider *dpp, entries_t&& e, std::unique_lock<std::mutex>&& l_, | |
f67539c2 | 154 | optional_yield y) noexcept; |
b3b6e05e | 155 | bs::error_code setup(const DoutPrefixProvider *dpp, log_type def, optional_yield y) noexcept; |
f67539c2 TL |
156 | |
157 | bs::error_code watch() noexcept; | |
158 | ||
159 | auto lowest_nomempty(const entries_t& es) { | |
160 | return std::find_if(es.begin(), es.end(), | |
161 | [](const auto& e) { | |
162 | return !e.second.pruned; | |
163 | }); | |
164 | } | |
165 | ||
166 | public: | |
167 | ||
168 | /// For the use of watch/notify. | |
169 | ||
170 | void handle_notify(uint64_t notify_id, | |
171 | uint64_t cookie, | |
172 | uint64_t notifier_id, | |
173 | bufferlist& bl) override final; | |
174 | ||
175 | void handle_error(uint64_t cookie, int err) override final; | |
176 | ||
177 | /// Public interface | |
178 | ||
179 | virtual ~logback_generations(); | |
180 | ||
181 | template<typename T, typename... Args> | |
182 | static tl::expected<std::unique_ptr<T>, bs::error_code> | |
b3b6e05e | 183 | init(const DoutPrefixProvider *dpp, librados::IoCtx& ioctx_, std::string oid_, |
f67539c2 TL |
184 | fu2::unique_function<std::string(uint64_t, int) const>&& get_oid_, |
185 | int shards_, log_type def, optional_yield y, | |
186 | Args&& ...args) noexcept { | |
187 | try { | |
188 | T* lgp = new T(ioctx_, std::move(oid_), | |
189 | std::move(get_oid_), | |
190 | shards_, std::forward<Args>(args)...); | |
191 | std::unique_ptr<T> lg(lgp); | |
192 | lgp = nullptr; | |
b3b6e05e | 193 | auto ec = lg->setup(dpp, def, y); |
f67539c2 TL |
194 | if (ec) |
195 | return tl::unexpected(ec); | |
196 | // Obnoxiousness for C++ Compiler in Bionic Beaver | |
197 | return tl::expected<std::unique_ptr<T>, bs::error_code>(std::move(lg)); | |
198 | } catch (const std::bad_alloc&) { | |
199 | return tl::unexpected(bs::error_code(ENOMEM, bs::system_category())); | |
200 | } | |
201 | } | |
202 | ||
b3b6e05e | 203 | bs::error_code update(const DoutPrefixProvider *dpp, optional_yield y) noexcept; |
f67539c2 TL |
204 | |
205 | entries_t entries() const { | |
206 | return entries_; | |
207 | } | |
208 | ||
b3b6e05e | 209 | bs::error_code new_backing(const DoutPrefixProvider *dpp, log_type type, optional_yield y) noexcept; |
f67539c2 | 210 | |
b3b6e05e | 211 | bs::error_code empty_to(const DoutPrefixProvider *dpp, uint64_t gen_id, optional_yield y) noexcept; |
f67539c2 | 212 | |
b3b6e05e | 213 | bs::error_code remove_empty(const DoutPrefixProvider *dpp, optional_yield y) noexcept; |
f67539c2 TL |
214 | |
215 | // Callbacks, to be defined by descendant. | |
216 | ||
217 | /// Handle initialization on startup | |
218 | /// | |
219 | /// @param e All non-empty generations | |
220 | virtual bs::error_code handle_init(entries_t e) noexcept = 0; | |
221 | ||
222 | /// Handle new generations. | |
223 | /// | |
224 | /// @param e Map of generations added since last update | |
225 | virtual bs::error_code handle_new_gens(entries_t e) noexcept = 0; | |
226 | ||
227 | /// Handle generations being marked empty | |
228 | /// | |
229 | /// @param new_tail Lowest non-empty generation | |
230 | virtual bs::error_code handle_empty_to(uint64_t new_tail) noexcept = 0; | |
231 | }; | |
232 | ||
233 | inline std::string gencursor(uint64_t gen_id, std::string_view cursor) { | |
234 | return (gen_id > 0 ? | |
235 | fmt::format("G{:0>20}@{}", gen_id, cursor) : | |
236 | std::string(cursor)); | |
237 | } | |
238 | ||
239 | inline std::pair<uint64_t, std::string_view> | |
240 | cursorgen(std::string_view cursor_) { | |
522d829b | 241 | if (cursor_.empty()) { |
20effc67 | 242 | return { 0, "" }; |
522d829b | 243 | } |
f67539c2 TL |
244 | std::string_view cursor = cursor_; |
245 | if (cursor[0] != 'G') { | |
246 | return { 0, cursor }; | |
247 | } | |
248 | cursor.remove_prefix(1); | |
249 | auto gen_id = ceph::consume<uint64_t>(cursor); | |
250 | if (!gen_id || cursor[0] != '@') { | |
251 | return { 0, cursor_ }; | |
252 | } | |
253 | cursor.remove_prefix(1); | |
254 | return { *gen_id, cursor }; | |
255 | } | |
256 | ||
f67539c2 TL |
257 | class LazyFIFO { |
258 | librados::IoCtx& ioctx; | |
259 | std::string oid; | |
260 | std::mutex m; | |
261 | std::unique_ptr<rgw::cls::fifo::FIFO> fifo; | |
262 | ||
b3b6e05e | 263 | int lazy_init(const DoutPrefixProvider *dpp, optional_yield y) { |
f67539c2 TL |
264 | std::unique_lock l(m); |
265 | if (fifo) return 0; | |
b3b6e05e | 266 | auto r = rgw::cls::fifo::FIFO::create(dpp, ioctx, oid, &fifo, y); |
f67539c2 TL |
267 | if (r) { |
268 | fifo.reset(); | |
269 | } | |
270 | return r; | |
271 | } | |
272 | ||
273 | public: | |
274 | ||
275 | LazyFIFO(librados::IoCtx& ioctx, std::string oid) | |
276 | : ioctx(ioctx), oid(std::move(oid)) {} | |
277 | ||
b3b6e05e TL |
278 | int read_meta(const DoutPrefixProvider *dpp, optional_yield y) { |
279 | auto r = lazy_init(dpp, y); | |
f67539c2 | 280 | if (r < 0) return r; |
b3b6e05e | 281 | return fifo->read_meta(dpp, y); |
f67539c2 TL |
282 | } |
283 | ||
b3b6e05e TL |
284 | int meta(const DoutPrefixProvider *dpp, rados::cls::fifo::info& info, optional_yield y) { |
285 | auto r = lazy_init(dpp, y); | |
f67539c2 TL |
286 | if (r < 0) return r; |
287 | info = fifo->meta(); | |
288 | return 0; | |
289 | } | |
290 | ||
b3b6e05e TL |
291 | int get_part_layout_info(const DoutPrefixProvider *dpp, |
292 | std::uint32_t& part_header_size, | |
f67539c2 TL |
293 | std::uint32_t& part_entry_overhead, |
294 | optional_yield y) { | |
b3b6e05e | 295 | auto r = lazy_init(dpp, y); |
f67539c2 TL |
296 | if (r < 0) return r; |
297 | std::tie(part_header_size, part_entry_overhead) | |
298 | = fifo->get_part_layout_info(); | |
299 | return 0; | |
300 | } | |
301 | ||
b3b6e05e TL |
302 | int push(const DoutPrefixProvider *dpp, |
303 | const ceph::buffer::list& bl, | |
f67539c2 | 304 | optional_yield y) { |
b3b6e05e | 305 | auto r = lazy_init(dpp, y); |
f67539c2 | 306 | if (r < 0) return r; |
b3b6e05e | 307 | return fifo->push(dpp, bl, y); |
f67539c2 TL |
308 | } |
309 | ||
b3b6e05e TL |
310 | int push(const DoutPrefixProvider *dpp, |
311 | ceph::buffer::list& bl, | |
f67539c2 TL |
312 | librados::AioCompletion* c, |
313 | optional_yield y) { | |
b3b6e05e | 314 | auto r = lazy_init(dpp, y); |
f67539c2 | 315 | if (r < 0) return r; |
b3b6e05e | 316 | fifo->push(dpp, bl, c); |
f67539c2 TL |
317 | return 0; |
318 | } | |
319 | ||
b3b6e05e TL |
320 | int push(const DoutPrefixProvider *dpp, |
321 | const std::vector<ceph::buffer::list>& data_bufs, | |
f67539c2 | 322 | optional_yield y) { |
b3b6e05e | 323 | auto r = lazy_init(dpp, y); |
f67539c2 | 324 | if (r < 0) return r; |
b3b6e05e | 325 | return fifo->push(dpp, data_bufs, y); |
f67539c2 TL |
326 | } |
327 | ||
b3b6e05e TL |
328 | int push(const DoutPrefixProvider *dpp, |
329 | const std::vector<ceph::buffer::list>& data_bufs, | |
f67539c2 TL |
330 | librados::AioCompletion* c, |
331 | optional_yield y) { | |
b3b6e05e | 332 | auto r = lazy_init(dpp, y); |
f67539c2 | 333 | if (r < 0) return r; |
b3b6e05e | 334 | fifo->push(dpp, data_bufs, c); |
f67539c2 TL |
335 | return 0; |
336 | } | |
337 | ||
b3b6e05e TL |
338 | int list(const DoutPrefixProvider *dpp, |
339 | int max_entries, std::optional<std::string_view> markstr, | |
f67539c2 TL |
340 | std::vector<rgw::cls::fifo::list_entry>* out, |
341 | bool* more, optional_yield y) { | |
b3b6e05e | 342 | auto r = lazy_init(dpp, y); |
f67539c2 | 343 | if (r < 0) return r; |
b3b6e05e | 344 | return fifo->list(dpp, max_entries, markstr, out, more, y); |
f67539c2 TL |
345 | } |
346 | ||
b3b6e05e | 347 | int list(const DoutPrefixProvider *dpp, int max_entries, std::optional<std::string_view> markstr, |
f67539c2 TL |
348 | std::vector<rgw::cls::fifo::list_entry>* out, bool* more, |
349 | librados::AioCompletion* c, optional_yield y) { | |
b3b6e05e | 350 | auto r = lazy_init(dpp, y); |
f67539c2 | 351 | if (r < 0) return r; |
b3b6e05e | 352 | fifo->list(dpp, max_entries, markstr, out, more, c); |
f67539c2 TL |
353 | return 0; |
354 | } | |
355 | ||
b3b6e05e TL |
356 | int trim(const DoutPrefixProvider *dpp, std::string_view markstr, bool exclusive, optional_yield y) { |
357 | auto r = lazy_init(dpp, y); | |
f67539c2 | 358 | if (r < 0) return r; |
b3b6e05e | 359 | return fifo->trim(dpp, markstr, exclusive, y); |
f67539c2 TL |
360 | } |
361 | ||
b3b6e05e | 362 | int trim(const DoutPrefixProvider *dpp, std::string_view markstr, bool exclusive, librados::AioCompletion* c, |
f67539c2 | 363 | optional_yield y) { |
b3b6e05e | 364 | auto r = lazy_init(dpp, y); |
f67539c2 | 365 | if (r < 0) return r; |
b3b6e05e | 366 | fifo->trim(dpp, markstr, exclusive, c); |
f67539c2 TL |
367 | return 0; |
368 | } | |
369 | ||
b3b6e05e | 370 | int get_part_info(const DoutPrefixProvider *dpp, int64_t part_num, rados::cls::fifo::part_header* header, |
f67539c2 | 371 | optional_yield y) { |
b3b6e05e | 372 | auto r = lazy_init(dpp, y); |
f67539c2 | 373 | if (r < 0) return r; |
b3b6e05e | 374 | return fifo->get_part_info(dpp, part_num, header, y); |
f67539c2 TL |
375 | } |
376 | ||
b3b6e05e | 377 | int get_part_info(const DoutPrefixProvider *dpp, int64_t part_num, rados::cls::fifo::part_header* header, |
f67539c2 | 378 | librados::AioCompletion* c, optional_yield y) { |
b3b6e05e | 379 | auto r = lazy_init(dpp, y); |
f67539c2 TL |
380 | if (r < 0) return r; |
381 | fifo->get_part_info(part_num, header, c); | |
382 | return 0; | |
383 | } | |
384 | ||
b3b6e05e | 385 | int get_head_info(const DoutPrefixProvider *dpp, fu2::unique_function< |
f67539c2 TL |
386 | void(int r, rados::cls::fifo::part_header&&)>&& f, |
387 | librados::AioCompletion* c, | |
388 | optional_yield y) { | |
b3b6e05e | 389 | auto r = lazy_init(dpp, y); |
f67539c2 | 390 | if (r < 0) return r; |
b3b6e05e | 391 | fifo->get_head_info(dpp, std::move(f), c); |
f67539c2 TL |
392 | return 0; |
393 | } | |
394 | }; |