From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/test/crimson/seastore/test_seastore_cache.cc | 260 +++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 src/test/crimson/seastore/test_seastore_cache.cc (limited to 'src/test/crimson/seastore/test_seastore_cache.cc') diff --git a/src/test/crimson/seastore/test_seastore_cache.cc b/src/test/crimson/seastore/test_seastore_cache.cc new file mode 100644 index 000000000..b249d27e4 --- /dev/null +++ b/src/test/crimson/seastore/test_seastore_cache.cc @@ -0,0 +1,260 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/crimson/gtest_seastar.h" + +#include "crimson/common/log.h" +#include "crimson/os/seastore/cache.h" +#include "crimson/os/seastore/segment_manager/ephemeral.h" + +#include "test/crimson/seastore/test_block.h" + +using namespace crimson; +using namespace crimson::os; +using namespace crimson::os::seastore; + +namespace { + [[maybe_unused]] seastar::logger& logger() { + return crimson::get_logger(ceph_subsys_test); + } +} + +struct cache_test_t : public seastar_test_suite_t { + segment_manager::EphemeralSegmentManagerRef segment_manager; + ExtentPlacementManagerRef epm; + CacheRef cache; + paddr_t current; + journal_seq_t seq = JOURNAL_SEQ_MIN; + + cache_test_t() = default; + + seastar::future submit_transaction( + TransactionRef t) { + auto record = cache->prepare_record(*t, JOURNAL_SEQ_NULL, JOURNAL_SEQ_NULL); + + bufferlist bl; + for (auto &&block : record.extents) { + bl.append(block.bl); + } + + ceph_assert((segment_off_t)bl.length() < + segment_manager->get_segment_size()); + if (current.as_seg_paddr().get_segment_off() + (segment_off_t)bl.length() > + segment_manager->get_segment_size()) + current = paddr_t::make_seg_paddr( + segment_id_t( + current.as_seg_paddr().get_segment_id().device_id(), + current.as_seg_paddr().get_segment_id().device_segment_id() + 1), + 0); + + auto prev = current; + current.as_seg_paddr().set_segment_off( + current.as_seg_paddr().get_segment_off() + + bl.length()); + return segment_manager->segment_write( + prev, + std::move(bl), + true + ).safe_then( + [this, prev, t=std::move(t)]() mutable { + cache->complete_commit(*t, prev, seq /* TODO */); + return prev; + }, + crimson::ct_error::all_same_way([](auto e) { + ASSERT_FALSE("failed to submit"); + }) + ); + } + + auto get_transaction() { + return cache->create_transaction( + Transaction::src_t::MUTATE, "test_cache", false); + } + + template + auto get_extent(Transaction &t, Args&&... args) { + return with_trans_intr( + t, + [this](auto &&... args) { + return cache->get_extent(args...); + }, + std::forward(args)...); + } + + seastar::future<> set_up_fut() final { + segment_manager = segment_manager::create_test_ephemeral(); + return segment_manager->init( + ).safe_then([this] { + return segment_manager->mkfs( + segment_manager::get_ephemeral_device_config(0, 1, 0)); + }).safe_then([this] { + epm.reset(new ExtentPlacementManager()); + cache.reset(new Cache(*epm)); + current = paddr_t::make_seg_paddr(segment_id_t(segment_manager->get_device_id(), 0), 0); + epm->test_init_no_background(segment_manager.get()); + return seastar::do_with( + get_transaction(), + [this](auto &ref_t) { + cache->init(); + return with_trans_intr(*ref_t, [&](auto &t) { + return cache->mkfs(t); + }).safe_then([this, &ref_t] { + return submit_transaction(std::move(ref_t) + ).then([](auto p) {}); + }); + }); + }).handle_error( + crimson::ct_error::all_same_way([](auto e) { + ASSERT_FALSE("failed to submit"); + }) + ); + } + + seastar::future<> tear_down_fut() final { + return cache->close( + ).safe_then([this] { + segment_manager.reset(); + epm.reset(); + cache.reset(); + }).handle_error( + Cache::close_ertr::assert_all{} + ); + } +}; + +TEST_F(cache_test_t, test_addr_fixup) +{ + run_async([this] { + paddr_t addr; + int csum = 0; + { + auto t = get_transaction(); + auto extent = cache->alloc_new_extent( + *t, + TestBlockPhysical::SIZE, + placement_hint_t::HOT, + 0); + extent->set_contents('c'); + csum = extent->get_crc32c(); + submit_transaction(std::move(t)).get0(); + addr = extent->get_paddr(); + } + { + auto t = get_transaction(); + auto extent = get_extent( + *t, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + ASSERT_EQ(extent->get_paddr(), addr); + ASSERT_EQ(extent->get_crc32c(), csum); + } + }); +} + +TEST_F(cache_test_t, test_dirty_extent) +{ + run_async([this] { + paddr_t addr; + int csum = 0; + int csum2 = 0; + { + // write out initial test block + auto t = get_transaction(); + auto extent = cache->alloc_new_extent( + *t, + TestBlockPhysical::SIZE, + placement_hint_t::HOT, + 0); + extent->set_contents('c'); + csum = extent->get_crc32c(); + auto reladdr = extent->get_paddr(); + ASSERT_TRUE(reladdr.is_relative()); + { + // test that read with same transaction sees new block though + // uncommitted + auto extent = get_extent( + *t, + reladdr, + TestBlockPhysical::SIZE).unsafe_get0(); + ASSERT_TRUE(extent->is_clean()); + ASSERT_TRUE(extent->is_pending()); + ASSERT_TRUE(extent->get_paddr().is_relative()); + ASSERT_EQ(extent->get_version(), 0); + ASSERT_EQ(csum, extent->get_crc32c()); + } + submit_transaction(std::move(t)).get0(); + addr = extent->get_paddr(); + } + { + // test that consecutive reads on the same extent get the same ref + auto t = get_transaction(); + auto extent = get_extent( + *t, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + auto t2 = get_transaction(); + auto extent2 = get_extent( + *t2, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + ASSERT_EQ(&*extent, &*extent2); + } + { + // read back test block + auto t = get_transaction(); + auto extent = get_extent( + *t, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + // duplicate and reset contents + extent = cache->duplicate_for_write(*t, extent)->cast(); + extent->set_contents('c'); + csum2 = extent->get_crc32c(); + ASSERT_EQ(extent->get_paddr(), addr); + { + // test that concurrent read with fresh transaction sees old + // block + auto t2 = get_transaction(); + auto extent = get_extent( + *t2, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + ASSERT_TRUE(extent->is_clean()); + ASSERT_FALSE(extent->is_pending()); + ASSERT_EQ(addr, extent->get_paddr()); + ASSERT_EQ(extent->get_version(), 0); + ASSERT_EQ(csum, extent->get_crc32c()); + } + { + // test that read with same transaction sees new block + auto extent = get_extent( + *t, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + ASSERT_TRUE(extent->is_dirty()); + ASSERT_TRUE(extent->is_pending()); + ASSERT_EQ(addr, extent->get_paddr()); + ASSERT_EQ(extent->get_version(), 1); + ASSERT_EQ(csum2, extent->get_crc32c()); + } + // submit transaction + submit_transaction(std::move(t)).get0(); + ASSERT_TRUE(extent->is_dirty()); + ASSERT_EQ(addr, extent->get_paddr()); + ASSERT_EQ(extent->get_version(), 1); + ASSERT_EQ(extent->get_crc32c(), csum2); + } + { + // test that fresh transaction now sees newly dirty block + auto t = get_transaction(); + auto extent = get_extent( + *t, + addr, + TestBlockPhysical::SIZE).unsafe_get0(); + ASSERT_TRUE(extent->is_dirty()); + ASSERT_EQ(addr, extent->get_paddr()); + ASSERT_EQ(extent->get_version(), 1); + ASSERT_EQ(csum2, extent->get_crc32c()); + } + }); +} -- cgit v1.2.3