]> git.proxmox.com Git - ceph.git/blame - ceph/src/osd/SnapMapper.cc
import quincy 17.2.0
[ceph.git] / ceph / src / osd / SnapMapper.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include "SnapMapper.h"
16
17#define dout_context cct
18#define dout_subsys ceph_subsys_osd
19#undef dout_prefix
20#define dout_prefix *_dout << "snap_mapper."
21
f67539c2
TL
22using std::make_pair;
23using std::map;
24using std::pair;
25using std::set;
7c673cae 26using std::string;
f67539c2
TL
27using std::vector;
28
29using ceph::bufferlist;
30using ceph::decode;
31using ceph::encode;
32using ceph::timespan_str;
7c673cae 33
9f95a23c
TL
34const string SnapMapper::LEGACY_MAPPING_PREFIX = "MAP_";
35const string SnapMapper::MAPPING_PREFIX = "SNA_";
7c673cae
FG
36const string SnapMapper::OBJECT_PREFIX = "OBJ_";
37
9f95a23c
TL
38const char *SnapMapper::PURGED_SNAP_PREFIX = "PSN_";
39
40/*
41
42 We have a bidirectional mapping, (1) from each snap+obj to object,
43 sorted by snapshot, such that we can enumerate to identify all clones
44 mapped to a particular snapshot, and (2) from object to snaps, so we
45 can identify which reverse mappings exist for any given object (and,
46 e.g., clean up on deletion).
47
48 "MAP_"
49 + ("%016x" % snapid)
50 + "_"
51 + (".%x" % shard_id)
52 + "_"
53 + hobject_t::to_str() ("%llx.%8x.%lx.name...." % pool, hash, snap)
54 -> SnapMapping::Mapping { snap, hoid }
55
56 "SNA_"
57 + ("%lld" % poolid)
58 + "_"
59 + ("%016x" % snapid)
60 + "_"
61 + (".%x" % shard_id)
62 + "_"
63 + hobject_t::to_str() ("%llx.%8x.%lx.name...." % pool, hash, snap)
64 -> SnapMapping::Mapping { snap, hoid }
65
66 "OBJ_" +
67 + (".%x" % shard_id)
68 + hobject_t::to_str()
69 -> SnapMapper::object_snaps { oid, set<snapid_t> }
70
71 */
72
7c673cae
FG
73int OSDriver::get_keys(
74 const std::set<std::string> &keys,
75 std::map<std::string, bufferlist> *out)
76{
11fdf7f2 77 return os->omap_get_values(ch, hoid, keys, out);
7c673cae
FG
78}
79
80int OSDriver::get_next(
81 const std::string &key,
82 pair<std::string, bufferlist> *next)
83{
84 ObjectMap::ObjectMapIterator iter =
11fdf7f2 85 os->get_omap_iterator(ch, hoid);
7c673cae
FG
86 if (!iter) {
87 ceph_abort();
88 return -EINVAL;
89 }
90 iter->upper_bound(key);
91 if (iter->valid()) {
92 if (next)
93 *next = make_pair(iter->key(), iter->value());
94 return 0;
95 } else {
96 return -ENOENT;
97 }
98}
99
9f95a23c 100string SnapMapper::get_prefix(int64_t pool, snapid_t snap)
7c673cae
FG
101{
102 char buf[100];
103 int len = snprintf(
104 buf, sizeof(buf),
9f95a23c
TL
105 "%lld_%.*X_",
106 (long long)pool,
107 (int)(sizeof(snap)*2), static_cast<unsigned>(snap));
7c673cae
FG
108 return MAPPING_PREFIX + string(buf, len);
109}
110
111string SnapMapper::to_raw_key(
112 const pair<snapid_t, hobject_t> &in)
113{
9f95a23c 114 return get_prefix(in.second.pool, in.first) + shard_prefix + in.second.to_str();
7c673cae
FG
115}
116
117pair<string, bufferlist> SnapMapper::to_raw(
118 const pair<snapid_t, hobject_t> &in)
119{
120 bufferlist bl;
11fdf7f2 121 encode(Mapping(in), bl);
7c673cae
FG
122 return make_pair(
123 to_raw_key(in),
124 bl);
125}
126
127pair<snapid_t, hobject_t> SnapMapper::from_raw(
128 const pair<std::string, bufferlist> &image)
129{
9f95a23c 130 using ceph::decode;
7c673cae
FG
131 Mapping map;
132 bufferlist bl(image.second);
11fdf7f2
TL
133 auto bp = bl.cbegin();
134 decode(map, bp);
7c673cae
FG
135 return make_pair(map.snap, map.hoid);
136}
137
138bool SnapMapper::is_mapping(const string &to_test)
139{
140 return to_test.substr(0, MAPPING_PREFIX.size()) == MAPPING_PREFIX;
141}
142
143string SnapMapper::to_object_key(const hobject_t &hoid)
144{
145 return OBJECT_PREFIX + shard_prefix + hoid.to_str();
146}
147
148void SnapMapper::object_snaps::encode(bufferlist &bl) const
149{
150 ENCODE_START(1, 1, bl);
11fdf7f2
TL
151 encode(oid, bl);
152 encode(snaps, bl);
7c673cae
FG
153 ENCODE_FINISH(bl);
154}
155
11fdf7f2 156void SnapMapper::object_snaps::decode(bufferlist::const_iterator &bl)
7c673cae
FG
157{
158 DECODE_START(1, bl);
11fdf7f2
TL
159 decode(oid, bl);
160 decode(snaps, bl);
7c673cae
FG
161 DECODE_FINISH(bl);
162}
163
11fdf7f2
TL
164bool SnapMapper::check(const hobject_t &hoid) const
165{
166 if (hoid.match(mask_bits, match)) {
167 return true;
168 }
169 derr << __func__ << " " << hoid << " mask_bits " << mask_bits
170 << " match 0x" << std::hex << match << std::dec << " is false"
171 << dendl;
172 return false;
173}
174
7c673cae
FG
175int SnapMapper::get_snaps(
176 const hobject_t &oid,
177 object_snaps *out)
178{
11fdf7f2 179 ceph_assert(check(oid));
7c673cae
FG
180 set<string> keys;
181 map<string, bufferlist> got;
182 keys.insert(to_object_key(oid));
183 int r = backend.get_keys(keys, &got);
11fdf7f2
TL
184 if (r < 0) {
185 dout(20) << __func__ << " " << oid << " got err " << r << dendl;
7c673cae 186 return r;
11fdf7f2
TL
187 }
188 if (got.empty()) {
189 dout(20) << __func__ << " " << oid << " got.empty()" << dendl;
7c673cae 190 return -ENOENT;
11fdf7f2 191 }
7c673cae 192 if (out) {
11fdf7f2
TL
193 auto bp = got.begin()->second.cbegin();
194 decode(*out, bp);
7c673cae 195 dout(20) << __func__ << " " << oid << " " << out->snaps << dendl;
28e407b8
AA
196 if (out->snaps.empty()) {
197 dout(1) << __func__ << " " << oid << " empty snapset" << dendl;
11fdf7f2 198 ceph_assert(!cct->_conf->osd_debug_verify_snaps);
28e407b8 199 }
7c673cae
FG
200 } else {
201 dout(20) << __func__ << " " << oid << " (out == NULL)" << dendl;
202 }
203 return 0;
204}
205
206void SnapMapper::clear_snaps(
207 const hobject_t &oid,
208 MapCacher::Transaction<std::string, bufferlist> *t)
209{
210 dout(20) << __func__ << " " << oid << dendl;
11fdf7f2 211 ceph_assert(check(oid));
7c673cae
FG
212 set<string> to_remove;
213 to_remove.insert(to_object_key(oid));
11fdf7f2 214 if (g_conf()->subsys.should_gather<ceph_subsys_osd, 20>()) {
31f18b77
FG
215 for (auto& i : to_remove) {
216 dout(20) << __func__ << " rm " << i << dendl;
217 }
218 }
7c673cae
FG
219 backend.remove_keys(to_remove, t);
220}
221
222void SnapMapper::set_snaps(
223 const hobject_t &oid,
224 const object_snaps &in,
225 MapCacher::Transaction<std::string, bufferlist> *t)
226{
11fdf7f2 227 ceph_assert(check(oid));
7c673cae
FG
228 map<string, bufferlist> to_set;
229 bufferlist bl;
11fdf7f2 230 encode(in, bl);
7c673cae
FG
231 to_set[to_object_key(oid)] = bl;
232 dout(20) << __func__ << " " << oid << " " << in.snaps << dendl;
11fdf7f2 233 if (g_conf()->subsys.should_gather<ceph_subsys_osd, 20>()) {
31f18b77
FG
234 for (auto& i : to_set) {
235 dout(20) << __func__ << " set " << i.first << dendl;
236 }
237 }
7c673cae
FG
238 backend.set_keys(to_set, t);
239}
240
241int SnapMapper::update_snaps(
242 const hobject_t &oid,
243 const set<snapid_t> &new_snaps,
244 const set<snapid_t> *old_snaps_check,
245 MapCacher::Transaction<std::string, bufferlist> *t)
246{
247 dout(20) << __func__ << " " << oid << " " << new_snaps
248 << " was " << (old_snaps_check ? *old_snaps_check : set<snapid_t>())
249 << dendl;
11fdf7f2 250 ceph_assert(check(oid));
7c673cae
FG
251 if (new_snaps.empty())
252 return remove_oid(oid, t);
253
254 object_snaps out;
255 int r = get_snaps(oid, &out);
11fdf7f2
TL
256 // Tolerate missing keys but not disk errors
257 if (r < 0 && r != -ENOENT)
7c673cae
FG
258 return r;
259 if (old_snaps_check)
11fdf7f2 260 ceph_assert(out.snaps == *old_snaps_check);
7c673cae
FG
261
262 object_snaps in(oid, new_snaps);
263 set_snaps(oid, in, t);
264
265 set<string> to_remove;
266 for (set<snapid_t>::iterator i = out.snaps.begin();
267 i != out.snaps.end();
268 ++i) {
269 if (!new_snaps.count(*i)) {
270 to_remove.insert(to_raw_key(make_pair(*i, oid)));
271 }
272 }
11fdf7f2 273 if (g_conf()->subsys.should_gather<ceph_subsys_osd, 20>()) {
31f18b77
FG
274 for (auto& i : to_remove) {
275 dout(20) << __func__ << " rm " << i << dendl;
276 }
277 }
7c673cae
FG
278 backend.remove_keys(to_remove, t);
279 return 0;
280}
281
282void SnapMapper::add_oid(
283 const hobject_t &oid,
284 const set<snapid_t>& snaps,
285 MapCacher::Transaction<std::string, bufferlist> *t)
286{
287 dout(20) << __func__ << " " << oid << " " << snaps << dendl;
11fdf7f2
TL
288 ceph_assert(!snaps.empty());
289 ceph_assert(check(oid));
7c673cae
FG
290 {
291 object_snaps out;
292 int r = get_snaps(oid, &out);
94b18763
FG
293 if (r != -ENOENT) {
294 derr << __func__ << " found existing snaps mapped on " << oid
295 << ", removing" << dendl;
11fdf7f2 296 ceph_assert(!cct->_conf->osd_debug_verify_snaps);
94b18763
FG
297 remove_oid(oid, t);
298 }
7c673cae
FG
299 }
300
301 object_snaps _snaps(oid, snaps);
302 set_snaps(oid, _snaps, t);
303
304 map<string, bufferlist> to_add;
305 for (set<snapid_t>::iterator i = snaps.begin();
306 i != snaps.end();
307 ++i) {
308 to_add.insert(to_raw(make_pair(*i, oid)));
309 }
11fdf7f2 310 if (g_conf()->subsys.should_gather<ceph_subsys_osd, 20>()) {
31f18b77
FG
311 for (auto& i : to_add) {
312 dout(20) << __func__ << " set " << i.first << dendl;
313 }
314 }
7c673cae
FG
315 backend.set_keys(to_add, t);
316}
317
318int SnapMapper::get_next_objects_to_trim(
319 snapid_t snap,
320 unsigned max,
321 vector<hobject_t> *out)
322{
11fdf7f2
TL
323 ceph_assert(out);
324 ceph_assert(out->empty());
1d09f67e
TL
325
326 // if max would be 0, we return ENOENT and the caller would mistakenly
327 // trim the snaptrim queue
328 ceph_assert(max > 0);
7c673cae
FG
329 int r = 0;
330 for (set<string>::iterator i = prefixes.begin();
331 i != prefixes.end() && out->size() < max && r == 0;
332 ++i) {
9f95a23c 333 string prefix(get_prefix(pool, snap) + *i);
7c673cae
FG
334 string pos = prefix;
335 while (out->size() < max) {
336 pair<string, bufferlist> next;
337 r = backend.get_next(pos, &next);
31f18b77
FG
338 dout(20) << __func__ << " get_next(" << pos << ") returns " << r
339 << " " << next << dendl;
7c673cae
FG
340 if (r != 0) {
341 break; // Done
342 }
343
344 if (next.first.substr(0, prefix.size()) !=
345 prefix) {
346 break; // Done with this prefix
347 }
348
11fdf7f2 349 ceph_assert(is_mapping(next.first));
7c673cae 350
31f18b77 351 dout(20) << __func__ << " " << next.first << dendl;
7c673cae 352 pair<snapid_t, hobject_t> next_decoded(from_raw(next));
11fdf7f2
TL
353 ceph_assert(next_decoded.first == snap);
354 ceph_assert(check(next_decoded.second));
7c673cae
FG
355
356 out->push_back(next_decoded.second);
357 pos = next.first;
358 }
359 }
360 if (out->size() == 0) {
361 return -ENOENT;
362 } else {
363 return 0;
364 }
365}
366
367
368int SnapMapper::remove_oid(
369 const hobject_t &oid,
370 MapCacher::Transaction<std::string, bufferlist> *t)
371{
372 dout(20) << __func__ << " " << oid << dendl;
11fdf7f2 373 ceph_assert(check(oid));
7c673cae
FG
374 return _remove_oid(oid, t);
375}
376
377int SnapMapper::_remove_oid(
378 const hobject_t &oid,
379 MapCacher::Transaction<std::string, bufferlist> *t)
380{
381 dout(20) << __func__ << " " << oid << dendl;
382 object_snaps out;
383 int r = get_snaps(oid, &out);
384 if (r < 0)
385 return r;
386
387 clear_snaps(oid, t);
388
389 set<string> to_remove;
390 for (set<snapid_t>::iterator i = out.snaps.begin();
391 i != out.snaps.end();
392 ++i) {
393 to_remove.insert(to_raw_key(make_pair(*i, oid)));
394 }
11fdf7f2 395 if (g_conf()->subsys.should_gather<ceph_subsys_osd, 20>()) {
31f18b77
FG
396 for (auto& i : to_remove) {
397 dout(20) << __func__ << " rm " << i << dendl;
398 }
399 }
7c673cae
FG
400 backend.remove_keys(to_remove, t);
401 return 0;
402}
403
404int SnapMapper::get_snaps(
405 const hobject_t &oid,
406 std::set<snapid_t> *snaps)
407{
11fdf7f2 408 ceph_assert(check(oid));
7c673cae
FG
409 object_snaps out;
410 int r = get_snaps(oid, &out);
411 if (r < 0)
412 return r;
413 if (snaps)
414 snaps->swap(out.snaps);
415 return 0;
416}
9f95a23c
TL
417
418
419// -- purged snaps --
420
421string SnapMapper::make_purged_snap_key(int64_t pool, snapid_t last)
422{
423 char k[80];
424 snprintf(k, sizeof(k), "%s_%llu_%016llx", PURGED_SNAP_PREFIX,
425 (unsigned long long)pool, (unsigned long long)last);
426 return k;
427}
428
429void SnapMapper::make_purged_snap_key_value(
430 int64_t pool, snapid_t begin, snapid_t end, map<string,bufferlist> *m)
431{
432 string k = make_purged_snap_key(pool, end - 1);
433 auto& v = (*m)[k];
434 ceph::encode(pool, v);
435 ceph::encode(begin, v);
436 ceph::encode(end, v);
437}
438
439int SnapMapper::_lookup_purged_snap(
440 CephContext *cct,
441 ObjectStore *store,
442 ObjectStore::CollectionHandle& ch,
443 const ghobject_t& hoid,
444 int64_t pool, snapid_t snap,
445 snapid_t *begin, snapid_t *end)
446{
447 string k = make_purged_snap_key(pool, snap);
448 auto it = store->get_omap_iterator(ch, hoid);
449 it->lower_bound(k);
450 if (!it->valid()) {
451 dout(20) << __func__ << " pool " << pool << " snap " << snap
452 << " key '" << k << "' lower_bound not found" << dendl;
453 return -ENOENT;
454 }
455 if (it->key().find(PURGED_SNAP_PREFIX) != 0) {
456 dout(20) << __func__ << " pool " << pool << " snap " << snap
457 << " key '" << k << "' lower_bound got mismatched prefix '"
458 << it->key() << "'" << dendl;
459 return -ENOENT;
460 }
461 bufferlist v = it->value();
462 auto p = v.cbegin();
463 int64_t gotpool;
464 decode(gotpool, p);
465 decode(*begin, p);
466 decode(*end, p);
467 if (snap < *begin || snap >= *end) {
468 dout(20) << __func__ << " pool " << pool << " snap " << snap
469 << " found [" << *begin << "," << *end << "), no overlap" << dendl;
470 return -ENOENT;
471 }
472 return 0;
473}
474
475void SnapMapper::record_purged_snaps(
476 CephContext *cct,
477 ObjectStore *store,
478 ObjectStore::CollectionHandle& ch,
479 ghobject_t hoid,
480 ObjectStore::Transaction *t,
481 map<epoch_t,mempool::osdmap::map<int64_t,snap_interval_set_t>> purged_snaps)
482{
483 dout(10) << __func__ << " purged_snaps " << purged_snaps << dendl;
484 map<string,bufferlist> m;
485 set<string> rm;
486 for (auto& [epoch, bypool] : purged_snaps) {
487 // index by (pool, snap)
488 for (auto& [pool, snaps] : bypool) {
489 for (auto i = snaps.begin();
490 i != snaps.end();
491 ++i) {
492 snapid_t begin = i.get_start();
493 snapid_t end = i.get_end();
494 snapid_t before_begin, before_end;
495 snapid_t after_begin, after_end;
496 int b = _lookup_purged_snap(cct, store, ch, hoid,
497 pool, begin - 1, &before_begin, &before_end);
498 int a = _lookup_purged_snap(cct, store, ch, hoid,
499 pool, end, &after_begin, &after_end);
500 if (!b && !a) {
501 dout(10) << __func__
502 << " [" << begin << "," << end << ") - joins ["
503 << before_begin << "," << before_end << ") and ["
504 << after_begin << "," << after_end << ")" << dendl;
505 // erase only the begin record; we'll overwrite the end one
506 rm.insert(make_purged_snap_key(pool, before_end - 1));
507 make_purged_snap_key_value(pool, before_begin, after_end, &m);
508 } else if (!b) {
509 dout(10) << __func__
510 << " [" << begin << "," << end << ") - join with earlier ["
511 << before_begin << "," << before_end << ")" << dendl;
512 rm.insert(make_purged_snap_key(pool, before_end - 1));
513 make_purged_snap_key_value(pool, before_begin, end, &m);
514 } else if (!a) {
515 dout(10) << __func__
516 << " [" << begin << "," << end << ") - join with later ["
517 << after_begin << "," << after_end << ")" << dendl;
518 // overwrite after record
519 make_purged_snap_key_value(pool, begin, after_end, &m);
520 } else {
521 make_purged_snap_key_value(pool, begin, end, &m);
522 }
523 }
524 }
525 }
526 t->omap_rmkeys(ch->cid, hoid, rm);
527 t->omap_setkeys(ch->cid, hoid, m);
528 dout(10) << __func__ << " rm " << rm.size() << " keys, set " << m.size()
529 << " keys" << dendl;
530}
531
532
533bool SnapMapper::Scrubber::_parse_p()
534{
535 if (!psit->valid()) {
536 pool = -1;
537 return false;
538 }
539 if (psit->key().find(PURGED_SNAP_PREFIX) != 0) {
540 pool = -1;
541 return false;
542 }
543 bufferlist v = psit->value();
544 auto p = v.cbegin();
545 ceph::decode(pool, p);
546 ceph::decode(begin, p);
547 ceph::decode(end, p);
548 dout(20) << __func__ << " purged_snaps pool " << pool
549 << " [" << begin << "," << end << ")" << dendl;
550 psit->next();
551 return true;
552}
553
554bool SnapMapper::Scrubber::_parse_m()
555{
556 if (!mapit->valid()) {
557 return false;
558 }
559 if (mapit->key().find(MAPPING_PREFIX) != 0) {
560 return false;
561 }
562 auto v = mapit->value();
563 auto p = v.cbegin();
564 mapping.decode(p);
565
566 {
567 unsigned long long p, s;
568 long sh;
569 string k = mapit->key();
570 int r = sscanf(k.c_str(), "SNA_%lld_%llx.%lx", &p, &s, &sh);
571 if (r != 1) {
572 shard = shard_id_t::NO_SHARD;
573 } else {
574 shard = shard_id_t(sh);
575 }
576 }
577 dout(20) << __func__ << " mapping pool " << mapping.hoid.pool
578 << " snap " << mapping.snap
579 << " shard " << shard
580 << " " << mapping.hoid << dendl;
581 mapit->next();
582 return true;
583}
584
585void SnapMapper::Scrubber::run()
586{
587 dout(10) << __func__ << dendl;
588
589 psit = store->get_omap_iterator(ch, purged_snaps_hoid);
590 psit->upper_bound(PURGED_SNAP_PREFIX);
591 _parse_p();
592
593 mapit = store->get_omap_iterator(ch, mapping_hoid);
594 mapit->upper_bound(MAPPING_PREFIX);
595
596 while (_parse_m()) {
597 // advance to next purged_snaps range?
598 while (pool >= 0 &&
599 (mapping.hoid.pool > pool ||
600 (mapping.hoid.pool == pool && mapping.snap >= end))) {
601 _parse_p();
602 }
603 if (pool < 0) {
604 dout(10) << __func__ << " passed final purged_snaps interval, rest ok"
605 << dendl;
606 break;
607 }
608 if (mapping.hoid.pool < pool ||
609 mapping.snap < begin) {
610 // ok
611 dout(20) << __func__ << " ok " << mapping.hoid
612 << " snap " << mapping.snap
613 << " precedes pool " << pool
614 << " purged_snaps [" << begin << "," << end << ")" << dendl;
615 } else {
616 assert(mapping.snap >= begin &&
617 mapping.snap < end &&
618 mapping.hoid.pool == pool);
619 // invalid
620 dout(10) << __func__ << " stray " << mapping.hoid
621 << " snap " << mapping.snap
622 << " in pool " << pool
623 << " shard " << shard
624 << " purged_snaps [" << begin << "," << end << ")" << dendl;
625 stray.emplace_back(std::tuple<int64_t,snapid_t,uint32_t,shard_id_t>(
626 pool, mapping.snap, mapping.hoid.get_hash(),
627 shard
628 ));
629 }
630 }
631
632 dout(10) << __func__ << " end, found " << stray.size() << " stray" << dendl;
633 psit = ObjectMap::ObjectMapIterator();
634 mapit = ObjectMap::ObjectMapIterator();
635}
636
637
638// -------------------------------------
639// legacy conversion/support
640
641string SnapMapper::get_legacy_prefix(snapid_t snap)
642{
643 char buf[100];
644 int len = snprintf(
645 buf, sizeof(buf),
646 "%.*X_",
647 (int)(sizeof(snap)*2), static_cast<unsigned>(snap));
648 return LEGACY_MAPPING_PREFIX + string(buf, len);
649}
650
651string SnapMapper::to_legacy_raw_key(
652 const pair<snapid_t, hobject_t> &in)
653{
654 return get_legacy_prefix(in.first) + shard_prefix + in.second.to_str();
655}
656
657bool SnapMapper::is_legacy_mapping(const string &to_test)
658{
659 return to_test.substr(0, LEGACY_MAPPING_PREFIX.size()) ==
660 LEGACY_MAPPING_PREFIX;
661}
662
663int SnapMapper::convert_legacy(
664 CephContext *cct,
665 ObjectStore *store,
666 ObjectStore::CollectionHandle& ch,
667 ghobject_t hoid,
668 unsigned max)
669{
670 uint64_t n = 0;
671
672 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(ch, hoid);
673 if (!iter) {
674 return -EIO;
675 }
676
677 auto start = ceph::mono_clock::now();
678
679 iter->upper_bound(SnapMapper::LEGACY_MAPPING_PREFIX);
680 map<string,bufferlist> to_set;
681 while (iter->valid()) {
682 bool valid = SnapMapper::is_legacy_mapping(iter->key());
683 if (valid) {
684 SnapMapper::Mapping m;
685 bufferlist bl(iter->value());
686 auto bp = bl.cbegin();
687 decode(m, bp);
688 to_set.emplace(
689 SnapMapper::get_prefix(m.hoid.pool, m.snap),
690 bl);
691 ++n;
692 iter->next();
693 }
694 if (!valid || !iter->valid() || to_set.size() >= max) {
695 ObjectStore::Transaction t;
696 t.omap_setkeys(ch->cid, hoid, to_set);
697 int r = store->queue_transaction(ch, std::move(t));
698 ceph_assert(r == 0);
699 to_set.clear();
700 if (!valid) {
701 break;
702 }
703 dout(10) << __func__ << " converted " << n << " keys" << dendl;
704 }
705 }
706
707 auto end = ceph::mono_clock::now();
708
709 dout(1) << __func__ << " converted " << n << " keys in "
710 << timespan_str(end - start) << dendl;
711
712 // remove the old keys
713 {
714 ObjectStore::Transaction t;
715 string end = SnapMapper::LEGACY_MAPPING_PREFIX;
716 ++end[end.size()-1]; // turn _ to whatever comes after _
717 t.omap_rmkeyrange(ch->cid, hoid,
718 SnapMapper::LEGACY_MAPPING_PREFIX,
719 end);
720 int r = store->queue_transaction(ch, std::move(t));
721 ceph_assert(r == 0);
722 }
723 return 0;
724}