]> git.proxmox.com Git - ceph.git/blame - ceph/src/osd/scrubber/PrimaryLogScrub.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / osd / scrubber / PrimaryLogScrub.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
3
4#include "PrimaryLogScrub.h"
5
6#include "common/scrub_types.h"
20effc67 7#include "osd/osd_types_fmt.h"
f67539c2 8
20effc67
TL
9#include "osd/PeeringState.h"
10#include "osd/PrimaryLogPG.h"
f67539c2
TL
11#include "scrub_machine.h"
12
20effc67 13#define dout_context (m_osds->cct)
f67539c2
TL
14#define dout_subsys ceph_subsys_osd
15#undef dout_prefix
20effc67 16#define dout_prefix _prefix(_dout, this)
f67539c2 17
20effc67
TL
18using std::vector;
19
20template <class T>
21static ostream& _prefix(std::ostream* _dout, T* t)
f67539c2 22{
20effc67 23 return t->gen_prefix(*_dout);
f67539c2
TL
24}
25
26using namespace Scrub;
f67539c2
TL
27
28bool PrimaryLogScrub::get_store_errors(const scrub_ls_arg_t& arg,
29 scrub_ls_result_t& res_inout) const
30{
31 if (!m_store) {
32 return false;
33 }
34
35 if (arg.get_snapsets) {
36 res_inout.vals =
37 m_store->get_snap_errors(m_pg->get_pgid().pool(), arg.start_after, arg.max_return);
38 } else {
39 res_inout.vals = m_store->get_object_errors(m_pg->get_pgid().pool(), arg.start_after,
40 arg.max_return);
41 }
42 return true;
43}
44
45void PrimaryLogScrub::_scrub_finish()
46{
20effc67 47 auto& info = m_pg->get_pg_info(ScrubberPasskey{}); ///< a temporary alias
f67539c2
TL
48
49 dout(10) << __func__
50 << " info stats: " << (info.stats.stats_invalid ? "invalid" : "valid")
51 << dendl;
52
f67539c2
TL
53 if (info.stats.stats_invalid) {
54 m_pl_pg->recovery_state.update_stats([=](auto& history, auto& stats) {
55 stats.stats = m_scrub_cstat;
56 stats.stats_invalid = false;
57 return false;
58 });
59
60 if (m_pl_pg->agent_state)
61 m_pl_pg->agent_choose_mode();
62 }
63
522d829b 64 dout(10) << m_mode_desc << " got " << m_scrub_cstat.sum.num_objects << "/"
f67539c2
TL
65 << info.stats.stats.sum.num_objects << " objects, "
66 << m_scrub_cstat.sum.num_object_clones << "/"
67 << info.stats.stats.sum.num_object_clones << " clones, "
68 << m_scrub_cstat.sum.num_objects_dirty << "/"
69 << info.stats.stats.sum.num_objects_dirty << " dirty, "
70 << m_scrub_cstat.sum.num_objects_omap << "/"
71 << info.stats.stats.sum.num_objects_omap << " omap, "
72 << m_scrub_cstat.sum.num_objects_pinned << "/"
73 << info.stats.stats.sum.num_objects_pinned << " pinned, "
74 << m_scrub_cstat.sum.num_objects_hit_set_archive << "/"
75 << info.stats.stats.sum.num_objects_hit_set_archive << " hit_set_archive, "
76 << m_scrub_cstat.sum.num_bytes << "/" << info.stats.stats.sum.num_bytes
77 << " bytes, " << m_scrub_cstat.sum.num_objects_manifest << "/"
78 << info.stats.stats.sum.num_objects_manifest << " manifest objects, "
79 << m_scrub_cstat.sum.num_bytes_hit_set_archive << "/"
80 << info.stats.stats.sum.num_bytes_hit_set_archive << " hit_set_archive bytes."
81 << dendl;
82
83 if (m_scrub_cstat.sum.num_objects != info.stats.stats.sum.num_objects ||
84 m_scrub_cstat.sum.num_object_clones != info.stats.stats.sum.num_object_clones ||
85 (m_scrub_cstat.sum.num_objects_dirty != info.stats.stats.sum.num_objects_dirty &&
86 !info.stats.dirty_stats_invalid) ||
87 (m_scrub_cstat.sum.num_objects_omap != info.stats.stats.sum.num_objects_omap &&
88 !info.stats.omap_stats_invalid) ||
89 (m_scrub_cstat.sum.num_objects_pinned != info.stats.stats.sum.num_objects_pinned &&
90 !info.stats.pin_stats_invalid) ||
91 (m_scrub_cstat.sum.num_objects_hit_set_archive !=
92 info.stats.stats.sum.num_objects_hit_set_archive &&
93 !info.stats.hitset_stats_invalid) ||
94 (m_scrub_cstat.sum.num_bytes_hit_set_archive !=
95 info.stats.stats.sum.num_bytes_hit_set_archive &&
96 !info.stats.hitset_bytes_stats_invalid) ||
97 (m_scrub_cstat.sum.num_objects_manifest !=
98 info.stats.stats.sum.num_objects_manifest &&
99 !info.stats.manifest_stats_invalid) ||
100 m_scrub_cstat.sum.num_whiteouts != info.stats.stats.sum.num_whiteouts ||
101 m_scrub_cstat.sum.num_bytes != info.stats.stats.sum.num_bytes) {
522d829b 102 m_osds->clog->error() << info.pgid << " " << m_mode_desc << " : stat mismatch, got "
f67539c2
TL
103 << m_scrub_cstat.sum.num_objects << "/"
104 << info.stats.stats.sum.num_objects << " objects, "
105 << m_scrub_cstat.sum.num_object_clones << "/"
106 << info.stats.stats.sum.num_object_clones << " clones, "
107 << m_scrub_cstat.sum.num_objects_dirty << "/"
108 << info.stats.stats.sum.num_objects_dirty << " dirty, "
109 << m_scrub_cstat.sum.num_objects_omap << "/"
110 << info.stats.stats.sum.num_objects_omap << " omap, "
111 << m_scrub_cstat.sum.num_objects_pinned << "/"
112 << info.stats.stats.sum.num_objects_pinned << " pinned, "
113 << m_scrub_cstat.sum.num_objects_hit_set_archive << "/"
114 << info.stats.stats.sum.num_objects_hit_set_archive
115 << " hit_set_archive, " << m_scrub_cstat.sum.num_whiteouts
116 << "/" << info.stats.stats.sum.num_whiteouts << " whiteouts, "
117 << m_scrub_cstat.sum.num_bytes << "/"
118 << info.stats.stats.sum.num_bytes << " bytes, "
119 << m_scrub_cstat.sum.num_objects_manifest << "/"
120 << info.stats.stats.sum.num_objects_manifest
121 << " manifest objects, "
122 << m_scrub_cstat.sum.num_bytes_hit_set_archive << "/"
123 << info.stats.stats.sum.num_bytes_hit_set_archive
124 << " hit_set_archive bytes.";
125 ++m_shallow_errors;
126
522d829b 127 if (m_is_repair) {
f67539c2
TL
128 ++m_fixed_count;
129 m_pl_pg->recovery_state.update_stats([this](auto& history, auto& stats) {
130 stats.stats = m_scrub_cstat;
131 stats.dirty_stats_invalid = false;
132 stats.omap_stats_invalid = false;
133 stats.hitset_stats_invalid = false;
134 stats.hitset_bytes_stats_invalid = false;
135 stats.pin_stats_invalid = false;
136 stats.manifest_stats_invalid = false;
137 return false;
138 });
139 m_pl_pg->publish_stats_to_osd();
140 m_pl_pg->recovery_state.share_pg_info();
141 }
142 }
143 // Clear object context cache to get repair information
522d829b 144 if (m_is_repair)
f67539c2
TL
145 m_pl_pg->object_contexts.clear();
146}
147
148static bool doing_clones(const std::optional<SnapSet>& snapset,
149 const vector<snapid_t>::reverse_iterator& curclone)
150{
151 return snapset && curclone != snapset->clones.rend();
152}
153
154void PrimaryLogScrub::log_missing(int missing,
155 const std::optional<hobject_t>& head,
156 LogChannelRef clog,
157 const spg_t& pgid,
158 const char* func,
f67539c2
TL
159 bool allow_incomplete_clones)
160{
161 ceph_assert(head);
162 if (allow_incomplete_clones) {
522d829b 163 dout(20) << func << " " << m_mode_desc << " " << pgid << " " << *head << " skipped "
f67539c2
TL
164 << missing << " clone(s) in cache tier" << dendl;
165 } else {
522d829b 166 clog->info() << m_mode_desc << " " << pgid << " " << *head << " : " << missing
f67539c2
TL
167 << " missing clone(s)";
168 }
169}
170
171int PrimaryLogScrub::process_clones_to(const std::optional<hobject_t>& head,
172 const std::optional<SnapSet>& snapset,
173 LogChannelRef clog,
174 const spg_t& pgid,
f67539c2
TL
175 bool allow_incomplete_clones,
176 std::optional<snapid_t> target,
177 vector<snapid_t>::reverse_iterator* curclone,
178 inconsistent_snapset_wrapper& e)
179{
180 ceph_assert(head);
181 ceph_assert(snapset);
182 int missing_count = 0;
183
184 // NOTE: clones are in descending order, thus **curclone > target test here
185 hobject_t next_clone(*head);
186 while (doing_clones(snapset, *curclone) && (!target || **curclone > *target)) {
187
188 ++missing_count;
189 // it is okay to be missing one or more clones in a cache tier.
190 // skip higher-numbered clones in the list.
191 if (!allow_incomplete_clones) {
192 next_clone.snap = **curclone;
522d829b 193 clog->error() << m_mode_desc << " " << pgid << " " << *head << " : expected clone "
f67539c2
TL
194 << next_clone << " " << m_missing << " missing";
195 ++m_shallow_errors;
196 e.set_clone_missing(next_clone.snap);
197 }
198 // Clones are descending
199 ++(*curclone);
200 }
201 return missing_count;
202}
203
204/*
205 * Validate consistency of the object info and snap sets.
206 *
207 * We are sort of comparing 2 lists. The main loop is on objmap.objects. But
208 * the comparison of the objects is against multiple snapset.clones. There are
209 * multiple clone lists and in between lists we expect head.
210 *
211 * Example
212 *
213 * objects expected
214 * ======= =======
215 * obj1 snap 1 head, unexpected obj1 snap 1
216 * obj2 head head, match
217 * [SnapSet clones 6 4 2 1]
218 * obj2 snap 7 obj2 snap 6, unexpected obj2 snap 7
219 * obj2 snap 6 obj2 snap 6, match
220 * obj2 snap 4 obj2 snap 4, match
221 * obj3 head obj2 snap 2 (expected), obj2 snap 1 (expected), match
222 * [Snapset clones 3 1]
223 * obj3 snap 3 obj3 snap 3 match
224 * obj3 snap 1 obj3 snap 1 match
225 * obj4 head head, match
226 * [Snapset clones 4]
227 * EOL obj4 snap 4, (expected)
228 */
229void PrimaryLogScrub::scrub_snapshot_metadata(ScrubMap& scrubmap,
230 const missing_map_t& missing_digest)
231{
232 dout(10) << __func__ << " num stat obj " << m_pl_pg->info.stats.stats.sum.num_objects
233 << dendl;
234
235 auto& info = m_pl_pg->info;
236 const PGPool& pool = m_pl_pg->pool;
237 bool allow_incomplete_clones = pool.info.allow_incomplete_clones();
238
f67539c2
TL
239 std::optional<snapid_t> all_clones; // Unspecified snapid_t or std::nullopt
240
241 // traverse in reverse order.
242 std::optional<hobject_t> head;
243 std::optional<SnapSet> snapset; // If initialized so will head (above)
244 vector<snapid_t>::reverse_iterator curclone; // Defined only if snapset initialized
245 int missing = 0;
246 inconsistent_snapset_wrapper soid_error, head_error;
247 int soid_error_count = 0;
248
249 for (auto p = scrubmap.objects.rbegin(); p != scrubmap.objects.rend(); ++p) {
250
251 const hobject_t& soid = p->first;
252 ceph_assert(!soid.is_snapdir());
253 soid_error = inconsistent_snapset_wrapper{soid};
254 object_stat_sum_t stat;
255 std::optional<object_info_t> oi;
256
257 stat.num_objects++;
258
259 if (soid.nspace == m_pl_pg->cct->_conf->osd_hit_set_namespace)
260 stat.num_objects_hit_set_archive++;
261
262 if (soid.is_snap()) {
263 // it's a clone
264 stat.num_object_clones++;
265 }
266
267 // basic checks.
268 if (p->second.attrs.count(OI_ATTR) == 0) {
269 oi = std::nullopt;
522d829b 270 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : no '"
f67539c2
TL
271 << OI_ATTR << "' attr";
272 ++m_shallow_errors;
273 soid_error.set_info_missing();
274 } else {
275 bufferlist bv;
276 bv.push_back(p->second.attrs[OI_ATTR]);
277 try {
20effc67 278 oi = object_info_t(bv);
f67539c2
TL
279 } catch (ceph::buffer::error& e) {
280 oi = std::nullopt;
522d829b 281 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
282 << " : can't decode '" << OI_ATTR << "' attr " << e.what();
283 ++m_shallow_errors;
284 soid_error.set_info_corrupted();
285 soid_error.set_info_missing(); // Not available too
286 }
287 }
288
289 if (oi) {
290 if (m_pl_pg->pgbackend->be_get_ondisk_size(oi->size) != p->second.size) {
522d829b 291 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
292 << " : on disk size (" << p->second.size
293 << ") does not match object info size (" << oi->size
294 << ") adjusted for ondisk to ("
295 << m_pl_pg->pgbackend->be_get_ondisk_size(oi->size) << ")";
296 soid_error.set_size_mismatch();
297 ++m_shallow_errors;
298 }
299
522d829b 300 dout(20) << m_mode_desc << " " << soid << " " << *oi << dendl;
f67539c2
TL
301
302 // A clone num_bytes will be added later when we have snapset
303 if (!soid.is_snap()) {
304 stat.num_bytes += oi->size;
305 }
306 if (soid.nspace == m_pl_pg->cct->_conf->osd_hit_set_namespace)
307 stat.num_bytes_hit_set_archive += oi->size;
308
309 if (oi->is_dirty())
310 ++stat.num_objects_dirty;
311 if (oi->is_whiteout())
312 ++stat.num_whiteouts;
313 if (oi->is_omap())
314 ++stat.num_objects_omap;
315 if (oi->is_cache_pinned())
316 ++stat.num_objects_pinned;
317 if (oi->has_manifest())
318 ++stat.num_objects_manifest;
319 }
320
321 // Check for any problems while processing clones
322 if (doing_clones(snapset, curclone)) {
323 std::optional<snapid_t> target;
324 // Expecting an object with snap for current head
325 if (soid.has_snapset() || soid.get_head() != head->get_head()) {
326
522d829b 327 dout(10) << __func__ << " " << m_mode_desc << " " << info.pgid << " new object " << soid
f67539c2
TL
328 << " while processing " << *head << dendl;
329
330 target = all_clones;
331 } else {
332 ceph_assert(soid.is_snap());
333 target = soid.snap;
334 }
335
336 // Log any clones we were expecting to be there up to target
337 // This will set missing, but will be a no-op if snap.soid == *curclone.
338 missing +=
522d829b 339 process_clones_to(head, snapset, m_osds->clog, info.pgid,
f67539c2
TL
340 allow_incomplete_clones, target, &curclone, head_error);
341 }
342
343 bool expected;
344 // Check doing_clones() again in case we ran process_clones_to()
345 if (doing_clones(snapset, curclone)) {
346 // A head would have processed all clones above
347 // or all greater than *curclone.
348 ceph_assert(soid.is_snap() && *curclone <= soid.snap);
349
350 // After processing above clone snap should match the expected curclone
351 expected = (*curclone == soid.snap);
352 } else {
353 // If we aren't doing clones any longer, then expecting head
354 expected = soid.has_snapset();
355 }
356 if (!expected) {
357 // If we couldn't read the head's snapset, just ignore clones
358 if (head && !snapset) {
522d829b 359 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
360 << " : clone ignored due to missing snapset";
361 } else {
522d829b 362 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
363 << " : is an unexpected clone";
364 }
365 ++m_shallow_errors;
366 soid_error.set_headless();
367 m_store->add_snap_error(pool.id, soid_error);
368 ++soid_error_count;
369 if (head && soid.get_head() == head->get_head())
370 head_error.set_clone(soid.snap);
371 continue;
372 }
373
374 // new snapset?
375 if (soid.has_snapset()) {
376
377 if (missing) {
522d829b 378 log_missing(missing, head, m_osds->clog, info.pgid, __func__,
f67539c2
TL
379 pool.info.allow_incomplete_clones());
380 }
381
382 // Save previous head error information
383 if (head && (head_error.errors || soid_error_count))
384 m_store->add_snap_error(pool.id, head_error);
385 // Set this as a new head object
386 head = soid;
387 missing = 0;
388 head_error = soid_error;
389 soid_error_count = 0;
390
522d829b 391 dout(20) << __func__ << " " << m_mode_desc << " new head " << head << dendl;
f67539c2
TL
392
393 if (p->second.attrs.count(SS_ATTR) == 0) {
522d829b 394 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : no '"
f67539c2
TL
395 << SS_ATTR << "' attr";
396 ++m_shallow_errors;
397 snapset = std::nullopt;
398 head_error.set_snapset_missing();
399 } else {
400 bufferlist bl;
401 bl.push_back(p->second.attrs[SS_ATTR]);
402 auto blp = bl.cbegin();
403 try {
404 snapset = SnapSet(); // Initialize optional<> before decoding into it
405 decode(*snapset, blp);
406 head_error.ss_bl.push_back(p->second.attrs[SS_ATTR]);
407 } catch (ceph::buffer::error& e) {
408 snapset = std::nullopt;
409 m_osds->clog->error()
522d829b 410 << m_mode_desc << " " << info.pgid << " " << soid << " : can't decode '" << SS_ATTR
f67539c2
TL
411 << "' attr " << e.what();
412 ++m_shallow_errors;
413 head_error.set_snapset_corrupted();
414 }
415 }
416
417 if (snapset) {
418 // what will be next?
419 curclone = snapset->clones.rbegin();
420
421 if (!snapset->clones.empty()) {
422 dout(20) << " snapset " << *snapset << dendl;
423 if (snapset->seq == 0) {
424 m_osds->clog->error()
522d829b 425 << m_mode_desc << " " << info.pgid << " " << soid << " : snaps.seq not set";
f67539c2
TL
426 ++m_shallow_errors;
427 head_error.set_snapset_error();
428 }
429 }
430 }
431 } else {
432 ceph_assert(soid.is_snap());
433 ceph_assert(head);
434 ceph_assert(snapset);
435 ceph_assert(soid.snap == *curclone);
436
522d829b 437 dout(20) << __func__ << " " << m_mode_desc << " matched clone " << soid << dendl;
f67539c2
TL
438
439 if (snapset->clone_size.count(soid.snap) == 0) {
522d829b 440 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
441 << " : is missing in clone_size";
442 ++m_shallow_errors;
443 soid_error.set_size_mismatch();
444 } else {
445 if (oi && oi->size != snapset->clone_size[soid.snap]) {
446 m_osds->clog->error()
522d829b 447 << m_mode_desc << " " << info.pgid << " " << soid << " : size " << oi->size
f67539c2
TL
448 << " != clone_size " << snapset->clone_size[*curclone];
449 ++m_shallow_errors;
450 soid_error.set_size_mismatch();
451 }
452
453 if (snapset->clone_overlap.count(soid.snap) == 0) {
522d829b 454 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
455 << " : is missing in clone_overlap";
456 ++m_shallow_errors;
457 soid_error.set_size_mismatch();
458 } else {
459 // This checking is based on get_clone_bytes(). The first 2 asserts
460 // can't happen because we know we have a clone_size and
461 // a clone_overlap. Now we check that the interval_set won't
462 // cause the last assert.
463 uint64_t size = snapset->clone_size.find(soid.snap)->second;
464 const interval_set<uint64_t>& overlap =
465 snapset->clone_overlap.find(soid.snap)->second;
466 bool bad_interval_set = false;
467 for (interval_set<uint64_t>::const_iterator i = overlap.begin();
468 i != overlap.end(); ++i) {
469 if (size < i.get_len()) {
470 bad_interval_set = true;
471 break;
472 }
473 size -= i.get_len();
474 }
475
476 if (bad_interval_set) {
522d829b 477 m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid
f67539c2
TL
478 << " : bad interval_set in clone_overlap";
479 ++m_shallow_errors;
480 soid_error.set_size_mismatch();
481 } else {
482 stat.num_bytes += snapset->get_clone_bytes(soid.snap);
483 }
484 }
485 }
486
487 // what's next?
488 ++curclone;
489 if (soid_error.errors) {
490 m_store->add_snap_error(pool.id, soid_error);
491 ++soid_error_count;
492 }
493 }
494 m_scrub_cstat.add(stat);
495 }
496
497 if (doing_clones(snapset, curclone)) {
522d829b 498 dout(10) << __func__ << " " << m_mode_desc << " " << info.pgid
f67539c2
TL
499 << " No more objects while processing " << *head << dendl;
500
501 missing +=
522d829b 502 process_clones_to(head, snapset, m_osds->clog, info.pgid,
f67539c2
TL
503 allow_incomplete_clones, all_clones, &curclone, head_error);
504 }
505
506 // There could be missing found by the test above or even
507 // before dropping out of the loop for the last head.
508 if (missing) {
522d829b 509 log_missing(missing, head, m_osds->clog, info.pgid, __func__,
f67539c2
TL
510 allow_incomplete_clones);
511 }
512 if (head && (head_error.errors || soid_error_count))
513 m_store->add_snap_error(pool.id, head_error);
514
515 dout(20) << __func__ << " - " << missing << " (" << missing_digest.size() << ") missing"
516 << dendl;
517 for (auto p = missing_digest.begin(); p != missing_digest.end(); ++p) {
518
519 ceph_assert(!p->first.is_snapdir());
520 dout(10) << __func__ << " recording digests for " << p->first << dendl;
521
522 ObjectContextRef obc = m_pl_pg->get_object_context(p->first, false);
523 if (!obc) {
522d829b 524 m_osds->clog->error() << info.pgid << " " << m_mode_desc
f67539c2
TL
525 << " cannot get object context for object " << p->first;
526 continue;
527 }
528 if (obc->obs.oi.soid != p->first) {
522d829b 529 m_osds->clog->error() << info.pgid << " " << m_mode_desc << " " << p->first
f67539c2
TL
530 << " : object has a valid oi attr with a mismatched name, "
531 << " obc->obs.oi.soid: " << obc->obs.oi.soid;
532 continue;
533 }
534 PrimaryLogPG::OpContextUPtr ctx = m_pl_pg->simple_opc_create(obc);
535 ctx->at_version = m_pl_pg->get_next_version();
536 ctx->mtime = utime_t(); // do not update mtime
537 if (p->second.first) {
538 ctx->new_obs.oi.set_data_digest(*p->second.first);
539 } else {
540 ctx->new_obs.oi.clear_data_digest();
541 }
542 if (p->second.second) {
543 ctx->new_obs.oi.set_omap_digest(*p->second.second);
544 } else {
545 ctx->new_obs.oi.clear_omap_digest();
546 }
547 m_pl_pg->finish_ctx(ctx.get(), pg_log_entry_t::MODIFY);
548
549 ++num_digest_updates_pending;
550 ctx->register_on_success([this]() {
551 dout(20) << "updating scrub digest " << num_digest_updates_pending << dendl;
20effc67 552 if ((num_digest_updates_pending >= 1) && (--num_digest_updates_pending == 0)) {
f67539c2
TL
553 m_osds->queue_scrub_digest_update(m_pl_pg, m_pl_pg->is_scrub_blocking_ops());
554 }
555 });
556
557 m_pl_pg->simple_opc_submit(std::move(ctx));
558 }
559
522d829b 560 dout(10) << __func__ << " (" << m_mode_desc << ") finish" << dendl;
f67539c2
TL
561}
562
563PrimaryLogScrub::PrimaryLogScrub(PrimaryLogPG* pg) : PgScrubber{pg}, m_pl_pg{pg} {}
564
565void PrimaryLogScrub::_scrub_clear_state()
566{
567 dout(15) << __func__ << dendl;
568 m_scrub_cstat = object_stat_collection_t();
569}
570
571void PrimaryLogScrub::stats_of_handled_objects(const object_stat_sum_t& delta_stats,
572 const hobject_t& soid)
573{
574 // We scrub objects in hobject_t order, so objects before m_start have already been
575 // scrubbed and their stats have already been added to the scrubber. Objects after that
576 // point haven't been included in the scrubber's stats accounting yet, so they will be
577 // included when the scrubber gets to that object.
f67539c2
TL
578 if (is_primary() && is_scrub_active()) {
579 if (soid < m_start) {
20effc67
TL
580
581 dout(20) << fmt::format("{} {} < [{},{})", __func__, soid, m_start, m_end) << dendl;
f67539c2 582 m_scrub_cstat.add(delta_stats);
20effc67 583
f67539c2 584 } else {
f67539c2 585
20effc67
TL
586 dout(25) << fmt::format("{} {} >= [{},{})", __func__, soid, m_start, m_end) << dendl;
587 }
f67539c2 588 }
f67539c2 589}