写**(聚簇索引 + 二级索引)**
graph TB
Start[INSERT操作开始] --> BuildRow[构建完整行数据]
BuildRow --> Phase1[阶段1: 聚簇索引写入]
Phase1 --> ClustSearch[搜索聚簇索引位置]
ClustSearch --> ClustLock[检查锁冲突]
ClustLock --> WriteUndo[写Undo日志<br/>trx_undo_report_row_operation]
WriteUndo --> GetRollPtr[获取roll_ptr回滚指针]
GetRollPtr --> FillRollPtr[将roll_ptr填入记录]
FillRollPtr --> ClustInsert{页面在<br/>buffer pool?}
ClustInsert -->|否| ReadClustPage[从磁盘读取页面]
ReadClustPage --> DoClustInsert
ClustInsert -->|是| DoClustInsert[物理插入记录<br/>page_cur_tuple_insert]
DoClustInsert --> ClustRedo[写Redo日志<br/>记录聚簇索引页修改]
ClustRedo --> CommitMtr1[提交mtr]
CommitMtr1 --> Phase2[阶段2: 二级索引写入]
Phase2 --> BuildSecEntry[构建二级索引entry]
BuildSecEntry --> SecSearch[搜索二级索引位置<br/>btr_cur_search_to_nth_level]
SecSearch --> SecInBuf{索引页在<br/>buffer pool?}
SecInBuf -->|是| DirectInsert[直接插入页面<br/>row_ins_sec_index_entry_low]
SecInBuf -->|否| CheckBuffer{检查Change Buffer<br/>使用条件}
CheckBuffer -->|满足条件| UseChangeBuffer[使用Change Buffer路径]
CheckBuffer -->|不满足| ForceRead[强制读取页面]
UseChangeBuffer --> CheckCond1{是非唯一<br/>二级索引?}
CheckCond1 -->|否<br/>唯一索引| ForceRead
CheckCond1 -->|是| CheckCond2{无buffer pool<br/>watch?}
CheckCond2 -->|有watch| ForceRead
CheckCond2 -->|无| CheckCond3{Change Buffer<br/>未满?}
CheckCond3 -->|已满| ForceRead
CheckCond3 -->|未满| InsertIbuf[插入到Change Buffer B-tree<br/>ibuf_insert_low]
InsertIbuf --> UpdateBitmap[更新ibuf bitmap<br/>记录页面空间]
UpdateBitmap --> IbufRedo[写Redo日志<br/>记录Change Buffer操作]
IbufRedo --> IbufReturn[返回BTR_CUR_INSERT_TO_IBUF<br/>异步完成]
ForceRead --> ReadSecPage[从磁盘读取索引页到buffer pool]
ReadSecPage --> DirectInsert
DirectInsert --> SecRedo[写Redo日志<br/>记录二级索引页修改]
SecRedo --> CommitMtr2[提交mtr<br/>同步完成]
IbufReturn --> End[插入操作完成]
CommitMtr2 --> End
style WriteUndo fill:#FFD700
style InsertIbuf fill:#90EE90
style IbufReturn fill:#87CEEB
style ForceRead fill:#FFA07A
style DoClustInsert fill:#DDA0DD
change buffer刷新写入合并
graph TB
Start[后台触发合并] --> Trigger{触发时机}
Trigger -->|方式1| PageRead[索引页被查询<br/>读入buffer pool]
Trigger -->|方式2| MasterThread[Master线程<br/>定期合并]
Trigger -->|方式3| Shutdown[数据库关闭<br/>强制合并]
PageRead --> Merge1[buf_read_page完成后<br/>调用ibuf_merge_or_delete_for_page]
MasterThread --> Merge2[ibuf_merge_in_background<br/>批量合并]
Shutdown --> Merge3[ibuf_merge_space<br/>表空间合并]
Merge1 --> MergeProcess
Merge2 --> MergeProcess
Merge3 --> MergeProcess
MergeProcess[合并过程] --> Step1[1. 查找Change Buffer中<br/>该页的所有操作记录]
Step1 --> Step2[2. 按顺序应用到索引页<br/>ibuf_insert_to_index_page_low]
Step2 --> Step3[3. 写Redo日志<br/>记录页面修改]
Step3 --> Step4[4. 从Change Buffer删除记录<br/>ibuf_delete_rec]
Step4 --> Step5[5. 更新ibuf bitmap]
Step5 --> Complete[合并完成]
style PageRead fill:#90EE90
style MasterThread fill:#87CEEB
style Shutdown fill:#FFB6C1
是否用change buffer
graph TB
Start[尝试使用Change Buffer] --> Check1{索引类型检查}
Check1 -->|聚簇索引| Fail1[❌ 不能使用]
Check1 -->|二级索引| Check2{唯一性检查}
Check2 -->|唯一索引| Fail2[❌ 不能使用<br/>需检查重复]
Check2 -->|非唯一索引| Check3{页面状态检查}
Check3 -->|页面在buffer pool| Fail3[❌ 不使用<br/>直接在内存操作更快]
Check3 -->|页面不在buffer pool| Check4{Buffer Pool Watch检查}
Check4 -->|有watch哨兵<br/>buf_page_get_also_watch!=NULL| Fail4[❌ 不能使用<br/>有purge线程正在操作该页<br/>避免并发冲突]
Check4 -->|无watch| Check5{Change Buffer容量检查}
Check5 -->|已满| Fail5[❌ 不能使用<br/>需要先合并]
Check5 -->|未满| Check6{记录大小检查}
Check6 -->|过大| Fail6[❌ 不能使用]
Check6 -->|合适| Success[✅ 可以使用Change Buffer]
Success --> UseIbuf[插入到Change Buffer<br/>异步完成]
Fail1 --> SyncWrite[同步写入路径]
Fail2 --> SyncWrite
Fail3 --> SyncWrite
Fail4 --> SyncWrite
Fail5 --> SyncWrite
Fail6 --> SyncWrite
SyncWrite --> ReadPage[读取页面到buffer pool]
ReadPage --> DirectWrite[直接在页面上操作]
style Fail4 fill:#FF6B6B
style Success fill:#90EE90
style UseIbuf fill:#87CEEB