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