Skip to content

Commit

Permalink
Remove extra layer of abstraction
Browse files Browse the repository at this point in the history
Having an extra layer between the store and AllStoreHolder caused a
significant regression probably due to the call sites being megamorhphic
preventing inlining to take place.
  • Loading branch information
pontusmelke committed Dec 20, 2017
1 parent d2c13fc commit 956c63c
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 222 deletions.
Expand Up @@ -247,25 +247,25 @@ public String propertyKeyGetName( int propertyKeyId ) throws PropertyKeyIdNotFou
@Override
PageCursor nodePage( long reference )
{
return nodes.openPageCursor( reference );
return nodes.openPageCursorForReading( reference );
}

@Override
PageCursor relationshipPage( long reference )
{
return relationships.openPageCursor( reference );
return relationships.openPageCursorForReading( reference );
}

@Override
PageCursor groupPage( long reference )
{
return groups.openPageCursor( reference );
return groups.openPageCursorForReading( reference );
}

@Override
PageCursor propertyPage( long reference )
{
return properties.openPageCursor( reference );
return properties.openPageCursorForReading( reference );
}

@Override
Expand All @@ -289,27 +289,27 @@ RecordCursor<DynamicRecord> labelCursor()
@Override
void node( NodeRecord record, long reference, PageCursor pageCursor )
{
nodes.loadRecordByCursor( reference, record, RecordLoad.CHECK, pageCursor );
nodes.getRecordByCursor( reference, record, RecordLoad.CHECK, pageCursor );
}

@Override
void relationship( RelationshipRecord record, long reference, PageCursor pageCursor )
{
relationships.loadRecordByCursor( reference, record, RecordLoad.CHECK, pageCursor );
relationships.getRecordByCursor( reference, record, RecordLoad.CHECK, pageCursor );
}

@Override
void property( PropertyRecord record, long reference, PageCursor pageCursor )
{
//We need to load forcefully here since otherwise we can have inconsistent reads
//for properties across blocks, see org.neo4j.graphdb.ConsistentPropertyReadsIT
properties.loadRecordByCursor( reference, record, RecordLoad.FORCE, pageCursor );
properties.getRecordByCursor( reference, record, RecordLoad.FORCE, pageCursor );
}

@Override
void group( RelationshipGroupRecord record, long reference, PageCursor page )
{
groups.loadRecordByCursor( reference, record, RecordLoad.NORMAL, page );
groups.getRecordByCursor( reference, record, RecordLoad.NORMAL, page );
}

@Override
Expand Down
Expand Up @@ -19,13 +19,10 @@
*/
package org.neo4j.kernel.impl.storageengine.impl.recordstorage;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.function.IntPredicate;
import java.util.function.Supplier;

import org.neo4j.cursor.Cursor;
import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.kernel.api.AssertOpen;
import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException;
import org.neo4j.kernel.api.schema.index.IndexDescriptor;
Expand All @@ -39,26 +36,13 @@
import org.neo4j.kernel.impl.api.store.StoreSingleRelationshipCursor;
import org.neo4j.kernel.impl.locking.Lock;
import org.neo4j.kernel.impl.locking.LockService;
import org.neo4j.kernel.impl.store.AbstractDynamicStore;
import org.neo4j.kernel.impl.store.DynamicArrayStore;
import org.neo4j.kernel.impl.store.DynamicStringStore;
import org.neo4j.kernel.impl.store.InvalidRecordException;
import org.neo4j.kernel.impl.store.NeoStores;
import org.neo4j.kernel.impl.store.NodeStore;
import org.neo4j.kernel.impl.store.PropertyStore;
import org.neo4j.kernel.impl.store.RecordCursor;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.RecordStore;
import org.neo4j.kernel.impl.store.RelationshipGroupStore;
import org.neo4j.kernel.impl.store.RelationshipStore;
import org.neo4j.kernel.impl.store.StoreType;
import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
import org.neo4j.kernel.impl.store.record.DynamicRecord;
import org.neo4j.kernel.impl.store.record.NodeRecord;
import org.neo4j.kernel.impl.store.record.PropertyRecord;
import org.neo4j.kernel.impl.store.record.RecordLoad;
import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.kernel.impl.util.InstanceCache;
import org.neo4j.storageengine.api.Direction;
import org.neo4j.storageengine.api.NodeItem;
Expand All @@ -68,9 +52,6 @@
import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.storageengine.api.schema.LabelScanReader;

