From 66bea86ab447b2db8a948c7913dc6c7a4a995c31 Mon Sep 17 00:00:00 2001 From: Manuel Lausch Date: Thu, 30 Jun 2022 14:29:53 +0200 Subject: [PATCH] osd/SnapMapper: fix pacific legacy key conversion and introduce test Octopus modified the SnapMapper key format from __ to ___ When this change was introduced, 94ebe0ea also introduced a conversion with a crucial bug which essentially destroyed legacy keys by mapping them to __ without the object-unique suffix. This commit fixes this conversion going forward, but a fix for existing clusters still needs to be developed. Fixes: https://tracker.ceph.com/issues/56147 Signed-off-by: Manuel Lausch Signed-off-by: Matan Breizman --- src/osd/SnapMapper.cc | 40 ++++++++++++++++++++++++++++++------ src/osd/SnapMapper.h | 5 +++++ src/test/test_snap_mapper.cc | 31 ++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/osd/SnapMapper.cc b/src/osd/SnapMapper.cc index 07c6f57c78ae4..804213b1f2644 100644 --- a/src/osd/SnapMapper.cc +++ b/src/osd/SnapMapper.cc @@ -660,6 +660,38 @@ bool SnapMapper::is_legacy_mapping(const string &to_test) LEGACY_MAPPING_PREFIX; } +/* Octopus modified the SnapMapper key format from + * + * __ + * + * to + * + * ___ + * + * We can't reconstruct the new key format just from the value since the + * Mapping object contains an hobject rather than a ghobject. Instead, + * we exploit the fact that the new format is identical starting at . + * + * Note that the original version of this conversion introduced in 94ebe0ea + * had a crucial bug which essentially destroyed legacy keys by mapping + * them to + * + * __ + * + * without the object-unique suffix. + * See https://tracker.ceph.com/issues/56147 + */ +std::string SnapMapper::convert_legacy_key( + const std::string& old_key, + const bufferlist& value) +{ + auto old = from_raw(make_pair(old_key, value)); + std::string object_suffix = old_key.substr( + SnapMapper::LEGACY_MAPPING_PREFIX.length()); + return SnapMapper::MAPPING_PREFIX + std::to_string(old.second.pool) + + "_" + object_suffix; +} + int SnapMapper::convert_legacy( CephContext *cct, ObjectStore *store, @@ -681,13 +713,9 @@ int SnapMapper::convert_legacy( while (iter->valid()) { bool valid = SnapMapper::is_legacy_mapping(iter->key()); if (valid) { - SnapMapper::Mapping m; - bufferlist bl(iter->value()); - auto bp = bl.cbegin(); - decode(m, bp); to_set.emplace( - SnapMapper::get_prefix(m.hoid.pool, m.snap), - bl); + convert_legacy_key(iter->key(), iter->value()), + iter->value()); ++n; iter->next(); } diff --git a/src/osd/SnapMapper.h b/src/osd/SnapMapper.h index f8c2aff1b20f4..90b0c7c8d82e1 100644 --- a/src/osd/SnapMapper.h +++ b/src/osd/SnapMapper.h @@ -100,6 +100,7 @@ public: * particular snap will group under up to 8 prefixes. */ class SnapMapper { + friend class MapperVerifier; public: CephContext* cct; struct object_snaps { @@ -174,6 +175,10 @@ public: void run(); }; + static std::string convert_legacy_key( + const std::string& old_key, + const bufferlist& value); + static int convert_legacy( CephContext *cct, ObjectStore *store, diff --git a/src/test/test_snap_mapper.cc b/src/test/test_snap_mapper.cc index 50730080d8dc7..77e31ec0eb730 100644 --- a/src/test/test_snap_mapper.cc +++ b/src/test/test_snap_mapper.cc @@ -496,6 +496,21 @@ public: } } + std::pair to_raw( + const std::pair &to_map) { + return mapper->to_raw(to_map); + } + + std::string to_legacy_raw_key( + const std::pair &to_map) { + return mapper->to_legacy_raw_key(to_map); + } + + std::string to_raw_key( + const std::pair &to_map) { + return mapper->to_raw_key(to_map); + } + void trim_snap() { std::lock_guard l{lock}; if (snap_to_hobject.empty()) @@ -652,3 +667,19 @@ TEST_F(SnapMapperTest, MultiPG) { init(50); run(); } + +TEST_F(SnapMapperTest, LegacyKeyConvertion) { + init(1); + auto obj = get_tester().random_hobject(); + snapid_t snapid = random() % 10; + auto snap_obj = make_pair(snapid, obj); + auto raw = get_tester().to_raw(snap_obj); + std::string old_key = get_tester().to_legacy_raw_key(snap_obj); + std::string converted_key = + SnapMapper::convert_legacy_key(old_key, raw.second); + std::string new_key = get_tester().to_raw_key(snap_obj); + std::cout << "Converted: " << old_key << "\nTo: " << converted_key + << "\nNew key: " << new_key << std::endl; + ASSERT_EQ(converted_key, new_key); +} + -- 2.39.5