]>
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 | |
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 |
18 | using std::vector; |
19 | ||
20 | template <class T> | |
21 | static ostream& _prefix(std::ostream* _dout, T* t) | |
f67539c2 | 22 | { |
20effc67 | 23 | return t->gen_prefix(*_dout); |
f67539c2 TL |
24 | } |
25 | ||
26 | using namespace Scrub; | |
f67539c2 TL |
27 | |
28 | bool 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 | ||
45 | void 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 | ||
148 | static 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 | ||
154 | void 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 | ||
171 | int 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 | */ | |
229 | void 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 | ||
563 | PrimaryLogScrub::PrimaryLogScrub(PrimaryLogPG* pg) : PgScrubber{pg}, m_pl_pg{pg} {} | |
564 | ||
565 | void PrimaryLogScrub::_scrub_clear_state() | |
566 | { | |
567 | dout(15) << __func__ << dendl; | |
568 | m_scrub_cstat = object_stat_collection_t(); | |
569 | } | |
570 | ||
571 | void 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 | } |