import static org.neo4j.kernel.impl.store.record.AbstractBaseRecord.NO_ID;
import static org.neo4j.kernel.impl.store.record.RecordLoad.NORMAL;

/**
* Statement for store layer. This allows for acquisition of cursors on the store data.
* <p/>
Expand All @@ -97,20 +78,13 @@ public class StoreStatement implements StorageStatement
private final RecordCursors recordCursors;
private final Supplier<LabelScanReader> labelScanStore;
private final RecordStorageCommandCreationContext commandCreationContext;
private final DynamicArrayStore propertyArrayStore;
private final DynamicStringStore propertyStringStore;

private IndexReaderFactory indexReaderFactory;
private LabelScanReader labelScanReader;

private boolean acquired;
private boolean closed;

private final Nodes nodes;
private final Relationships relationships;
private final Groups groups;
private final Properties properties;

public StoreStatement( NeoStores neoStores, Supplier<IndexReaderFactory> indexReaderFactory,
Supplier<LabelScanReader> labelScanReaderSupplier, LockService lockService,
RecordStorageCommandCreationContext commandCreationContext )
Expand All @@ -124,8 +98,6 @@ public StoreStatement( NeoStores neoStores, Supplier<IndexReaderFactory> indexRe
this.relationshipStore = neoStores.getRelationshipStore();
this.relationshipGroupStore = neoStores.getRelationshipGroupStore();
this.propertyStore = neoStores.getPropertyStore();
this.propertyArrayStore = propertyStore.getArrayStore();
this.propertyStringStore = propertyStore.getStringStore();
this.recordCursors = new RecordCursors( neoStores );

singleNodeCursor = new InstanceCache<StoreSingleNodeCursor>()
Expand Down Expand Up @@ -180,11 +152,6 @@ protected StorePropertyCursor create()
return new StorePropertyCursor( recordCursors, this );
}
};

nodes = new Nodes();
relationships = new Relationships();
groups = new Groups();
properties = new Properties();
}

@Override
Expand Down Expand Up @@ -321,188 +288,24 @@ public long reserveRelationship()
@Override
public Nodes nodes()
{
return nodes;
return nodeStore;
}

@Override
public Relationships relationships()
{
return relationships;
return relationshipStore;
}

@Override
public Groups groups()
{
return groups;
return relationshipGroupStore;
}

@Override
public Properties properties()
{
return properties;
}

class Nodes implements StorageStatement.Nodes
{
@Override
public PageCursor openPageCursor( long reference )
{
return nodeStore.openPageCursorForReading( reference );
}

@Override
public void loadRecordByCursor( long reference, NodeRecord nodeRecord, RecordLoad mode, PageCursor cursor )
throws InvalidRecordException
{
nodeStore.getRecordByCursor( reference, nodeRecord, mode, cursor );
}

@Override
public long getHighestPossibleIdInUse()
{
return nodeStore.getHighestPossibleIdInUse();
}

@Override
public RecordCursor<DynamicRecord> newLabelCursor()
{
return newCursor( nodeStore.getDynamicLabelStore() );
}
}

class Relationships implements StorageStatement.Relationships
{
@Override
public PageCursor openPageCursor( long reference )
{
return relationshipStore.openPageCursorForReading( reference );
}

@Override
public void loadRecordByCursor( long reference, RelationshipRecord relationshipRecord, RecordLoad mode,
PageCursor cursor ) throws InvalidRecordException
{
relationshipStore.getRecordByCursor( reference, relationshipRecord, mode, cursor );
}

@Override
public long getHighestPossibleIdInUse()
{
return relationshipStore.getHighestPossibleIdInUse();
}
}

class Groups implements StorageStatement.Groups
{
@Override
public PageCursor openPageCursor( long reference )
{
return relationshipGroupStore.openPageCursorForReading( reference );
}

@Override
public void loadRecordByCursor( long reference, RelationshipGroupRecord relationshipGroupRecord,
RecordLoad mode, PageCursor cursor ) throws InvalidRecordException
{
relationshipGroupStore.getRecordByCursor( reference, relationshipGroupRecord, mode, cursor );
}

@Override
public long getHighestPossibleIdInUse()
{
return relationshipGroupStore.getHighestPossibleIdInUse();
}
}

class Properties implements StorageStatement.Properties
{
@Override
public PageCursor openPageCursor( long reference )
{
return propertyStore.openPageCursorForReading( reference );
}

@Override
public void loadRecordByCursor( long reference, PropertyRecord propertyBlocks, RecordLoad mode,
PageCursor cursor ) throws InvalidRecordException
{
propertyStore.getRecordByCursor( reference, propertyBlocks, mode, cursor );
}

@Override
public long getHighestPossibleIdInUse()
{
return propertyStore.getHighestPossibleIdInUse();
}

@Override
public PageCursor openStringPageCursor( long reference )
{
return propertyStringStore.openPageCursorForReading( reference );
}

@Override
public PageCursor openArrayPageCursor( long reference )
{
return propertyArrayStore.openPageCursorForReading( reference );
}

@Override
public ByteBuffer loadString( long reference, ByteBuffer buffer, PageCursor page )
{
return readDynamic( propertyStore.getStringStore(), reference, buffer, page );
}

@Override
public ByteBuffer loadArray( long reference, ByteBuffer buffer, PageCursor page )
{
return readDynamic( propertyStore.getArrayStore(), reference, buffer, page );
}
}

private static ByteBuffer readDynamic( AbstractDynamicStore store, long reference, ByteBuffer buffer,
PageCursor page )
{
if ( buffer == null )
{
buffer = ByteBuffer.allocate( 512 );
}
else
{
buffer.clear();
}
DynamicRecord record = store.newRecord();
do
{
//We need to load forcefully here since otherwise we can have inconsistent reads
//for properties across blocks, see org.neo4j.graphdb.ConsistentPropertyReadsIT
store.getRecordByCursor( reference, record, RecordLoad.FORCE, page );
reference = record.getNextBlock();
byte[] data = record.getData();
if ( buffer.remaining() < data.length )
{
buffer = grow( buffer, data.length );
}
buffer.put( data, 0, data.length );
}
while ( reference != NO_ID );
return buffer;
}

private static ByteBuffer grow( ByteBuffer buffer, int required )
{
buffer.flip();
int capacity = buffer.capacity();
do
{
capacity *= 2;
}
while ( capacity - buffer.limit() < required );
return ByteBuffer.allocate( capacity ).order( ByteOrder.LITTLE_ENDIAN ).put( buffer );
}

private static <R extends AbstractBaseRecord> RecordCursor<R> newCursor( RecordStore<R> store )
{
return store.newRecordCursor( store.newRecord() ).acquire( store.getNumberOfReservedLowIds(), NORMAL );
return propertyStore;
}
}
Expand Up @@ -26,6 +26,7 @@

import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.storageengine.impl.recordstorage.StoreStatement;
import org.neo4j.kernel.impl.store.format.RecordFormats;
import org.neo4j.kernel.impl.store.id.IdGeneratorFactory;
import org.neo4j.kernel.impl.store.id.IdType;
Expand All @@ -40,7 +41,7 @@
/**
* Implementation of the node store.
*/
public class NodeStore extends CommonAbstractStore<NodeRecord,NoStoreHeader>
public class NodeStore extends CommonAbstractStore<NodeRecord,NoStoreHeader> implements StoreStatement.Nodes
{
public static Long readOwnerFromDynamicLabelsRecord( DynamicRecord record )
{
Expand All @@ -57,6 +58,13 @@ public static Long readOwnerFromDynamicLabelsRecord( DynamicRecord record )
return bits.getLong( requiredBits );
}

@Override
public RecordCursor<DynamicRecord> newLabelCursor()
{
return dynamicLabelStore.newRecordCursor( dynamicLabelStore.newRecord() ).acquire( getNumberOfReservedLowIds(),
RecordLoad.NORMAL );
}

public abstract static class Configuration
extends CommonAbstractStore.Configuration
{
Expand Down

0 comments on commit 956c63c

Please sign in to comment.