org.h2.mvstore.MVStore的MVMap<String, String> meta存放哪些key/value:
key value
=============================================
"name." + mapName mapId
"map."+ mapId {map metadata}形如"k1:v1, k2:v2..."这样的字符串格式
"root." + mapId map的root page pos
"chunk." + chunkId Chunk.asString()
"setting.storeVersion" storeVersion
运行时,一个数据库对应一个MVStore实例、对应一个TransactionStore实例
并且对应一个preparedTransactions MVMap和一个undoLog MVMap
MVStore
TransactionStore
* The persisted map of open transaction.
* Key: transactionId, value: [ status, name ].
*/
final MVMap<Long, Object[]> preparedTransactions;
/**
* The undo log.
* Key: [ transactionId, logId ], value: [ opType, mapId, key, oldValue ].
*/
final MVMap<long[], Object[]> undoLog;
主表记录对应一个MVPrimaryIndex实例
每个索引对应一个MVSecondaryIndex实例
一个MVTable类型的表只有一个MVPrimaryIndex实例,可以有多个MVSecondaryIndex实例,
每个MVPrimaryIndex实例和MVSecondaryIndex实例都有一个MVMap,
在对MVPrimaryIndex和MVSecondaryIndex增加或删除数据时,除了为各自的MVMap进行操作外,
还往undoLog这个MVMap增加或删除log,当需要rollback时,
根据transactionId和logId取出值,值里有[ opType, mapId, key, oldValue ],
根据mapId能从MVStore实例中取出MVPrimaryIndex实例和MVSecondaryIndex实例对应的MVMap,
然后根据oldValue是否为null,null表示进行的是增加操作,rollback时,
就按key从MVPrimaryIndex实例和MVSecondaryIndex实例对应的MVMap中删除,若不为null,就表示删除操作,
此时要重新put回去。
TODO undoLog这个MVMap中的opType似乎没用,因为根据oldValue是否为null,就能判断操作类型了(增加或删除)
MVStore.Builder可配置的参数:
autoCommitBufferSize
autoCompactFillRate
backgroundExceptionHandler
cacheSize
compress (LZF和Deflate)
encryptionKey
fileName
fileStore
pageSplitSize
readOnly
=================================
MVStore格式
MVStore {
4096字节 StoreHeader
4096字节 StoreHeader
[ Chunk ] *
128字节 ChunkFooter
}
StoreHeader {
4096字节是一个块的大小,上面两个是一样的,防止块损坏,
一个StoreHeader的大小不固定,取决于具体的值,但是不会超过4096字节,
StoreHeader有8个属性:
-----------------------
H:3,
blockSize:4096,
created:1368493299954,
format:1,
block:0, //lastChunk.block
chunk:0, //lastChunk.id
version:0, //lastChunk.version
fletcher:3bde3c9a (使用Fletcher32算法得到的checksum,是对前面7个属性求checksum)
-----------------------
}
ChunkFooter {
chunk:1,block:2,version:1,fletcher:84d0d5f6
}
Chunk {
[ ChunkHeader MVMapPage MetaMapPage FileHeader] *
}
//每个ChunkHeader最多占1024字节
ChunkHeader {
byte 固定是'c'
int length
int id
int pageCount
long metaRootPos
long maxLength
long maxLengthLive
}
MVMapPage = Page
MetaMapPage = Page
Page {
int page length(包含这4字节)
short check value(并不是校验和,不用计算所有字节),check value的值取决于当前page所在chunk的chunkId、start位置(或称offset)、page length
varInt map id
varInt key count
byte page type(0: leaf, 1: node)
接下来分两种情况:
===========================
1. 如果不需压缩: {
if (type == leaf) {
key count {
Object key
}
key count {
Object value
}
}
else if (type == node) {
key count + 1 {
long child page pos
}
key count + 1 {
varLong child key count
}
key count {
Object key
}
}
}
2. 如果需要压缩,先按1的方式写入buffer,计算1的字节长度,然后尝试压缩buffer中的字节,
如果"压缩后的长度+(压缩后的长度-buffer长度)的差的VarIntLen < buffer长度"那么就进行压缩:
重写page type
byte page type(2: leaf+compressed, 3: node+compressed)
varInt buffer长度-压缩后的长度
压缩后的长度 压缩后的字节
}
meta map样例:
PageLeaf{
id = 23191477
pos = 1099511630162
version = -1
keyCount = 10
chunk.1:id:1,length:2352,maxLength:3008,maxLengthLive:1024,metaRoot:274878040014,pageCount:7,pageCountLive:2,start:8192,time:16,version:1
chunk.2:id:2,length:426,maxLength:512,maxLengthLive:512,metaRoot:549755816272,pageCount:1,pageCountLive:1,start:16384,time:16,version:2
chunk.3:id:3,length:2865,maxLength:3424,maxLengthLive:2656,metaRoot:824633869138,pageCount:7,pageCountLive:6,start:24576,time:16,version:3
chunk.4:id:4,length:2147483647,maxLength:0,maxLengthLive:0,metaRoot:0,pageCount:0,pageCountLive:0,start:9223372036854775807,time:16,version:4
map.1:name:data
map.2:name:data2
name.data:1
name.data2:2
root.1:824633866563
root.2:824633793603
}
下面的数字是16进制
file header:
=================
H:2,block:2,blockSize:1000,chunk:129,created:149b6ac28ee,format:1,version:129,fletcher:424fcf1c
H:2,block:2,blockSize:1000,chunk:129,created:149b6ac28ee,format:1,version:129,fletcher:424fcf1c
footer
===========
chunk:128,block:4,version:128,fletcher:8097485b
readChunkHeader:
================
chunk:129,block:2,len:1,map:1f,max:900,next:3,pages:8,root:4a4000012743,time:1ad588de,version:129
readChunkFooter
======================
chunk:129,block:2,version:129,fletcher:7e97485b
readChunkHeader:
================
chunk:127,block:3,len:1,map:1f,max:900,next:4,pages:8,root:49c000012743,time:1ad42913,version:127
chunk:1,block:2,len:1,map:1,max:5a0,next:3,pages:e,root:40000119c4,time:274e1,version:1
==========================================================================================
以下是老版本(已经过时)
==========================================================================================
org.h2.mvstore.MVStore的MVMapConcurrent<String, String> meta存放哪些key/value:
key value
=============================================
"map."+ mapId {map metadata}形如"k1:v1, k2:v2..."这样的字符串格式
"name." + mapName mapId
"chunk." + chunkId Chunk.asString()
"root." + mapId pagePos
"setting.storeVersion" storeVersion
"rollbackOnOpen" lastCommittedVersion
运行时,一个数据库对应一个MVStore实例、对应一个TransactionStore实例
并且对应一个preparedTransactions MVMap和一个undoLog MVMap
MVStore
TransactionStore
* The persisted map of open transaction.
* Key: transactionId, value: [ status, name ].
*/
final MVMap<Long, Object[]> preparedTransactions;
/**
* The undo log.
* Key: [ transactionId, logId ], value: [ opType, mapId, key, oldValue ].
*/
final MVMap<long[], Object[]> undoLog;
主表记录对应一个MVPrimaryIndex实例
每个索引对应一个MVSecondaryIndex实例
一个MVTable类型的表只有一个MVPrimaryIndex实例,可以有多个MVSecondaryIndex实例,
每个MVPrimaryIndex实例和MVSecondaryIndex实例都有一个MVMap,
在对MVPrimaryIndex和MVSecondaryIndex增加或删除数据时,除了为各自的MVMap进行操作外,
还往undoLog这个MVMap增加或删除log,当需要rollback时,
根据transactionId和logId取出值,值里有[ opType, mapId, key, oldValue ],
根据mapId能从MVStore实例中取出MVPrimaryIndex实例和MVSecondaryIndex实例对应的MVMap,
然后根据oldValue是否为null,null表示进行的是增加操作,rollback时,
就按key从MVPrimaryIndex实例和MVSecondaryIndex实例对应的MVMap中删除,若不为null,就表示删除操作,
此时要重新put回去。
TODO undoLog这个MVMap中的opType似乎没用,因为根据oldValue是否为null,就能判断操作类型了(增加或删除)
MVStore.Builder可配置的参数:
autoCommitBufferSize
autoCompactFillRate
backgroundExceptionHandler
cacheSize
compress (LZF和Deflate)
encryptionKey
fileName
fileStore
pageSplitSize
readOnly
=================================
MVStore格式
MVStore {
4096字节 StoreHeader
4096字节 StoreHeader
[ Chunk ] *
128字节 ChunkFooter
}
StoreHeader {
4096字节是一个块的大小,上面两个是一样的,防止块损坏,
一个StoreHeader的大小不固定,取决于具体的值,但是不会超过4096字节,
StoreHeader有8个属性:
-----------------------
H:3,
blockSize:4096,
created:1368493299954,
format:1,
block:0, //lastChunk.block
chunk:0, //lastChunk.id
version:0, //lastChunk.version
fletcher:3bde3c9a (使用Fletcher32算法得到的checksum,是对前面7个属性求checksum)
-----------------------
}
ChunkFooter {
chunk:1,block:2,version:1,fletcher:84d0d5f6
}
Chunk {
[ ChunkHeader MVMapPage MetaMapPage FileHeader] *
}
//每个ChunkHeader最多占1024字节
ChunkHeader {
byte 固定是'c'
int length
int id
int pageCount
long metaRootPos
long maxLength
long maxLengthLive
}
MVMapPage = Page
MetaMapPage = Page
Page {
int page length(包含这4字节)
short check value(并不是校验和,不用计算所有字节),check value的值取决于当前page所在chunk的chunkId、start位置(或称offset)、page length
varInt map id
varInt key count
byte page type(0: leaf, 1: node)
接下来分两种情况:
===========================
1. 如果不需压缩: {
if (type == leaf) {
key count {
Object key
}
key count {
Object value
}
}
else if (type == node) {
key count + 1 {
long child page pos
}
key count + 1 {
varLong child key count
}
key count {
Object key
}
}
}
2. 如果需要压缩,先按1的方式写入buffer,计算1的字节长度,然后尝试压缩buffer中的字节,
如果"压缩后的长度+(压缩后的长度-buffer长度)的差的VarIntLen < buffer长度"那么就进行压缩:
重写page type
byte page type(2: leaf+compressed, 3: node+compressed)
varInt buffer长度-压缩后的长度
压缩后的长度 压缩后的字节
}
meta map样例:
PageLeaf{
id = 23191477
pos = 1099511630162
version = -1
keyCount = 10
chunk.1:id:1,length:2352,maxLength:3008,maxLengthLive:1024,metaRoot:274878040014,pageCount:7,pageCountLive:2,start:8192,time:16,version:1
chunk.2:id:2,length:426,maxLength:512,maxLengthLive:512,metaRoot:549755816272,pageCount:1,pageCountLive:1,start:16384,time:16,version:2
chunk.3:id:3,length:2865,maxLength:3424,maxLengthLive:2656,metaRoot:824633869138,pageCount:7,pageCountLive:6,start:24576,time:16,version:3
chunk.4:id:4,length:2147483647,maxLength:0,maxLengthLive:0,metaRoot:0,pageCount:0,pageCountLive:0,start:9223372036854775807,time:16,version:4
map.1:name:data
map.2:name:data2
name.data:1
name.data2:2
root.1:824633866563
root.2:824633793603
}
下面的数字是16进制
file header:
=================
H:2,block:2,blockSize:1000,chunk:129,created:149b6ac28ee,format:1,version:129,fletcher:424fcf1c
H:2,block:2,blockSize:1000,chunk:129,created:149b6ac28ee,format:1,version:129,fletcher:424fcf1c
footer
===========
chunk:128,block:4,version:128,fletcher:8097485b
readChunkHeader:
================
chunk:129,block:2,len:1,map:1f,max:900,next:3,pages:8,root:4a4000012743,time:1ad588de,version:129
readChunkFooter
======================
chunk:129,block:2,version:129,fletcher:7e97485b
readChunkHeader:
================
chunk:127,block:3,len:1,map:1f,max:900,next:4,pages:8,root:49c000012743,time:1ad42913,version:127
chunk:1,block:2,len:1,map:1,max:5a0,next:3,pages:e,root:40000119c4,time:274e1,version:1