summaryrefslogtreecommitdiffstats
path: root/src/test/crimson/seastore/test_seastore_cache.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/test/crimson/seastore/test_seastore_cache.cc
parentInitial commit. (diff)
downloadceph-upstream/18.2.2.tar.xz
ceph-upstream/18.2.2.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/crimson/seastore/test_seastore_cache.cc')
-rw-r--r--src/test/crimson/seastore/test_seastore_cache.cc260
1 files changed, 260 insertions, 0 deletions
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<paddr_t> 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 <typename T, typename... Args>
+ auto get_extent(Transaction &t, Args&&... args) {
+ return with_trans_intr(
+ t,
+ [this](auto &&... args) {
+ return cache->get_extent<T>(args...);
+ },
+ std::forward<Args>(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<TestBlockPhysical>(
+ *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<TestBlockPhysical>(
+ *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<TestBlockPhysical>(
+ *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<TestBlockPhysical>(
+ *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<TestBlockPhysical>(
+ *t,
+ addr,
+ TestBlockPhysical::SIZE).unsafe_get0();
+ auto t2 = get_transaction();
+ auto extent2 = get_extent<TestBlockPhysical>(
+ *t2,
+ addr,
+ TestBlockPhysical::SIZE).unsafe_get0();
+ ASSERT_EQ(&*extent, &*extent2);
+ }
+ {
+ // read back test block
+ auto t = get_transaction();
+ auto extent = get_extent<TestBlockPhysical>(
+ *t,
+ addr,
+ TestBlockPhysical::SIZE).unsafe_get0();
+ // duplicate and reset contents
+ extent = cache->duplicate_for_write(*t, extent)->cast<TestBlockPhysical>();
+ 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<TestBlockPhysical>(
+ *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<TestBlockPhysical>(
+ *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<TestBlockPhysical>(
+ *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());
+ }
+ });
+}