]>
git.proxmox.com Git - ceph.git/blob - ceph/src/osd/SnapMapper.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #include "SnapMapper.h"
17 #define dout_context cct
18 #define dout_subsys ceph_subsys_osd
20 #define dout_prefix *_dout << "snap_mapper."
24 const string
SnapMapper::LEGACY_MAPPING_PREFIX
= "MAP_";
25 const string
SnapMapper::MAPPING_PREFIX
= "SNA_";
26 const string
SnapMapper::OBJECT_PREFIX
= "OBJ_";
28 const char *SnapMapper::PURGED_SNAP_PREFIX
= "PSN_";
32 We have a bidirectional mapping, (1) from each snap+obj to object,
33 sorted by snapshot, such that we can enumerate to identify all clones
34 mapped to a particular snapshot, and (2) from object to snaps, so we
35 can identify which reverse mappings exist for any given object (and,
36 e.g., clean up on deletion).
43 + hobject_t::to_str() ("%llx.%8x.%lx.name...." % pool, hash, snap)
44 -> SnapMapping::Mapping { snap, hoid }
53 + hobject_t::to_str() ("%llx.%8x.%lx.name...." % pool, hash, snap)
54 -> SnapMapping::Mapping { snap, hoid }
59 -> SnapMapper::object_snaps { oid, set<snapid_t> }
63 int OSDriver::get_keys(
64 const std::set
<std::string
> &keys
,
65 std::map
<std::string
, bufferlist
> *out
)
67 return os
->omap_get_values(ch
, hoid
, keys
, out
);
70 int OSDriver::get_next(
71 const std::string
&key
,
72 pair
<std::string
, bufferlist
> *next
)
74 ObjectMap::ObjectMapIterator iter
=
75 os
->get_omap_iterator(ch
, hoid
);
80 iter
->upper_bound(key
);
83 *next
= make_pair(iter
->key(), iter
->value());
90 string
SnapMapper::get_prefix(int64_t pool
, snapid_t snap
)
97 (int)(sizeof(snap
)*2), static_cast<unsigned>(snap
));
98 return MAPPING_PREFIX
+ string(buf
, len
);
101 string
SnapMapper::to_raw_key(
102 const pair
<snapid_t
, hobject_t
> &in
)
104 return get_prefix(in
.second
.pool
, in
.first
) + shard_prefix
+ in
.second
.to_str();
107 pair
<string
, bufferlist
> SnapMapper::to_raw(
108 const pair
<snapid_t
, hobject_t
> &in
)
111 encode(Mapping(in
), bl
);
117 pair
<snapid_t
, hobject_t
> SnapMapper::from_raw(
118 const pair
<std::string
, bufferlist
> &image
)
122 bufferlist
bl(image
.second
);
123 auto bp
= bl
.cbegin();
125 return make_pair(map
.snap
, map
.hoid
);
128 bool SnapMapper::is_mapping(const string
&to_test
)
130 return to_test
.substr(0, MAPPING_PREFIX
.size()) == MAPPING_PREFIX
;
133 string
SnapMapper::to_object_key(const hobject_t
&hoid
)
135 return OBJECT_PREFIX
+ shard_prefix
+ hoid
.to_str();
138 void SnapMapper::object_snaps::encode(bufferlist
&bl
) const
140 ENCODE_START(1, 1, bl
);
146 void SnapMapper::object_snaps::decode(bufferlist::const_iterator
&bl
)
154 bool SnapMapper::check(const hobject_t
&hoid
) const
156 if (hoid
.match(mask_bits
, match
)) {
159 derr
<< __func__
<< " " << hoid
<< " mask_bits " << mask_bits
160 << " match 0x" << std::hex
<< match
<< std::dec
<< " is false"
165 int SnapMapper::get_snaps(
166 const hobject_t
&oid
,
169 ceph_assert(check(oid
));
171 map
<string
, bufferlist
> got
;
172 keys
.insert(to_object_key(oid
));
173 int r
= backend
.get_keys(keys
, &got
);
175 dout(20) << __func__
<< " " << oid
<< " got err " << r
<< dendl
;
179 dout(20) << __func__
<< " " << oid
<< " got.empty()" << dendl
;
183 auto bp
= got
.begin()->second
.cbegin();
185 dout(20) << __func__
<< " " << oid
<< " " << out
->snaps
<< dendl
;
186 if (out
->snaps
.empty()) {
187 dout(1) << __func__
<< " " << oid
<< " empty snapset" << dendl
;
188 ceph_assert(!cct
->_conf
->osd_debug_verify_snaps
);
191 dout(20) << __func__
<< " " << oid
<< " (out == NULL)" << dendl
;
196 void SnapMapper::clear_snaps(
197 const hobject_t
&oid
,
198 MapCacher::Transaction
<std::string
, bufferlist
> *t
)
200 dout(20) << __func__
<< " " << oid
<< dendl
;
201 ceph_assert(check(oid
));
202 set
<string
> to_remove
;
203 to_remove
.insert(to_object_key(oid
));
204 if (g_conf()->subsys
.should_gather
<ceph_subsys_osd
, 20>()) {
205 for (auto& i
: to_remove
) {
206 dout(20) << __func__
<< " rm " << i
<< dendl
;
209 backend
.remove_keys(to_remove
, t
);
212 void SnapMapper::set_snaps(
213 const hobject_t
&oid
,
214 const object_snaps
&in
,
215 MapCacher::Transaction
<std::string
, bufferlist
> *t
)
217 ceph_assert(check(oid
));
218 map
<string
, bufferlist
> to_set
;
221 to_set
[to_object_key(oid
)] = bl
;
222 dout(20) << __func__
<< " " << oid
<< " " << in
.snaps
<< dendl
;
223 if (g_conf()->subsys
.should_gather
<ceph_subsys_osd
, 20>()) {
224 for (auto& i
: to_set
) {
225 dout(20) << __func__
<< " set " << i
.first
<< dendl
;
228 backend
.set_keys(to_set
, t
);
231 int SnapMapper::update_snaps(
232 const hobject_t
&oid
,
233 const set
<snapid_t
> &new_snaps
,
234 const set
<snapid_t
> *old_snaps_check
,
235 MapCacher::Transaction
<std::string
, bufferlist
> *t
)
237 dout(20) << __func__
<< " " << oid
<< " " << new_snaps
238 << " was " << (old_snaps_check
? *old_snaps_check
: set
<snapid_t
>())
240 ceph_assert(check(oid
));
241 if (new_snaps
.empty())
242 return remove_oid(oid
, t
);
245 int r
= get_snaps(oid
, &out
);
246 // Tolerate missing keys but not disk errors
247 if (r
< 0 && r
!= -ENOENT
)
250 ceph_assert(out
.snaps
== *old_snaps_check
);
252 object_snaps
in(oid
, new_snaps
);
253 set_snaps(oid
, in
, t
);
255 set
<string
> to_remove
;
256 for (set
<snapid_t
>::iterator i
= out
.snaps
.begin();
257 i
!= out
.snaps
.end();
259 if (!new_snaps
.count(*i
)) {
260 to_remove
.insert(to_raw_key(make_pair(*i
, oid
)));
263 if (g_conf()->subsys
.should_gather
<ceph_subsys_osd
, 20>()) {
264 for (auto& i
: to_remove
) {
265 dout(20) << __func__
<< " rm " << i
<< dendl
;
268 backend
.remove_keys(to_remove
, t
);
272 void SnapMapper::add_oid(
273 const hobject_t
&oid
,
274 const set
<snapid_t
>& snaps
,
275 MapCacher::Transaction
<std::string
, bufferlist
> *t
)
277 dout(20) << __func__
<< " " << oid
<< " " << snaps
<< dendl
;
278 ceph_assert(!snaps
.empty());
279 ceph_assert(check(oid
));
282 int r
= get_snaps(oid
, &out
);
284 derr
<< __func__
<< " found existing snaps mapped on " << oid
285 << ", removing" << dendl
;
286 ceph_assert(!cct
->_conf
->osd_debug_verify_snaps
);
291 object_snaps
_snaps(oid
, snaps
);
292 set_snaps(oid
, _snaps
, t
);
294 map
<string
, bufferlist
> to_add
;
295 for (set
<snapid_t
>::iterator i
= snaps
.begin();
298 to_add
.insert(to_raw(make_pair(*i
, oid
)));
300 if (g_conf()->subsys
.should_gather
<ceph_subsys_osd
, 20>()) {
301 for (auto& i
: to_add
) {
302 dout(20) << __func__
<< " set " << i
.first
<< dendl
;
305 backend
.set_keys(to_add
, t
);
308 int SnapMapper::get_next_objects_to_trim(
311 vector
<hobject_t
> *out
)
314 ceph_assert(out
->empty());
316 for (set
<string
>::iterator i
= prefixes
.begin();
317 i
!= prefixes
.end() && out
->size() < max
&& r
== 0;
319 string
prefix(get_prefix(pool
, snap
) + *i
);
321 while (out
->size() < max
) {
322 pair
<string
, bufferlist
> next
;
323 r
= backend
.get_next(pos
, &next
);
324 dout(20) << __func__
<< " get_next(" << pos
<< ") returns " << r
325 << " " << next
<< dendl
;
330 if (next
.first
.substr(0, prefix
.size()) !=
332 break; // Done with this prefix
335 ceph_assert(is_mapping(next
.first
));
337 dout(20) << __func__
<< " " << next
.first
<< dendl
;
338 pair
<snapid_t
, hobject_t
> next_decoded(from_raw(next
));
339 ceph_assert(next_decoded
.first
== snap
);
340 ceph_assert(check(next_decoded
.second
));
342 out
->push_back(next_decoded
.second
);
346 if (out
->size() == 0) {
354 int SnapMapper::remove_oid(
355 const hobject_t
&oid
,
356 MapCacher::Transaction
<std::string
, bufferlist
> *t
)
358 dout(20) << __func__
<< " " << oid
<< dendl
;
359 ceph_assert(check(oid
));
360 return _remove_oid(oid
, t
);
363 int SnapMapper::_remove_oid(
364 const hobject_t
&oid
,
365 MapCacher::Transaction
<std::string
, bufferlist
> *t
)
367 dout(20) << __func__
<< " " << oid
<< dendl
;
369 int r
= get_snaps(oid
, &out
);
375 set
<string
> to_remove
;
376 for (set
<snapid_t
>::iterator i
= out
.snaps
.begin();
377 i
!= out
.snaps
.end();
379 to_remove
.insert(to_raw_key(make_pair(*i
, oid
)));
381 if (g_conf()->subsys
.should_gather
<ceph_subsys_osd
, 20>()) {
382 for (auto& i
: to_remove
) {
383 dout(20) << __func__
<< " rm " << i
<< dendl
;
386 backend
.remove_keys(to_remove
, t
);
390 int SnapMapper::get_snaps(
391 const hobject_t
&oid
,
392 std::set
<snapid_t
> *snaps
)
394 ceph_assert(check(oid
));
396 int r
= get_snaps(oid
, &out
);
400 snaps
->swap(out
.snaps
);
405 // -- purged snaps --
407 string
SnapMapper::make_purged_snap_key(int64_t pool
, snapid_t last
)
410 snprintf(k
, sizeof(k
), "%s_%llu_%016llx", PURGED_SNAP_PREFIX
,
411 (unsigned long long)pool
, (unsigned long long)last
);
415 void SnapMapper::make_purged_snap_key_value(
416 int64_t pool
, snapid_t begin
, snapid_t end
, map
<string
,bufferlist
> *m
)
418 string k
= make_purged_snap_key(pool
, end
- 1);
420 ceph::encode(pool
, v
);
421 ceph::encode(begin
, v
);
422 ceph::encode(end
, v
);
425 int SnapMapper::_lookup_purged_snap(
428 ObjectStore::CollectionHandle
& ch
,
429 const ghobject_t
& hoid
,
430 int64_t pool
, snapid_t snap
,
431 snapid_t
*begin
, snapid_t
*end
)
433 string k
= make_purged_snap_key(pool
, snap
);
434 auto it
= store
->get_omap_iterator(ch
, hoid
);
437 dout(20) << __func__
<< " pool " << pool
<< " snap " << snap
438 << " key '" << k
<< "' lower_bound not found" << dendl
;
441 if (it
->key().find(PURGED_SNAP_PREFIX
) != 0) {
442 dout(20) << __func__
<< " pool " << pool
<< " snap " << snap
443 << " key '" << k
<< "' lower_bound got mismatched prefix '"
444 << it
->key() << "'" << dendl
;
447 bufferlist v
= it
->value();
453 if (snap
< *begin
|| snap
>= *end
) {
454 dout(20) << __func__
<< " pool " << pool
<< " snap " << snap
455 << " found [" << *begin
<< "," << *end
<< "), no overlap" << dendl
;
461 void SnapMapper::record_purged_snaps(
464 ObjectStore::CollectionHandle
& ch
,
466 ObjectStore::Transaction
*t
,
467 map
<epoch_t
,mempool::osdmap::map
<int64_t,snap_interval_set_t
>> purged_snaps
)
469 dout(10) << __func__
<< " purged_snaps " << purged_snaps
<< dendl
;
470 map
<string
,bufferlist
> m
;
472 for (auto& [epoch
, bypool
] : purged_snaps
) {
473 // index by (pool, snap)
474 for (auto& [pool
, snaps
] : bypool
) {
475 for (auto i
= snaps
.begin();
478 snapid_t begin
= i
.get_start();
479 snapid_t end
= i
.get_end();
480 snapid_t before_begin
, before_end
;
481 snapid_t after_begin
, after_end
;
482 int b
= _lookup_purged_snap(cct
, store
, ch
, hoid
,
483 pool
, begin
- 1, &before_begin
, &before_end
);
484 int a
= _lookup_purged_snap(cct
, store
, ch
, hoid
,
485 pool
, end
, &after_begin
, &after_end
);
488 << " [" << begin
<< "," << end
<< ") - joins ["
489 << before_begin
<< "," << before_end
<< ") and ["
490 << after_begin
<< "," << after_end
<< ")" << dendl
;
491 // erase only the begin record; we'll overwrite the end one
492 rm
.insert(make_purged_snap_key(pool
, before_end
- 1));
493 make_purged_snap_key_value(pool
, before_begin
, after_end
, &m
);
496 << " [" << begin
<< "," << end
<< ") - join with earlier ["
497 << before_begin
<< "," << before_end
<< ")" << dendl
;
498 rm
.insert(make_purged_snap_key(pool
, before_end
- 1));
499 make_purged_snap_key_value(pool
, before_begin
, end
, &m
);
502 << " [" << begin
<< "," << end
<< ") - join with later ["
503 << after_begin
<< "," << after_end
<< ")" << dendl
;
504 // overwrite after record
505 make_purged_snap_key_value(pool
, begin
, after_end
, &m
);
507 make_purged_snap_key_value(pool
, begin
, end
, &m
);
512 t
->omap_rmkeys(ch
->cid
, hoid
, rm
);
513 t
->omap_setkeys(ch
->cid
, hoid
, m
);
514 dout(10) << __func__
<< " rm " << rm
.size() << " keys, set " << m
.size()
519 bool SnapMapper::Scrubber::_parse_p()
521 if (!psit
->valid()) {
525 if (psit
->key().find(PURGED_SNAP_PREFIX
) != 0) {
529 bufferlist v
= psit
->value();
531 ceph::decode(pool
, p
);
532 ceph::decode(begin
, p
);
533 ceph::decode(end
, p
);
534 dout(20) << __func__
<< " purged_snaps pool " << pool
535 << " [" << begin
<< "," << end
<< ")" << dendl
;
540 bool SnapMapper::Scrubber::_parse_m()
542 if (!mapit
->valid()) {
545 if (mapit
->key().find(MAPPING_PREFIX
) != 0) {
548 auto v
= mapit
->value();
553 unsigned long long p
, s
;
555 string k
= mapit
->key();
556 int r
= sscanf(k
.c_str(), "SNA_%lld_%llx.%lx", &p
, &s
, &sh
);
558 shard
= shard_id_t::NO_SHARD
;
560 shard
= shard_id_t(sh
);
563 dout(20) << __func__
<< " mapping pool " << mapping
.hoid
.pool
564 << " snap " << mapping
.snap
565 << " shard " << shard
566 << " " << mapping
.hoid
<< dendl
;
571 void SnapMapper::Scrubber::run()
573 dout(10) << __func__
<< dendl
;
575 psit
= store
->get_omap_iterator(ch
, purged_snaps_hoid
);
576 psit
->upper_bound(PURGED_SNAP_PREFIX
);
579 mapit
= store
->get_omap_iterator(ch
, mapping_hoid
);
580 mapit
->upper_bound(MAPPING_PREFIX
);
583 // advance to next purged_snaps range?
585 (mapping
.hoid
.pool
> pool
||
586 (mapping
.hoid
.pool
== pool
&& mapping
.snap
>= end
))) {
590 dout(10) << __func__
<< " passed final purged_snaps interval, rest ok"
594 if (mapping
.hoid
.pool
< pool
||
595 mapping
.snap
< begin
) {
597 dout(20) << __func__
<< " ok " << mapping
.hoid
598 << " snap " << mapping
.snap
599 << " precedes pool " << pool
600 << " purged_snaps [" << begin
<< "," << end
<< ")" << dendl
;
602 assert(mapping
.snap
>= begin
&&
603 mapping
.snap
< end
&&
604 mapping
.hoid
.pool
== pool
);
606 dout(10) << __func__
<< " stray " << mapping
.hoid
607 << " snap " << mapping
.snap
608 << " in pool " << pool
609 << " shard " << shard
610 << " purged_snaps [" << begin
<< "," << end
<< ")" << dendl
;
611 stray
.emplace_back(std::tuple
<int64_t,snapid_t
,uint32_t,shard_id_t
>(
612 pool
, mapping
.snap
, mapping
.hoid
.get_hash(),
618 dout(10) << __func__
<< " end, found " << stray
.size() << " stray" << dendl
;
619 psit
= ObjectMap::ObjectMapIterator();
620 mapit
= ObjectMap::ObjectMapIterator();
624 // -------------------------------------
625 // legacy conversion/support
627 string
SnapMapper::get_legacy_prefix(snapid_t snap
)
633 (int)(sizeof(snap
)*2), static_cast<unsigned>(snap
));
634 return LEGACY_MAPPING_PREFIX
+ string(buf
, len
);
637 string
SnapMapper::to_legacy_raw_key(
638 const pair
<snapid_t
, hobject_t
> &in
)
640 return get_legacy_prefix(in
.first
) + shard_prefix
+ in
.second
.to_str();
643 bool SnapMapper::is_legacy_mapping(const string
&to_test
)
645 return to_test
.substr(0, LEGACY_MAPPING_PREFIX
.size()) ==
646 LEGACY_MAPPING_PREFIX
;
649 int SnapMapper::convert_legacy(
652 ObjectStore::CollectionHandle
& ch
,
658 ObjectMap::ObjectMapIterator iter
= store
->get_omap_iterator(ch
, hoid
);
663 auto start
= ceph::mono_clock::now();
665 iter
->upper_bound(SnapMapper::LEGACY_MAPPING_PREFIX
);
666 map
<string
,bufferlist
> to_set
;
667 while (iter
->valid()) {
668 bool valid
= SnapMapper::is_legacy_mapping(iter
->key());
670 SnapMapper::Mapping m
;
671 bufferlist
bl(iter
->value());
672 auto bp
= bl
.cbegin();
675 SnapMapper::get_prefix(m
.hoid
.pool
, m
.snap
),
680 if (!valid
|| !iter
->valid() || to_set
.size() >= max
) {
681 ObjectStore::Transaction t
;
682 t
.omap_setkeys(ch
->cid
, hoid
, to_set
);
683 int r
= store
->queue_transaction(ch
, std::move(t
));
689 dout(10) << __func__
<< " converted " << n
<< " keys" << dendl
;
693 auto end
= ceph::mono_clock::now();
695 dout(1) << __func__
<< " converted " << n
<< " keys in "
696 << timespan_str(end
- start
) << dendl
;
698 // remove the old keys
700 ObjectStore::Transaction t
;
701 string end
= SnapMapper::LEGACY_MAPPING_PREFIX
;
702 ++end
[end
.size()-1]; // turn _ to whatever comes after _
703 t
.omap_rmkeyrange(ch
->cid
, hoid
,
704 SnapMapper::LEGACY_MAPPING_PREFIX
,
706 int r
= store
->queue_transaction(ch
, std::move(t
));