}
struct b_dummy_tree_test_t : public seastar_test_suite_t {
- NodeExtentManagerURef moved_nm;
TransactionRef ref_t;
- Transaction& t;
- ValueBuilderImpl<UnboundedValue> vb;
- context_t c;
- UnboundedBtree tree;
+ std::unique_ptr<UnboundedBtree> tree;
- b_dummy_tree_test_t()
- : moved_nm{NodeExtentManager::create_dummy(IS_DUMMY_SYNC)},
- ref_t{make_test_transaction()},
- t{*ref_t},
- c{*moved_nm, vb, t},
- tree{std::move(moved_nm)} {}
+ b_dummy_tree_test_t() = default;
seastar::future<> set_up_fut() override final {
- return INTR(tree.mkfs, t).handle_error(
+ ref_t = make_test_transaction();
+ tree.reset(
+ new UnboundedBtree(NodeExtentManager::create_dummy(IS_DUMMY_SYNC))
+ );
+ return INTR(tree->mkfs, *ref_t).handle_error(
crimson::ct_error::all_same_way([] {
ASSERT_FALSE("Unable to mkfs");
})
);
}
+
+ seastar::future<> tear_down_fut() final {
+ ref_t.reset();
+ tree.reset();
+ return seastar::now();
+ }
};
TEST_F(b_dummy_tree_test_t, 3_random_insert_erase_leaf_node)
"\nrandomized leaf node insert:\n");
auto key_s = ghobject_t();
auto key_e = ghobject_t::get_max();
- ASSERT_TRUE(INTR_R(tree.find, t, key_s).unsafe_get0().is_end());
- ASSERT_TRUE(INTR(tree.begin, t).unsafe_get0().is_end());
- ASSERT_TRUE(INTR(tree.last, t).unsafe_get0().is_end());
+ ASSERT_TRUE(INTR_R(tree->find, *ref_t, key_s).unsafe_get0().is_end());
+ ASSERT_TRUE(INTR(tree->begin, *ref_t).unsafe_get0().is_end());
+ ASSERT_TRUE(INTR(tree->last, *ref_t).unsafe_get0().is_end());
std::map<ghobject_t,
std::tuple<test_item_t, UnboundedBtree::Cursor>> insert_history;
auto f_validate_insert_new = [this, &insert_history] (
const ghobject_t& key, const test_item_t& value) {
auto conf = UnboundedBtree::tree_value_config_t{value.get_payload_size()};
- auto [cursor, success] = INTR_R(tree.insert,
- t, key, conf).unsafe_get0();
- initialize_cursor_from_item(t, key, value, cursor, success);
+ auto [cursor, success] = INTR_R(tree->insert,
+ *ref_t, key, conf).unsafe_get0();
+ initialize_cursor_from_item(*ref_t, key, value, cursor, success);
insert_history.emplace(key, std::make_tuple(value, cursor));
- auto cursor_ = INTR_R(tree.find, t, key).unsafe_get0();
- ceph_assert(cursor_ != tree.end());
+ auto cursor_ = INTR_R(tree->find, *ref_t, key).unsafe_get0();
+ ceph_assert(cursor_ != tree->end());
ceph_assert(cursor_.value() == cursor.value());
validate_cursor_from_item(key, value, cursor_);
return cursor.value();
};
auto f_validate_erase = [this, &insert_history] (const ghobject_t& key) {
- auto cursor_erase = INTR_R(tree.find, t, key).unsafe_get0();
- auto cursor_next = INTR(cursor_erase.get_next, t).unsafe_get0();
- auto cursor_ret = INTR_R(tree.erase, t, cursor_erase).unsafe_get0();
+ auto cursor_erase = INTR_R(tree->find, *ref_t, key).unsafe_get0();
+ auto cursor_next = INTR(cursor_erase.get_next, *ref_t).unsafe_get0();
+ auto cursor_ret = INTR_R(tree->erase, *ref_t, cursor_erase).unsafe_get0();
ceph_assert(cursor_erase.is_end());
ceph_assert(cursor_ret == cursor_next);
- auto cursor_lb = INTR_R(tree.lower_bound, t, key).unsafe_get0();
+ auto cursor_lb = INTR_R(tree->lower_bound, *ref_t, key).unsafe_get0();
ceph_assert(cursor_lb == cursor_next);
auto it = insert_history.find(key);
ceph_assert(std::get<1>(it->second).is_end());
// validate lookup
{
- auto cursor1_s = INTR_R(tree.lower_bound, t, key_s).unsafe_get0();
+ auto cursor1_s = INTR_R(tree->lower_bound, *ref_t, key_s).unsafe_get0();
ASSERT_EQ(cursor1_s.get_ghobj(), key1);
ASSERT_EQ(cursor1_s.value(), test_value1);
- auto cursor1_e = INTR_R(tree.lower_bound, t, key_e).unsafe_get0();
+ auto cursor1_e = INTR_R(tree->lower_bound, *ref_t, key_e).unsafe_get0();
ASSERT_TRUE(cursor1_e.is_end());
}
{
auto value1_dup = values.pick();
auto conf = UnboundedBtree::tree_value_config_t{value1_dup.get_payload_size()};
- auto [cursor1_dup, ret1_dup] = INTR_R(tree.insert,
- t, key1, conf).unsafe_get0();
+ auto [cursor1_dup, ret1_dup] = INTR_R(tree->insert,
+ *ref_t, key1, conf).unsafe_get0();
ASSERT_FALSE(ret1_dup);
validate_cursor_from_item(key1, value1, cursor1_dup);
}
std::for_each(kvs.begin(), kvs.end(), [&f_insert_erase_insert] (auto& kv) {
f_insert_erase_insert(kv.first, kv.second);
});
- ASSERT_EQ(INTR(tree.height, t).unsafe_get0(), 1);
- ASSERT_FALSE(tree.test_is_clean());
+ ASSERT_EQ(INTR(tree->height, *ref_t).unsafe_get0(), 1);
+ ASSERT_FALSE(tree->test_is_clean());
for (auto& [k, val] : insert_history) {
auto& [v, c] = val;
// validate values in tree keep intact
- auto cursor = with_trans_intr(t, [this, &k=k](auto& tr) {
- return tree.find(tr, k);
+ auto cursor = with_trans_intr(*ref_t, [this, &k=k](auto& tr) {
+ return tree->find(tr, k);
}).unsafe_get0();
- EXPECT_NE(cursor, tree.end());
+ EXPECT_NE(cursor, tree->end());
validate_cursor_from_item(k, v, cursor);
// validate values in cursors keep intact
validate_cursor_from_item(k, v, c);
}
{
- auto cursor = INTR_R(tree.lower_bound, t, key_s).unsafe_get0();
+ auto cursor = INTR_R(tree->lower_bound, *ref_t, key_s).unsafe_get0();
validate_cursor_from_item(smallest_key, smallest_value, cursor);
}
{
- auto cursor = INTR(tree.begin, t).unsafe_get0();
+ auto cursor = INTR(tree->begin, *ref_t).unsafe_get0();
validate_cursor_from_item(smallest_key, smallest_value, cursor);
}
{
- auto cursor = INTR(tree.last, t).unsafe_get0();
+ auto cursor = INTR(tree->last, *ref_t).unsafe_get0();
validate_cursor_from_item(largest_key, largest_value, cursor);
}
std::sort(kvs.begin(), kvs.end(), [](auto& l, auto& r) {
return l.first < r.first;
});
- auto cursor = INTR(tree.begin, t).unsafe_get0();
+ auto cursor = INTR(tree->begin, *ref_t).unsafe_get0();
for (auto& [k, v] : kvs) {
ASSERT_FALSE(cursor.is_end());
validate_cursor_from_item(k, v, cursor);
- cursor = INTR(cursor.get_next, t).unsafe_get0();
+ cursor = INTR(cursor.get_next, *ref_t).unsafe_get0();
}
ASSERT_TRUE(cursor.is_end());
}
std::ostringstream oss;
- tree.dump(t, oss);
+ tree->dump(*ref_t, oss);
logger().info("\n{}\n", oss.str());
// randomized erase until empty
std::random_shuffle(kvs.begin(), kvs.end());
for (auto& [k, v] : kvs) {
- auto e_size = with_trans_intr(t, [this, &k=k](auto& tr) {
- return tree.erase(tr, k);
+ auto e_size = with_trans_intr(*ref_t, [this, &k=k](auto& tr) {
+ return tree->erase(tr, k);
}).unsafe_get0();
ASSERT_EQ(e_size, 1);
}
- auto cursor = INTR(tree.begin, t).unsafe_get0();
+ auto cursor = INTR(tree->begin, *ref_t).unsafe_get0();
ASSERT_TRUE(cursor.is_end());
- ASSERT_EQ(INTR(tree.height, t).unsafe_get0(), 1);
+ ASSERT_EQ(INTR(tree->height, *ref_t).unsafe_get0(), 1);
});
}
segment_manager::EphemeralSegmentManagerRef segment_manager;
ExtentReaderRef scanner;
- Journal journal;
- Cache cache;
+ JournalRef journal;
+ CacheRef cache;
- const size_t block_size;
+ size_t block_size;
WritePipeline pipeline;
segment_id_t next;
- btree_test_base()
- : segment_manager(segment_manager::create_test_ephemeral()),
- scanner(new ExtentReader()),
- journal(*segment_manager, *scanner),
- cache(*scanner),
- block_size(segment_manager->get_block_size()),
- next(segment_manager->get_device_id(), 0)
- {
- scanner->add_segment_manager(segment_manager.get());
- journal.set_segment_provider(this);
- journal.set_write_pipeline(&pipeline);
- }
+ btree_test_base() = default;
get_segment_ret get_segment(device_id_t id) final {
auto ret = next;
virtual void complete_commit(Transaction &t) {}
seastar::future<> submit_transaction(TransactionRef t)
{
- auto record = cache.prepare_record(*t);
- return journal.submit_record(std::move(record), t->get_handle()).safe_then(
+ auto record = cache->prepare_record(*t);
+ return journal->submit_record(std::move(record), t->get_handle()).safe_then(
[this, t=std::move(t)](auto p) mutable {
auto [addr, seq] = p;
- cache.complete_commit(*t, addr, seq);
+ cache->complete_commit(*t, addr, seq);
complete_commit(*t);
}).handle_error(crimson::ct_error::assert_all{});
}
virtual LBAManager::mkfs_ret test_structure_setup(Transaction &t) = 0;
seastar::future<> set_up_fut() final {
+ segment_manager = segment_manager::create_test_ephemeral();
+ scanner.reset(new ExtentReader());
+ journal.reset(new Journal(*segment_manager, *scanner));
+ cache.reset(new Cache(*scanner));
+
+ block_size = segment_manager->get_block_size();
+ next = segment_id_t{segment_manager->get_device_id(), 0};
+ scanner->add_segment_manager(segment_manager.get());
+ journal->set_segment_provider(this);
+ journal->set_write_pipeline(&pipeline);
+
return segment_manager->init(
).safe_then([this] {
- return journal.open_for_write();
+ return journal->open_for_write();
}).safe_then([this](auto addr) {
return seastar::do_with(
- cache.create_transaction(Transaction::src_t::MUTATE),
+ cache->create_transaction(Transaction::src_t::MUTATE),
[this](auto &ref_t) {
return with_trans_intr(*ref_t, [&](auto &t) {
- cache.init();
- return cache.mkfs(t
+ cache->init();
+ return cache->mkfs(t
).si_then([this, &t] {
return test_structure_setup(t);
});
);
}
+ virtual void test_structure_reset() {}
seastar::future<> tear_down_fut() final {
- return cache.close(
+ return cache->close(
).safe_then([this] {
- return journal.close();
+ return journal->close();
+ }).safe_then([this] {
+ test_structure_reset();
+ segment_manager.reset();
+ scanner.reset();
+ journal.reset();
+ cache.reset();
}).handle_error(
crimson::ct_error::all_same_way([] {
ASSERT_FALSE("Unable to close");
std::map<laddr_t, lba_map_val_t> check;
auto get_op_context(Transaction &t) {
- return op_context_t{cache, t};
+ return op_context_t{*cache, t};
}
LBAManager::mkfs_ret test_structure_setup(Transaction &t) final {
- return cache.get_root(
+ return cache->get_root(
t
).si_then([this, &t](RootBlockRef croot) {
- auto mut_croot = cache.duplicate_for_write(
+ auto mut_croot = cache->duplicate_for_write(
t, croot
)->cast<RootBlock>();
mut_croot->root.lba_root = LBABtree::mkfs(get_op_context(t));
void update_if_dirty(Transaction &t, LBABtree &btree, RootBlockRef croot) {
if (btree.is_root_dirty()) {
- auto mut_croot = cache.duplicate_for_write(
+ auto mut_croot = cache->duplicate_for_write(
t, croot
)->cast<RootBlock>();
mut_croot->root.lba_root = btree.get_root_undirty();
template <typename F>
auto lba_btree_update(F &&f) {
- auto tref = cache.create_transaction(Transaction::src_t::MUTATE);
+ auto tref = cache->create_transaction(Transaction::src_t::MUTATE);
auto &t = *tref;
with_trans_intr(
t,
[this, tref=std::move(tref), f=std::forward<F>(f)](auto &t) mutable {
- return cache.get_root(
+ return cache->get_root(
t
).si_then([this, f=std::move(f), &t](RootBlockRef croot) {
return seastar::do_with(
template <typename F>
auto lba_btree_read(F &&f) {
- auto t = cache.create_transaction(Transaction::src_t::READ);
+ auto t = cache->create_transaction(Transaction::src_t::READ);
return with_trans_intr(
*t,
[this, f=std::forward<F>(f)](auto &t) mutable {
- return cache.get_root(
+ return cache->get_root(
t
).si_then([f=std::move(f), &t](RootBlockRef croot) mutable {
return seastar::do_with(
struct btree_lba_manager_test : btree_test_base {
BtreeLBAManagerRef lba_manager;
- btree_lba_manager_test()
- : lba_manager(new BtreeLBAManager(*segment_manager, cache)) {}
+ btree_lba_manager_test() = default;
void complete_commit(Transaction &t) final {
lba_manager->complete_transaction(t);
}
LBAManager::mkfs_ret test_structure_setup(Transaction &t) final {
+ lba_manager.reset(new BtreeLBAManager(*segment_manager, *cache));
return lba_manager->mkfs(t);
}
+ void test_structure_reset() final {
+ lba_manager.reset();
+ }
+
struct test_extent_t {
paddr_t addr;
size_t len = 0;
auto create_transaction(bool create_fake_extent=true) {
auto t = test_transaction_t{
- cache.create_transaction(Transaction::src_t::MUTATE),
+ cache->create_transaction(Transaction::src_t::MUTATE),
test_lba_mappings
};
if (create_fake_extent) {
- cache.alloc_new_extent<TestBlockPhysical>(*t.t, TestBlockPhysical::SIZE);
+ cache->alloc_new_extent<TestBlockPhysical>(*t.t, TestBlockPhysical::SIZE);
};
return t;
}
auto create_weak_transaction() {
auto t = test_transaction_t{
- cache.create_weak_transaction(Transaction::src_t::READ),
+ cache->create_weak_transaction(Transaction::src_t::READ),
test_lba_mappings
};
return t;
RandomBlockManager::mkfs_config_t config;
paddr_t current;
- rbm_test_t() {
+ rbm_test_t() = default;
+
+ seastar::future<> set_up_fut() final {
device.reset(new nvme_device::TestMemory(DEFAULT_TEST_SIZE));
rbm_manager.reset(new NVMeManager(device.get(), std::string()));
config.start = paddr_t {0, 0, 0};
config.end = paddr_t {0, 0, DEFAULT_TEST_SIZE};
config.block_size = DEFAULT_BLOCK_SIZE;
config.total_size = DEFAULT_TEST_SIZE;
- }
-
- seastar::future<> set_up_fut() final {
return tm_setup();
}
seastar::future<> tear_down_fut() final {
+ rbm_manager.reset();
device.reset();
return tm_teardown();
}
}
seastar::future<> tear_down_fut() final {
+ coll.reset();
return tm_teardown();
}
struct cache_test_t : public seastar_test_suite_t {
segment_manager::EphemeralSegmentManagerRef segment_manager;
ExtentReaderRef reader;
- Cache cache;
+ CacheRef cache;
paddr_t current;
journal_seq_t seq;
- cache_test_t()
- : segment_manager(segment_manager::create_test_ephemeral()),
- reader(new ExtentReader()),
- cache(*reader),
- current(segment_id_t(segment_manager->get_device_id(), 0), 0) {
- reader->add_segment_manager(segment_manager.get());
- }
+ cache_test_t() = default;
seastar::future<paddr_t> submit_transaction(
TransactionRef t) {
- auto record = cache.prepare_record(*t);
+ auto record = cache->prepare_record(*t);
bufferlist bl;
for (auto &&block : record.extents) {
true
).safe_then(
[this, prev, t=std::move(t)]() mutable {
- cache.complete_commit(*t, prev, seq /* TODO */);
+ cache->complete_commit(*t, prev, seq /* TODO */);
return prev;
},
crimson::ct_error::all_same_way([](auto e) {
}
auto get_transaction() {
- return cache.create_transaction(Transaction::src_t::MUTATE);
+ return cache->create_transaction(Transaction::src_t::MUTATE);
}
template <typename T, typename... Args>
return with_trans_intr(
t,
[this](auto &&... args) {
- return cache.get_extent<T>(args...);
+ return cache->get_extent<T>(args...);
},
std::forward<Args>(args)...);
}
seastar::future<> set_up_fut() final {
+ segment_manager = segment_manager::create_test_ephemeral();
+ reader.reset(new ExtentReader());
+ cache.reset(new Cache(*reader));
+ current = paddr_t(segment_id_t(segment_manager->get_device_id(), 0), 0);
+ reader->add_segment_manager(segment_manager.get());
return segment_manager->init(
).safe_then([this] {
return seastar::do_with(
get_transaction(),
[this](auto &ref_t) {
- cache.init();
+ cache->init();
return with_trans_intr(*ref_t, [&](auto &t) {
- return cache.mkfs(t);
+ return cache->mkfs(t);
}).safe_then([this, &ref_t] {
return submit_transaction(std::move(ref_t)
).then([](auto p) {});
}
seastar::future<> tear_down_fut() final {
- return cache.close().handle_error(
- Cache::close_ertr::assert_all{});
+ return cache->close(
+ ).safe_then([this] {
+ segment_manager.reset();
+ reader.reset();
+ cache.reset();
+ }).handle_error(
+ Cache::close_ertr::assert_all{}
+ );
}
};
int csum = 0;
{
auto t = get_transaction();
- auto extent = cache.alloc_new_extent<TestBlockPhysical>(
+ auto extent = cache->alloc_new_extent<TestBlockPhysical>(
*t,
TestBlockPhysical::SIZE);
extent->set_contents('c');
{
// write out initial test block
auto t = get_transaction();
- auto extent = cache.alloc_new_extent<TestBlockPhysical>(
+ auto extent = cache->alloc_new_extent<TestBlockPhysical>(
*t,
TestBlockPhysical::SIZE);
extent->set_contents('c');
addr,
TestBlockPhysical::SIZE).unsafe_get0();
// duplicate and reset contents
- extent = cache.duplicate_for_write(*t, extent)->cast<TestBlockPhysical>();
+ extent = cache->duplicate_for_write(*t, extent)->cast<TestBlockPhysical>();
extent->set_contents('c');
csum2 = extent->get_crc32c();
ASSERT_EQ(extent->get_paddr(), addr);
std::default_random_engine generator;
- const segment_off_t block_size;
+ segment_off_t block_size;
ExtentReaderRef scanner;
segment_id_t next;
- journal_test_t()
- : segment_manager(segment_manager::create_test_ephemeral()),
- block_size(segment_manager->get_block_size()),
- scanner(new ExtentReader()),
- next(segment_manager->get_device_id(), 0)
- {
- scanner->add_segment_manager(segment_manager.get());
- }
+ journal_test_t() = default;
get_segment_ret get_segment(device_id_t id) final {
auto ret = next;
void update_journal_tail_committed(journal_seq_t paddr) final {}
seastar::future<> set_up_fut() final {
+ segment_manager = segment_manager::create_test_ephemeral();
+ block_size = segment_manager->get_block_size();
+ scanner.reset(new ExtentReader());
+ next = segment_id_t(segment_manager->get_device_id(), 0);
journal.reset(new Journal(*segment_manager, *scanner));
+
journal->set_segment_provider(this);
journal->set_write_pipeline(&pipeline);
+ scanner->add_segment_manager(segment_manager.get());
return segment_manager->init(
).safe_then([this] {
return journal->open_for_write();
seastar::future<> tear_down_fut() final {
return journal->close(
- ).handle_error(
+ ).safe_then([this] {
+ segment_manager.reset();
+ scanner.reset();
+ journal.reset();
+ }).handle_error(
crimson::ct_error::all_same_way([](auto e) {
ASSERT_FALSE("Unable to close");
})
protected:
segment_manager::EphemeralSegmentManagerRef segment_manager;
- EphemeralTestState()
- : segment_manager(segment_manager::create_test_ephemeral()) {}
+ EphemeralTestState() = default;
virtual void _init() = 0;
void init() {
}
seastar::future<> tm_setup() {
+ segment_manager = segment_manager::create_test_ephemeral();
init();
return segment_manager->init(
).safe_then([this] {
}
seastar::future<> tm_teardown() {
- return _teardown();
+ return _teardown().then([this] {
+ segment_manager.reset();
+ });
}
};