miniob
miniob copied to clipboard
B+ tree optimizations
1. 锁的管理优化
- 目标:提高并发性能,避免死锁,减少锁的持有时间。
-
方案详情:
- 在
insert_entry_into_parent函数中,创建新根节点时,先释放子节点的锁(disk_buffer_pool_->unpin_page(frame); disk_buffer_pool_->unpin_page(new_frame);),再进行根节点的加锁和更新操作。这样可以避免在创建根节点过程中长时间持有子节点的锁,提高并发性能,因为在创建新根节点时,子节点的修改已经完成,不需要再持有其锁。 - 递归调用
insert_entry_into_parent之前,释放当前父节点的锁(disk_buffer_pool_->unpin_page(parent_frame);)。这是因为在递归调用过程中,当前父节点的操作已经完成,不需要继续持有锁,减少锁的持有时间,提高并发性能。 - 在
split函数中,将新节点的初始化操作封装到initializeNewNode函数中,使锁的获取和节点初始化逻辑更清晰,便于维护和理解锁的使用范围。
- 在
2. 资源管理优化
- 目标:确保资源正确分配和释放,避免资源泄漏,提高资源使用效率。
-
方案详情:
- 在
make_key函数中,使用auto关键字简化mem_pool_item_->alloc_unique_ptr()的返回值处理。同时,添加try-catch块来捕获memcpy操作可能抛出的异常,更细致地处理内存复制过程中的错误情况。如果内存复制失败,不仅记录错误日志,还能确保函数返回nullptr,避免返回未完全初始化的指针,防止后续使用该指针导致未定义行为。 - 在
open函数中,当打开文件失败时,添加更详细的错误日志(LOG_ERROR("Failed to fully open b+tree. File name: %s, Error code: %d:%s", file_name, rc, strrc(rc));),方便问题排查。同时,对于错误情况,可以根据具体需求在注释中添加更详细的错误恢复操作建议,例如清理部分已分配的资源,虽然目前只是注释,但为后续优化提供了方向。
- 在
3. 代替裸指针进行内存管理
- 目标:使用智能指针代替裸指针,简化内存管理,避免手动释放内存带来的错误,确保内存安全。
-
方案详情:在
make_key函数中,使用std::unique_ptr(通过mem_pool_item_->alloc_unique_ptr()返回)来管理动态分配的内存。std::unique_ptr会在其生命周期结束时自动释放所管理的内存,避免了手动释放内存可能导致的内存泄漏或悬挂指针问题。通过这种方式,提高了内存管理的安全性和可靠性,减少了因内存管理不当而引入的错误。
4. insert_entry_into_leaf_node 函数性能优化
- 目标:减少节点分裂操作的性能开销,提高插入操作的整体性能。
-
方案详情:
-
预分配逻辑:添加了节点接近满时的预分配逻辑,当
leaf_node.size() >= leaf_node.max_size() - 5时,提前调用split函数分配新节点。这是因为节点分裂操作是一个相对耗时的操作,涉及到节点数据的移动和新节点的创建等复杂操作。通过提前预分配,当节点真正满时,无需立即进行分裂操作,直接将数据插入到新节点中,避免了在高并发插入场景下,节点满时才进行分裂可能导致的性能瓶颈,从而减少性能开销,提高插入操作的整体性能。 - 减少节点满时的处理时间:预分配新节点后,在后续插入操作中,根据插入位置判断数据应插入到原节点还是新节点,减少了节点满时才进行分裂操作的等待时间,提高了插入操作的响应速度。同时,这种方式也能在一定程度上均衡节点的负载,避免某些节点频繁分裂而影响性能。
-
预分配逻辑:添加了节点接近满时的预分配逻辑,当
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.
@Lss-lmj 看起来你优化了一些性能,可以给出一些数字嘛?看起来在你修改后产生了死锁,ci 也没有通过。