diff --git a/bpt/include/bpt/bpt.hpp b/bpt/include/bpt/bpt.hpp index 607e63e..969880f 100644 --- a/bpt/include/bpt/bpt.hpp +++ b/bpt/include/bpt/bpt.hpp @@ -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()->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()->data.key_count) return; + parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second].first = + page_guard.template As()->data.p_data[page_guard.template As()->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()->data.p_data + pos.path.back().second + 1, (page_guard.template As()->data.key_count - pos.path.back().second - 1) * sizeof(key_index_pair_t)); page_guard.template AsMut()->data.key_count--; + bool need_update = false; if (pos.path.size() >= 2 && page_guard.template AsMut()->data.key_count == pos.path.back().second) { auto &parent_page_guard = pos.path[pos.path.size() - 2].first; - parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second].first = - page_guard.template As()->data.p_data[page_guard.template As()->data.key_count - 1].first; + if (pos.path[pos.path.size() - 2].second < parent_page_guard.template As()->data.key_count) { + parent_page_guard.template AsMut()->data.p_data[pos.path[pos.path.size() - 2].second].first = + page_guard.template As() + ->data.p_data[page_guard.template As()->data.key_count - 1] + .first; + need_update = true; + } } if (has_enough_keys) { if (page_guard.template As()->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; } diff --git a/design.md b/design.md index a78cc82..dfc1415 100644 --- a/design.md +++ b/design.md @@ -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 diff --git a/test/t1_mk.cpp b/test/t1_mk.cpp index 6a30e2b..9775e3d 100644 --- a/test/t1_mk.cpp +++ b/test/t1_mk.cpp @@ -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 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())]; }