README 整理
kernel.impl.coreapi
这个包包含核心API的直接实现。核心API是org.neo4j中定义的API。graphdb及其子包。这里的类是实现细节,可能会在不通知的情况下更改。
IO
这是Neo4j IO抽象层。它当前包含磁盘IO机制和文件分页。
Neo4j Kernel
由于历史原因,这个模块包含了Neo4j的多个重要组件: - 嵌入的Java API - org.neo4j.graphdb - 嵌入的Java API实现 - org.neo4j.kernel.coreapi - org.neo4j.kernel.core - 嵌入的遍历Java API - org.neo4j.graphdb.traversal - 嵌入的遍历API实现 - org.neo4j.kernel.traversal - 批量导入 - org.neo4j.unsafe.impl.batchimport - 批处理插入器(遗留) - org.neo4j.unsafe.batchinsert - 事务状态构建层(“内核API”) - org.neo4j.kernel.api - org.neo4j.kernel.impl.api - 存储引擎 - org.neo4j.kernel.impl.store, - org.neo4j.kernel.impl.recovery - org.neo4j.kernel.impl.transaction - 配置 - org.neo4j.kernel.configuration - 常见的工具 - org.neo4j.helpers - org.neo4j.kernel.impl.util - org.neo4j.kernel.lifecycle - org.neo4j.kernel.monitoring - 锁 - org.neo4j.kernel.impl.locking - 内核扩展 - org.neo4j.kernel.extension
The Kernel API
内核API管理与Neo4j内核的所有交互,主要由Cypher runtime 和 Core API。
Usage
这个接口的入口点是链接:src/main/java/org/neo4j/impl/kernel/api/Kernel.java[Kernel] 通过这里,我们可以开始一个链接:src/main/java/org/neo4j/impl/kernel/api/Session.java[Session], 它允许我们开始链接:src/main/java/org/neo4j/impl/kernel api/Transaction.java[Transactions]. 一旦进入事务,我们可以直接访问内核的所有主要功能:
- link:src/main/java/org/neo4j/impl/kernel/api/Read.java[dataRead()] 支持所有数据读取操作
- link:src/main/java/org/neo4j/impl/kernel/api/Write.java[dataWrite()] 支持所有数据写操作
- link:src/main/java/org/neo4j/impl/kernel/api/TokenRead.java[tokenRead()] & link:src/main/java/org/neo4j/impl/kernel/api/TokenWrite.java[tokenWrite()] 允许属性键、节点标签和关系类型的字符串和整数表示形式之间的映射
- 等等……
使用游标读取
读操作使用特殊的游标,这允许在热路径中非常低的对象分配率。
- link:src/main/java/org/neo4j/impl/kernel/api/NodeCursor.java[NodeCursor], link:src/main/java/org/neo4j/impl/kernel/api/RelationshipScanCursor.java[RelationshipScanCursor] and link:src/main/java/org/neo4j/impl/kernel/api/RelationshipTraversalCursor.java[RelationshipTraversalCursor] are the main entry points for accessing nodes and relationships respectively. These types are used directly with the store for scan operations. + For accessing the relationships of a node, we first have to find the relationships of the types we are interested in via an link:src/main/java/org/neo4j/impl/kernel/api/RelationshipGroupCursor.java[RelationshipGroupCursor]. +
- link:src/main/java/org/neo4j/impl/kernel/api/NodeIndexCursor.java[NodeValueIndexCursor] and link:src/main/java/org/neo4j/impl/kernel/api/NodeIndexCursor.java[NodeLabelIndexCursor] (and their shared base link:src/main/java/org/neo4j/impl/kernel/api/NodeIndexCursor.java[NodeIndexCursor]) are used for index lookups. This differentiation allows access to data available within the index which makes it possible to defer and sometimes avoid accessing the node store.
- link:src/main/java/org/neo4j/impl/kernel/api/PropertyCursor.java[PropertyCursor] is used for accessing properties for both nodes and relationships. Property values (and other types of values used in the runtime) are represented by the link:src/main/java/org/neo4j/impl/kernel/api/Value.java[Value] class, but for common predicates link:src/main/java/org/neo4j/impl/kernel/api/PropertyCursor.java[PropertyCursor] provides direct methods for performing these without de-serialization.
- “Explicit Indexes” are accessed through link:src/main/java/org/neo4j/impl/kernel/api/NodeExplicitIndexCursor.java[NodeExplicitIndexCursor] and link:src/main/java/org/neo4j/impl/kernel/api/RelationshipExplicitIndexCursor.java[RelationshipExplicitIndexCursor]. The shared base class link:src/main/java/org/neo4j/impl/kernel/api/ExplicitIndexCursor.java[ExplicitIndexCursor] defines access to the lucene information that leaks through from these search structures out via the “Core API”.
- NOT IMPLEMENTED YET: Parallel scans are initialized through a (thread safe) link:src/main/java/org/neo4j/impl/kernel/api/Scan.java[Scan initializer]. The usage of these is to initialize one cursor per thread. Each thread-local cursor will then proceed through ranges of underlying data elements automatically - no re-initialization is required.
设计说明 通常,游标的设计方法是通过游标直接公开底层表示包含的所有信息。 其思想是将暴露给运行时的游标实现为直接位于页面数据之上的“视图”或“投影”,提供对存储的原始字节的解释。 不过,数据的公开并不会一直进行下去,而是试图在允许底层格式的未来更改之间取得平衡。 作为一个思想实验,我尝试以这样一种方式定义API,应该可以沿着这些方面改变实现:
- 关系可以是现在的独立记录,也可以是非规范化的,对于没有独立id的每个节点按类型分组。
- 属性可以存储在单独的属性存储中,也可以内联存储在节点存储中。
在大多数情况下,通过使用不同的游标类型显式地访问不同的存储。 除了一个例外:link:src/main/java/ org/neo4j/impl/kernel/api/labelset。java[节点的标签]。
总体设计方法是让API的客户机控制游标的生命周期。 这比将游标集中在引擎内更有效。
这样做的原因是,由于客户机是一个查询,所以使用模式是完全已知的,因此可以显式地从池中取出和返回到池中。 同样,可以显式地在同一个查询中重用。但是不允许客户机提供自己的游标类型,必须使用链接提供的类型: link:src/main/java/org/neo4j/impl/kernel/api/CursorFactory.java[CursorFactory].
客户机控制游标的生命周期后,就排除了“Cursor”之类的通用接口,因为我们需要游标是已知的具体类型。
“规范”用法是从其他游标初始化游标,而不是从记录中访问指针值,然后显式初始化游标。 指针值也可以访问,因为向量化的操作管道更喜欢这样的使用模式。
对底层表示的一个更改将使实现这个API更加容易,即使所有节点按照类型对它们的关系进行分组,而不仅仅是密集节点。
此外,如果事务状态以与存储中相同的格式存储在堆外缓冲区中,则实现将更容易和更有效。
Neo4j UDC
Usage Data Collector (UDC)是一个内核扩展,它收集关于Neo4j服务器的统计信息。详见:https://neo4j.com/docs/operations-manual/current/configuration/usage-data-collector/
procedure-compiler
Neo4j工具-过程|用户功能编译器这是一个注释处理器,它将在编译时验证存储过程。虽然可以执行大多数基本检查,但是仍然需要一些单元测试来验证一些运行时行为。它是做什么的?一旦将存储过程编译器添加到项目类路径中(请参阅下面的Maven/Gradle说明),如果不满足以下任何要求,它将触发编译失败: - `@Context` 字段必须是' public '且非' final ' - 所有其他字段必须是 `static` - `Map` 记录字段/过程参数必须将键类型定义为 `String` - `@Procedure`|`@UserFunction` 类必须定义一个没有参数的公共构造函数 - `@Procedure` 方法必须返回一个流Stream - `@Procedure`|`@UserFunction` 参数和记录类型必须支持 - `@Procedure`|`@UserFunction` 参数必须用 `@Name`标注 - `@UserFunction` 不能在根名称空间中定义 - 所有访问过的 `@Procedure`|`@UserFunction`名称必须是唯一的*已部署的Neo4j实例可以聚合来自不同jar的存储过程。注释处理器无法检测到jar之间的命名冲突。根据定义,它一次只能检查一个编译单元。
====== ## class StoreType
StoreType.javapublic enum StoreType{ NODE_LABEL( DatabaseFile.NODE_LABEL_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createNodeLabelStore(); } }, NODE( DatabaseFile.NODE_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createNodeStore(); } }, PROPERTY_KEY_TOKEN_NAME( DatabaseFile.PROPERTY_KEY_TOKEN_NAMES_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createPropertyKeyTokenNamesStore(); } }, PROPERTY_KEY_TOKEN( DatabaseFile.PROPERTY_KEY_TOKEN_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createPropertyKeyTokenStore(); } }, PROPERTY_STRING( DatabaseFile.PROPERTY_STRING_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createPropertyStringStore(); } }, PROPERTY_ARRAY( DatabaseFile.PROPERTY_ARRAY_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createPropertyArrayStore(); } }, PROPERTY( DatabaseFile.PROPERTY_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createPropertyStore(); } }, RELATIONSHIP( DatabaseFile.RELATIONSHIP_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createRelationshipStore(); } }, RELATIONSHIP_TYPE_TOKEN_NAME( DatabaseFile.RELATIONSHIP_TYPE_TOKEN_NAMES_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createRelationshipTypeTokenNamesStore(); } }, RELATIONSHIP_TYPE_TOKEN( DatabaseFile.RELATIONSHIP_TYPE_TOKEN_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createRelationshipTypeTokenStore(); } }, LABEL_TOKEN_NAME( DatabaseFile.LABEL_TOKEN_NAMES_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createLabelTokenNamesStore(); } }, LABEL_TOKEN( DatabaseFile.LABEL_TOKEN_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createLabelTokenStore(); } }, SCHEMA( DatabaseFile.SCHEMA_STORE, true, true ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createSchemaStore(); } }, RELATIONSHIP_GROUP( DatabaseFile.RELATIONSHIP_GROUP_STORE, true, false ) { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createRelationshipGroupStore(); } }, COUNTS( DatabaseFile.COUNTS_STORES, false, false ) { @Override public CountsTracker open( NeoStores neoStores ) { return neoStores.createCountStore(); } @Override void close( Object object ) { try { ((CountsTracker) object).shutdown(); } catch ( IOException e ) { throw new UnderlyingStorageException( e ); } } }, META_DATA( DatabaseFile.METADATA_STORE, true, true ) // Make sure this META store is last { @Override public CommonAbstractStore open( NeoStores neoStores ) { return neoStores.createMetadataStore(); } };
ENUM_YPE | CALL_FUNC |
---|---|
NODE_LABEL | createNodeLabelStore |
NODE | createNodeStore |
PROPERTY_KEY_TOKEN_NAME | createPropertyKeyTokenNamesStore |
… | … |
class NeoStores
该类包含对“NodeStore、RelationshipStore、PropertyStore和RelationshipTypeStore”的引用。 实际上,NeoStores并不“存储”任何东西,而是为在其中执行的“类型和版本”验证扩展了AbstractStore。
CommonAbstractStore createNodeStore(){ return initialize( new NodeStore( layout.nodeStore(), layout.idNodeStore(), config, idGeneratorFactory, pageCache, logProvider, (DynamicArrayStore) getOrCreateStore( StoreType.NODE_LABEL ), recordFormats, openOptions ) );}CommonAbstractStore createNodeLabelStore(){ return createDynamicArrayStore( layout.nodeLabelStore(), layout.idNodeLabelStore(), IdType.NODE_LABELS, GraphDatabaseSettings.label_block_size );}CommonAbstractStore createPropertyKeyTokenStore(){ return initialize( new PropertyKeyTokenStore( layout.propertyKeyTokenStore(), layout.idPropertyKeyTokenStore(), config, idGeneratorFactory, pageCache, logProvider, (DynamicStringStore) getOrCreateStore( StoreType.PROPERTY_KEY_TOKEN_NAME ), recordFormats, openOptions ) );}CommonAbstractStore createPropertyKeyTokenNamesStore(){ return createDynamicStringStore( layout.propertyKeyTokenNamesStore(), layout.idPropertyKeyTokenNamesStore(), IdType.PROPERTY_KEY_TOKEN_NAME, TokenStore.NAME_STORE_BLOCK_SIZE );}CommonAbstractStore createPropertyStore(){ return initialize( new PropertyStore( layout.propertyStore(), layout.idPropertyStore(), config, idGeneratorFactory, pageCache, logProvider, (DynamicStringStore) getOrCreateStore( StoreType.PROPERTY_STRING ), (PropertyKeyTokenStore) getOrCreateStore( StoreType.PROPERTY_KEY_TOKEN ), (DynamicArrayStore) getOrCreateStore( StoreType.PROPERTY_ARRAY ), recordFormats, openOptions ) );}CommonAbstractStore createPropertyStringStore(){ return createDynamicStringStore( layout.propertyStringStore(), layout.idPropertyStringStore(), IdType.STRING_BLOCK, GraphDatabaseSettings.string_block_size );}CommonAbstractStore createPropertyArrayStore(){ return createDynamicArrayStore( layout.propertyArrayStore(), layout.idPropertyArrayStore(), IdType.ARRAY_BLOCK, GraphDatabaseSettings.array_block_size );}CommonAbstractStore createRelationshipStore(){ return initialize( new RelationshipStore( layout.relationshipStore(), layout.idRelationshipStore(), config, idGeneratorFactory, pageCache, logProvider, recordFormats, openOptions ) );}CommonAbstractStore createRelationshipTypeTokenStore(){ return initialize( new RelationshipTypeTokenStore( layout.relationshipTypeTokenStore(), layout.idRelationshipTypeTokenStore(), config, idGeneratorFactory, pageCache, logProvider, (DynamicStringStore) getOrCreateStore( StoreType.RELATIONSHIP_TYPE_TOKEN_NAME ), recordFormats, openOptions ) );}CommonAbstractStore createRelationshipTypeTokenNamesStore(){ return createDynamicStringStore( layout.relationshipTypeTokenNamesStore(), layout.idRelationshipTypeTokenNamesStore(), IdType.RELATIONSHIP_TYPE_TOKEN_NAME, TokenStore.NAME_STORE_BLOCK_SIZE );}CommonAbstractStore createLabelTokenStore(){ return initialize( new LabelTokenStore( layout.labelTokenStore(), layout.idLabelTokenStore(), config, idGeneratorFactory, pageCache, logProvider, (DynamicStringStore) getOrCreateStore( StoreType.LABEL_TOKEN_NAME ), recordFormats, openOptions ) );}CommonAbstractStore createSchemaStore(){ return initialize( new SchemaStore( layout.schemaStore(), layout.idSchemaStore(), config, IdType.SCHEMA, idGeneratorFactory, pageCache, logProvider, recordFormats, openOptions ) );}CommonAbstractStore createRelationshipGroupStore(){ return initialize( new RelationshipGroupStore( layout.relationshipGroupStore(), layout.idRelationshipGroupStore(), config, idGeneratorFactory, pageCache, logProvider, recordFormats, openOptions ) );}CommonAbstractStore createLabelTokenNamesStore(){ return createDynamicStringStore( layout.labelTokenNamesStore(), layout.idLabelTokenNamesStore(), IdType.LABEL_TOKEN_NAME, TokenStore.NAME_STORE_BLOCK_SIZE );}CountsTracker createCountStore(){ boolean readOnly = config.get( GraphDatabaseSettings.read_only ); CountsTracker counts = readOnly ? createReadOnlyCountsTracker( layout ) : createWritableCountsTracker( layout ); NeoStores neoStores = this; counts.setInitializer( new DataInitializer() { private final Log log = logProvider.getLog( MetaDataStore.class ); @Override public void initialize( CountsAccessor.Updater updater ) { log.warn( "Missing counts store, rebuilding it." ); new CountsComputer( neoStores, pageCache, layout ).initialize( updater ); log.warn( "Counts store rebuild completed." ); } @Override public long initialVersion() { return ((MetaDataStore) getOrCreateStore( StoreType.META_DATA )).getLastCommittedTransactionId(); } } ); try { counts.init(); // TODO: move this to LifeCycle } catch ( IOException e ) { throw new UnderlyingStorageException( "Failed to initialize counts store", e ); } return counts;}CommonAbstractStore createMetadataStore(){ return initialize( new MetaDataStore( metadataStore, layout.idMetadataStore(), config, idGeneratorFactory, pageCache, logProvider, recordFormats.metaData(), recordFormats.storeVersion(), openOptions ) );}private CommonAbstractStore createDynamicStringStore( File storeFile, File idFile, IdType idType, Setting blockSizeProperty ){ return createDynamicStringStore( storeFile, idFile, idType, config.get( blockSizeProperty ) );}private CommonAbstractStore createDynamicStringStore( File storeFile, File idFile, IdType idType, int blockSize ){ return initialize( new DynamicStringStore( storeFile, idFile, config, idType, idGeneratorFactory, pageCache, logProvider, blockSize, recordFormats.dynamic(), recordFormats.storeVersion(), openOptions ) );}private CommonAbstractStore createDynamicArrayStore( File storeFile, File idFile, IdType idType, Setting blockSizeProperty ){ return createDynamicArrayStore( storeFile, idFile, idType, config.get( blockSizeProperty ) );}CommonAbstractStore createDynamicArrayStore( File storeFile, File idFile, IdType idType, int blockSize ){ if ( blockSize <= 0 ) { throw new IllegalArgumentException( "Block size of dynamic array store should be positive integer." ); } return initialize( new DynamicArrayStore( storeFile, idFile, config, idType, idGeneratorFactory, pageCache, logProvider, blockSize, recordFormats, openOptions ) );}
createCountStore() | createCountStore() |
… | CommonAbstractStore |
显然,仅有createCountStore() 返回 createCountStore().其余均为CommonAbstractStore.
createNodeStore | initialize(new NodeStore()) |
createPropertyKeyTokenStore | initialize( new PropertyKeyTokenStore()) |
createPropertyStore | initialize( new PropertyStore()) |
createRelationshipStore | initialize(new RelationshipStore()) |
createRelationshipTypeTokenStore | initialize(new RelationshipTypeTokenStore()) |
createLabelTokenStore | initialize(new LabelTokenStore()) |
createSchemaStore | initialize(new SchemaStore()) |
createRelationshipGroupStore | initialize( new RelationshipGroupStore()) |
createMetadataStore | initialize(new MetaDataStore()) |
createDynamicStringStore | initialize( new DynamicStringStore()) |
createDynamicArrayStore | initialize( new DynamicArrayStore()) private 检查blockSize |
createNodeLabelStore | createDynamicArrayStore() |
createPropertyArrayStore | createDynamicArrayStore() |
createDynamicArrayStore | createDynamicArrayStore() |
createPropertyKeyTokenNamesStore | createDynamicStringStore() |
createPropertyStringStore | createDynamicStringStore() |
createRelationshipTypeTokenNamesStore | createDynamicStringStore() |
createLabelTokenNamesStore | createDynamicStringStore() |
createDynamicStringStore | createDynamicStringStore() |
createCountStore | special |
NeoStores.javaprivate CommonAbstractStore createDynamicStringStore( File storeFile, File idFile, IdType idType, SettingblockSizeProperty ){ return createDynamicStringStore( storeFile, idFile, idType, config.get( blockSizeProperty ) );}private CommonAbstractStore createDynamicStringStore( File storeFile, File idFile, IdType idType, int blockSize ){ return initialize( new DynamicStringStore( storeFile, idFile, config, idType, idGeneratorFactory, pageCache, logProvider, blockSize, recordFormats.dynamic(), recordFormats.storeVersion(), openOptions ) );}private CommonAbstractStore createDynamicArrayStore( File storeFile, File idFile, IdType idType, Setting blockSizeProperty ){ return createDynamicArrayStore( storeFile, idFile, idType, config.get( blockSizeProperty ) );}CommonAbstractStore createDynamicArrayStore( File storeFile, File idFile, IdType idType, int blockSize ){ if ( blockSize <= 0 ) { throw new IllegalArgumentException( "Block size of dynamic array store should be positive integer." ); } return initialize( new DynamicArrayStore( storeFile, idFile, config, idType, idGeneratorFactory, pageCache, logProvider, blockSize, recordFormats, openOptions ) );}
可见,这里都是直接或间接调用 initialize(new <type>(args…)) 实现的.
NeoStores.javaprivateT initialize( T store ) { store.initialise( createIfNotExist ); return store; }
CommonAbstractStore.javavoid initialise( boolean createIfNotExists ) { try { checkAndLoadStorage( createIfNotExists ); } catch ( Exception e ) { closeAndThrow( e ); } }
NeoStores类包含对“NodeStore、RelationshipStore、PropertyStore和RelationshipTypeStore”的引用。 实际上,NeoStores并不“存储”任何东西,而是为在其中执行的“类型和版本”验证扩展了AbstractStore。
CommonAbstractStore.java/** * This method is called by constructors. Checks the header record and loads the store. ** Note: This method will map the file with the page cache. The store file must not * be accessed directly until it has been unmapped - the store file must only be * accessed through the page cache. * @param createIfNotExists If true, creates and initialises the store file if it does not exist already. If false, * this method will instead throw an exception in that situation. */protected void checkAndLoadStorage( boolean createIfNotExists ){ int pageSize = pageCache.pageSize(); int filePageSize; try ( PagedFile pagedFile = pageCache.map( storageFile, pageSize, ANY_PAGE_SIZE ) ) { extractHeaderRecord( pagedFile ); filePageSize = pageCache.pageSize() - pageCache.pageSize() % getRecordSize(); } catch ( NoSuchFileException | StoreNotFoundException e ) { if ( createIfNotExists ) { try { createStore( pageSize ); return; } catch ( IOException e1 ) { e.addSuppressed( e1 ); } } if ( e instanceof StoreNotFoundException ) { throw (StoreNotFoundException) e; } throw new StoreNotFoundException( "Store file not found: " + storageFile, e ); } catch ( IOException e ) { throw new UnderlyingStorageException( "Unable to open store file: " + storageFile, e ); } loadStorage( filePageSize );}
此方法由构造函数调用。检查头记录并加载存储。
注意:这个方法将用页面缓存映射文件。在未映射之前,不能直接访问存储文件——只能通过页面缓存访问存储文件。 @param createIfNotExists(如果为真)创建并初始化存储文件(如果它还不存在)。如果为false,则此方法将在这种情况下抛出异常。 这里调用createStore(pageSize)创建存储文件.
CommonAbstractStore.javaprivate void createStore( int pageSize ) throws IOException{ try ( PagedFile file = pageCache.map( storageFile, pageSize, StandardOpenOption.CREATE ) ) { initialiseNewStoreFile( file ); } checkAndLoadStorage( false );}protected void initialiseNewStoreFile( PagedFile file ) throws IOException{ if ( getNumberOfReservedLowIds() > 0 ) { try ( PageCursor pageCursor = file.io( 0, PF_SHARED_WRITE_LOCK ) ) { if ( pageCursor.next() ) { pageCursor.setOffset( 0 ); createHeaderRecord( pageCursor ); if ( pageCursor.checkAndClearBoundsFlag() ) { throw new UnderlyingStorageException( "Out of page bounds when writing header; page size too small: " + pageCache.pageSize() + " bytes." ); } } } } // Determine record size right after writing the header since some stores // use it when initializing their stores to write some records. recordSize = determineRecordSize(); idGeneratorFactory.create( idFile, getNumberOfReservedLowIds(), false );}private void createHeaderRecord( PageCursor cursor ){ int offset = cursor.getOffset(); storeHeaderFormat.writeHeader( cursor ); cursor.setOffset( offset ); readHeaderAndInitializeRecordFormat( cursor );}/** * This method is called when opening the store to extract header data and determine things like * record size of the specific record format for this store. Some formats rely on information * in the store header, that's why it happens at this stage. * * @param cursor {@link PageCursor} initialized at the start of the store header where header information * can be read if need be. This can be {@code null} if this store has no store header. The initialization * of the record format still happens in here. * @throws IOException if there were problems reading header information. */private void readHeaderAndInitializeRecordFormat( PageCursor cursor ){ storeHeader = storeHeaderFormat.readHeader( cursor );}
IntStoreHeaderFormat.java@Overridepublic IntStoreHeader readHeader( PageCursor cursor ){ return new IntStoreHeader( cursor.getInt() );}
IO
org.neo4j.io.pagecache.PageCache
ChangeLog
[ ] 发现了 readme.md 或许有点用