mirror of
https://github.com/ceph/ceph
synced 2025-01-18 00:43:38 +00:00
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 <sjust@redhat.com>
This commit is contained in:
parent
2fe1469c2b
commit
9ab4acd484
@ -126,20 +126,19 @@ struct test_block_mutator_t {
|
||||
offset_distribution = std::uniform_int_distribution<uint16_t>(
|
||||
0, TestBlock::SIZE - 1);
|
||||
|
||||
std::default_random_engine generator = std::default_random_engine(0);
|
||||
|
||||
std::uniform_int_distribution<uint16_t> length_distribution(uint16_t offset) {
|
||||
return std::uniform_int_distribution<uint16_t>(
|
||||
0, TestBlock::SIZE - offset - 1);
|
||||
}
|
||||
|
||||
|
||||
void mutate(TestBlock &block) {
|
||||
auto offset = offset_distribution(generator);
|
||||
template <typename generator_t>
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
|
||||
// vim: ts=8 sw=2 smarttab
|
||||
|
||||
#include <random>
|
||||
|
||||
#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<SegmentManager> segment_manager;
|
||||
SegmentCleaner segment_cleaner;
|
||||
Journal journal;
|
||||
Cache cache;
|
||||
std::unique_ptr<SegmentCleaner> segment_cleaner;
|
||||
std::unique_ptr<Journal> journal;
|
||||
std::unique_ptr<Cache> cache;
|
||||
LBAManagerRef lba_manager;
|
||||
TransactionManager tm;
|
||||
std::unique_ptr<TransactionManager> 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>(
|
||||
SegmentCleaner::config_t::default_from_segment_manager(
|
||||
*segment_manager));
|
||||
journal = std::make_unique<Journal>(*segment_manager);
|
||||
cache = std::make_unique<Cache>(*segment_manager);
|
||||
lba_manager = lba_manager::create_lba_manager(*segment_manager, *cache);
|
||||
tm = std::make_unique<TransactionManager>(
|
||||
*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<char>(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<TestBlock>(
|
||||
auto extent = tm->alloc_extent<TestBlock>(
|
||||
*(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<TestBlock>(
|
||||
auto ret_list = tm->read_extents<TestBlock>(
|
||||
*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<TestBlock>();
|
||||
auto ext = tm->get_mutable_extent(*t.t, ref)->cast<TestBlock>();
|
||||
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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user