]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/driver/rados/rgw_log_backing.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / driver / rados / rgw_log_backing.cc
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
4#include "cls/log/cls_log_client.h"
5#include "cls/version/cls_version_client.h"
6
7#include "rgw_log_backing.h"
8#include "rgw_tools.h"
9#include "cls_fifo_legacy.h"
10
20effc67 11using namespace std::chrono_literals;
f67539c2
TL
12namespace cb = ceph::buffer;
13
14static constexpr auto dout_subsys = ceph_subsys_rgw;
15
16enum class shard_check { dne, omap, fifo, corrupt };
17inline std::ostream& operator <<(std::ostream& m, const shard_check& t) {
18 switch (t) {
19 case shard_check::dne:
20 return m << "shard_check::dne";
21 case shard_check::omap:
22 return m << "shard_check::omap";
23 case shard_check::fifo:
24 return m << "shard_check::fifo";
25 case shard_check::corrupt:
26 return m << "shard_check::corrupt";
27 }
28
29 return m << "shard_check::UNKNOWN=" << static_cast<uint32_t>(t);
30}
31
32namespace {
33/// Return the shard type, and a bool to see whether it has entries.
b3b6e05e
TL
34shard_check
35probe_shard(const DoutPrefixProvider *dpp, librados::IoCtx& ioctx, const std::string& oid,
f67539c2
TL
36 bool& fifo_unsupported, optional_yield y)
37{
b3b6e05e
TL
38 ldpp_dout(dpp, 20) << __PRETTY_FUNCTION__ << ":" << __LINE__
39 << " probing oid=" << oid
40 << dendl;
f67539c2
TL
41 if (!fifo_unsupported) {
42 std::unique_ptr<rgw::cls::fifo::FIFO> fifo;
b3b6e05e 43 auto r = rgw::cls::fifo::FIFO::open(dpp, ioctx, oid,
f67539c2
TL
44 &fifo, y,
45 std::nullopt, true);
b3b6e05e
TL
46 switch (r) {
47 case 0:
48 ldpp_dout(dpp, 20) << __PRETTY_FUNCTION__ << ":" << __LINE__
49 << ": oid=" << oid << " is FIFO"
50 << dendl;
51 return shard_check::fifo;
52
53 case -ENODATA:
54 ldpp_dout(dpp, 20) << __PRETTY_FUNCTION__ << ":" << __LINE__
55 << ": oid=" << oid << " is empty and therefore OMAP"
56 << dendl;
57 return shard_check::omap;
58
59 case -ENOENT:
60 ldpp_dout(dpp, 20) << __PRETTY_FUNCTION__ << ":" << __LINE__
61 << ": oid=" << oid << " does not exist"
62 << dendl;
63 return shard_check::dne;
64
65 case -EPERM:
66 ldpp_dout(dpp, 20) << __PRETTY_FUNCTION__ << ":" << __LINE__
67 << ": FIFO is unsupported, marking."
68 << dendl;
f67539c2 69 fifo_unsupported = true;
b3b6e05e
TL
70 return shard_check::omap;
71
72 default:
73 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
74 << ": error probing: r=" << r
75 << ", oid=" << oid << dendl;
76 return shard_check::corrupt;
f67539c2 77 }
b3b6e05e
TL
78 } else {
79 // Since FIFO is unsupported, OMAP is the only alternative
80 return shard_check::omap;
f67539c2 81 }
f67539c2
TL
82}
83
84tl::expected<log_type, bs::error_code>
b3b6e05e 85handle_dne(const DoutPrefixProvider *dpp, librados::IoCtx& ioctx,
f67539c2
TL
86 log_type def,
87 std::string oid,
88 bool fifo_unsupported,
89 optional_yield y)
90{
f67539c2
TL
91 if (def == log_type::fifo) {
92 if (fifo_unsupported) {
b3b6e05e 93 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
94 << " WARNING: FIFO set as default but not supported by OSD. "
95 << "Falling back to OMAP." << dendl;
96 return log_type::omap;
97 }
98 std::unique_ptr<rgw::cls::fifo::FIFO> fifo;
b3b6e05e 99 auto r = rgw::cls::fifo::FIFO::create(dpp, ioctx, oid,
f67539c2
TL
100 &fifo, y,
101 std::nullopt);
102 if (r < 0) {
b3b6e05e 103 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
104 << " error creating FIFO: r=" << r
105 << ", oid=" << oid << dendl;
106 return tl::unexpected(bs::error_code(-r, bs::system_category()));
107 }
108 }
109 return def;
110}
111}
112
113tl::expected<log_type, bs::error_code>
b3b6e05e
TL
114log_backing_type(const DoutPrefixProvider *dpp,
115 librados::IoCtx& ioctx,
f67539c2
TL
116 log_type def,
117 int shards,
118 const fu2::unique_function<std::string(int) const>& get_oid,
119 optional_yield y)
120{
f67539c2
TL
121 auto check = shard_check::dne;
122 bool fifo_unsupported = false;
123 for (int i = 0; i < shards; ++i) {
b3b6e05e 124 auto c = probe_shard(dpp, ioctx, get_oid(i), fifo_unsupported, y);
f67539c2
TL
125 if (c == shard_check::corrupt)
126 return tl::unexpected(bs::error_code(EIO, bs::system_category()));
127 if (c == shard_check::dne) continue;
128 if (check == shard_check::dne) {
129 check = c;
130 continue;
131 }
132
133 if (check != c) {
b3b6e05e 134 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
135 << " clashing types: check=" << check
136 << ", c=" << c << dendl;
137 return tl::unexpected(bs::error_code(EIO, bs::system_category()));
138 }
139 }
140 if (check == shard_check::corrupt) {
b3b6e05e 141 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
142 << " should be unreachable!" << dendl;
143 return tl::unexpected(bs::error_code(EIO, bs::system_category()));
144 }
145
146 if (check == shard_check::dne)
b3b6e05e 147 return handle_dne(dpp, ioctx,
f67539c2
TL
148 def,
149 get_oid(0),
150 fifo_unsupported,
151 y);
152
153 return (check == shard_check::fifo ? log_type::fifo : log_type::omap);
154}
155
b3b6e05e
TL
156bs::error_code log_remove(const DoutPrefixProvider *dpp,
157 librados::IoCtx& ioctx,
f67539c2
TL
158 int shards,
159 const fu2::unique_function<std::string(int) const>& get_oid,
160 bool leave_zero,
161 optional_yield y)
162{
163 bs::error_code ec;
f67539c2
TL
164 for (int i = 0; i < shards; ++i) {
165 auto oid = get_oid(i);
166 rados::cls::fifo::info info;
167 uint32_t part_header_size = 0, part_entry_overhead = 0;
168
20effc67 169 auto r = rgw::cls::fifo::get_meta(dpp, ioctx, oid, std::nullopt, &info,
f67539c2
TL
170 &part_header_size, &part_entry_overhead,
171 0, y, true);
172 if (r == -ENOENT) continue;
173 if (r == 0 && info.head_part_num > -1) {
174 for (auto j = info.tail_part_num; j <= info.head_part_num; ++j) {
175 librados::ObjectWriteOperation op;
176 op.remove();
177 auto part_oid = info.part_oid(j);
b3b6e05e 178 auto subr = rgw_rados_operate(dpp, ioctx, part_oid, &op, null_yield);
f67539c2
TL
179 if (subr < 0 && subr != -ENOENT) {
180 if (!ec)
181 ec = bs::error_code(-subr, bs::system_category());
b3b6e05e 182 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
183 << ": failed removing FIFO part: part_oid=" << part_oid
184 << ", subr=" << subr << dendl;
185 }
186 }
187 }
188 if (r < 0 && r != -ENODATA) {
189 if (!ec)
190 ec = bs::error_code(-r, bs::system_category());
b3b6e05e 191 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
192 << ": failed checking FIFO part: oid=" << oid
193 << ", r=" << r << dendl;
194 }
195 librados::ObjectWriteOperation op;
196 if (i == 0 && leave_zero) {
197 // Leave shard 0 in existence, but remove contents and
198 // omap. cls_lock stores things in the xattrs. And sync needs to
199 // rendezvous with locks on generation 0 shard 0.
200 op.omap_set_header({});
201 op.omap_clear();
202 op.truncate(0);
203 } else {
204 op.remove();
205 }
b3b6e05e 206 r = rgw_rados_operate(dpp, ioctx, oid, &op, null_yield);
f67539c2
TL
207 if (r < 0 && r != -ENOENT) {
208 if (!ec)
209 ec = bs::error_code(-r, bs::system_category());
b3b6e05e 210 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
211 << ": failed removing shard: oid=" << oid
212 << ", r=" << r << dendl;
213 }
214 }
215 return ec;
216}
217
218logback_generations::~logback_generations() {
219 if (watchcookie > 0) {
220 auto cct = static_cast<CephContext*>(ioctx.cct());
221 auto r = ioctx.unwatch2(watchcookie);
222 if (r < 0) {
223 lderr(cct) << __PRETTY_FUNCTION__ << ":" << __LINE__
224 << ": failed unwatching oid=" << oid
225 << ", r=" << r << dendl;
226 }
227 }
228}
229
b3b6e05e
TL
230bs::error_code logback_generations::setup(const DoutPrefixProvider *dpp,
231 log_type def,
f67539c2
TL
232 optional_yield y) noexcept
233{
234 try {
f67539c2 235 // First, read.
b3b6e05e
TL
236 auto cct = static_cast<CephContext*>(ioctx.cct());
237 auto res = read(dpp, y);
f67539c2
TL
238 if (!res && res.error() != bs::errc::no_such_file_or_directory) {
239 return res.error();
240 }
241 if (res) {
242 std::unique_lock lock(m);
243 std::tie(entries_, version) = std::move(*res);
244 } else {
245 // Are we the first? Then create generation 0 and the generations
246 // metadata.
247 librados::ObjectWriteOperation op;
b3b6e05e 248 auto type = log_backing_type(dpp, ioctx, def, shards,
f67539c2
TL
249 [this](int shard) {
250 return this->get_oid(0, shard);
251 }, y);
252 if (!type)
253 return type.error();
254
255 logback_generation l;
256 l.type = *type;
257
258 std::unique_lock lock(m);
259 version.ver = 1;
260 static constexpr auto TAG_LEN = 24;
261 version.tag.clear();
262 append_rand_alpha(cct, version.tag, version.tag, TAG_LEN);
263 op.create(true);
264 cls_version_set(op, version);
265 cb::list bl;
266 entries_.emplace(0, std::move(l));
267 encode(entries_, bl);
268 lock.unlock();
269
270 op.write_full(bl);
b3b6e05e 271 auto r = rgw_rados_operate(dpp, ioctx, oid, &op, y);
f67539c2 272 if (r < 0 && r != -EEXIST) {
b3b6e05e 273 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
274 << ": failed writing oid=" << oid
275 << ", r=" << r << dendl;
276 bs::system_error(-r, bs::system_category());
277 }
278 // Did someone race us? Then re-read.
279 if (r != 0) {
b3b6e05e 280 res = read(dpp, y);
f67539c2
TL
281 if (!res)
282 return res.error();
283 if (res->first.empty())
284 return bs::error_code(EIO, bs::system_category());
285 auto l = res->first.begin()->second;
286 // In the unlikely event that someone raced us, created
287 // generation zero, incremented, then erased generation zero,
288 // don't leave generation zero lying around.
289 if (l.gen_id != 0) {
b3b6e05e 290 auto ec = log_remove(dpp, ioctx, shards,
f67539c2
TL
291 [this](int shard) {
292 return this->get_oid(0, shard);
293 }, true, y);
294 if (ec) return ec;
295 }
296 std::unique_lock lock(m);
297 std::tie(entries_, version) = std::move(*res);
298 }
299 }
300 // Pass all non-empty generations to the handler
301 std::unique_lock lock(m);
302 auto i = lowest_nomempty(entries_);
303 entries_t e;
304 std::copy(i, entries_.cend(),
305 std::inserter(e, e.end()));
306 m.unlock();
307 auto ec = watch();
308 if (ec) {
b3b6e05e 309 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
310 << ": failed to re-establish watch, unsafe to continue: oid="
311 << oid << ", ec=" << ec.message() << dendl;
312 }
313 return handle_init(std::move(e));
314 } catch (const std::bad_alloc&) {
315 return bs::error_code(ENOMEM, bs::system_category());
316 }
317}
318
b3b6e05e 319bs::error_code logback_generations::update(const DoutPrefixProvider *dpp, optional_yield y) noexcept
f67539c2
TL
320{
321 try {
b3b6e05e 322 auto res = read(dpp, y);
f67539c2
TL
323 if (!res) {
324 return res.error();
325 }
326
327 std::unique_lock l(m);
328 auto& [es, v] = *res;
329 if (v == version) {
330 // Nothing to do!
331 return {};
332 }
333
334 // Check consistency and prepare update
335 if (es.empty()) {
b3b6e05e 336 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
337 << ": INCONSISTENCY! Read empty update." << dendl;
338 return bs::error_code(EFAULT, bs::system_category());
339 }
340 auto cur_lowest = lowest_nomempty(entries_);
341 // Straight up can't happen
342 assert(cur_lowest != entries_.cend());
343 auto new_lowest = lowest_nomempty(es);
344 if (new_lowest == es.cend()) {
b3b6e05e 345 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
346 << ": INCONSISTENCY! Read update with no active head." << dendl;
347 return bs::error_code(EFAULT, bs::system_category());
348 }
349 if (new_lowest->first < cur_lowest->first) {
b3b6e05e 350 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
351 << ": INCONSISTENCY! Tail moved wrong way." << dendl;
352 return bs::error_code(EFAULT, bs::system_category());
353 }
354
355 std::optional<uint64_t> highest_empty;
356 if (new_lowest->first > cur_lowest->first && new_lowest != es.begin()) {
357 --new_lowest;
358 highest_empty = new_lowest->first;
359 }
360
361 entries_t new_entries;
362
363 if ((es.end() - 1)->first < (entries_.end() - 1)->first) {
b3b6e05e 364 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
365 << ": INCONSISTENCY! Head moved wrong way." << dendl;
366 return bs::error_code(EFAULT, bs::system_category());
367 }
368
369 if ((es.end() - 1)->first > (entries_.end() - 1)->first) {
370 auto ei = es.lower_bound((entries_.end() - 1)->first + 1);
371 std::copy(ei, es.end(), std::inserter(new_entries, new_entries.end()));
372 }
373
374 // Everything checks out!
375
376 version = v;
377 entries_ = es;
378 l.unlock();
379
380 if (highest_empty) {
381 auto ec = handle_empty_to(*highest_empty);
382 if (ec) return ec;
383 }
384
385 if (!new_entries.empty()) {
386 auto ec = handle_new_gens(std::move(new_entries));
387 if (ec) return ec;
388 }
389 } catch (const std::bad_alloc&) {
390 return bs::error_code(ENOMEM, bs::system_category());
391 }
392 return {};
393}
394
b3b6e05e 395auto logback_generations::read(const DoutPrefixProvider *dpp, optional_yield y) noexcept ->
f67539c2
TL
396 tl::expected<std::pair<entries_t, obj_version>, bs::error_code>
397{
398 try {
f67539c2
TL
399 librados::ObjectReadOperation op;
400 std::unique_lock l(m);
401 cls_version_check(op, version, VER_COND_GE);
402 l.unlock();
403 obj_version v2;
404 cls_version_read(op, &v2);
405 cb::list bl;
406 op.read(0, 0, &bl, nullptr);
b3b6e05e 407 auto r = rgw_rados_operate(dpp, ioctx, oid, &op, nullptr, y);
f67539c2
TL
408 if (r < 0) {
409 if (r == -ENOENT) {
b3b6e05e 410 ldpp_dout(dpp, 5) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
411 << ": oid=" << oid
412 << " not found" << dendl;
413 } else {
b3b6e05e 414 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
415 << ": failed reading oid=" << oid
416 << ", r=" << r << dendl;
417 }
418 return tl::unexpected(bs::error_code(-r, bs::system_category()));
419 }
420 auto bi = bl.cbegin();
421 entries_t e;
422 try {
423 decode(e, bi);
424 } catch (const cb::error& err) {
425 return tl::unexpected(err.code());
426 }
427 return std::pair{ std::move(e), std::move(v2) };
428 } catch (const std::bad_alloc&) {
429 return tl::unexpected(bs::error_code(ENOMEM, bs::system_category()));
430 }
431}
432
b3b6e05e 433bs::error_code logback_generations::write(const DoutPrefixProvider *dpp, entries_t&& e,
f67539c2
TL
434 std::unique_lock<std::mutex>&& l_,
435 optional_yield y) noexcept
436{
437 auto l = std::move(l_);
438 ceph_assert(l.mutex() == &m &&
439 l.owns_lock());
440 try {
f67539c2
TL
441 librados::ObjectWriteOperation op;
442 cls_version_check(op, version, VER_COND_GE);
443 cb::list bl;
444 encode(e, bl);
445 op.write_full(bl);
446 cls_version_inc(op);
b3b6e05e 447 auto r = rgw_rados_operate(dpp, ioctx, oid, &op, y);
f67539c2
TL
448 if (r == 0) {
449 entries_ = std::move(e);
450 version.inc();
451 return {};
452 }
453 l.unlock();
454 if (r < 0 && r != -ECANCELED) {
b3b6e05e 455 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
456 << ": failed reading oid=" << oid
457 << ", r=" << r << dendl;
458 return { -r, bs::system_category() };
459 }
460 if (r == -ECANCELED) {
b3b6e05e 461 auto ec = update(dpp, y);
f67539c2
TL
462 if (ec) {
463 return ec;
464 } else {
465 return { ECANCELED, bs::system_category() };
466 }
467 }
468 } catch (const std::bad_alloc&) {
469 return { ENOMEM, bs::system_category() };
470 }
471 return {};
472}
473
474
475bs::error_code logback_generations::watch() noexcept {
476 try {
477 auto cct = static_cast<CephContext*>(ioctx.cct());
478 auto r = ioctx.watch2(oid, &watchcookie, this);
479 if (r < 0) {
480 lderr(cct) << __PRETTY_FUNCTION__ << ":" << __LINE__
481 << ": failed to set watch oid=" << oid
482 << ", r=" << r << dendl;
483 return { -r, bs::system_category() };
484 }
485 } catch (const std::bad_alloc&) {
486 return bs::error_code(ENOMEM, bs::system_category());
487 }
488 return {};
489}
490
b3b6e05e
TL
491bs::error_code logback_generations::new_backing(const DoutPrefixProvider *dpp,
492 log_type type,
f67539c2 493 optional_yield y) noexcept {
f67539c2
TL
494 static constexpr auto max_tries = 10;
495 try {
b3b6e05e 496 auto ec = update(dpp, y);
f67539c2
TL
497 if (ec) return ec;
498 auto tries = 0;
499 entries_t new_entries;
500 do {
501 std::unique_lock l(m);
502 auto last = entries_.end() - 1;
503 if (last->second.type == type) {
504 // Nothing to be done
505 return {};
506 }
507 auto newgenid = last->first + 1;
508 logback_generation newgen;
509 newgen.gen_id = newgenid;
510 newgen.type = type;
511 new_entries.emplace(newgenid, newgen);
512 auto es = entries_;
513 es.emplace(newgenid, std::move(newgen));
b3b6e05e 514 ec = write(dpp, std::move(es), std::move(l), y);
f67539c2
TL
515 ++tries;
516 } while (ec == bs::errc::operation_canceled &&
517 tries < max_tries);
518 if (tries >= max_tries) {
b3b6e05e 519 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
520 << ": exhausted retry attempts." << dendl;
521 return ec;
522 }
523
524 if (ec) {
b3b6e05e 525 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
526 << ": write failed with ec=" << ec.message() << dendl;
527 return ec;
528 }
529
530 cb::list bl, rbl;
531
b3b6e05e 532 auto r = rgw_rados_notify(dpp, ioctx, oid, bl, 10'000, &rbl, y);
f67539c2 533 if (r < 0) {
b3b6e05e 534 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
535 << ": notify failed with r=" << r << dendl;
536 return { -r, bs::system_category() };
537 }
538 ec = handle_new_gens(new_entries);
539 } catch (const std::bad_alloc&) {
540 return bs::error_code(ENOMEM, bs::system_category());
541 }
542 return {};
543}
544
b3b6e05e
TL
545bs::error_code logback_generations::empty_to(const DoutPrefixProvider *dpp,
546 uint64_t gen_id,
f67539c2 547 optional_yield y) noexcept {
f67539c2
TL
548 static constexpr auto max_tries = 10;
549 try {
b3b6e05e 550 auto ec = update(dpp, y);
f67539c2
TL
551 if (ec) return ec;
552 auto tries = 0;
553 uint64_t newtail = 0;
554 do {
555 std::unique_lock l(m);
556 {
557 auto last = entries_.end() - 1;
558 if (gen_id >= last->first) {
b3b6e05e 559 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
560 << ": Attempt to trim beyond the possible." << dendl;
561 return bs::error_code(EINVAL, bs::system_category());
562 }
563 }
564 auto es = entries_;
565 auto ei = es.upper_bound(gen_id);
566 if (ei == es.begin()) {
567 // Nothing to be done.
568 return {};
569 }
570 for (auto i = es.begin(); i < ei; ++i) {
571 newtail = i->first;
572 i->second.pruned = ceph::real_clock::now();
573 }
b3b6e05e 574 ec = write(dpp, std::move(es), std::move(l), y);
f67539c2
TL
575 ++tries;
576 } while (ec == bs::errc::operation_canceled &&
577 tries < max_tries);
578 if (tries >= max_tries) {
b3b6e05e 579 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
580 << ": exhausted retry attempts." << dendl;
581 return ec;
582 }
583
584 if (ec) {
b3b6e05e 585 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
586 << ": write failed with ec=" << ec.message() << dendl;
587 return ec;
588 }
589
590 cb::list bl, rbl;
591
b3b6e05e 592 auto r = rgw_rados_notify(dpp, ioctx, oid, bl, 10'000, &rbl, y);
f67539c2 593 if (r < 0) {
b3b6e05e 594 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
595 << ": notify failed with r=" << r << dendl;
596 return { -r, bs::system_category() };
597 }
598 ec = handle_empty_to(newtail);
599 } catch (const std::bad_alloc&) {
600 return bs::error_code(ENOMEM, bs::system_category());
601 }
602 return {};
603}
604
b3b6e05e 605bs::error_code logback_generations::remove_empty(const DoutPrefixProvider *dpp, optional_yield y) noexcept {
f67539c2
TL
606 static constexpr auto max_tries = 10;
607 try {
b3b6e05e 608 auto ec = update(dpp, y);
f67539c2
TL
609 if (ec) return ec;
610 auto tries = 0;
611 entries_t new_entries;
612 std::unique_lock l(m);
613 ceph_assert(!entries_.empty());
614 {
615 auto i = lowest_nomempty(entries_);
616 if (i == entries_.begin()) {
617 return {};
618 }
619 }
620 entries_t es;
621 auto now = ceph::real_clock::now();
622 l.unlock();
623 do {
624 std::copy_if(entries_.cbegin(), entries_.cend(),
625 std::inserter(es, es.end()),
626 [now](const auto& e) {
627 if (!e.second.pruned)
628 return false;
629
630 auto pruned = *e.second.pruned;
631 return (now - pruned) >= 1h;
632 });
633 auto es2 = entries_;
634 for (const auto& [gen_id, e] : es) {
635 ceph_assert(e.pruned);
b3b6e05e
TL
636 auto ec = log_remove(dpp, ioctx, shards,
637 [this, gen_id = gen_id](int shard) {
f67539c2
TL
638 return this->get_oid(gen_id, shard);
639 }, (gen_id == 0), y);
640 if (ec) {
b3b6e05e
TL
641 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
642 << ": Error pruning: gen_id=" << gen_id
643 << " ec=" << ec.message() << dendl;
f67539c2
TL
644 }
645 if (auto i = es2.find(gen_id); i != es2.end()) {
646 es2.erase(i);
647 }
648 }
649 l.lock();
650 es.clear();
b3b6e05e 651 ec = write(dpp, std::move(es2), std::move(l), y);
f67539c2
TL
652 ++tries;
653 } while (ec == bs::errc::operation_canceled &&
654 tries < max_tries);
655 if (tries >= max_tries) {
b3b6e05e 656 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
657 << ": exhausted retry attempts." << dendl;
658 return ec;
659 }
660
661 if (ec) {
b3b6e05e 662 ldpp_dout(dpp, -1) << __PRETTY_FUNCTION__ << ":" << __LINE__
f67539c2
TL
663 << ": write failed with ec=" << ec.message() << dendl;
664 return ec;
665 }
666 } catch (const std::bad_alloc&) {
667 return bs::error_code(ENOMEM, bs::system_category());
668 }
669 return {};
670}
671
672void logback_generations::handle_notify(uint64_t notify_id,
673 uint64_t cookie,
674 uint64_t notifier_id,
675 bufferlist& bl)
676{
677 auto cct = static_cast<CephContext*>(ioctx.cct());
b3b6e05e 678 const DoutPrefix dp(cct, dout_subsys, "logback generations handle_notify: ");
f67539c2 679 if (notifier_id != my_id) {
b3b6e05e 680 auto ec = update(&dp, null_yield);
f67539c2
TL
681 if (ec) {
682 lderr(cct)
683 << __PRETTY_FUNCTION__ << ":" << __LINE__
684 << ": update failed, no one to report to and no safe way to continue."
685 << dendl;
686 abort();
687 }
688 }
689 cb::list rbl;
690 ioctx.notify_ack(oid, notify_id, watchcookie, rbl);
691}
692
693void logback_generations::handle_error(uint64_t cookie, int err) {
694 auto cct = static_cast<CephContext*>(ioctx.cct());
695 auto r = ioctx.unwatch2(watchcookie);
696 if (r < 0) {
697 lderr(cct) << __PRETTY_FUNCTION__ << ":" << __LINE__
698 << ": failed to set unwatch oid=" << oid
699 << ", r=" << r << dendl;
700 }
701
702 auto ec = watch();
703 if (ec) {
704 lderr(cct) << __PRETTY_FUNCTION__ << ":" << __LINE__
705 << ": failed to re-establish watch, unsafe to continue: oid="
706 << oid << ", ec=" << ec.message() << dendl;
707 }
708}