fix: add case for update till root

This commit is contained in:
2024-04-30 05:21:30 +00:00
parent a037bf97cb
commit a75b5d8ed5
3 changed files with 29 additions and 7 deletions

View File

@ -410,6 +410,17 @@ class BPlusTreeIndexer {
RemoveEntryInRightSkewPath(pos);
return;
}
void TryUpdateTillRoot(PositionSignType &pos) {
if (pos.path.size() < 2) return;
BasicPageGuard &page_guard = pos.path.back().first;
if (pos.path.back().second != page_guard.template As<PageType>()->data.key_count - 1) return;
BasicPageGuard &parent_page_guard = pos.path[pos.path.size() - 2].first;
if (pos.path[pos.path.size() - 2].second >= parent_page_guard.template As<PageType>()->data.key_count) return;
parent_page_guard.template AsMut<PageType>()->data.p_data[pos.path[pos.path.size() - 2].second].first =
page_guard.template As<PageType>()->data.p_data[page_guard.template As<PageType>()->data.key_count - 1].first;
pos.path.pop_back();
TryUpdateTillRoot(pos);
}
void RemoveEntryAt(PositionSignType &pos, bool is_fixing_up_recursive = false) {
if (siz == 1) {
// special case for the last entry
@ -429,10 +440,16 @@ class BPlusTreeIndexer {
page_guard.template As<PageType>()->data.p_data + pos.path.back().second + 1,
(page_guard.template As<PageType>()->data.key_count - pos.path.back().second - 1) * sizeof(key_index_pair_t));
page_guard.template AsMut<PageType>()->data.key_count--;
bool need_update = false;
if (pos.path.size() >= 2 && page_guard.template AsMut<PageType>()->data.key_count == pos.path.back().second) {
auto &parent_page_guard = pos.path[pos.path.size() - 2].first;
parent_page_guard.template AsMut<PageType>()->data.p_data[pos.path[pos.path.size() - 2].second].first =
page_guard.template As<PageType>()->data.p_data[page_guard.template As<PageType>()->data.key_count - 1].first;
if (pos.path[pos.path.size() - 2].second < parent_page_guard.template As<PageType>()->data.key_count) {
parent_page_guard.template AsMut<PageType>()->data.p_data[pos.path[pos.path.size() - 2].second].first =
page_guard.template As<PageType>()
->data.p_data[page_guard.template As<PageType>()->data.key_count - 1]
.first;
need_update = true;
}
}
if (has_enough_keys) {
if (page_guard.template As<PageType>()->data.page_status & PageStatusType::ROOT &&
@ -444,7 +461,11 @@ class BPlusTreeIndexer {
page_id_t page_to_delete = page_guard.PageId();
pos.path.clear(); // all page_guards are invalid now
bpm->DeletePage(page_to_delete);
return;
}
if (need_update) {
// now we need to check if we have to update the right bound till the root
pos.path.pop_back();
TryUpdateTillRoot(pos);
}
return;
}

View File

@ -23,6 +23,7 @@
- p[i]子树中的所有key K都满足 k[i-1] \< K \<= k[i]且k[i]一定能取到即直接无缝对接lower_bound
- 对外接口提供类似于迭代器的东西但该迭代器只支持向后单项移动、读取value值、修改value值并且迭代器会保留PageGuard因此如果B+树在迭代器之前析构,会出现访问越界。
- 由于子区间**左开右闭**于是绝大多数Internal Page和Leaf Page一样都没有尾后指针整棵树的左下角会有一大片的leaf like pages它们都有个共同特性即指针数量和键值数量相同但真正的leaf page还需要额外维护page状态标号和p_n指针。
- 当删除时有一定可能在leaf like区域触发一路更新到树根的操作
# UI设计
- 语言Python

View File

@ -21,8 +21,8 @@ int main(int argc, char *argv[]) {
fprintf(fout, "Seed = %u\n", RndSeed);
fclose(fout);
// ======================================
int n = 1000;
int total_keys = 300;
int n = 100000;
int total_keys = 30000;
set<string> keys_set;
for (int i = 0; i < total_keys; i++) {
string key = "#" + to_string(rnd_less(1000000)) + "#";
@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
cout << n << endl;
for (int i = 0; i < n; i++) {
int tmp = rnd() % 10;
if (tmp <= 4) {
if (tmp <= 3) {
string key = keys_vec[rnd_less(keys_vec.size())];
int val = rnd_less(1000000);
cout << "insert " << key << " " << val << "\n";
@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
} else if (tmp <= 6) {
string key = keys_vec[rnd_less(keys_vec.size())];
int val = rnd_less(1000000);
if (rnd() % 2 == 0 && mp[key].size() > 0) {
if (rnd() % 4 > 0 && mp[key].size() > 0) {
// 选择一个有意义的删除项
val = mp[key][rnd_less(mp[key].size())];
}