最基本的注意点: PageBtreeNode的子结点要么全是PageBtreeNode,要是全是PageBtreeLeaf,不会混合两者。
类图:
与org.h2.index.PageBtreeLeaf类似
类图:
org.h2.util.CacheObject (此类中的pos字段就是PageBtreeLeaf的pageId)
org.h2.store.Page
org.h2.index.PageBtree
org.h2.index.PageBtreeNode
CacheObject的直接子类只有org.h2.util.CacheHead和org.h2.store.Page
org.h2.store.Page类定义了8种页面类型,分别对应8个子类:
页面类型id 页面名称 对应的类
------------------------------------------------------------------
0 TYPE_EMPTY 有没类,主要用于异常或其他情况
1 TYPE_DATA_LEAF org.h2.index.PageDataLeaf
2 TYPE_DATA_NODE org.h2.index.PageDataNode
3 TYPE_DATA_OVERFLOW org.h2.index.PageDataOverflow
4 TYPE_BTREE_LEAF org.h2.index.PageBtreeLeaf
5 TYPE_BTREE_NODE org.h2.index.PageBtreeNode
6 TYPE_FREE_LIST org.h2.store.PageFreeList
7 TYPE_STREAM_TRUNK org.h2.store.PageStreamTrunk
8 TYPE_STREAM_DATA org.h2.store.PageStreamData
------------------------------------------------------------------
PageDataLeaf、PageBtreeLeaf、PageBtreeNode这三者的可以在业面类型字段中加上FLAG_LAST
FLAG_LAST表示此页是最后一页。
org.h2.util.CacheObject的字段有:
public CacheObject cachePrevious
public CacheObject cacheNext
public CacheObject cacheChained
private int pos
private boolean changed
org.h2.store.Page的字段有:
protected int changeCount;
两个抽象方法:
moveTo(Session, int) //移动当前page到新的位置
write() //写当前页面的数据到硬盘
提供了三类static方法,add、insert、remove,用于从数据中给原有元素加上一个(可能是负值)、增加一个新元素、删除一个元素
这类方法多用于在rows数组和offsets、keys数组中,rows用于放记录,offsets用于放记录在page中的相对位置,keys用于放记录的key。
org.h2.index.PageBtree的字段有:
protected final PageBtreeIndex index
protected int parentPageId
protected final Data data
protected int[] offsets
protected int entryCount
protected SearchRow[] rows
protected int start
protected boolean onlyPosition
protected boolean written
protected int memoryEstimated
org.h2.index.PageBtreeNode的字段有:
private final boolean pageStoreInternalCount; //默认是false,通过参数PAGE_STORE_INTERNAL_COUNT设置
/**
* The page ids of the children.
*/
private int[] childPageIds;
private int rowCountStored = UNKNOWN_ROWCOUNT; // -1;
private int rowCount = UNKNOWN_ROWCOUNT; // -1;
以下是格式分析
------------------------------------------------------------------
字节数 代表什么
头
=======================
1 type 有两值(Page.TYPE_BTREE_NODE | Page.FLAG_LAST(最后一页)) 或 Page.TYPE_BTREE_NODE
2 checksum 预先写0,在写完page后回填(见org.h2.store.PageStore.writePage(int, Data))
4 parentPageId
VarInt index对象id(注意,不是表对象id,PageDataNode才是表对象id)
4 rowCountStored 已存储的行数
2 entryCount 分隔点的个数(rows数组的有效个数),也等于子节点个数-1
体:
=======================
4 rightmost child page id (最右边的子页id)
entryCount个
{
4 child page id
2 offset
}
entryCount个
{ (从offset开始写)
columnCount个
{
VarLong key
Value 索引列值 (如果onlyPosition为true,那么不包含这一部分,只有前面的VarLong key)
}
}
(****一个PageBtreeNode下面挂4个PageBtreeLeaf, 超过4个时切分****)
上面这句话理解错了,如果PageBtreeLeaf个数小于4时快速返回-1表示不需要对PageBtreeNode切分,
PageBtreeNode什么时候切分需要看pageSize和索引字段的长度,
不过PageBtreeNode最少有4个PageBtreeLeaf
page size = 128
rowLength = 12
[( /* 8 */ '1000000008' ), ( /* 7 */ '1000000007' ), ( /* 6 */ '1000000006' ), ( /* 5 */ '1000000005' ), ( /* 4 */ '1000000004' ), ( /* 3 */ '1000000003' ), ( /* 2 */ '1000000002' ), ( /* 1 */ '1000000001' ), null, null]
[116, 104, 92, 80, 68, 56, 44, 32, 0, 0]
splitPoint= 2
从下标为2的位置开始split(切分),从splitPoint(包含)到结束的元素放在page2
从开始到splitPoint的元素在page1,
splitPoint前面的元素单独抽出来做为父结点的分隔key,
也就是说中间层的结点中的分隔key,>=分隔key的在左边的子结点,<分隔key的在右边的子结点
pivot = ( /* 7 */ '1000000007' )
page1 = 2
[( /* 8 */ '1000000008' ), ( /* 7 */ '1000000007' ), ( /* 1 */ '1000000001' ), ( /* 1 */ '1000000001' ), ( /* 1 */ '1000000001' )]
page2 = 6
[( /* 6 */ '1000000006' ), ( /* 5 */ '1000000005' ), ( /* 4 */ '1000000004' ), ( /* 3 */ '1000000003' ), ( /* 2 */ '1000000002' ), ( /* 1 */ '1000000001' ), null, null, null, null]
[116, 104, 92, 80, 68]
[116, 104, 92, 80, 0]
PageBtreeNode分隔前
---------------------------
childPageIds = [74, 86, 84, 81, 79, 76, 73, 0, 0, 0, 0]
rows(分隔key) = [( /* 37 */ '1000000037' ), ( /* 31 */ '1000000031' ), ( /* 25 */ '1000000025' ), ( /* 19 */ '1000000019' ), ( /* 13 */ '1000000013' ), ( /* 7 */ '1000000007' ), null, null, null, null]
entryCount = 6
splitPoint =3
pivot = ( /* 25 */ '1000000025' )
---------------------------
PageBtreeNode p2
---------------------------
childPageIds = [81, 79, 76, 73, 0, 0]
rows(分隔key) = [( /* 19 */ '1000000019' ), ( /* 13 */ '1000000013' ), ( /* 7 */ '1000000007' ), null, null]
entryCount = 3
---------------------------
pageId=89
PageBtreeNode p1
---------------------------
childPageIds = [74, 86, 84, 73, 73, 73]
rows(分隔key) = [( /* 37 */ '1000000037' ), ( /* 31 */ '1000000031' ), ( /* 25 */ '1000000025' ), ( /* 7 */ '1000000007' ), ( /* 7 */ '1000000007' )]
entryCount = 2
---------------------------
pageId=90 (新分配一个pageId)
得到一个新的PageBtreeNode后,
此PageBtreeNode的childPageIds是[90, 89] rows(分隔key) = [( /* 25 */ '1000000025' )]
0 1 2 3 4 5 6 7 ... 116 117 118 119 120 121 122 123 124 125 126 127
( /* key:1 */ 1, 'abcdef1234')
116 117 118 119 120 121 122 123 124 125 126 127
1 10 a b c d e f 1 2 3 4
104 ... 115
( /* key:2 */ 2, 'abcdef1234')
92 ... 103
( /* key:3 */ 3, 'abcdef1234')
80 ... 91
( /* key:4 */ 4, 'abcdef1234')
68 ... 79
( /* key:5 */ 5, 'abcdef1234')
56 ... 67
( /* key:6 */ 6, 'abcdef1234')
44 ... 55
( /* key:7 */ 7, 'abcdef1234')
keys = [1, 2, 3, 4, 5, 6, 7, 0, 0, 0]
rows = [( /* key:1 */ 1, 'abcdef1234'), ( /* key:2 */ 2, 'abcdef1234'), ( /* key:3 */ 3, 'abcdef1234'), ( /* key:4 */ 4, 'abcdef1234'), ( /* key:5 */ 5, 'abcdef1234'), ( /* key:6 */ 6, 'abcdef1234'), ( /* key:7 */ 7, 'abcdef1234'), null, null, null]
offsets = [116, 104, 92, 80, 68, 56, 44, 0, 0, 0]
entryCount = 7
last = 44
rowLength = 12
start = 32
keyOffsetPairLen = 3
last - rowLength = 44 - 12 = 32
start + keyOffsetPairLen = 32 + 3 = 35
当前行: ( /* key:8 */ 8, 'abcdef1234')
也就是说先看看当前page(128字节)如果要存当前行的话是否有足够空间存keyOffsetPair,
因为当前行的长度是12,page中只剩下44个字节了(0到43),再存12个就只剩32个可用,
而start当前已经到32了,再存当前行的keyOffsetPair的话要多加3,则start位置移到35,超过剩余可用的32个字节了。
所以此时要对当前的PageDataLeaf进行切割。
if (entryCount > 0 && last - rowLength < start + keyOffsetPairLen) {
int x = findInsertionPoint(row.getKey()); //x = 7
if (entryCount > 1) {
if (entryCount < 5) {
// required, otherwise the index doesn't work correctly
return entryCount / 2;
}
if (index.isSortedInsertMode()) {
return x < 2 ? 1 : x > entryCount - 1 ? entryCount - 1 : x;
}
// split near the insertion point to better fill pages
// split in half would be:
// return entryCount / 2;
int third = entryCount / 3;
return x < third ? third : x >= 2 * third ? 2 * third : x; //返回4 (从rows[4]=( /* key:5 */ 5, 'abcdef1234')开始切割)
}
return x;
}
新的PageDataLeaf的
rows = [( /* key:5 */ 5, 'abcdef1234'), ( /* key:6 */ 6, 'abcdef1234'), ( /* key:7 */ 7, 'abcdef1234'), null, null, null]
splitPoint = 3
childPageIds = [46, 45, 48, 50, 52, 54, 56, 0, 0, 0, 0]
firstChild = 50
entryCount = 2
[46, 45, 48, 56, 56, 56]
[50, 52, 54, 56, 0, 0]
PageBtreeNode {
pageId = 8
parentPageId = 0
childPageIds = 84, 83, 89
childPageIds.length = 3
entryCount = 2
rows = {
( /* key:8 */ 8, '1000000008', null)
( /* key:16 */ 16, '1000000016', null)
}
PageBtreeNode {
pageId = 84
parentPageId = 8
childPageIds = 13, 12
childPageIds.length = 2
entryCount = 1
rows = {
( /* key:4 */ 4, '1000000004', null)
}
PageBtreeLeaf {
indexId = 15
parentPageId = 84
pageId = 13
start = 18
offsets = 115, 102, 89, 76
entryCount = 4
rows = {
( /* key:1 */ 1, '1000000001', null)
( /* key:2 */ 2, '1000000002', null)
( /* key:3 */ 3, '1000000003', null)
( /* key:4 */ 4, '1000000004', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 84
pageId = 12
start = 18
offsets = 115, 102, 89, 76
entryCount = 4
rows = {
( /* key:5 */ 5, '1000000005', null)
( /* key:6 */ 6, '1000000006', null)
( /* key:7 */ 7, '1000000007', null)
( /* key:8 */ 8, '1000000008', null)
}
}
}
PageBtreeNode {
pageId = 83
parentPageId = 8
childPageIds = 15, 16
childPageIds.length = 2
entryCount = 1
rows = {
( /* key:12 */ 12, '1000000012', null)
}
PageBtreeLeaf {
indexId = 15
parentPageId = 83
pageId = 15
start = 18
offsets = 115, 102, 89, 76
entryCount = 4
rows = {
( /* key:9 */ 9, '1000000009', null)
( /* key:10 */ 10, '1000000010', null)
( /* key:11 */ 11, '1000000011', null)
( /* key:12 */ 12, '1000000012', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 83
pageId = 16
start = 18
offsets = 115, 102, 89, 75
entryCount = 4
rows = {
( /* key:13 */ 13, '1000000013', null)
( /* key:14 */ 14, '1000000014', null)
( /* key:15 */ 15, '1000000015', null)
( /* key:16 */ 16, '1000000016', null)
}
}
}
PageBtreeNode {
pageId = 89
parentPageId = 8
childPageIds = 18, 81, 85, 87, 90, 92
childPageIds.length = 6
entryCount = 5
rows = {
( /* key:20 */ 20, '1000000020', null)
( /* key:24 */ 24, '1000000024', null)
( /* key:28 */ 28, '1000000028', null)
( /* key:32 */ 32, '1000000032', null)
( /* key:36 */ 36, '1000000036', null)
}
PageBtreeLeaf {
indexId = 15
parentPageId = 89
pageId = 18
start = 18
offsets = 114, 100, 86, 72
entryCount = 4
rows = {
( /* key:17 */ 17, '1000000017', null)
( /* key:18 */ 18, '1000000018', null)
( /* key:19 */ 19, '1000000019', null)
( /* key:20 */ 20, '1000000020', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 89
pageId = 81
start = 18
offsets = 114, 100, 86, 72
entryCount = 4
rows = {
( /* key:21 */ 21, '1000000021', null)
( /* key:22 */ 22, '1000000022', null)
( /* key:23 */ 23, '1000000023', null)
( /* key:24 */ 24, '1000000024', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 89
pageId = 85
start = 18
offsets = 114, 100, 86, 72
entryCount = 4
rows = {
( /* key:25 */ 25, '1000000025', null)
( /* key:26 */ 26, '1000000026', null)
( /* key:27 */ 27, '1000000027', null)
( /* key:28 */ 28, '1000000028', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 89
pageId = 87
start = 18
offsets = 114, 100, 86, 72
entryCount = 4
rows = {
( /* key:29 */ 29, '1000000029', null)
( /* key:30 */ 30, '1000000030', null)
( /* key:31 */ 31, '1000000031', null)
( /* key:32 */ 32, '1000000032', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 89
pageId = 90
start = 18
offsets = 114, 100, 86, 72
entryCount = 4
rows = {
( /* key:33 */ 33, '1000000033', null)
( /* key:34 */ 34, '1000000034', null)
( /* key:35 */ 35, '1000000035', null)
( /* key:36 */ 36, '1000000036', null)
}
}
PageBtreeLeaf {
indexId = 15
parentPageId = 89
pageId = 92
start = 18
offsets = 114, 100, 86, 72
entryCount = 4
rows = {
( /* key:37 */ 37, '1000000037', null)
( /* key:38 */ 38, '1000000038', null)
( /* key:39 */ 39, '1000000039', null)
( /* key:40 */ 40, '1000000040', null)
}
}
}
}