]>
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 | ||
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 | 11 | using namespace std::chrono_literals; |
f67539c2 TL |
12 | namespace cb = ceph::buffer; |
13 | ||
14 | static constexpr auto dout_subsys = ceph_subsys_rgw; | |
15 | ||
16 | enum class shard_check { dne, omap, fifo, corrupt }; | |
17 | inline 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 | ||
32 | namespace { | |
33 | /// Return the shard type, and a bool to see whether it has entries. | |
b3b6e05e TL |
34 | shard_check |
35 | probe_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 | ||
84 | tl::expected<log_type, bs::error_code> | |
b3b6e05e | 85 | handle_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 | ||
113 | tl::expected<log_type, bs::error_code> | |
b3b6e05e TL |
114 | log_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 |
156 | bs::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 | ||
218 | logback_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 |
230 | bs::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 | 319 | bs::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 | 395 | auto 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 | 433 | bs::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 | ||
475 | bs::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 |
491 | bs::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 |
545 | bs::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 | 605 | bs::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 | ||
672 | void 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 | ||
693 | void 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 | } |