Conversation
|
|
| LOG_WARN("Failed to open file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); | ||
| return rc; | ||
| }else { | ||
| LOG_ERROR("Failed to fully open b+tree. File name: %s, Error code: %d:%s", file_name, rc, strrc(rc)); |
|
|
||
|
|
||
| /* | ||
| 优化信息@sjk |
There was a problem hiding this comment.
can we remove unnecessary comments @sjk ?
| if (key == nullptr) { | ||
| LOG_WARN("Failed to alloc memory for key."); | ||
| return nullptr; | ||
| auto key = mem_pool_item_->alloc_unique_ptr(); |
There was a problem hiding this comment.
here is no need to change to auto.
| return nullptr; | ||
| } | ||
| try { | ||
| memcpy(key.get(), user_key, file_header_.attr_length); |
There was a problem hiding this comment.
why memcpy maybe fail? what is the scenario?
|
|
||
| /* | ||
| 优化信息 | ||
| 在创建新根节点时,原代码在更新根节点相关信息后才释放子节点锁,优化后先释放子节点锁,再处理根节点加锁和更新,减少了子节点锁的持有时间,提高并发性能。 |
There was a problem hiding this comment.
Comments are not appropriate here.
| template <typename IndexNodeHandlerType> | ||
| void BplusTreeHandler::initializeNewNode(BplusTreeMiniTransaction &mtr, Frame *new_frame, IndexNodeHandlerType &old_node) | ||
| { | ||
| IndexNodeHandlerType new_node(mtr, file_header_, new_frame); |
There was a problem hiding this comment.
why new_node appears in function and out of function?
|
|
||
| Frame *new_frame = nullptr; | ||
| // 添加预分配逻辑,当节点接近满时提前分配新节点 | ||
| if (leaf_node.size() < leaf_node.max_size() - 5) { |
There was a problem hiding this comment.
hard code 5 is ok? if max_size() <=5 ?
|
@Lss-lmj 看起来你优化了一些性能,可以给出一些数字嘛?看起来在你修改后产生了死锁,ci 也没有通过。 |
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函数分配新节点。这是因为节点分裂操作是一个相对耗时的操作,涉及到节点数据的移动和新节点的创建等复杂操作。通过提前预分配,当节点真正满时,无需立即进行分裂操作,直接将数据插入到新节点中,避免了在高并发插入场景下,节点满时才进行分裂可能导致的性能瓶颈,从而减少性能开销,提高插入操作的整体性能。