mirror of
https://github.com/ceph/ceph
synced 2025-02-21 18:17:42 +00:00
crimson/onode-staged-tree: imlement fair locate split strategy
Also make adjustments in unit tests. Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
This commit is contained in:
parent
1757afc98d
commit
c32c1032de
@ -361,7 +361,7 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
|
||||
size_t split_size = 0;
|
||||
std::optional<bool> _is_insert_left;
|
||||
split_at.set(node_stage);
|
||||
STAGE_T::recursively_locate_split_inserted(
|
||||
bool locate_nxt = STAGE_T::recursively_locate_split_inserted(
|
||||
split_size, 0, target_split_size, insert_pos,
|
||||
insert_stage, insert_size, _is_insert_left, split_at);
|
||||
is_insert_left = *_is_insert_left;
|
||||
@ -371,7 +371,14 @@ class NodeLayoutT final : public InternalNodeImpl, public LeafNodeImpl {
|
||||
<< "(target=" << target_split_size
|
||||
<< ", current=" << node_stage.size_before(node_stage.keys())
|
||||
<< ")" << std::endl;
|
||||
assert(split_size <= target_split_size);
|
||||
// split_size can be larger than target_split_size in strategy B
|
||||
// assert(split_size <= target_split_size);
|
||||
if (locate_nxt) {
|
||||
assert(insert_stage == STAGE);
|
||||
assert(split_at.get().is_last());
|
||||
split_at.set_end();
|
||||
assert(insert_pos.index == split_at.index());
|
||||
}
|
||||
}
|
||||
|
||||
auto append_at = split_at;
|
||||
|
@ -575,6 +575,7 @@ struct staged {
|
||||
}
|
||||
|
||||
// Note: possible to return an end iterator when is_exclusive is true
|
||||
// insert_index can still be INDEX_LAST or INDEX_END
|
||||
template <bool is_exclusive>
|
||||
size_t seek_split_inserted(
|
||||
size_t start_size, size_t extra_size, size_t target_size,
|
||||
@ -1424,26 +1425,50 @@ struct staged {
|
||||
std::optional<iterator_t> iter;
|
||||
};
|
||||
|
||||
static void recursively_locate_split(
|
||||
static bool recursively_locate_split(
|
||||
size_t& current_size, size_t extra_size,
|
||||
size_t target_size, StagedIterator& split_at) {
|
||||
assert(current_size <= target_size);
|
||||
iterator_t& split_iter = split_at.get();
|
||||
current_size = split_iter.seek_split(current_size, extra_size, target_size);
|
||||
assert(current_size <= target_size);
|
||||
assert(!split_iter.is_end());
|
||||
if (split_iter.index() == 0) {
|
||||
extra_size += iterator_t::header_size();
|
||||
} else {
|
||||
extra_size = 0;
|
||||
}
|
||||
bool locate_nxt;
|
||||
if constexpr (!IS_BOTTOM) {
|
||||
NXT_STAGE_T::recursively_locate_split(
|
||||
locate_nxt = NXT_STAGE_T::recursively_locate_split(
|
||||
current_size, extra_size + split_iter.size_to_nxt(),
|
||||
target_size, split_at.nxt());
|
||||
} else { // IS_BOTTOM
|
||||
// located upper_bound, fair split strategy
|
||||
size_t nxt_size = split_iter.size() + extra_size;
|
||||
assert(current_size + nxt_size > target_size);
|
||||
if (current_size + nxt_size/2 < target_size) {
|
||||
// include next
|
||||
current_size += nxt_size;
|
||||
locate_nxt = true;
|
||||
} else {
|
||||
// exclude next
|
||||
locate_nxt = false;
|
||||
}
|
||||
}
|
||||
if (locate_nxt) {
|
||||
if (split_iter.is_last()) {
|
||||
return true;
|
||||
} else {
|
||||
++split_at;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void recursively_locate_split_inserted(
|
||||
static bool recursively_locate_split_inserted(
|
||||
size_t& current_size, size_t extra_size, size_t target_size,
|
||||
position_t& insert_pos, match_stage_t insert_stage, size_t insert_size,
|
||||
std::optional<bool>& is_insert_left, StagedIterator& split_at) {
|
||||
@ -1456,6 +1481,7 @@ struct staged {
|
||||
current_size, extra_size, target_size,
|
||||
insert_index, insert_size, is_insert_left);
|
||||
assert(is_insert_left.has_value());
|
||||
assert(current_size <= target_size);
|
||||
if (split_iter.index() == 0) {
|
||||
extra_size += iterator_t::header_size();
|
||||
} else {
|
||||
@ -1465,16 +1491,71 @@ struct staged {
|
||||
// split_iter can be end
|
||||
// found the lower-bound of target_size
|
||||
// ...[s_index-1] |!| (i_index) [s_index]...
|
||||
return;
|
||||
|
||||
// located upper-bound, fair split strategy
|
||||
// look at the next slot (the insert item)
|
||||
size_t nxt_size = insert_size + extra_size;
|
||||
assert(current_size + nxt_size > target_size);
|
||||
if (current_size + nxt_size/2 < target_size) {
|
||||
// include next
|
||||
*is_insert_left = true;
|
||||
current_size += nxt_size;
|
||||
if (split_iter.is_end()) {
|
||||
// ...[s_index-1] (i_index) |!|
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// exclude next
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Already considered insert effect in the current stage.
|
||||
// Look into the next stage to identify the target_size lower-bound w/o
|
||||
// insert effect.
|
||||
assert(!split_iter.is_end());
|
||||
bool locate_nxt;
|
||||
if constexpr (!IS_BOTTOM) {
|
||||
NXT_STAGE_T::recursively_locate_split(
|
||||
locate_nxt = NXT_STAGE_T::recursively_locate_split(
|
||||
current_size, extra_size + split_iter.size_to_nxt(),
|
||||
target_size, split_at.nxt());
|
||||
} else { // IS_BOTTOM
|
||||
// located upper-bound, fair split strategy
|
||||
// look at the next slot
|
||||
size_t nxt_size = split_iter.size() + extra_size;
|
||||
assert(current_size + nxt_size > target_size);
|
||||
if (current_size + nxt_size/2 < target_size) {
|
||||
// include next
|
||||
current_size += nxt_size;
|
||||
locate_nxt = true;
|
||||
} else {
|
||||
// exclude next
|
||||
locate_nxt = false;
|
||||
}
|
||||
}
|
||||
if (locate_nxt) {
|
||||
if (split_iter.is_last()) {
|
||||
auto end_index = split_iter.index() + 1;
|
||||
if (insert_index == INDEX_END) {
|
||||
insert_index = end_index;
|
||||
}
|
||||
assert(insert_index <= end_index);
|
||||
if (insert_index == end_index) {
|
||||
assert(*is_insert_left == false);
|
||||
split_iter.set_end();
|
||||
// ...[s_index-1] |!| (i_index)
|
||||
return false;
|
||||
} else {
|
||||
assert(*is_insert_left == true);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
++split_at;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1484,36 +1565,59 @@ struct staged {
|
||||
current_size, extra_size, target_size,
|
||||
insert_index, insert_size, is_insert_left);
|
||||
assert(!split_iter.is_end());
|
||||
assert(current_size <= target_size);
|
||||
if (split_iter.index() == 0) {
|
||||
extra_size += iterator_t::header_size();
|
||||
} else {
|
||||
extra_size = 0;
|
||||
}
|
||||
bool locate_nxt;
|
||||
if (!is_insert_left.has_value()) {
|
||||
// Considered insert effect in the current stage, and insert happens
|
||||
// in the lower stage.
|
||||
// Look into the next stage to identify the target_size lower-bound w/
|
||||
// insert effect.
|
||||
assert(split_iter.index() == insert_index);
|
||||
NXT_STAGE_T::recursively_locate_split_inserted(
|
||||
locate_nxt = NXT_STAGE_T::recursively_locate_split_inserted(
|
||||
current_size, extra_size + split_iter.size_to_nxt(), target_size,
|
||||
insert_pos.nxt, insert_stage, insert_size,
|
||||
is_insert_left, split_at.nxt());
|
||||
assert(is_insert_left.has_value());
|
||||
return;
|
||||
#ifndef NDEBUG
|
||||
if (locate_nxt) {
|
||||
assert(*is_insert_left == true);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// is_insert_left.has_value() == true
|
||||
// Insert will *not* happen in the lower stage.
|
||||
// Need to look into the next stage to identify the target_size
|
||||
// lower-bound w/ insert effect
|
||||
NXT_STAGE_T::recursively_locate_split(
|
||||
assert(split_iter.index() != insert_index);
|
||||
locate_nxt = NXT_STAGE_T::recursively_locate_split(
|
||||
current_size, extra_size + split_iter.size_to_nxt(),
|
||||
target_size, split_at.nxt());
|
||||
return;
|
||||
#ifndef NDEBUG
|
||||
if (split_iter.index() < insert_index) {
|
||||
assert(*is_insert_left == false);
|
||||
} else {
|
||||
assert(*is_insert_left == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (locate_nxt) {
|
||||
if (split_iter.is_last()) {
|
||||
return true;
|
||||
} else {
|
||||
++split_at;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
assert(false && "impossible path");
|
||||
return;
|
||||
return false;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -521,7 +521,7 @@ TEST_F(c_dummy_test_t, 4_split_leaf_node)
|
||||
TestTree test;
|
||||
test.build_tree({2, 5}, {2, 5}, {2, 5}, 120).get0();
|
||||
|
||||
auto& onode = test.create_onode(1084);
|
||||
auto& onode = test.create_onode(1144);
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nsplit at stage 2; insert to left front at stage 2, 1, 0\n");
|
||||
test.split(make_ghobj(1, 1, 1, "ns3", "oid3", 3, 3), onode).get0();
|
||||
@ -536,7 +536,7 @@ TEST_F(c_dummy_test_t, 4_split_leaf_node)
|
||||
test.split(make_ghobj(3, 3, 3, "ns1", "oid1", 3, 3), onode).get0();
|
||||
test.split(make_ghobj(3, 3, 3, "ns2", "oid2", 1, 1), onode).get0();
|
||||
|
||||
auto& onode0 = test.create_onode(1476);
|
||||
auto& onode0 = test.create_onode(1416);
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nsplit at stage 2; insert to right front at stage 0, 1, 2, 1, 0\n");
|
||||
test.split(make_ghobj(3, 3, 3, "ns4", "oid4", 5, 5), onode0).get0();
|
||||
@ -581,7 +581,7 @@ TEST_F(c_dummy_test_t, 4_split_leaf_node)
|
||||
test.split(make_ghobj(4, 4, 4, "ns1", "oid1", 3, 3), onode2).get0();
|
||||
test.split(make_ghobj(4, 4, 4, "ns2", "oid2", 1, 1), onode2).get0();
|
||||
|
||||
auto& onode3 = test.create_onode(964);
|
||||
auto& onode3 = test.create_onode(834);
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nsplit at stage 0; insert to right middle at stage 0, 1, 2, 1, 0\n");
|
||||
test.split(make_ghobj(3, 3, 3, "ns4", "oid4", 5, 5), onode3).get0();
|
||||
@ -912,6 +912,20 @@ TEST_F(c_dummy_test_t, 5_split_internal_node)
|
||||
"\nbefore internal node insert:\n");
|
||||
auto padding = std::string(250, '_');
|
||||
auto keys = build_key_set({2, 6}, {2, 5}, {2, 5}, padding, true);
|
||||
keys.erase(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 2, 2));
|
||||
keys.erase(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 3, 3));
|
||||
keys.erase(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 4, 4));
|
||||
keys.erase(make_ghobj(5, 5, 5, "ns4", "oid4" + padding, 2, 2));
|
||||
keys.erase(make_ghobj(5, 5, 5, "ns4", "oid4" + padding, 3, 3));
|
||||
keys.erase(make_ghobj(5, 5, 5, "ns4", "oid4" + padding, 4, 4));
|
||||
auto padding_s = std::string(257, '_');
|
||||
keys.insert(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 2, 2));
|
||||
keys.insert(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 3, 3));
|
||||
keys.insert(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 4, 4));
|
||||
auto padding_e = std::string(248, '_');
|
||||
keys.insert(make_ghobj(5, 5, 5, "ns4", "oid4" + padding_e, 2, 2));
|
||||
keys.insert(make_ghobj(5, 5, 5, "ns4", "oid4" + padding_e, 3, 3));
|
||||
keys.insert(make_ghobj(5, 5, 5, "ns4", "oid4" + padding_e, 4, 4));
|
||||
pool.build_tree(keys).unsafe_get0();
|
||||
|
||||
logger().info("\n---------------------------------------------"
|
||||
@ -933,7 +947,7 @@ TEST_F(c_dummy_test_t, 5_split_internal_node)
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nsplit at stage 2; insert to right back at stage 0, 1, 2\n");
|
||||
pool.test_split(
|
||||
make_ghobj(5, 5, 5, "ns4", "oid4" + padding, 5, 5), search_position_t::end()).get();
|
||||
make_ghobj(5, 5, 5, "ns4", "oid4" + padding_e, 5, 5), search_position_t::end()).get();
|
||||
pool.test_split(make_ghobj(5, 5, 5, "ns5", "oid5", 3, 3), search_position_t::end()).get();
|
||||
pool.test_split(make_ghobj(6, 6, 6, "ns3", "oid3", 3, 3), search_position_t::end()).get();
|
||||
|
||||
@ -941,7 +955,7 @@ TEST_F(c_dummy_test_t, 5_split_internal_node)
|
||||
"\nsplit at stage 0; insert to left front at stage 2, 1, 0\n");
|
||||
pool.test_split(make_ghobj(1, 1, 1, "ns3", "oid3", 3, 3), {0, {0, {0}}}).get();
|
||||
pool.test_split(make_ghobj(2, 2, 2, "ns1", "oid1", 3, 3), {0, {0, {0}}}).get();
|
||||
pool.test_split(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 1, 1), {0, {0, {0}}}).get();
|
||||
pool.test_split(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 1, 1), {0, {0, {0}}}).get();
|
||||
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nsplit at stage 0/1; insert to left middle at stage 0, 1, 2, 1, 0\n");
|
||||
@ -997,9 +1011,8 @@ TEST_F(c_dummy_test_t, 5_split_internal_node)
|
||||
{
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nbefore internal node insert (3):\n");
|
||||
auto padding = std::string(417, '_');
|
||||
auto padding = std::string(420, '_');
|
||||
auto keys = build_key_set({2, 5}, {2, 5}, {2, 5}, padding, true);
|
||||
keys.insert(make_ghobj(4, 4, 4, "ns3", "oid3" + padding, 5, 5));
|
||||
keys.erase(make_ghobj(4, 4, 4, "ns4", "oid4" + padding, 2, 2));
|
||||
keys.erase(make_ghobj(4, 4, 4, "ns4", "oid4" + padding, 3, 3));
|
||||
keys.erase(make_ghobj(4, 4, 4, "ns4", "oid4" + padding, 4, 4));
|
||||
@ -1015,9 +1028,15 @@ TEST_F(c_dummy_test_t, 5_split_internal_node)
|
||||
{
|
||||
logger().info("\n---------------------------------------------"
|
||||
"\nbefore internal node insert (4):\n");
|
||||
auto padding = std::string(360, '_');
|
||||
auto padding = std::string(361, '_');
|
||||
auto keys = build_key_set({2, 5}, {2, 5}, {2, 5}, padding, true);
|
||||
keys.insert(make_ghobj(4, 4, 4, "ns4", "oid4" + padding, 5, 5));
|
||||
keys.erase(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 2, 2));
|
||||
keys.erase(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 3, 3));
|
||||
keys.erase(make_ghobj(2, 2, 2, "ns2", "oid2" + padding, 4, 4));
|
||||
auto padding_s = std::string(387, '_');
|
||||
keys.insert(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 2, 2));
|
||||
keys.insert(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 3, 3));
|
||||
keys.insert(make_ghobj(2, 2, 2, "ns2", "oid2" + padding_s, 4, 4));
|
||||
pool.build_tree(keys).unsafe_get0();
|
||||
|
||||
logger().info("\n---------------------------------------------"
|
||||
|
Loading…
Reference in New Issue
Block a user