H2 Database 事务 Commit 实现原理

H2 Database 事务 Commit 流程实现原理

使用

测试 Demo:

begin;
insert into test values(1);
commit;

功能

模块

总体流程

解析 commit 语句
执行 commit 语句
    设置事务状态为已提交
    根据 undoLogId 判断事务是否有更改操作,有更改继续提交
    CAS 设置当前事务状态为已提交到 committingTransactions
    遍历 undoLog mvMap
        追加标记 undoLog 已提交到 undoLog mvMap 上
        获取当前 undoLog 操作涉及的 mvMap id
            遍历到对应 Page 的对应 index
            将 VersionedValueUncommitted 类型更新成 DefaultRow 类型
事务清理操作
    清理 undoLog mvMap(更新 root 节点为 empty)
    清理事务状态
    释放 table 锁

代码流程

org.h2.command.dml.TransactionCommand#update
    org.h2.engine.SessionLocal#commit
        org.h2.mvstore.tx.Transaction#commit 
        提交事务
            org.h2.mvstore.tx.Transaction#markTransactionEnd 
            标记事务结束
            org.h2.mvstore.tx.Transaction#setStatus 
            2.设置事务状态为已提交
                1.获取当前 state & logId
                org.h2.mvstore.tx.Transaction#getLogId 
                获取当前 undo log id
                org.h2.mvstore.tx.Transaction#getStatus 
                1.获取当前状态
                2.判断当前状态允许变更为目标状态,然后变更为目标状态,此处设置为STATUS_COMMITTED状态
                org.h2.mvstore.tx.Transaction#composeState 
                创建新状态(transaction status + undo log id)
                原子变更状态
            org.h2.mvstore.tx.Transaction#hasChanges 
            3.判断是否有更改(undo log id 不为0)
            org.h2.mvstore.tx.TransactionStore#commit 
            4.如果有更改,执行提交操作
                获取当前事务对应的 undo log mvMap
                org.h2.mvstore.MVMap#cursor 
                获取 undo log mvMap 的 cursor
                org.h2.mvstore.tx.TransactionStore#markUndoLogAsCommitted 
                1.2.标记 undo log 已提交
                    org.h2.mvstore.tx.TransactionStore#addUndoLogRecord 
                    追加标记 undo log 为 committed(不会修改之前的)
                        org.h2.mvstore.tx.TransactionStore#getOperationId 
                        2.计算得到 undo log key(transaction id + undo log id)
                        org.h2.mvstore.MVMap#append 
                        3.追加 undo log mvMap(将 key:undoLogKey, value:undoLogRecord 添加到 map 里)
                            org.h2.mvstore.MVMap#getRoot 
                            获取根节点
                            org.h2.mvstore.MVMap#lockRoot 
                            1.锁定根节点
                            org.h2.mvstore.RootReference#getAppendCounter 
                            2.获取当前写入下标
                            4.key 写入 buffer
                            5.value 写入 buffer
                            如果 buffer 超出阈值,则先将未保存到 btree 页面上的 buffer 数据保存到 btree 上
                            org.h2.mvstore.MVMap#unlockRoot
                            4.解锁 root
                org.h2.mvstore.tx.TransactionStore#flipCommittingTransactionsBit 
                2.标记事务更改为“已提交”的原子操作(cas 设置当前事务状态为已提交到 committingTransactions)
                org.h2.mvstore.Cursor#next 
                3.遍历当前事务对应的 undoLog mvMap 里的所有 undo log key
                org.h2.mvstore.Cursor#getValue 
                获取 undo log key 和 undo log record
                获取 undo log 操作涉及的 map id
                org.h2.mvstore.tx.TransactionStore#openMap 
                5.打开 mvMap(当前事务的当前 undo log 操作对应的行数据map)
                获取当前 undo log 操作的 key(比如行主键id)
                org.h2.mvstore.tx.CommitDecisionMaker#setUndoKey
                org.h2.mvstore.MVMap#operate 
                根据 undo key 操作 map
                    org.h2.mvstore.MVMap#flushAndGetRoot 
                    1.获取 mvMap 根节点
                    org.h2.mvstore.CursorPos#traverseDown  
                    2.从根节点开始,根据 key 遍历 tree,找到 key 的位置 pos
                    3.获取操作(插入/删除..)位置对应的 pos 对应的 page
                    获取当前 key 对应的在 page 上的下标
                    org.h2.mvstore.Page.Leaf#getValue 
                    4.根据索引获取 page 上的值,如果是插入操作此处为 null,因为原来没有值
                    org.h2.mvstore.MVMap.DecisionMaker#decide 
                    5.根据 当前值、目标值 和 游标位置 决定操作类型
                    org.h2.mvstore.tx.CommitDecisionMaker#selectValue 
                    获取当前值(如果是事务commit操作,此处会获取 VersionedValueUncommitted 里的 defaultRow)
                    org.h2.mvstore.Page#copy 
                    复制当前page
                    org.h2.mvstore.Page.Leaf#setValue 
                    设置值(更新成DefaultRow)
                    org.h2.mvstore.RootReference#updateRootPage
                    更新 root page
                org.h2.mvstore.MVMap#clear 
                清理 undo log mvMap(更新 root 为 empty.可以 debug 查看进入这个方法前后 undoLog 对象的变化)
            org.h2.mvstore.tx.TransactionStore#endTransaction 
            结束事务-清理事务状态
        org.h2.engine.SessionLocal#endTransaction 
        结束事务-释放table锁
posted on 2025-05-09 08:18  flyingzc  阅读(0)  评论(0)    收藏  举报  来源