Graph database_neo4j 底层存储结构分析(4)
3.3.2 DynamicStore 类型
3.3.2.1 AbstractDynamicStore 的存储格式
neo4j 中对于字符串等变长值的保存策略是用一组定长的 block 来保存,block之间用单向链表链接。类 AbstractDynamicStore 实现了该功能,下面是其注释说明。
/**
* An abstract representation of a dynamic store. The difference between a
* normal AbstractStore and a AbstractDynamicStore is
* that the size of a record/entry can be dynamic.
* Instead of a fixed record this class uses blocks to store a record. If a
* record size is greater than the block size the record will use one or more
* blocks to store its data.
* A dynamic store don’t have a IdGenerator because the position of a
* record can’t be calculated just by knowing the id. Instead one should use a
* AbstractStore and store the start block of the record located in the
* dynamic store. Note: This class makes use of an id generator internally for
* managing free and non free blocks.
* Note, the first block of a dynamic store is reserved and contains information
* about the store.
*/

AbstractDynamicStore 类对应的存储文件格式如上图所示, 整个文件是有一个block_size=BLOCK_HEADER_SIZE(8Bytes)+block_content_size的定长数组和一个字符串“StringPropertyStore v0.A.2”或“ArrayPropertyStore v0.A.2”或“SchemaStore v0.A.2”(文件类型描述TYPE_DESCRIPTOR和 neo4j 的 ALL_STORES_VERSION构成)。访问时,可以通过 id 作为数组的下标进行访问。其中,文件的第1个 record 中前4 字节用来保存 block_size。文件的第2个 record开始保存实际的block数据,它由8个字节的block_header和定长的 block_content(可配置)构成. block_header 结构如下:
- inUse(1 Byte):第1字节,共分成3部分
[x__ , ] 0: start record, 1: linked record
[ x, ] inUse
[ ,xxxx] high next block bits
- 第1~4 bit 表示next_block 的高4位
- 第5 bit表示block 是否在 use;
- 第8 bit 表示 block 是否是单向链表的第1个 block;0 表示第1个block, 1表示后续 block.
- nr_of_bytes(3Bytes):本 block 中保存的数据的长度。
- next_block(4Bytes): next_block 的低 4 个字节,加上 inUse 的第1~4 位,next_block 的实际长度共 36 bit。以数组方式存储的单向链表的指针,指向保存同一条数据的下一个 block 的id.
3.3.2.2 AbstractDynamicStore.java
下面看一下 AbstractDynamicStore.java 中 getRecord() 和readAndVerifyBlockSize() 成员函数,可以帮助理解 DynamicStore 的存储格式。
- getRecord( long blockId, PersistenceWindow window, RecordLoad load )
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
private DynamicRecord getRecord( long blockId, PersistenceWindow window, RecordLoad load )</pre><div>{DynamicRecord record = new DynamicRecord( blockId );Buffer buffer = window.getOffsettedBuffer( blockId );/** First 4b* [x , ][ , ][ , ][ , ] 0: start record, 1: linked record* [ x, ][ , ][ , ][ , ] inUse* [ ,xxxx][ , ][ , ][ , ] high next block bits* [ , ][xxxx,xxxx][xxxx,xxxx][xxxx,xxxx] nr of bytes in the data field in this record**/long firstInteger = buffer.getUnsignedInt();boolean isStartRecord = (firstInteger & 0x80000000) == 0;long maskedInteger = firstInteger & ~0x80000000;int highNibbleInMaskedInteger = (int) ( ( maskedInteger ) >> 28 );boolean inUse = highNibbleInMaskedInteger == Record.IN_USE.intValue();if ( !inUse && load != RecordLoad.FORCE ){throw new InvalidRecordException( "DynamicRecord Not in use, blockId[" + blockId + "]" );}int dataSize = getBlockSize() - BLOCK_HEADER_SIZE;int nrOfBytes = (int) ( firstInteger & 0xFFFFFF );/** Pointer to next block 4b (low bits of the pointer)*/long nextBlock = buffer.getUnsignedInt();long nextModifier = ( firstInteger & 0xF000000L ) << 8;long longNextBlock = longFromIntAndMod( nextBlock, nextModifier );boolean readData = load != RecordLoad.CHECK;if ( longNextBlock != Record.NO_NEXT_BLOCK.intValue()&& nrOfBytes < dataSize || nrOfBytes > dataSize ){readData = false;if ( load != RecordLoad.FORCE ){throw new InvalidRecordException( "Next block set[" + nextBlock+ "] current block illegal size[" + nrOfBytes + "/" + dataSize + "]" );}}record.setInUse( inUse );record.setStartRecord( isStartRecord );record.setLength( nrOfBytes );record.setNextBlock( longNextBlock );/** Data 'nrOfBytes' bytes*/if ( readData ){byte byteArrayElement[] = new byte[nrOfBytes];buffer.get( byteArrayElement );record.setData( byteArrayElement );}return record;} |
- readAndVerifyBlockSize()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
</pre><div>protected void readAndVerifyBlockSize() throws IOException{ByteBuffer buffer = ByteBuffer.allocate( 4 );getFileChannel().position( 0 );getFileChannel().read( buffer );buffer.flip();blockSize = buffer.getInt();if ( blockSize <= 0 ){throw new InvalidRecordException( "Illegal block size: " +blockSize + " in " + getStorageFileName() );}} |
3.3.2.3 类DynamicArrayStore, DynamicStringStore
类SchemaStore,DynamicArrayStore(ArrayPropertyStore), DynamicStringStore(StringPropertyStore)都是继承成自类AbstractDynamicStore,所以与类DynamicArrayStore, DynamicStringStore和 SchemaStore对应文件的存储格式,都是遵循AbstractDynamicStore的存储格式,除了block块的大小(block_size)不同外。
| db 文件 | 存储类型 | block_size |
| neostore.labeltokenstore.db.names | StringPropertyStore | NAME_STORE_BLOCK_SIZE=30 |
| neostore.propertystore.db.index.keys | StringPropertyStore | NAME_STORE_BLOCK_SIZE=30 |
| neostore.relationshiptypestore.db.names | StringPropertyStore | NAME_STORE_BLOCK_SIZE=30 |
| neostore.propertystore.db.strings | StringPropertyStore | string_block_size=120 |
| neostore.nodestore.db.labels | ArrayPropertyStore | label_block_size=60 |
| neostore.propertystore.db.arrays | ArrayPropertyStore | array_block_size=120 |
| neostore.schemastore.db | SchemaStore | BLOCK_SIZE=56 |
block_size 通过配置文件或缺省值来设置的,下面的代码片段展示了neostore.propertystore.db.strings 文件的创建过程及block_size 的大小如何传入。
1) GraphDatabaseSettings.java
|
1
2
3
4
5
6
7
|
</pre><div>public static final Setting string_block_size = setting("string_block_size", INTEGER, "120",min(1));public static final Setting array_block_size = setting("array_block_size", INTEGER, "120",min(1));public static final Setting label_block_size = setting("label_block_size", INTEGER, "60",min(1));</div><pre> |
- 2) StoreFactory.java的Configuration 类
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
</pre><div>public static abstract class Configuration{public static final Setting string_block_size = GraphDatabaseSettings.string_block_size;public static final Setting array_block_size = GraphDatabaseSettings.array_block_size;public static final Setting label_block_size = GraphDatabaseSettings.label_block_size;public static final Setting dense_node_threshold = GraphDatabaseSettings.dense_node_threshold;} |
3) StoreFactory.java的createPropertyStore 函数
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
</pre><div>public void createPropertyStore( File fileName ){createEmptyStore( fileName, buildTypeDescriptorAndVersion( PropertyStore.TYPE_DESCRIPTOR ));int stringStoreBlockSize = config.get( Configuration.string_block_size );int arrayStoreBlockSize = config.get( Configuration.array_block_size )createDynamicStringStore(new File( fileName.getPath() + STRINGS_PART), stringStoreBlockSize, IdType.STRING_BLOCK);createPropertyKeyTokenStore( new File( fileName.getPath() + INDEX_PART ) );createDynamicArrayStore( new File( fileName.getPath() + ARRAYS_PART ), arrayStoreBlockSize );} |
4) StoreFactory.java的createDynamicStringStore函数
|
1
2
3
4
5
6
7
8
|
</pre><div>private void createDynamicStringStore( File fileName, int blockSize, IdType idType ){createEmptyDynamicStore(fileName, blockSize, DynamicStringStore.VERSION, idType);} |
5) StoreFactory.java的createEmptyDynamicStore 函数
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
</pre><div>/*** Creates a new empty store. A factory method returning an implementation* should make use of this method to initialize an empty store. Block size* must be greater than zero. Not that the first block will be marked as* reserved (contains info about the block size). There will be an overhead* for each block of <CODE>AbstractDynamicStore.BLOCK_HEADER_SIZE</CODE>bytes.*/public void createEmptyDynamicStore( File fileName, int baseBlockSize,String typeAndVersionDescriptor, IdType idType){int blockSize = baseBlockSize;// sanity checks…blockSize += AbstractDynamicStore.BLOCK_HEADER_SIZE;// write the headertry{FileChannel channel = fileSystemAbstraction.create(fileName);int endHeaderSize = blockSize+ UTF8.encode( typeAndVersionDescriptor ).length;ByteBuffer buffer = ByteBuffer.allocate( endHeaderSize );buffer.putInt( blockSize );buffer.position( endHeaderSize - typeAndVersionDescriptor.length() );buffer.put( UTF8.encode( typeAndVersionDescriptor ) ).flip();channel.write( buffer );channel.force( false );channel.close();}catch ( IOException e ){throw new UnderlyingStorageException( "Unable to create store "+ fileName, e );}idGeneratorFactory.create( fileSystemAbstraction, new File( fileName.getPath() + ".id"), 0 );// TODO highestIdInUse = 0 works now, but not when slave can create store files.IdGenerator idGenerator = idGeneratorFactory.open(fileSystemAbstraction,new File( fileName.getPath() + ".id"),idType.getGrabSize(), idType, 0 );idGenerator.nextId(); // reserve first for blockSizeidGenerator.close();} |
Graph database_neo4j 底层存储结构分析(4)的更多相关文章
- Graph database_neo4j 底层存储结构分析(8)
3.8 示例1:neo4j_exam 下面看一个简单的例子,然后看一下几个主要的存储文件,有助于理解<3–neo4j存储结构>描述的neo4j 的存储格式. 3.8.1 neo4j ...
- Graph database_neo4j 底层存储结构分析(7)
3.7 Relationship 的存储 下面是neo4j graph db 中,Relationship数据存储对应的文件: neostore.relationshipgroupstore.db ...
- Graph database_neo4j 底层存储结构分析(6)
3.6 Node 数据存储 neo4j 中, Node 的存储是由 NodeStore 和 ArrayPropertyStore 2中类型配合来完成的. node 的label 内容是存在Array ...
- Graph database_neo4j 底层存储结构分析(5)
3.5 Property 的存储 下面是neo4j graph db 中,Property数据存储对应的文件: neostore.propertystore.db neostore.propertys ...
- Graph database_neo4j 底层存储结构分析(1)
1 neo4j 中节点和关系的物理存储模型 1.1 neo4j存储模型 The node records contain only a pointer to their first pr ...
- Graph database_neo4j 底层存储结构分析(3)
3.3 通用的Store 类型 3.3.1 id 类型 下面是 neo4j db 中,每种Store都有自己的ID文件(即后缀.id 文件),它们的格式都是一样的. [test00]$ls - ...
- Graph database_neo4j 底层存储结构分析(2)
3 neo4j存储结构 neo4j 中,主要有4类节点,属性,关系等文件是以数组作为核心存储结构:同时对节点,属性,关系等类型的每个数据项都会分配一个唯一的ID,在存储时以该ID 为数组的 ...
- Redis(一) 数据结构与底层存储 & 事务 & 持久化 & lua
参考文档:redis持久化:http://blog.csdn.net/freebird_lb/article/details/7778981 https://blog.csdn.net/jy69240 ...
- HBase底层存储原理
HBase底层存储原理——我靠,和cassandra本质上没有区别啊!都是kv 列存储,只是一个是p2p另一个是集中式而已! 首先HBase不同于一般的关系数据库, 它是一个适合于非结构化数据存储的数 ...
随机推荐
- CSS3.0盒模型display:-webkit-box;的使用
box-flex是css3新添加的盒子模型属性,它的出现可以解决我们通过N多结构.css实现的布局方式.经典 的一个布局应用就是布局的垂直等高.水平均分.按比例划分. 目前box-flex属性还没 ...
- BestCoder13 1001.Beautiful Palindrome Number(hdu 5062) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5062 题目意思:给出 N,找出 1 - 10^N 中满足 Beautiful Palindrome N ...
- codeforces A. Flipping Game 解题报告
题目链接:http://codeforces.com/problemset/problem/327/A 题意是输入一个只有0和1的序列,要求找出一个合理的区间,在这个区间里面把0变成1,1变成0,使得 ...
- Intellj IDEA快捷键
Alt+回车 导入包,自动修正 Ctrl+N 查找类 Ctrl+Shift+N 查找文件 Ctrl+Alt+L 格式化代码 Ctrl+Alt+O 优化导入的类和包 Alt+Insert 生成代码 ...
- [Android Pro] fragment中嵌套viewpager,vierpager中有多个fragment,不显示
referece to : http://blog.csdn.net/mybook1122/article/details/24003343 现在好多应用流行一种布局.底部几个工具栏选项,上面也有类 ...
- 决策树之C4.5算法
决策树之C4.5算法 一.C4.5算法概述 C4.5算法是最常用的决策树算法,因为它继承了ID3算法的所有优点并对ID3算法进行了改进和补充. 改进有如下几个要点: 用信息增益率来选择属性,克服了ID ...
- Java编程设计2
一般我们会以这种设计方式生产对象实例,如: 创建一个接口: public interface TestOpen { String getVirtualHost(); String getCapabil ...
- ShareSDK集成微信、QQ、微博分享
1.前言 为什么要使用第三方的作为集成分享的工具呢?而不去用官方的呢?有什么区别么? 一个字"快",如果你使用官方的得一个个集成他们的SDK,相信这是一个痛苦的过程. 2.准备需要 ...
- 数码管的封装实验 --- verilog
数码管的封装实验.显示使能信号置高才可以显示.对于小数点不用,故不显示. 数码管分为共阴数码管和共阳数码管,数码管不同,编码不同,下面是两种数码管显示0-F以及消隐的不同编码: 共阴数码管(高有效): ...
- javascript散列表实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...