auto alloc_mappings(
test_transaction_t &t,
- laddr_t addr,
+ laddr_hint_t hint,
size_t len) {
auto rets = with_trans_intr(
*t.t,
return seastar::do_with(
std::vector<LogicalChildNodeRef>(
extents.begin(), extents.end()),
- [this, &t, addr](auto &extents) {
- laddr_hint_t hint;
- hint.addr = addr;
- hint.condition = laddr_conflict_condition_t::all_at_object_content;
- hint.policy = laddr_conflict_policy_t::linear_search;
+ [this, &t, hint](auto &extents) {
return lba_manager->alloc_extents(t, hint, std::move(extents), EXTENT_DEFAULT_REF_COUNT);
});
}).unsafe_get();
return rets;
}
+ auto alloc_mappings(
+ test_transaction_t &t,
+ laddr_t addr,
+ size_t len) {
+ laddr_hint_t hint;
+ hint.addr = addr;
+ hint.condition = laddr_conflict_condition_t::all_at_object_content;
+ hint.policy = laddr_conflict_policy_t::linear_search;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ return alloc_mappings(t, hint, len);
+ }
+
auto decref_mapping(
test_transaction_t &t,
laddr_t addr) {
check_mappings();
});
}
+
+TEST_F(btree_lba_manager_test, conflict_policy_global_linear)
+{
+ run_async([this] {
+ constexpr auto MAX = std::numeric_limits<uint64_t>::max();
+ auto t = create_transaction(false);
+
+ laddr_hint_t hint;
+ hint.addr = L_ADDR_MIN.with_object_content(MAX - 1);
+ hint.condition = laddr_conflict_condition_t::all_at_never;
+ hint.policy = laddr_conflict_policy_t::linear_search;
+ hint.block_size = laddr_t::UNIT_SIZE;
+
+ auto alloc = [&]() -> laddr_t {
+ std::vector<LBACursorRef> ret = alloc_mappings(t, hint, 4096);
+ assert(ret.size() == 1);
+ return ret.front()->get_key();
+ };
+
+ // 1 base
+ auto addr = alloc();
+ ASSERT_EQ(addr, hint.addr);
+
+ // 2 global end
+ hint.condition = laddr_conflict_condition_t::all_at_object_content;
+ addr = alloc();
+ ASSERT_EQ(addr, L_ADDR_MIN.with_object_content(MAX));
+
+ // 3 loop back
+ addr = alloc();
+ ASSERT_EQ(addr, L_ADDR_MIN);
+
+ submit_test_transaction(std::move(t));
+ check_mappings();
+ });
+}
+
+TEST_F(btree_lba_manager_test, conflict_policy_global_random)
+{
+ run_async([this] {
+ auto t = create_transaction(false);
+
+ laddr_hint_t hint = laddr_hint_t::create_global_md_hint();
+ hint.addr = L_ADDR_MIN;
+
+ std::set<laddr_t> addrs;
+ for (int i = 0; i < 128; i++) {
+ std::vector<LBACursorRef> ret = alloc_mappings(t, hint, 4096);
+ assert(ret.size() == 1);
+ auto addr = ret.front()->get_key();
+ ASSERT_EQ(addr.get_object_prefix(), L_ADDR_MIN.get_object_prefix());
+ auto p = addrs.insert(addr);
+ ASSERT_TRUE(p.second);
+ }
+
+ submit_test_transaction(std::move(t));
+ check_mappings();
+ });
+}
+
+TEST_F(btree_lba_manager_test, conflict_policy_object_data)
+{
+ run_async([this] {
+ auto t = create_transaction(false);
+ laddr_shard_t shard = 1;
+ laddr_pool_t pool = 1;
+ laddr_crush_hash_t crush = 1;
+
+ auto alloc = [&](laddr_hint_t hint) -> laddr_t {
+ auto ret = alloc_mappings(t, hint, 4096);
+ assert(ret.size() == 1);
+ return ret.front()->get_key();
+ };
+
+ auto hint = laddr_hint_t::create_fresh_object_data_hint(
+ shard, pool, crush, laddr_t::UNIT_SHIFT);
+ {
+ auto object_id = hint.addr.get_local_object_id();
+ if (object_id == LOCAL_OBJECT_ID_NULL) {
+ hint.addr.set_local_object_id(object_id - 1);
+ }
+ auto clone_id = hint.addr.get_local_clone_id();
+ if (clone_id == LOCAL_CLONE_ID_NULL) {
+ hint.addr.set_local_clone_id(clone_id - 1);
+ }
+ }
+
+ auto base_addr = alloc(hint);
+ auto object_id = base_addr.get_local_object_id();
+ auto clone_id = base_addr.get_local_clone_id();
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr;
+ // conflict with other object
+ hint.condition = laddr_conflict_condition_t::object_prefix_at_object_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_NE(object_id, addr.get_local_object_id());
+ ASSERT_EQ(clone_id, addr.get_local_clone_id());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr.with_local_clone_id(clone_id + 1);
+ // conflict with other object, check prev
+ hint.condition = laddr_conflict_condition_t::object_prefix_at_object_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_NE(object_id, addr.get_local_object_id());
+ ASSERT_EQ(clone_id + 1, addr.get_local_clone_id());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr.with_offset_by_blocks(rand());
+ hint.addr.set_metadata(true);
+ // allocating metadata for fresh clone conflicts with other clone, check prev
+ hint.condition = laddr_conflict_condition_t::clone_prefix_at_clone_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_EQ(object_id, addr.get_local_object_id());
+ ASSERT_NE(clone_id, addr.get_local_clone_id());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr;
+ // conflict with other clone
+ hint.condition = laddr_conflict_condition_t::clone_prefix_at_clone_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_EQ(object_id, addr.get_local_object_id());
+ ASSERT_NE(clone_id, addr.get_local_clone_id());
+ }
+
+ submit_test_transaction(std::move(t));
+ check_mappings();
+ });
+}
+
+TEST_F(btree_lba_manager_test, conflict_policy_object_metadata)
+{
+ run_async([this] {
+ auto t = create_transaction(false);
+ laddr_shard_t shard = 1;
+ laddr_pool_t pool = 1;
+ laddr_crush_hash_t crush = 1;
+
+ auto alloc = [&](laddr_hint_t hint) -> laddr_t {
+ auto ret = alloc_mappings(t, hint, 4096);
+ assert(ret.size() == 1);
+ return ret.front()->get_key();
+ };
+
+ auto hint = laddr_hint_t::create_fresh_object_md_hint(
+ shard, pool, crush, laddr_t::UNIT_SIZE);
+ // set to max - 1 to test the linear_search policy
+ hint.addr.set_offset_by_blocks(
+ uint64_t(std::numeric_limits<uint32_t>::max() - 1));
+
+ auto base_addr = alloc(hint);
+ auto object_id = base_addr.get_local_object_id();
+ auto clone_id = base_addr.get_local_clone_id();
+ auto block_offset = base_addr.get_offset_bytes();
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr;
+ // conflict with other object
+ hint.condition = laddr_conflict_condition_t::object_prefix_at_object_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_NE(object_id, addr.get_local_object_id());
+ ASSERT_EQ(clone_id, addr.get_local_clone_id());
+ ASSERT_EQ(block_offset, addr.get_offset_bytes());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr.with_offset_by_bytes(block_offset + laddr_t::UNIT_SIZE);
+ // conflict with other object, check prev
+ hint.condition = laddr_conflict_condition_t::object_prefix_at_object_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_NE(object_id, addr.get_local_object_id());
+ ASSERT_EQ(clone_id, addr.get_local_clone_id());
+ ASSERT_EQ(block_offset + laddr_t::UNIT_SIZE, addr.get_offset_bytes());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr;
+ // conflict with other clone
+ hint.condition = laddr_conflict_condition_t::clone_prefix_at_clone_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_EQ(object_id, addr.get_local_object_id());
+ ASSERT_NE(clone_id, addr.get_local_clone_id());
+ ASSERT_EQ(block_offset, addr.get_offset_bytes());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr.with_offset_by_bytes(block_offset + laddr_t::UNIT_SIZE);
+ // conflict with other clone, check prev
+ hint.condition = laddr_conflict_condition_t::clone_prefix_at_clone_id;
+ hint.policy = laddr_conflict_policy_t::gen_random;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_EQ(object_id, addr.get_local_object_id());
+ ASSERT_NE(clone_id, addr.get_local_clone_id());
+ ASSERT_EQ(block_offset + laddr_t::UNIT_SIZE, addr.get_offset_bytes());
+ }
+
+ {
+ laddr_hint_t hint;
+ hint.addr = base_addr;
+ // conflict with other extents
+ hint.condition = laddr_conflict_condition_t::all_at_object_content;
+ hint.policy = laddr_conflict_policy_t::linear_search;
+ hint.block_size = laddr_t::UNIT_SIZE;
+ auto addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_EQ(object_id, addr.get_local_object_id());
+ ASSERT_EQ(clone_id, addr.get_local_clone_id());
+ ASSERT_EQ(block_offset + laddr_t::UNIT_SIZE, addr.get_offset_bytes());
+
+ addr = alloc(hint);
+ ASSERT_EQ(base_addr.get_shard(), addr.get_shard());
+ ASSERT_EQ(base_addr.get_pool(), addr.get_pool());
+ ASSERT_EQ(base_addr.get_reversed_hash(), addr.get_reversed_hash());
+ ASSERT_EQ(object_id, addr.get_local_object_id());
+ ASSERT_EQ(clone_id, addr.get_local_clone_id());
+ ASSERT_EQ(0, addr.get_offset_bytes());
+ }
+
+ submit_test_transaction(std::move(t));
+ check_mappings();
+ });
+}