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 header
 
try
 
{
 
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 blockSize
 
idGenerator.close();
 
}

Graph database_neo4j 底层存储结构分析(4)的更多相关文章

  1. Graph database_neo4j 底层存储结构分析(8)

    3.8  示例1:neo4j_exam 下面看一个简单的例子,然后看一下几个主要的存储文件,有助于理解<3–neo4j存储结构>描述的neo4j 的存储格式. 3.8.1    neo4j ...

  2. Graph database_neo4j 底层存储结构分析(7)

    3.7  Relationship 的存储 下面是neo4j graph db 中,Relationship数据存储对应的文件: neostore.relationshipgroupstore.db ...

  3. Graph database_neo4j 底层存储结构分析(6)

    3.6  Node 数据存储 neo4j 中, Node 的存储是由 NodeStore 和 ArrayPropertyStore 2中类型配合来完成的. node 的label 内容是存在Array ...

  4. Graph database_neo4j 底层存储结构分析(5)

    3.5 Property 的存储 下面是neo4j graph db 中,Property数据存储对应的文件: neostore.propertystore.db neostore.propertys ...

  5. Graph database_neo4j 底层存储结构分析(1)

    1       neo4j 中节点和关系的物理存储模型 1.1  neo4j存储模型 The node records contain only a pointer to their first pr ...

  6. Graph database_neo4j 底层存储结构分析(3)

    3.3  通用的Store 类型 3.3.1    id 类型 下面是 neo4j db 中,每种Store都有自己的ID文件(即后缀.id 文件),它们的格式都是一样的. [test00]$ls - ...

  7. Graph database_neo4j 底层存储结构分析(2)

    3       neo4j存储结构 neo4j 中,主要有4类节点,属性,关系等文件是以数组作为核心存储结构:同时对节点,属性,关系等类型的每个数据项都会分配一个唯一的ID,在存储时以该ID 为数组的 ...

  8. Redis(一) 数据结构与底层存储 & 事务 & 持久化 & lua

    参考文档:redis持久化:http://blog.csdn.net/freebird_lb/article/details/7778981 https://blog.csdn.net/jy69240 ...

  9. HBase底层存储原理

    HBase底层存储原理——我靠,和cassandra本质上没有区别啊!都是kv 列存储,只是一个是p2p另一个是集中式而已! 首先HBase不同于一般的关系数据库, 它是一个适合于非结构化数据存储的数 ...

随机推荐

  1. 【转】Spring Quartz的原理

    Quartz是一个大名鼎鼎的Java版开源定时调度器,功能强悍,使用方便. 一.核心概念 Quartz的原理不是很复杂,只要搞明白几个概念,然后知道如何去启动和关闭一个调度程序即可. 1.Job 表示 ...

  2. 如何让你的scrapy爬虫不再被ban之二(利用第三方平台crawlera做scrapy爬虫防屏蔽)

    我们在做scrapy爬虫的时候,爬虫经常被ban是常态.然而前面的文章如何让你的scrapy爬虫不再被ban,介绍了scrapy爬虫防屏蔽的各种策略组合.前面采用的是禁用cookies.动态设置use ...

  3. BestCoder16 1002.Revenge of LIS II(hdu 5087) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5087 题目意思:找出第二个最长递增子序列,输出长度.就是说,假如序列为 1 1 2,第二长递增子序列是 ...

  4. HDU1267 递推

    下沙的沙子有几粒? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  5. 谈Web前端安全编码

    最近开发中涉及到有关输出正确的HTML标签这样的问题,正好对字符编码这块儿多看看,之前对这个方面认识的不深,思考的确实不够,如果下次再碰见类似的问题,若再次不少时间去调研的花,就得不偿失了. 就像正则 ...

  6. Android文件Apk下载变ZIP压缩包解决方案

    [root@ conf]# pwd /alidata/server/nginx/conf [root@ conf]# vi mime.types application/vnd.android.pac ...

  7. 9.装饰者模式(Decorator Pattern)

    using System; namespace ConsoleApplication7 { class Program { static void Main(string[] args) { // 我 ...

  8. Entity FrameWork 中使用Expression<Func<T,true>>访问数据库性能优化

    问题的本质是:扩展的Where方法有四个参数重载.传进去Func<T,true>那么返回值是IEnumable的接口类型的集合,如果是Expression<Func<T,tru ...

  9. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

  10. Wcf for wp8 连接数据库,读写数据库,显示数据库数据(二)

    下载: Microsoft® SQL Server® 2012 Express http://www.microsoft.com/zh-cn/download/details.aspx?id=2906 ...