我正在学习你的论文 ARIES/KVL[1],从论文中,B+树结构看起来像:
------------------------------------ | p0 | k0 | p1 | k1 | p2 | ------------------------------------ / \ / \ / \ / \ / \ -------- <----- -------- | c0 | | c1 | -------- -----> --------
从 Search 伪代码中,Fetch、Insert 和 Delete 永远不会在 progrss SMO 中看到,因为在 SMO 完成后重新启动搜索。有一次,我们进入插入过程,满足以下条件:
- x 锁存第一叶,
- 没有涉及 1st_leaf 的 SMO 正在进行中。
- 1st_leaf 的最高键 < 分隔键
- 2nd_leaf 的键 >= 分隔键
- 1st_leaf 的键 < 2nd_leaf 的键
- 要插入的密钥 < 分隔的密钥。
例如,给定上图,当我们在 c0 中插入一个键时,那么
- c0 被 x 锁存
- 没有涉及 c0 的 SMO 正在进行。
- c0 < k0 的最高键
- c1 >= k0 的键
- c0 的键 < c1 的键
- 待插入密钥 < k0。
以下代码摘自[1],我删除了问题中不相关的部分。
/*No Space for Insert of Key*/
.....
/* No Need to Lock Next Key */
.....
/* Insert Key Value NOT Already in 1st_Leaf */
IF No Higher Key Value in 1st_Leaf AND 2nd_leaf Exists THEN
S Latch 2nd_Leaf /* while Holding X Latch on 1st_Leaf */
IF 2nd_Leaf is Empty THEN /*Page Delete in Progress-Wait for it to be Over*/
Unlatch 1st_Leaf and 2nd_Leaf
S Latch Tree for Instant-Duration
Unwind Recursion as far as Necessary Based on Noted Page VNs and Go Down Again
ELSE /* 2nd_Leaf is NOT Empty */
IF Insert Key Value found in 2nd_Leaf THEN /* This Can't be a Unique Index */
IX Lock Insert Key Value for Commit Duration
Unlatch 2nd_Leaf, Insert Key in 1st_Leaf, Log, Unlatch 1st_leaf and Return
ELSE Next Key Value := First Key Value in 2nd_Leaf
ELSE
IF No Higher Key Value in 1st_Leaf THEN Next Key Value := End_Of_file
ELSE Next Key Value := Higher Key Value in 1st_Leaf
IX Lock Next Key Value for Instant Duration
/*Insert Key into 1st_leaf*/
.....
Q1:为什么我们可以在 2nd_leaf 中找到插入键值?我的猜测是,从释放 1st_leaf 的父级闩锁到尝试 s_latch 2nd_leaf期间,其他事务引起了许多更新,因此在 2nd_leaf 中找到了一个待插入的密钥。但是,这将导致分隔键被更改,我无法理解它是如何发生的。
- 插入可能会导致拆分第二页,但不需要更改第一页和第二页之间的分隔键,因为拆分总是向右。
- 删除可能会导致删除 2nd_page,但它仍然不需要更改分隔键。
Q2:即使我们在2nd_leaf中找到了一个Insert Key Value,为什么还要把这样的key插入到1st_leaf中?因为它显然违反了 b+tree 属性(1st_leaf 的键 < 2nd_leaf 的键)。除了#6,上述条件仍然成立,因为分隔键被改变了,所以我们可以在2nd_leaf中找到to-be-inserted-key。
参考
- Mohan, C. ARIES/KVL:一种键值锁定方法,用于对 B 树索引上操作的多操作事务进行并发控制,Proc。第 16 届超大型数据库国际会议,布里斯班,1990 年 8 月。