diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/test/crimson/seastore/test_object_data_handler.cc | |
parent | Initial commit. (diff) | |
download | ceph-b26c4052f3542036551aa9dec9caa4226e456195.tar.xz ceph-b26c4052f3542036551aa9dec9caa4226e456195.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_object_data_handler.cc')
-rw-r--r-- | src/test/crimson/seastore/test_object_data_handler.cc | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/src/test/crimson/seastore/test_object_data_handler.cc b/src/test/crimson/seastore/test_object_data_handler.cc new file mode 100644 index 000000000..6510cb5d9 --- /dev/null +++ b/src/test/crimson/seastore/test_object_data_handler.cc @@ -0,0 +1,431 @@ +// -*- 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 "test/crimson/seastore/transaction_manager_test_state.h" + +#include "crimson/os/seastore/onode.h" +#include "crimson/os/seastore/object_data_handler.h" + +using namespace crimson; +using namespace crimson::os; +using namespace crimson::os::seastore; + +#define MAX_OBJECT_SIZE (16<<20) +#define DEFAULT_OBJECT_DATA_RESERVATION (16<<20) +#define DEFAULT_OBJECT_METADATA_RESERVATION (16<<20) + +namespace { + [[maybe_unused]] seastar::logger& logger() { + return crimson::get_logger(ceph_subsys_test); + } +} + +class TestOnode final : public Onode { + onode_layout_t layout; + bool dirty = false; + +public: + TestOnode(uint32_t ddr, uint32_t dmr) : Onode(ddr, dmr) {} + const onode_layout_t &get_layout() const final { + return layout; + } + onode_layout_t &get_mutable_layout(Transaction &t) final { + dirty = true; + return layout; + } + bool is_alive() const { + return true; + } + bool is_dirty() const { return dirty; } + laddr_t get_hint() const final {return L_ADDR_MIN; } + ~TestOnode() final = default; +}; + +struct object_data_handler_test_t: + public seastar_test_suite_t, + TMTestState { + OnodeRef onode; + + bufferptr known_contents; + extent_len_t size = 0; + + object_data_handler_test_t() {} + + void write(Transaction &t, objaddr_t offset, extent_len_t len, char fill) { + ceph_assert(offset + len <= known_contents.length()); + size = std::max<extent_len_t>(size, offset + len); + memset( + known_contents.c_str() + offset, + fill, + len); + bufferlist bl; + bl.append( + bufferptr( + known_contents, + offset, + len)); + with_trans_intr(t, [&](auto &t) { + return ObjectDataHandler(MAX_OBJECT_SIZE).write( + ObjectDataHandler::context_t{ + *tm, + t, + *onode, + }, + offset, + bl); + }).unsafe_get0(); + } + void write(objaddr_t offset, extent_len_t len, char fill) { + auto t = create_mutate_transaction(); + write(*t, offset, len, fill); + return submit_transaction(std::move(t)); + } + + void truncate(Transaction &t, objaddr_t offset) { + if (size > offset) { + memset( + known_contents.c_str() + offset, + 0, + size - offset); + with_trans_intr(t, [&](auto &t) { + return ObjectDataHandler(MAX_OBJECT_SIZE).truncate( + ObjectDataHandler::context_t{ + *tm, + t, + *onode + }, + offset); + }).unsafe_get0(); + } + size = offset; + } + void truncate(objaddr_t offset) { + auto t = create_mutate_transaction(); + truncate(*t, offset); + return submit_transaction(std::move(t)); + } + + void read(Transaction &t, objaddr_t offset, extent_len_t len) { + bufferlist bl = with_trans_intr(t, [&](auto &t) { + return ObjectDataHandler(MAX_OBJECT_SIZE).read( + ObjectDataHandler::context_t{ + *tm, + t, + *onode + }, + offset, + len); + }).unsafe_get0(); + bufferlist known; + known.append( + bufferptr( + known_contents, + offset, + len)); + EXPECT_EQ(bl.length(), known.length()); + EXPECT_EQ(bl, known); + } + void read(objaddr_t offset, extent_len_t len) { + auto t = create_read_transaction(); + read(*t, offset, len); + } + void read_near(objaddr_t offset, extent_len_t len, extent_len_t fuzz) { + auto fuzzes = std::vector<int32_t>{-1 * (int32_t)fuzz, 0, (int32_t)fuzz}; + for (auto left_fuzz : fuzzes) { + for (auto right_fuzz : fuzzes) { + read(offset + left_fuzz, len - left_fuzz + right_fuzz); + } + } + } + std::list<LBAMappingRef> get_mappings(objaddr_t offset, extent_len_t length) { + auto t = create_mutate_transaction(); + auto ret = with_trans_intr(*t, [&](auto &t) { + return tm->get_pins(t, offset, length); + }).unsafe_get0(); + return ret; + } + + seastar::future<> set_up_fut() final { + onode = new TestOnode( + DEFAULT_OBJECT_DATA_RESERVATION, + DEFAULT_OBJECT_METADATA_RESERVATION); + known_contents = buffer::create(4<<20 /* 4MB */); + memset(known_contents.c_str(), 0, known_contents.length()); + size = 0; + return tm_setup(); + } + + seastar::future<> tear_down_fut() final { + onode.reset(); + size = 0; + return tm_teardown(); + } +}; + +TEST_P(object_data_handler_test_t, single_write) +{ + run_async([this] { + write(1<<20, 8<<10, 'c'); + + read_near(1<<20, 8<<10, 1); + read_near(1<<20, 8<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, multi_write) +{ + run_async([this] { + write((1<<20) - (4<<10), 4<<10, 'a'); + write(1<<20, 4<<10, 'b'); + write((1<<20) + (4<<10), 4<<10, 'c'); + + read_near(1<<20, 4<<10, 1); + read_near(1<<20, 4<<10, 512); + + read_near((1<<20)-(4<<10), 12<<10, 1); + read_near((1<<20)-(4<<10), 12<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, write_hole) +{ + run_async([this] { + write((1<<20) - (4<<10), 4<<10, 'a'); + // hole at 1<<20 + write((1<<20) + (4<<10), 4<<10, 'c'); + + read_near(1<<20, 4<<10, 1); + read_near(1<<20, 4<<10, 512); + + read_near((1<<20)-(4<<10), 12<<10, 1); + read_near((1<<20)-(4<<10), 12<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, overwrite_single) +{ + run_async([this] { + write((1<<20), 4<<10, 'a'); + write((1<<20), 4<<10, 'c'); + + read_near(1<<20, 4<<10, 1); + read_near(1<<20, 4<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, overwrite_double) +{ + run_async([this] { + write((1<<20), 4<<10, 'a'); + write((1<<20)+(4<<10), 4<<10, 'c'); + write((1<<20), 8<<10, 'b'); + + read_near(1<<20, 8<<10, 1); + read_near(1<<20, 8<<10, 512); + + read_near(1<<20, 4<<10, 1); + read_near(1<<20, 4<<10, 512); + + read_near((1<<20) + (4<<10), 4<<10, 1); + read_near((1<<20) + (4<<10), 4<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, overwrite_partial) +{ + run_async([this] { + write((1<<20), 12<<10, 'a'); + read_near(1<<20, 12<<10, 1); + + write((1<<20)+(8<<10), 4<<10, 'b'); + read_near(1<<20, 12<<10, 1); + + write((1<<20)+(4<<10), 4<<10, 'c'); + read_near(1<<20, 12<<10, 1); + + write((1<<20), 4<<10, 'd'); + + read_near(1<<20, 12<<10, 1); + read_near(1<<20, 12<<10, 512); + + read_near(1<<20, 4<<10, 1); + read_near(1<<20, 4<<10, 512); + + read_near((1<<20) + (4<<10), 4<<10, 1); + read_near((1<<20) + (4<<10), 4<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, unaligned_write) +{ + run_async([this] { + objaddr_t base = 1<<20; + write(base, (4<<10)+(1<<10), 'a'); + read_near(base-(4<<10), 12<<10, 512); + + base = (1<<20) + (64<<10); + write(base+(1<<10), (4<<10)+(1<<10), 'b'); + read_near(base-(4<<10), 12<<10, 512); + + base = (1<<20) + (128<<10); + write(base-(1<<10), (4<<10)+(2<<20), 'c'); + read_near(base-(4<<10), 12<<10, 512); + }); +} + +TEST_P(object_data_handler_test_t, unaligned_overwrite) +{ + run_async([this] { + objaddr_t base = 1<<20; + write(base, (128<<10) + (16<<10), 'x'); + + write(base, (4<<10)+(1<<10), 'a'); + read_near(base-(4<<10), 12<<10, 2<<10); + + base = (1<<20) + (64<<10); + write(base+(1<<10), (4<<10)+(1<<10), 'b'); + read_near(base-(4<<10), 12<<10, 2<<10); + + base = (1<<20) + (128<<10); + write(base-(1<<10), (4<<10)+(2<<20), 'c'); + read_near(base-(4<<10), 12<<10, 2<<10); + + read(base, (128<<10) + (16<<10)); + }); +} + +TEST_P(object_data_handler_test_t, truncate) +{ + run_async([this] { + objaddr_t base = 1<<20; + write(base, 8<<10, 'a'); + write(base+(8<<10), 8<<10, 'b'); + write(base+(16<<10), 8<<10, 'c'); + + truncate(base + (32<<10)); + read(base, 64<<10); + + truncate(base + (24<<10)); + read(base, 64<<10); + + truncate(base + (12<<10)); + read(base, 64<<10); + + truncate(base - (12<<10)); + read(base, 64<<10); + }); +} + +TEST_P(object_data_handler_test_t, no_split) { + run_async([this] { + write(0, 8<<10, 'x'); + write(0, 8<<10, 'a'); + + auto pins = get_mappings(0, 8<<10); + EXPECT_EQ(pins.size(), 1); + + read(0, 8<<10); + }); +} + +TEST_P(object_data_handler_test_t, split_left) { + run_async([this] { + write(0, 128<<10, 'x'); + + write(64<<10, 60<<10, 'a'); + + auto pins = get_mappings(0, 128<<10); + EXPECT_EQ(pins.size(), 2); + + size_t res[2] = {0, 64<<10}; + auto base = pins.front()->get_key(); + int i = 0; + for (auto &pin : pins) { + EXPECT_EQ(pin->get_key() - base, res[i]); + i++; + } + read(0, 128<<10); + }); +} + +TEST_P(object_data_handler_test_t, split_right) { + run_async([this] { + write(0, 128<<10, 'x'); + write(4<<10, 60<<10, 'a'); + + auto pins = get_mappings(0, 128<<10); + EXPECT_EQ(pins.size(), 2); + + size_t res[2] = {0, 64<<10}; + auto base = pins.front()->get_key(); + int i = 0; + for (auto &pin : pins) { + EXPECT_EQ(pin->get_key() - base, res[i]); + i++; + } + read(0, 128<<10); + }); +} +TEST_P(object_data_handler_test_t, split_left_right) { + run_async([this] { + write(0, 128<<10, 'x'); + write(48<<10, 32<<10, 'a'); + + auto pins = get_mappings(0, 128<<10); + EXPECT_EQ(pins.size(), 3); + + size_t res[3] = {0, 48<<10, 80<<10}; + auto base = pins.front()->get_key(); + int i = 0; + for (auto &pin : pins) { + EXPECT_EQ(pin->get_key() - base, res[i]); + i++; + } + }); +} +TEST_P(object_data_handler_test_t, multiple_split) { + run_async([this] { + write(0, 128<<10, 'x'); + + auto t = create_mutate_transaction(); + // normal split + write(*t, 120<<10, 4<<10, 'a'); + // not aligned right + write(*t, 4<<10, 5<<10, 'b'); + // split right extent of last split result + write(*t, 32<<10, 4<<10, 'c'); + // non aligned overwrite + write(*t, 13<<10, 4<<10, 'd'); + + write(*t, 64<<10, 32<<10, 'e'); + // not split right + write(*t, 60<<10, 8<<10, 'f'); + + submit_transaction(std::move(t)); + + auto pins = get_mappings(0, 128<<10); + EXPECT_EQ(pins.size(), 10); + + size_t res[10] = {0, 4<<10, 12<<10, 20<<10, 32<<10, + 36<<10, 60<<10, 96<<10, 120<<10, 124<<10}; + auto base = pins.front()->get_key(); + int i = 0; + for (auto &pin : pins) { + EXPECT_EQ(pin->get_key() - base, res[i]); + i++; + } + read(0, 128<<10); + }); +} + +INSTANTIATE_TEST_SUITE_P( + object_data_handler_test, + object_data_handler_test_t, + ::testing::Values ( + "segmented", + "circularbounded" + ) +); + + |