]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/driver/rados/rgw_log_backing.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / driver / rados / rgw_log_backing.h
CommitLineData
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
29namespace bc = boost::container;
30namespace 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.
36enum class log_type {
37 omap = 0,
38 fifo = 1
39};
40
41inline void encode(const log_type& type, ceph::buffer::list& bl) {
42 auto t = static_cast<uint8_t>(type);
43 encode(t, bl);
44}
45
46inline 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
52inline 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}
61inline 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.
73tl::expected<log_type, bs::error_code>
b3b6e05e
TL
74log_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.
84bs::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
93struct 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};
114WRITE_CLASS_ENCODER(logback_generation)
b3b6e05e
TL
115inline 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
120class logback_generations : public librados::WatchCtx2 {
121public:
122 using entries_t = bc::flat_map<uint64_t, logback_generation>;
123
124protected:
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
136private:
137 const std::string oid;
138 const fu2::unique_function<std::string(uint64_t, int) const> get_oid;
139
140protected:
141 const int shards;
142
143private:
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
166public:
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
233inline 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
239inline std::pair<uint64_t, std::string_view>
240cursorgen(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
257class 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
273public:
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};