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