From 78eea58f3328cb1d42ef40162dc32219d8ba37e9 Mon Sep 17 00:00:00 2001 From: Igor Fedotov Date: Wed, 19 Apr 2023 18:00:10 +0300 Subject: [PATCH] test/bluestore_types: introduce basic UT for new ExtentMap::dup Signed-off-by: Igor Fedotov --- src/test/objectstore/test_bluestore_types.cc | 166 +++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/src/test/objectstore/test_bluestore_types.cc b/src/test/objectstore/test_bluestore_types.cc index 18ccaff913d2a..eac7b223cdbd0 100644 --- a/src/test/objectstore/test_bluestore_types.cc +++ b/src/test/objectstore/test_bluestore_types.cc @@ -1285,6 +1285,172 @@ TEST(ExtentMap, compress_extent_map) } +TEST(ExtentMap, dup_extent_map) +{ + BlueStore store(g_ceph_context, "", 4096); + BlueStore::OnodeCacheShard *oc = BlueStore::OnodeCacheShard::create( + g_ceph_context, "lru", NULL); + BlueStore::BufferCacheShard *bc = BlueStore::BufferCacheShard::create( + g_ceph_context, "lru", NULL); + + size_t csum_order = 12; //1^12 = 4096 bytes + auto coll = ceph::make_ref(&store, oc, bc, coll_t()); + std::unique_ptr formatter(Formatter::create("json")); + + /////////////////////////// + //constructing onode1 + BlueStore::OnodeRef onode1(new BlueStore::Onode(coll.get(), ghobject_t(), "")); + + //BlueStore::ExtentMap em1(&onode1, + // g_ceph_context->_conf->bluestore_extent_map_inline_shard_prealloc_size); + BlueStore::ExtentMap& em1 = onode1->extent_map; + /////////////////////////// + // constructing extent/Blob: 0x0~2000 at <0x100000~2000> + size_t ext1_offs = 0x0; + size_t ext1_len = 0x2000; + size_t ext1_boffs = 0x0; + BlueStore::BlobRef b1(new BlueStore::Blob); + b1->shared_blob = new BlueStore::SharedBlob(coll.get()); + auto &_b1 = b1->dirty_blob(); + _b1.init_csum(Checksummer::CSUM_CRC32C, csum_order, ext1_len); + for(size_t i = 0; i < _b1.get_csum_count(); i++) { + *(_b1.get_csum_item_ptr(i)) = i + 1; + } + PExtentVector pextents; + pextents.emplace_back(0x100000, ext1_len); + _b1.allocated(0, ext1_len, pextents); + + auto *ext1 = new BlueStore::Extent(ext1_offs, ext1_boffs, ext1_len, b1); + em1.extent_map.insert(*ext1); + b1->get_ref(coll.get(), ext1->blob_offset, ext1->length); + _b1.mark_used(ext1->blob_offset, ext1->length); + + /////////////////////////// + //constructing onode2 which is a full clone from onode1 + BlueStore::OnodeRef onode2(new BlueStore::Onode(coll.get(), ghobject_t(), "")); + //BlueStore::ExtentMap em2(&onode2, + // g_ceph_context->_conf->bluestore_extent_map_inline_shard_prealloc_size); + BlueStore::ExtentMap& em2 = onode2->extent_map; + { + BlueStore::TransContext txc(store.cct, coll.get(), nullptr, nullptr); + + //em1.dup(&store, &txc, coll, em2, ext1_offs, ext1_len, ext1_offs); + onode1->extent_map.dup(&store, &txc, coll, onode1, onode2, ext1_offs, ext1_len, ext1_offs); + + em1.dump(formatter.get()); // see the log if any + formatter->flush(std::cout); + std::cout << std::endl; + em2.dump(formatter.get()); + formatter->flush(std::cout); + std::cout << std::endl; + + ASSERT_TRUE(b1->get_blob().is_shared()); + ASSERT_EQ(b1->get_referenced_bytes(), ext1_len); + + BlueStore::BlobRef b2 = em2.seek_lextent(ext1_offs)->blob; + ASSERT_TRUE(b2->get_blob().is_shared()); + ASSERT_EQ(b2->get_referenced_bytes(), ext1_len); + ASSERT_EQ(b1->shared_blob, b2->shared_blob); + auto &_b2 = b2->get_blob(); + ASSERT_EQ(_b1.get_csum_count(), _b2.get_csum_count()); + for(size_t i = 0; i < _b2.get_csum_count(); i++) { + ASSERT_EQ(*(_b1.get_csum_item_ptr(i)), *(_b2.get_csum_item_ptr(i))); + } + } + + /////////////////////////// + //constructing onode3 which is partial clone (tail part) from onode2 + BlueStore::OnodeRef onode3(new BlueStore::Onode(coll.get(), ghobject_t(), "")); + //BlueStore::ExtentMap em3(&onode3, + // g_ceph_context->_conf->bluestore_extent_map_inline_shard_prealloc_size); + BlueStore::ExtentMap& em3 = onode3->extent_map; + { + size_t clone_shift = 0x1000; + ceph_assert(ext1_len > clone_shift); + size_t clone_offs = ext1_offs + clone_shift; + size_t clone_len = ext1_len - clone_shift; + BlueStore::TransContext txc(store.cct, coll.get(), nullptr, nullptr); + + onode1->extent_map.dup(&store, &txc, coll, onode1, onode3, clone_offs, clone_len, clone_offs); + em1.dump(formatter.get()); // see the log if any + formatter->flush(std::cout); + std::cout << std::endl; + em3.dump(formatter.get()); + formatter->flush(std::cout); + std::cout << std::endl; + + // make sure (basically) onode1&2 are unmodified + BlueStore::BlobRef b1 = em1.seek_lextent(ext1_offs)->blob; + BlueStore::BlobRef b2 = em2.seek_lextent(ext1_offs)->blob; + ASSERT_EQ(b1->shared_blob, b2->shared_blob); + + BlueStore::Extent &ext3 = *em3.seek_lextent(clone_offs); + ASSERT_EQ(ext3.blob_offset, clone_shift); + ASSERT_EQ(ext3.length, clone_len); + BlueStore::BlobRef b3 = ext3.blob; + ASSERT_TRUE(b3->get_blob().is_shared()); + ASSERT_EQ(b3->shared_blob, b1->shared_blob); + ASSERT_EQ(b3->get_referenced_bytes(), clone_len); + auto ll = b3->get_blob().get_logical_length(); + ASSERT_EQ(ll, ext1_len); + auto &_b3 = b3->get_blob(); + ASSERT_EQ(_b1.get_csum_count(), _b3.get_csum_count()); + for(size_t i = 0; i < _b3.get_csum_count(); i++) { + ASSERT_EQ(*(_b1.get_csum_item_ptr(i)), *(_b3.get_csum_item_ptr(i))); + } + } + + /////////////////////////// + //constructing onode4 which is partial clone (head part) from onode2 + BlueStore::OnodeRef onode4(new BlueStore::Onode(coll.get(), ghobject_t(), "")); + //BlueStore::ExtentMap em4(&onode4, + // g_ceph_context->_conf->bluestore_extent_map_inline_shard_prealloc_size); + BlueStore::ExtentMap& em4 = onode4->extent_map; + + { + size_t clone_shift = 0; + size_t clone_len = 0x1000; + ceph_assert(ext1_len >= clone_shift + clone_len); + size_t clone_offs = ext1_offs + clone_shift; + BlueStore::TransContext txc(store.cct, coll.get(), nullptr, nullptr); + + onode2->extent_map.dup(&store, &txc, coll, onode2, onode4, clone_offs, clone_len, clone_offs); + em2.dump(formatter.get()); // see the log if any + formatter->flush(std::cout); + std::cout << std::endl; + em4.dump(formatter.get()); + formatter->flush(std::cout); + std::cout << std::endl; + + // make sure (basically) onode1&2 are unmodified + BlueStore::BlobRef b1 = em1.seek_lextent(ext1_offs)->blob; + BlueStore::BlobRef b2 = em2.seek_lextent(ext1_offs)->blob; + BlueStore::BlobRef b3 = em3.seek_lextent(ext1_offs)->blob; + ASSERT_EQ(b1->shared_blob, b2->shared_blob); + ASSERT_EQ(b1->shared_blob, b3->shared_blob); + auto &_b2 = b2->get_blob(); + + BlueStore::Extent &ext4 = *em4.seek_lextent(clone_offs); + ASSERT_EQ(ext4.blob_offset, clone_shift); + ASSERT_EQ(ext4.length, clone_len); + BlueStore::BlobRef b4 = ext4.blob; + ASSERT_TRUE(b4->get_blob().is_shared()); + ASSERT_EQ(b4->shared_blob, b2->shared_blob); + ASSERT_EQ(b4->get_referenced_bytes(), clone_len); + auto &_b4 = b4->get_blob(); + auto ll = _b4.get_logical_length(); + auto csum_entries = ll / (1 << csum_order); + ASSERT_EQ(ll, clone_len); + ASSERT_EQ(csum_entries, _b4.get_csum_count()); + + ASSERT_GT(_b2.get_csum_count(), csum_entries); + for(size_t i = 0; i < csum_entries; i++) { + ASSERT_EQ(*(_b2.get_csum_item_ptr(i)), *(_b4.get_csum_item_ptr(i))); + } + } +} + + void clear_and_dispose(BlueStore::old_extent_map_t& old_em) { auto oep = old_em.begin(); -- 2.39.5