From 9ab4acd484cdc75b0d162046785a488bb6b043c0 Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Thu, 20 Aug 2020 14:17:31 -0700 Subject: [PATCH] test/crimson/seastore/test_transaction_manager: add random overwrite test Also improves replay() by recycling all structures except for the segment_manager. Signed-off-by: Samuel Just --- src/test/crimson/seastore/test_block.h | 11 +- .../seastore/test_transaction_manager.cc | 140 ++++++++++++++---- 2 files changed, 118 insertions(+), 33 deletions(-) diff --git a/src/test/crimson/seastore/test_block.h b/src/test/crimson/seastore/test_block.h index e105ccec7533b..44ec65a237516 100644 --- a/src/test/crimson/seastore/test_block.h +++ b/src/test/crimson/seastore/test_block.h @@ -126,20 +126,19 @@ struct test_block_mutator_t { offset_distribution = std::uniform_int_distribution( 0, TestBlock::SIZE - 1); - std::default_random_engine generator = std::default_random_engine(0); - std::uniform_int_distribution length_distribution(uint16_t offset) { return std::uniform_int_distribution( 0, TestBlock::SIZE - offset - 1); } - void mutate(TestBlock &block) { - auto offset = offset_distribution(generator); + template + void mutate(TestBlock &block, generator_t &gen) { + auto offset = offset_distribution(gen); block.set_contents( - contents_distribution(generator), + contents_distribution(gen), offset, - length_distribution(offset)(generator)); + length_distribution(offset)(gen)); } }; diff --git a/src/test/crimson/seastore/test_transaction_manager.cc b/src/test/crimson/seastore/test_transaction_manager.cc index e0e72be8a99af..843618fb303cb 100644 --- a/src/test/crimson/seastore/test_transaction_manager.cc +++ b/src/test/crimson/seastore/test_transaction_manager.cc @@ -1,6 +1,8 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab +#include + #include "test/crimson/gtest_seastar.h" #include "crimson/os/seastore/segment_cleaner.h" @@ -47,31 +49,57 @@ std::ostream &operator<<(std::ostream &lhs, const test_extent_record_t &rhs) { struct transaction_manager_test_t : public seastar_test_suite_t { std::unique_ptr segment_manager; - SegmentCleaner segment_cleaner; - Journal journal; - Cache cache; + std::unique_ptr segment_cleaner; + std::unique_ptr journal; + std::unique_ptr cache; LBAManagerRef lba_manager; - TransactionManager tm; + std::unique_ptr tm; + + std::random_device rd; + std::mt19937 gen; transaction_manager_test_t() : segment_manager(create_ephemeral(segment_manager::DEFAULT_TEST_EPHEMERAL)), - segment_cleaner( - SegmentCleaner::config_t::default_from_segment_manager( - *segment_manager)), - journal(*segment_manager), - cache(*segment_manager), - lba_manager( - lba_manager::create_lba_manager(*segment_manager, cache)), - tm(*segment_manager, segment_cleaner, journal, cache, *lba_manager) { - journal.set_segment_provider(&segment_cleaner); - segment_cleaner.set_extent_callback(&tm); + gen(rd()) { + init(); + } + + void init() { + segment_cleaner = std::make_unique( + SegmentCleaner::config_t::default_from_segment_manager( + *segment_manager)); + journal = std::make_unique(*segment_manager); + cache = std::make_unique(*segment_manager); + lba_manager = lba_manager::create_lba_manager(*segment_manager, *cache); + tm = std::make_unique( + *segment_manager, *segment_cleaner, *journal, *cache, *lba_manager); + + journal->set_segment_provider(&*segment_cleaner); + segment_cleaner->set_extent_callback(&*tm); + } + + void destroy() { + tm.reset(); + lba_manager.reset(); + cache.reset(); + journal.reset(); + segment_cleaner.reset(); + } + + laddr_t get_random_laddr(size_t block_size, laddr_t limit) { + return block_size * + std::uniform_int_distribution<>(0, (limit / block_size) - 1)(gen); + } + + char get_random_contents() { + return static_cast(std::uniform_int_distribution<>(0, 255)(gen)); } seastar::future<> set_up_fut() final { return segment_manager->init().safe_then([this] { - return tm.mkfs(); + return tm->mkfs(); }).safe_then([this] { - return tm.mount(); + return tm->mount(); }).handle_error( crimson::ct_error::all_same_way([] { ASSERT_FALSE("Unable to mount"); @@ -80,7 +108,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { } seastar::future<> tear_down_fut() final { - return tm.close( + return tm->close( ).handle_error( crimson::ct_error::all_same_way([] { ASSERT_FALSE("Unable to close"); @@ -135,7 +163,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { }; test_transaction_t create_transaction() { - return { tm.create_transaction(), test_mappings }; + return { tm->create_transaction(), test_mappings }; } TestBlockRef alloc_extent( @@ -143,7 +171,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { laddr_t hint, extent_len_t len, char contents) { - auto extent = tm.alloc_extent( + auto extent = tm->alloc_extent( *(t.t), hint, len).unsafe_get0(); @@ -154,9 +182,24 @@ struct transaction_manager_test_t : public seastar_test_suite_t { return extent; } + TestBlockRef alloc_extent( + test_transaction_t &t, + laddr_t hint, + extent_len_t len) { + return alloc_extent( + t, + hint, + len, + get_random_contents()); + } + void replay() { - tm.close().unsafe_get(); - tm.mount().unsafe_get(); + tm->close().unsafe_get(); + auto next = segment_cleaner->get_next(); + destroy(); + init(); + segment_cleaner->set_next(next); + tm->mount().unsafe_get(); } void check_mappings() { @@ -171,7 +214,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { ceph_assert(t.mappings.count(addr)); ceph_assert(t.mappings[addr].desc.len == len); - auto ret_list = tm.read_extents( + auto ret_list = tm->read_extents( *t.t, addr, len ).unsafe_get0(); EXPECT_EQ(ret_list.size(), 1); @@ -188,10 +231,10 @@ struct transaction_manager_test_t : public seastar_test_suite_t { TestBlockRef ref) { ceph_assert(t.mappings.count(ref->get_laddr())); ceph_assert(t.mappings[ref->get_laddr()].desc.len == ref->get_length()); - auto ext = tm.get_mutable_extent(*t.t, ref)->cast(); + auto ext = tm->get_mutable_extent(*t.t, ref)->cast(); EXPECT_EQ(ext->get_laddr(), ref->get_laddr()); EXPECT_EQ(ext->get_desc(), ref->get_desc()); - mutator.mutate(*ext); + mutator.mutate(*ext, gen); t.mappings[ext->get_laddr()].update(ext->get_desc()); return ext; } @@ -199,7 +242,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { void inc_ref(test_transaction_t &t, laddr_t offset) { ceph_assert(t.mappings.count(offset)); ceph_assert(t.mappings[offset].refcount > 0); - auto refcnt = tm.inc_ref(*t.t, offset).unsafe_get0(); + auto refcnt = tm->inc_ref(*t.t, offset).unsafe_get0(); t.mappings[offset].refcount++; EXPECT_EQ(refcnt, t.mappings[offset].refcount); } @@ -207,7 +250,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { void dec_ref(test_transaction_t &t, laddr_t offset) { ceph_assert(t.mappings.count(offset)); ceph_assert(t.mappings[offset].refcount > 0); - auto refcnt = tm.dec_ref(*t.t, offset).unsafe_get0(); + auto refcnt = tm->dec_ref(*t.t, offset).unsafe_get0(); t.mappings[offset].refcount--; EXPECT_EQ(refcnt, t.mappings[offset].refcount); if (t.mappings[offset].refcount == 0) { @@ -224,7 +267,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t { } void submit_transaction(test_transaction_t t) { - tm.submit_transaction(std::move(t.t)).unsafe_get(); + tm->submit_transaction(std::move(t.t)).unsafe_get(); test_mappings = t.mappings; } }; @@ -382,3 +425,46 @@ TEST_F(transaction_manager_test_t, cause_lba_split) check_mappings(); }); } + +TEST_F(transaction_manager_test_t, random_writes) +{ + constexpr size_t TOTAL = 4<<20; + constexpr size_t BSIZE = 4<<10; + constexpr size_t PADDING_SIZE = 256<<10; + constexpr size_t BLOCKS = TOTAL / BSIZE; + run_async([this] { + for (unsigned i = 0; i < BLOCKS; ++i) { + auto t = create_transaction(); + auto extent = alloc_extent( + t, + i * BSIZE, + BSIZE); + ASSERT_EQ(i * BSIZE, extent->get_laddr()); + submit_transaction(std::move(t)); + } + + for (unsigned i = 0; i < 5; ++i) { + for (unsigned j = 0; j < 50; ++j) { + auto t = create_transaction(); + for (unsigned k = 0; k < 2; ++k) { + auto ext = get_extent( + t, + get_random_laddr(BSIZE, TOTAL), + BSIZE); + auto mut = mutate_extent(t, ext); + // pad out transaction + auto padding = alloc_extent( + t, + TOTAL + (k * PADDING_SIZE), + PADDING_SIZE); + dec_ref(t, padding->get_laddr()); + } + submit_transaction(std::move(t)); + } + replay(); + logger().debug("random_writes: checking"); + check_mappings(); + logger().debug("random_writes: done replaying/checking"); + } + }); +} -- 2.39.5