diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/spi/v3_3/TransactionBoundQueryContextTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/spi/v3_3/TransactionBoundQueryContextTest.scala index 4e7942cde5bf..fc3984d0f707 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/spi/v3_3/TransactionBoundQueryContextTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/spi/v3_3/TransactionBoundQueryContextTest.scala @@ -42,7 +42,7 @@ import org.neo4j.kernel.impl.locking.LockTracer import org.neo4j.kernel.impl.proc.Procedures import org.neo4j.kernel.impl.query.clientconnection.ClientConnectionInfo import org.neo4j.kernel.impl.query.{Neo4jTransactionalContext, Neo4jTransactionalContextFactory} -import org.neo4j.storageengine.api.SchemaResources +import org.neo4j.storageengine.api.StorageStatement import org.neo4j.test.TestGraphDatabaseFactory import scala.collection.JavaConverters._ @@ -61,7 +61,7 @@ class TransactionBoundQueryContextTest extends CypherFunSuite { outerTx = mock[InternalTransaction] val kernelTransaction = mock[KernelTransactionImplementation] when(kernelTransaction.securityContext()).thenReturn(AUTH_DISABLED) - val storeStatement = mock[SchemaResources] + val storeStatement = mock[StorageStatement] val operations = mock[StatementOperationParts](RETURNS_DEEP_STUBS) statement = new KernelStatementImplementation(kernelTransaction, null, storeStatement, new Procedures(), new CanWrite(), LockTracer.NONE) statement.initialize(null, operations, PageCursorTracerSupplier.NULL.get()) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java b/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java index c2a1844449b8..c025cc6ff285 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java @@ -87,6 +87,7 @@ import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.StorageStatementFactory; import org.neo4j.kernel.impl.store.MetaDataStore; import org.neo4j.kernel.impl.store.StoreId; import org.neo4j.kernel.impl.store.format.RecordFormatPropertyConfigurator; @@ -264,6 +265,7 @@ boolean applicable( DiagnosticsPhase phase ) private final Map indexProviders = new HashMap<>(); private final LegacyIndexProviderLookup legacyIndexProviderLookup; private final ConstraintSemantics constraintSemantics; + private final StorageStatementFactory storageStatementFactory; private final Procedures procedures; private final IOLimiter ioLimiter; private final AvailabilityGuard availabilityGuard; @@ -318,6 +320,7 @@ public NeoStoreDataSource( AutoIndexing autoIndexing, PageCache pageCache, ConstraintSemantics constraintSemantics, + StorageStatementFactory storageStatementFactory, Monitors monitors, Tracers tracers, Procedures procedures, @@ -356,6 +359,7 @@ public NeoStoreDataSource( this.startupStatistics = startupStatistics; this.guard = guard; this.constraintSemantics = constraintSemantics; + this.storageStatementFactory = storageStatementFactory; this.monitors = monitors; this.tracers = tracers; this.procedures = procedures; @@ -586,7 +590,7 @@ private StorageEngine buildStorageEngine( PropertyKeyTokenHolder propertyKeyToke RecordStorageEngine storageEngine = new RecordStorageEngine( storeDir, config, idGeneratorFactory, eligibleForReuse, idTypeConfigurationProvider, pageCache, fs, logProvider, propertyKeyTokenHolder, labelTokens, - relationshipTypeTokens, schemaStateChangeCallback, constraintSemantics, + relationshipTypeTokens, schemaStateChangeCallback, constraintSemantics, storageStatementFactory, scheduler, tokenNameLookup, lockService, schemaIndexProvider, indexingServiceMonitor, databaseHealth, labelScanStoreProvider, legacyIndexProviderLookup, indexConfigStore, legacyIndexTransactionOrdering, transactionSnapshotSupplier, progressionFactory ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/TransactionHook.java b/community/kernel/src/main/java/org/neo4j/kernel/api/TransactionHook.java index 07c4cfa8ddf3..c89a812a082b 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/TransactionHook.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/TransactionHook.java @@ -19,6 +19,7 @@ */ package org.neo4j.kernel.api; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -34,7 +35,7 @@ interface Outcome } OUTCOME beforeCommit( ReadableTransactionState state, KernelTransaction transaction, - StoreReadLayer storeReadLayer ); + StoreReadLayer storeReadLayer, StorageStatement statement ); void afterCommit( ReadableTransactionState state, KernelTransaction transaction, OUTCOME outcome ); void afterRollback( ReadableTransactionState state, KernelTransaction transaction, OUTCOME outcome ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionCountingStateVisitor.java b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionCountingStateVisitor.java index 66fc795d93cf..92d926ad53e0 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionCountingStateVisitor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionCountingStateVisitor.java @@ -29,6 +29,7 @@ import org.neo4j.kernel.impl.api.CountsRecordState; import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.RelationshipItem; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import org.neo4j.storageengine.api.txstate.TxStateVisitor; @@ -39,14 +40,16 @@ public class TransactionCountingStateVisitor extends TxStateVisitor.Delegator { private final StoreReadLayer storeLayer; + private final StorageStatement statement; private final CountsRecordState counts; private final ReadableTransactionState txState; - public TransactionCountingStateVisitor( TxStateVisitor next, StoreReadLayer storeLayer, + public TransactionCountingStateVisitor( TxStateVisitor next, StoreReadLayer storeLayer, StorageStatement statement, ReadableTransactionState txState, CountsRecordState counts ) { super( next ); this.storeLayer = storeLayer; + this.statement = statement; this.txState = txState; this.counts = counts; } @@ -62,7 +65,7 @@ public void visitCreatedNode( long id ) public void visitDeletedNode( long id ) { counts.incrementNodeCount( ANY_LABEL, -1 ); - storeLayer.nodeGetSingleCursor( id, ReadableTransactionState.EMPTY ) + storeLayer.nodeGetSingleCursor( statement, id, ReadableTransactionState.EMPTY ) .forAll( this::decrementCountForLabelsAndRelationships ); super.visitDeletedNode( id ); } @@ -76,7 +79,7 @@ private void decrementCountForLabelsAndRelationships( NodeItem node ) return false; } ); - storeLayer.degrees( node, + storeLayer.degrees( statement, node, ( type, out, in ) -> updateRelationshipsCountsFromDegrees( labelIds, type, -out, -in ) ); } @@ -91,7 +94,8 @@ public void visitCreatedRelationship( long id, int type, long startNode, long en @Override public void visitDeletedRelationship( long id ) { - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( id, ReadableTransactionState.EMPTY ) ) + try ( Cursor cursor = storeLayer + .relationshipCursor( statement, id, ReadableTransactionState.EMPTY ) ) { if ( !cursor.next() ) { @@ -121,11 +125,12 @@ public void visitNodeLabelChanges( long id, final Set added, final Set< } // get the relationship counts from *before* this transaction, // the relationship changes will compensate for what happens during the transaction - storeLayer.nodeGetSingleCursor( id, ReadableTransactionState.EMPTY ) - .forAll( node -> storeLayer.degrees( node, ( type, out, in ) -> + storeLayer.nodeGetSingleCursor( statement, id, ReadableTransactionState.EMPTY ) + .forAll( node -> storeLayer.degrees( statement, node, ( type, out, in ) -> { added.forEach( label -> updateRelationshipsCountsFromDegrees( type, label, out, in ) ); - removed.forEach( label -> updateRelationshipsCountsFromDegrees( type, label, -out, -in ) ); + removed.forEach( + label -> updateRelationshipsCountsFromDegrees( type, label, -out, -in ) ); } ) ); } super.visitNodeLabelChanges( id, added, removed ); @@ -156,6 +161,6 @@ private void updateRelationshipCount( long startNode, int type, long endNode, in private void visitLabels( long nodeId, PrimitiveIntVisitor visitor ) { - storeLayer.nodeGetSingleCursor( nodeId, txState ).forAll( node -> node.labels().visitKeys( visitor ) ); + storeLayer.nodeGetSingleCursor( statement, nodeId, txState ).forAll( node -> node.labels().visitKeys( visitor ) ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatement.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatement.java index 2f6c4745f3dd..1b94feed9634 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatement.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatement.java @@ -26,7 +26,7 @@ import org.neo4j.kernel.api.txstate.TxStateHolder; import org.neo4j.kernel.impl.locking.LockTracer; import org.neo4j.kernel.impl.locking.StatementLocks; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; public interface KernelStatement extends TxStateHolder, Statement { @@ -38,7 +38,7 @@ public interface KernelStatement extends TxStateHolder, Statement PageCursorTracer pageCursorTracer(); - SchemaResources schemaResources(); + StorageStatement storageStatement(); KernelTransaction transaction(); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatementImplementation.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatementImplementation.java index f2f1cea0253b..016de91821cb 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatementImplementation.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelStatementImplementation.java @@ -44,7 +44,7 @@ import org.neo4j.kernel.impl.locking.LockTracer; import org.neo4j.kernel.impl.locking.StatementLocks; import org.neo4j.kernel.impl.proc.Procedures; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import org.neo4j.storageengine.api.txstate.WritableTransactionState; @@ -70,7 +70,7 @@ public class KernelStatementImplementation implements KernelStatement { private final TxStateHolder txStateHolder; - private final SchemaResources schemaResources; + private final StorageStatement storeStatement; private final AccessCapability accessCapability; private final KernelTransactionImplementation transaction; private final OperationsFacade facade; @@ -82,14 +82,14 @@ public class KernelStatementImplementation implements KernelStatement public KernelStatementImplementation( KernelTransactionImplementation transaction, TxStateHolder txStateHolder, - SchemaResources schemaResources, + StorageStatement storeStatement, Procedures procedures, AccessCapability accessCapability, LockTracer systemLockTracer ) { this.transaction = transaction; this.txStateHolder = txStateHolder; - this.schemaResources = schemaResources; + this.storeStatement = storeStatement; this.accessCapability = accessCapability; this.facade = new OperationsFacade( transaction, this, procedures ); this.executingQueryList = ExecutingQueryList.EMPTY; @@ -224,7 +224,10 @@ public PageCursorTracer pageCursorTracer() public final void acquire() { - referenceCount++; + if ( referenceCount++ == 0 ) + { + storeStatement.acquire(); + } } final boolean isAcquired() @@ -267,15 +270,15 @@ public final void stopQueryExecution( ExecutingQuery executingQuery ) } @Override - public SchemaResources schemaResources() + public StorageStatement storageStatement() { - return schemaResources; + return storeStatement; } private void cleanupResources() { // closing is done by KTI - schemaResources.close(); + storeStatement.release(); executingQueryList = ExecutingQueryList.EMPTY; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java index 5b26356719fd..6087bf71f7a8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactionImplementation.java @@ -65,7 +65,7 @@ import org.neo4j.kernel.impl.transaction.tracing.TransactionTracer; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import org.neo4j.storageengine.api.txstate.TxStateVisitor; @@ -117,7 +117,7 @@ public class KernelTransactionImplementation implements KernelTransaction, TxSta private TransactionHooks.TransactionHooksState hooksState; private StatementOperationParts currentTransactionOperations; private final KernelStatementImplementation currentStatement; - private final SchemaResources schemaResources; + private final StorageStatement storageStatement; private final List closeListeners = new ArrayList<>( 2 ); private SecurityContext securityContext; private volatile StatementLocks statementLocks; @@ -178,9 +178,9 @@ public KernelTransactionImplementation( StatementOperationContainer operationCon this.clock = clock; this.transactionTracer = transactionTracer; this.cursorTracerSupplier = cursorTracerSupplier; - this.schemaResources = storeLayer.schemaResources(); + this.storageStatement = storeLayer.newStatement(); this.currentStatement = - new KernelStatementImplementation( this, this, schemaResources, procedures, accessCapability, lockTracer ); + new KernelStatementImplementation( this, this, storageStatement, procedures, accessCapability, lockTracer ); this.userMetaData = Collections.emptyMap(); } @@ -535,7 +535,7 @@ private long commit() throws TransactionFailureException { try { - hooksState = hooks.beforeCommit( txState, this, storageEngine.storeReadLayer() ); + hooksState = hooks.beforeCommit( txState, this, storageEngine.storeReadLayer(), storageStatement ); if ( hooksState != null && hooksState.failed() ) { TransactionHookException cause = hooksState.failure(); @@ -560,7 +560,8 @@ private long commit() throws TransactionFailureException Collection extractedCommands = new ArrayList<>(); storageEngine.createCommands( extractedCommands, - txState, schemaResources, + txState, + storageStatement, commitLocks, lastTransactionIdWhenStarted ); if ( hasLegacyIndexChanges() ) @@ -805,7 +806,7 @@ public String toString() @Override public void dispose() { - schemaResources.close(); + storageStatement.close(); } /** diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactions.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactions.java index 3f96cbf14b13..5849527d9292 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactions.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelTransactions.java @@ -28,6 +28,7 @@ import org.neo4j.collection.pool.LinkedQueuePool; import org.neo4j.collection.pool.MarshlandPool; +import org.neo4j.function.Factory; import org.neo4j.graphdb.DatabaseShutdownException; import org.neo4j.graphdb.TransactionFailureException; import org.neo4j.kernel.AvailabilityGuard; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java index 7b75e1d83ae4..00abbae445d5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/StateHandlingStatementOperations.java @@ -144,25 +144,25 @@ public StateHandlingStatementOperations( StoreReadLayer storeLayer, AutoIndexing @Override public BatchingLongProgression parallelNodeScanProgression( KernelStatement statement ) { - return storeLayer.parallelNodeScanProgression(); + return storeLayer.parallelNodeScanProgression( statement.storageStatement() ); } @Override public Cursor nodeGetCursor( KernelStatement statement, BatchingLongProgression progression ) { - return storeLayer.nodeGetCursor( progression, statement.readableTxState() ); + return storeLayer.nodeGetCursor( statement.storageStatement(), progression, statement.readableTxState() ); } @Override public Cursor nodeGetAllCursor( KernelStatement statement ) { - return storeLayer.nodeGetAllCursor( statement.readableTxState() ); + return storeLayer.nodeGetAllCursor( statement.storageStatement(), statement.readableTxState() ); } @Override public Cursor nodeCursorById( KernelStatement statement, long nodeId ) throws EntityNotFoundException { - Cursor node = storeLayer.nodeGetSingleCursor( nodeId, statement.readableTxState() ); + Cursor node = nodeCursor( statement, nodeId ); if ( !node.next() ) { node.close(); @@ -171,12 +171,16 @@ public Cursor nodeCursorById( KernelStatement statement, long nodeId ) return node; } + private Cursor nodeCursor( KernelStatement statement, long nodeId ) + { + return storeLayer.nodeGetSingleCursor( statement.storageStatement(), nodeId, statement.readableTxState() ); + } + @Override public Cursor relationshipCursorById( KernelStatement statement, long relationshipId ) throws EntityNotFoundException { - Cursor relationship = - storeLayer.relationshipGetSingleCursor( relationshipId, statement.readableTxState() ); + Cursor relationship = relationshipCursor( statement, relationshipId ); if ( !relationship.next() ) { relationship.close(); @@ -185,11 +189,17 @@ public Cursor relationshipCursorById( KernelStatement statemen return relationship; } + private Cursor relationshipCursor( KernelStatement statement, long relationshipId ) + { + ReadableTransactionState state = statement.readableTxState(); + return storeLayer.relationshipCursor( statement.storageStatement(), relationshipId, state ); + } + @Override public Cursor relationshipCursorGetAll( KernelStatement statement ) { ReadableTransactionState state = statement.readableTxState(); - return storeLayer.relationshipsGetAllCursor( state ); + return storeLayer.relationshipsGetAllCursor( statement.storageStatement(), state ); } @Override @@ -197,7 +207,7 @@ public Cursor nodeGetRelationships( KernelStatement statement, Direction direction ) { ReadableTransactionState state = statement.readableTxState(); - return storeLayer.nodeGetRelationships( node, direction, state ); + return storeLayer.nodeGetRelationships( statement.storageStatement(), node, direction, state ); } @Override @@ -205,14 +215,14 @@ public Cursor nodeGetRelationships( KernelStatement statement, int[] relTypes ) { ReadableTransactionState state = statement.readableTxState(); - return storeLayer.nodeGetRelationships( node, direction, relTypes, state ); + return storeLayer.nodeGetRelationships( statement.storageStatement(), node, direction, relTypes, state ); } @Override public Cursor nodeGetProperties( KernelStatement statement, NodeItem node ) { NodeState nodeState = statement.readableTxState().getNodeState( node.id() ); - return storeLayer.nodeGetProperties( node, nodeState ); + return storeLayer.nodeGetProperties( statement.storageStatement(), node, nodeState ); } @Override @@ -260,14 +270,14 @@ public boolean nodeHasProperty( KernelStatement statement, NodeItem node, int pr private Cursor nodeGetPropertyCursor( KernelStatement statement, NodeItem node, int propertyKeyId ) { NodeState nodeState = statement.readableTxState().getNodeState( node.id() ); - return storeLayer.nodeGetProperty( node, propertyKeyId, nodeState ); + return storeLayer.nodeGetProperty( statement.storageStatement(), node, propertyKeyId, nodeState ); } @Override public Cursor relationshipGetProperties( KernelStatement statement, RelationshipItem relationship ) { RelationshipState relationshipState = statement.readableTxState().getRelationshipState( relationship.id() ); - return storeLayer.relationshipGetProperties( relationship, relationshipState ); + return storeLayer.relationshipGetProperties( statement.storageStatement(), relationship, relationshipState ); } @Override @@ -318,7 +328,8 @@ private Cursor relationshipGetPropertyCursor( KernelStatement stat RelationshipItem relationship, int propertyKeyId ) { RelationshipState relationshipState = statement.readableTxState().getRelationshipState( relationship.id() ); - return storeLayer.relationshipGetProperty( relationship, propertyKeyId, relationshipState ); + return storeLayer.relationshipGetProperty( statement.storageStatement(), relationship, propertyKeyId, + relationshipState ); } // @@ -445,7 +456,7 @@ public boolean nodeRemoveLabel( KernelStatement state, long nodeId, int labelId @Override public PrimitiveLongIterator nodesGetForLabel( KernelStatement state, int labelId ) { - PrimitiveLongIterator source = storeLayer.nodesGetForLabel( state.schemaResources(), labelId ); + PrimitiveLongIterator source = storeLayer.nodesGetForLabel( state.storageStatement(), labelId ); PrimitiveLongIterator wLabelChanges = state.readableTxState().nodesWithLabelChanged( labelId ).augment( source ); return state.readableTxState().addedAndRemovedNodes().augmentWithRemovals( wLabelChanges ); @@ -678,7 +689,7 @@ public long nodeGetFromUniqueIndexSeek( KernelStatement statement, IndexDescript IndexQuery.ExactPredicate... query ) throws IndexNotFoundKernelException, IndexBrokenKernelException, IndexNotApplicableKernelException { - IndexReader reader = storeLayer.indexGetFreshReader( statement.schemaResources(), index ); + IndexReader reader = storeLayer.indexGetFreshReader( statement.storageStatement(), index ); /* Here we have an intricate scenario where we need to return the PrimitiveLongIterator * since subsequent filtering will happen outside, but at the same time have the ability to @@ -696,7 +707,7 @@ public long nodeGetFromUniqueIndexSeek( KernelStatement statement, IndexDescript public PrimitiveLongIterator indexQuery( KernelStatement statement, IndexDescriptor index, IndexQuery... predicates ) throws IndexNotFoundKernelException, IndexNotApplicableKernelException { - IndexReader reader = storeLayer.indexGetReader( statement.schemaResources(), index ); + IndexReader reader = storeLayer.indexGetReader( statement.storageStatement(), index ); PrimitiveLongIterator committed = reader.query( predicates ); PrimitiveLongIterator exactMatches = LookupFilter.exactIndexMatches( this, statement, committed, predicates ); @@ -776,7 +787,7 @@ private void assertSinglePredicate( IndexQuery[] predicates ) public long nodesCountIndexed( KernelStatement statement, IndexDescriptor index, long nodeId, Object value ) throws IndexNotFoundKernelException, IndexBrokenKernelException { - IndexReader reader = storeLayer.indexGetReader( statement.schemaResources(), index ); + IndexReader reader = storeLayer.indexGetReader( statement.storageStatement(), index ); return reader.countIndexedNodes( nodeId, value ); } @@ -1048,7 +1059,8 @@ public long countsForNode( final KernelStatement statement, int labelId ) try { statement.readableTxState().accept( - new TransactionCountingStateVisitor( EMPTY, storeLayer, statement.readableTxState(), counts ) ); + new TransactionCountingStateVisitor( EMPTY, storeLayer, statement.storageStatement(), + statement.readableTxState(), counts ) ); if ( counts.hasChanges() ) { count += counts.nodeCount( labelId, newDoubleLongRegister() ).readSecond(); @@ -1078,7 +1090,8 @@ public long countsForRelationship( KernelStatement statement, int startLabelId, try { statement.readableTxState().accept( - new TransactionCountingStateVisitor( EMPTY, storeLayer, statement.readableTxState(), counts ) ); + new TransactionCountingStateVisitor( EMPTY, storeLayer, statement.storageStatement(), + statement.readableTxState(), counts ) ); if ( counts.hasChanges() ) { count += counts.relationshipCount( startLabelId, typeId, endLabelId, newDoubleLongRegister() ) @@ -1398,7 +1411,8 @@ public void relationshipRemoveFromLegacyIndex( final KernelStatement statement, long relId, final String key, final Object value ) throws LegacyIndexNotFoundKernelException, EntityNotFoundException { - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( relId, statement.readableTxState() ) ) + try ( Cursor cursor = storeLayer + .relationshipCursor( statement.storageStatement(), relId, statement.readableTxState() ) ) { // Apparently it is OK if the relationship does not exist if ( cursor.next() ) @@ -1415,7 +1429,8 @@ public void relationshipRemoveFromLegacyIndex( final KernelStatement statement, long relId, final String key ) throws EntityNotFoundException, LegacyIndexNotFoundKernelException { - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( relId, statement.readableTxState() ) ) + try ( Cursor cursor = storeLayer + .relationshipCursor( statement.storageStatement(), relId, statement.readableTxState() ) ) { // Apparently it is OK if the relationship does not exist if ( cursor.next() ) @@ -1431,7 +1446,8 @@ public void relationshipRemoveFromLegacyIndex( final KernelStatement statement, public void relationshipRemoveFromLegacyIndex( final KernelStatement statement, final String indexName, long relId ) throws LegacyIndexNotFoundKernelException, EntityNotFoundException { - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( relId, statement.readableTxState() ) ) + try ( Cursor cursor = storeLayer + .relationshipCursor( statement.storageStatement(), relId, statement.readableTxState() ) ) { if ( cursor.next() ) { @@ -1550,7 +1566,7 @@ public PrimitiveIntSet relationshipTypes( KernelStatement statement, NodeItem no // Augment with types stored on disk, minus any types where all rels of that type are deleted // in current tx. - types.addAll( filter( storeLayer.relationshipTypes( node ).iterator(), + types.addAll( filter( storeLayer.relationshipTypes( statement.storageStatement(), node ).iterator(), ( current ) -> !types.contains( current ) && degree( statement, node, Direction.BOTH, current ) > 0 ) ); return types; @@ -1560,13 +1576,13 @@ public PrimitiveIntSet relationshipTypes( KernelStatement statement, NodeItem no public int degree( KernelStatement statement, NodeItem node, Direction direction ) { ReadableTransactionState state = statement.readableTxState(); - return storeLayer.countDegrees( node, direction, state ); + return storeLayer.countDegrees( statement.storageStatement(), node, direction, state ); } @Override public int degree( KernelStatement statement, NodeItem node, Direction direction, int relType ) { ReadableTransactionState state = statement.readableTxState(); - return storeLayer.countDegrees( node, direction, relType, state ); + return storeLayer.countDegrees( statement.storageStatement(), node, direction, relType, state ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/TransactionHooks.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/TransactionHooks.java index 68525a359345..868f1381994c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/TransactionHooks.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/TransactionHooks.java @@ -29,6 +29,7 @@ import org.neo4j.kernel.api.TransactionHook; import org.neo4j.kernel.api.TransactionHook.Outcome; import org.neo4j.kernel.api.exceptions.TransactionHookException; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -47,7 +48,7 @@ public void unregister( TransactionHook hook ) } public TransactionHooksState beforeCommit( ReadableTransactionState state, KernelTransaction tx, - StoreReadLayer storeReadLayer ) + StoreReadLayer storeReadLayer, StorageStatement storageStatement ) { if ( hooks.size() == 0 ) { @@ -57,7 +58,7 @@ public TransactionHooksState beforeCommit( ReadableTransactionState state, Kerne TransactionHooksState hookState = new TransactionHooksState(); for ( TransactionHook hook : hooks ) { - hookState.add( hook, hook.beforeCommit( state, tx, storeReadLayer ) ); + hookState.add( hook, hook.beforeCommit( state, tx, storeReadLayer, storageStatement ) ); } return hookState; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CursorPool.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CursorPool.java deleted file mode 100644 index 524423b77b83..000000000000 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/CursorPool.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2002-2017 "Neo Technology," - * Network Engine for Objects in Lund AB [http://neotechnology.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.kernel.impl.api.store; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.neo4j.collection.pool.LinkedQueuePool; -import org.neo4j.collection.pool.MarshlandPool; -import org.neo4j.function.Disposable; - -public class CursorPool implements AutoCloseable, Supplier -{ - public interface CursorFactory - { - C create( Consumer consumer ); - } - - // Global pool of cursors, wrapped by the thread-local marshland pool and so is not used directly. - private final LinkedQueuePool globalPool; - // Pool of unused cursors to be used to acquire cursors. - private final MarshlandPool localPool; - - CursorPool( int poolMinSize, CursorFactory cursorFactory ) - { - this.globalPool = new LinkedQueuePool( poolMinSize ) - { - @Override - protected T create() - { - return cursorFactory.create( localPool::release ); - } - - @Override - protected void dispose( T resource ) - { - super.dispose( resource ); - resource.dispose(); - } - }; - this.localPool = new MarshlandPool<>( globalPool ); - } - - public T get() - { - return localPool.acquire(); - } - - @Override - public void close() - { - localPool.disposeAll(); - globalPool.disposeAll(); - } -} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/GlobalCursorPools.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/GlobalCursorPools.java deleted file mode 100644 index f2247111e24e..000000000000 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/GlobalCursorPools.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2002-2017 "Neo Technology," - * Network Engine for Objects in Lund AB [http://neotechnology.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.kernel.impl.api.store; - -import org.neo4j.cursor.Cursor; -import org.neo4j.kernel.impl.locking.Lock; -import org.neo4j.kernel.impl.locking.LockService; -import org.neo4j.kernel.impl.store.NeoStores; -import org.neo4j.storageengine.api.BatchingLongProgression; -import org.neo4j.storageengine.api.CursorPools; -import org.neo4j.storageengine.api.Direction; -import org.neo4j.storageengine.api.NodeItem; -import org.neo4j.storageengine.api.PropertyItem; -import org.neo4j.storageengine.api.RelationshipGroupItem; -import org.neo4j.storageengine.api.RelationshipItem; -import org.neo4j.storageengine.api.txstate.NodeTransactionStateView; -import org.neo4j.storageengine.api.txstate.PropertyContainerState; -import org.neo4j.storageengine.api.txstate.ReadableTransactionState; - -public class GlobalCursorPools implements CursorPools -{ - private final CursorPool nodeCursor; - private final CursorPool singleRelationshipCursor; - private final CursorPool iteratorRelationshipCursor; - private final CursorPool nodeRelationshipsCursor; - private final CursorPool propertyCursor; - private final CursorPool singlePropertyCursor; - private final CursorPool relationshipGroupCursorCache; - private final CursorPool degreeCounter; - private final NeoStores neoStores; - - public GlobalCursorPools( NeoStores neoStores, LockService lockService ) - { - this.neoStores = neoStores; - this.nodeCursor = - new CursorPool<>( 10, cache -> new NodeCursor( neoStores.getNodeStore(), cache, lockService ) ); - this.singleRelationshipCursor = new CursorPool<>( 10, - cache -> new StoreSingleRelationshipCursor( neoStores.getRelationshipStore(), cache, lockService ) ); - this.iteratorRelationshipCursor = new CursorPool<>( 10, - cache -> new StoreIteratorRelationshipCursor( neoStores.getRelationshipStore(), cache, lockService ) ); - this.nodeRelationshipsCursor = new CursorPool<>( 10, - cache -> new StoreNodeRelationshipCursor( neoStores.getRelationshipStore(), - neoStores.getRelationshipGroupStore(), cache, lockService ) ); - this.propertyCursor = - new CursorPool<>( 10, cache -> new StorePropertyCursor( neoStores.getPropertyStore(), cache ) ); - this.singlePropertyCursor = - new CursorPool<>( 10, cache -> new StoreSinglePropertyCursor( neoStores.getPropertyStore(), cache ) ); - this.degreeCounter = new CursorPool<>( 10, - cache -> new DenseNodeDegreeCounter( neoStores.getRelationshipStore(), - neoStores.getRelationshipGroupStore(), cache ) ); - this.relationshipGroupCursorCache = new CursorPool<>( 10, - cache -> new RelationshipGroupCursor( neoStores.getRelationshipGroupStore(), cache ) ); - } - - @Override - public Cursor acquireNodeCursor( BatchingLongProgression progression, NodeTransactionStateView stateView ) - { - neoStores.assertOpen(); - return nodeCursor.get().init( progression, stateView ); - } - - @Override - public Cursor acquireSingleRelationshipCursor( long relId, ReadableTransactionState state ) - { - neoStores.assertOpen(); - return singleRelationshipCursor.get().init( relId, state ); - } - - @Override - public Cursor acquireNodeRelationshipCursor( boolean isDense, long nodeId, long relationshipId, - Direction direction, int[] relTypes, ReadableTransactionState state ) - { - neoStores.assertOpen(); - return relTypes == null - ? nodeRelationshipsCursor.get().init( isDense, relationshipId, nodeId, direction, state ) - : nodeRelationshipsCursor.get().init( isDense, relationshipId, nodeId, direction, relTypes, state ); - } - - @Override - public Cursor relationshipsGetAllCursor( ReadableTransactionState state ) - { - neoStores.assertOpen(); - return iteratorRelationshipCursor.get().init( new AllIdIterator( neoStores.getRelationshipStore() ), state ); - } - - @Override - public Cursor acquirePropertyCursor( long propertyId, Lock lock, PropertyContainerState state ) - { - neoStores.assertOpen(); - return propertyCursor.get().init( propertyId, lock, state ); - } - - @Override - public Cursor acquireSinglePropertyCursor( long propertyId, int propertyKeyId, Lock lock, - PropertyContainerState state ) - { - neoStores.assertOpen(); - return singlePropertyCursor.get().init( propertyKeyId, propertyId, lock, state ); - } - - @Override - public Cursor acquireRelationshipGroupCursor( long relationshipGroupId ) - { - neoStores.assertOpen(); - return relationshipGroupCursorCache.get().init( relationshipGroupId ); - } - - @Override - public NodeDegreeCounter acquireNodeDegreeCounter( long nodeId, long relationshipGroupId ) - { - neoStores.assertOpen(); - return degreeCounter.get().init( nodeId, relationshipGroupId ); - } - - @Override - public void dispose() - { - nodeCursor.close(); - singleRelationshipCursor.close(); - iteratorRelationshipCursor.close(); - nodeRelationshipsCursor.close(); - propertyCursor.close(); - singlePropertyCursor.close(); - relationshipGroupCursorCache.close(); - degreeCounter.close(); - } -} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StorageLayer.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StorageLayer.java index 11ec7035250f..101acb42af07 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StorageLayer.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StorageLayer.java @@ -63,13 +63,12 @@ import org.neo4j.register.Register.DoubleLongRegister; import org.neo4j.storageengine.api.BatchingLongProgression; import org.neo4j.storageengine.api.BatchingProgressionFactory; -import org.neo4j.storageengine.api.CursorPools; import org.neo4j.storageengine.api.Direction; import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.PropertyItem; import org.neo4j.storageengine.api.RelationshipItem; -import org.neo4j.storageengine.api.SchemaResources; import org.neo4j.storageengine.api.StorageProperty; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.Token; import org.neo4j.storageengine.api.schema.IndexReader; @@ -102,35 +101,33 @@ public class StorageLayer implements StoreReadLayer private final SchemaStorage schemaStorage; private final CountsTracker counts; private final PropertyLoader propertyLoader; - private final Supplier schemaResourcesSupplier; + private final Supplier statementProvider; private final SchemaCache schemaCache; - private final CursorPools cursorPools; private final BatchingProgressionFactory progressionFactory; public StorageLayer( PropertyKeyTokenHolder propertyKeyTokenHolder, LabelTokenHolder labelTokenHolder, RelationshipTypeTokenHolder relationshipTokenHolder, SchemaStorage schemaStorage, NeoStores neoStores, - IndexingService indexService, Supplier schemaResourcesSupplier, SchemaCache schemaCache, - CursorPools cursorPools, BatchingProgressionFactory progressionFactory ) + IndexingService indexService, Supplier storeStatementSupplier, SchemaCache schemaCache, + BatchingProgressionFactory progressionFactory ) { this.relationshipTokenHolder = relationshipTokenHolder; this.schemaStorage = schemaStorage; this.indexService = indexService; this.propertyKeyTokenHolder = propertyKeyTokenHolder; this.labelTokenHolder = labelTokenHolder; - this.schemaResourcesSupplier = schemaResourcesSupplier; + this.statementProvider = storeStatementSupplier; this.nodeStore = neoStores.getNodeStore(); this.relationshipStore = neoStores.getRelationshipStore(); this.counts = neoStores.getCounts(); this.propertyLoader = new PropertyLoader( neoStores ); this.schemaCache = schemaCache; - this.cursorPools = cursorPools; this.progressionFactory = progressionFactory; } @Override - public SchemaResources schemaResources() + public StorageStatement newStatement() { - return schemaResourcesSupplier.get(); + return statementProvider.get(); } @Override @@ -175,7 +172,7 @@ public String labelGetName( int labelId ) throws LabelNotFoundKernelException } @Override - public PrimitiveLongIterator nodesGetForLabel( SchemaResources statement, int labelId ) + public PrimitiveLongIterator nodesGetForLabel( StorageStatement statement, int labelId ) { return statement.getLabelScanReader().nodesWithLabel( labelId ); } @@ -260,17 +257,17 @@ public String indexGetFailure( LabelSchemaDescriptor descriptor ) throws IndexNo } @Override - public IndexReader indexGetReader( SchemaResources schemaResources, IndexDescriptor index ) + public IndexReader indexGetReader( StorageStatement statement, IndexDescriptor index ) throws IndexNotFoundKernelException { - return schemaResources.getIndexReader( index ); + return statement.getIndexReader( index ); } @Override - public IndexReader indexGetFreshReader( SchemaResources schemaResources, IndexDescriptor index ) + public IndexReader indexGetFreshReader( StorageStatement statement, IndexDescriptor index ) throws IndexNotFoundKernelException { - return schemaResources.getFreshIndexReader( index ); + return statement.getFreshIndexReader( index ); } @Override @@ -403,85 +400,90 @@ public RelationshipIterator relationshipsGetAll() } @Override - public BatchingLongProgression parallelNodeScanProgression() + public BatchingLongProgression parallelNodeScanProgression( StorageStatement statement ) { return progressionFactory.parallelAllNodeScan( nodeStore ); } @Override - public Cursor nodeGetCursor( BatchingLongProgression progression, NodeTransactionStateView stateView ) + public Cursor nodeGetCursor( StorageStatement statement, BatchingLongProgression progression, + NodeTransactionStateView stateView ) { - return cursorPools.acquireNodeCursor( progression, stateView ); + return statement.acquireNewNodeCursor( progression, stateView ); } @Override - public Cursor nodeGetAllCursor( NodeTransactionStateView stateView ) + public Cursor nodeGetAllCursor( StorageStatement statement, NodeTransactionStateView stateView ) { - return cursorPools.acquireNodeCursor( progressionFactory.allNodeScan( nodeStore ), stateView ); + return statement.acquireNodeCursor( progressionFactory.allNodeScan( nodeStore ), stateView ); } @Override - public Cursor nodeGetSingleCursor( long nodeId, NodeTransactionStateView stateView ) + public Cursor nodeGetSingleCursor( StorageStatement statement, long nodeId, + NodeTransactionStateView stateView ) { - return cursorPools.acquireNodeCursor( progressionFactory.singleNodeFetch( nodeId ), stateView ); + return statement.acquireNodeCursor( progressionFactory.singleNodeFetch( nodeId ), stateView ); } @Override - public Cursor relationshipGetSingleCursor( long relationshipId, ReadableTransactionState state ) + public Cursor relationshipCursor( StorageStatement statement, long relationshipId, + ReadableTransactionState state ) { - return cursorPools.acquireSingleRelationshipCursor( relationshipId, state ); + return statement.acquireSingleRelationshipCursor( relationshipId, state ); } @Override - public Cursor relationshipsGetAllCursor( ReadableTransactionState state ) + public Cursor relationshipsGetAllCursor( StorageStatement statement, + ReadableTransactionState state ) { - return cursorPools.relationshipsGetAllCursor( state ); + return statement.relationshipsGetAllCursor( state ); } @Override - public Cursor nodeGetRelationships( NodeItem nodeItem, Direction direction, - ReadableTransactionState state ) + public Cursor nodeGetRelationships( StorageStatement statement, NodeItem nodeItem, + Direction direction, ReadableTransactionState state ) { - return nodeGetRelationships( nodeItem, direction, null, state ); + return nodeGetRelationships( statement, nodeItem, direction, null, state ); } @Override - public Cursor nodeGetRelationships( NodeItem node, Direction direction, int[] relTypes, - ReadableTransactionState state ) + public Cursor nodeGetRelationships( StorageStatement statement, NodeItem node, + Direction direction, int[] relTypes, ReadableTransactionState state ) { - return cursorPools - .acquireNodeRelationshipCursor( node.isDense(), node.id(), node.nextRelationshipId(), direction, + return statement.acquireNodeRelationshipCursor( node.isDense(), node.id(), node.nextRelationshipId(), direction, relTypes, state ); } @Override - public Cursor nodeGetProperties( NodeItem node, PropertyContainerState state ) + public Cursor nodeGetProperties( StorageStatement statement, NodeItem node, + PropertyContainerState state ) { Lock lock = node.lock(); // lock before reading the property id, since we might need to reload the record - return cursorPools.acquirePropertyCursor( node.nextPropertyId(), lock, state ); + return statement.acquirePropertyCursor( node.nextPropertyId(), lock, state ); } @Override - public Cursor nodeGetProperty( NodeItem node, int propertyKeyId, PropertyContainerState state ) + public Cursor nodeGetProperty( StorageStatement statement, NodeItem node, int propertyKeyId, + PropertyContainerState state ) { Lock lock = node.lock(); // lock before reading the property id, since we might need to reload the record - return cursorPools.acquireSinglePropertyCursor( node.nextPropertyId(), propertyKeyId, lock, state ); + return statement.acquireSinglePropertyCursor( node.nextPropertyId(), propertyKeyId, lock, state ); } @Override - public Cursor relationshipGetProperties( RelationshipItem relationship, PropertyContainerState state ) + public Cursor relationshipGetProperties( StorageStatement statement, RelationshipItem relationship, + PropertyContainerState state ) { - Lock lock = - relationship.lock(); // lock before reading the property id, since we might need to reload the record - return cursorPools.acquirePropertyCursor( relationship.nextPropertyId(), lock, state ); + Lock lock = relationship.lock(); // lock before reading the property id, since we might need to reload the record + return statement.acquirePropertyCursor( relationship.nextPropertyId(), lock, state ); } @Override - public Cursor relationshipGetProperty( RelationshipItem relationship, + public Cursor relationshipGetProperty( StorageStatement statement, RelationshipItem relationship, int propertyKeyId, PropertyContainerState state ) { Lock lock = relationship.lock(); // lock before reading the property id, since we might need to reload the record - return cursorPools.acquireSinglePropertyCursor( relationship.nextPropertyId(), propertyKeyId, lock, state ); + return statement.acquireSinglePropertyCursor( relationship.nextPropertyId(), propertyKeyId, lock, state ); } @Override @@ -586,26 +588,27 @@ public boolean nodeExists( long id ) } @Override - public PrimitiveIntSet relationshipTypes( NodeItem node ) + public PrimitiveIntSet relationshipTypes( StorageStatement statement, NodeItem node ) { PrimitiveIntSet set = intSet(); if ( node.isDense() ) { - cursorPools.acquireRelationshipGroupCursor( node.nextGroupId() ).forAll( group -> set.add( group.type() ) ); + statement.acquireRelationshipGroupCursor( node.nextGroupId() ).forAll( group -> set.add( group.type() ) ); } else { - nodeGetRelationships( node, BOTH, EMPTY ).forAll( relationship -> set.add( relationship.type() ) ); + nodeGetRelationships( statement, node, BOTH, EMPTY ) + .forAll( relationship -> set.add( relationship.type() ) ); } return set; } @Override - public void degrees( NodeItem node, DegreeVisitor visitor ) + public void degrees( StorageStatement statement, NodeItem node, DegreeVisitor visitor ) { if ( node.isDense() ) { - try ( NodeDegreeCounter degreeCounter = cursorPools + try ( NodeDegreeCounter degreeCounter = statement .acquireNodeDegreeCounter( node.id(), node.nextGroupId() ) ) { degreeCounter.accept( visitor ); @@ -613,12 +616,13 @@ public void degrees( NodeItem node, DegreeVisitor visitor ) } else { - visitNode( node, visitor ); + visitNode( statement, node, visitor ); } } @Override - public int countDegrees( NodeItem node, Direction direction, ReadableTransactionState state ) + public int countDegrees( StorageStatement statement, NodeItem node, Direction direction, + ReadableTransactionState state ) { int count; if ( state != null && state.nodeIsAddedInThisTx( node.id() ) ) @@ -629,7 +633,7 @@ public int countDegrees( NodeItem node, Direction direction, ReadableTransaction { if ( node.isDense() ) { - try ( NodeDegreeCounter degreeCounter = cursorPools + try ( NodeDegreeCounter degreeCounter = statement .acquireNodeDegreeCounter( node.id(), node.nextGroupId() ) ) { count = degreeCounter.count( direction ); @@ -637,7 +641,7 @@ public int countDegrees( NodeItem node, Direction direction, ReadableTransaction } else { - count = count( nodeGetRelationships( node, direction, EMPTY ) ); + count = count( nodeGetRelationships( statement, node, direction, EMPTY ) ); } } @@ -645,7 +649,8 @@ public int countDegrees( NodeItem node, Direction direction, ReadableTransaction } @Override - public int countDegrees( NodeItem node, Direction direction, int relType, ReadableTransactionState state ) + public int countDegrees( StorageStatement statement, NodeItem node, Direction direction, int relType, + ReadableTransactionState state ) { int count; if ( state != null && state.nodeIsAddedInThisTx( node.id() ) ) @@ -656,7 +661,7 @@ public int countDegrees( NodeItem node, Direction direction, int relType, Readab { if ( node.isDense() ) { - try ( NodeDegreeCounter degreeCounter = cursorPools + try ( NodeDegreeCounter degreeCounter = statement .acquireNodeDegreeCounter( node.id(), node.nextGroupId() ) ) { count = degreeCounter.count( direction, relType ); @@ -664,16 +669,16 @@ public int countDegrees( NodeItem node, Direction direction, int relType, Readab } else { - count = count( nodeGetRelationships( node, direction, new int[]{relType}, EMPTY ) ); + count = count( nodeGetRelationships( statement, node, direction, new int[]{relType}, EMPTY ) ); } } return state == null ? count : state.getNodeState( node.id() ).augmentDegree( direction, count, relType ); } - private void visitNode( NodeItem node, DegreeVisitor visitor ) + private void visitNode( StorageStatement statement, NodeItem node, DegreeVisitor visitor ) { - try ( Cursor relationships = nodeGetRelationships( node, BOTH, EMPTY ) ) + try ( Cursor relationships = nodeGetRelationships( statement, node, BOTH, EMPTY ) ) { while ( relationships.next() ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursor.java index d597bc0d448b..2d114106dc83 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursor.java @@ -19,11 +19,11 @@ */ package org.neo4j.kernel.impl.api.store; -import java.util.function.Consumer; - import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.store.RelationshipStore; +import org.neo4j.kernel.impl.store.record.RelationshipRecord; +import org.neo4j.kernel.impl.util.InstanceCache; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import static org.neo4j.collection.primitive.PrimitiveLongCollections.toPrimitiveIterator; @@ -34,11 +34,11 @@ */ public class StoreIteratorRelationshipCursor extends StoreAbstractIteratorRelationshipCursor { - private final Consumer instanceCache; private PrimitiveLongIterator iterator; + private final InstanceCache instanceCache; StoreIteratorRelationshipCursor( RelationshipStore relationshipStore, - Consumer instanceCache, + InstanceCache instanceCache, LockService lockService ) { super( relationshipStore, lockService ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSchemaResources.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSchemaResources.java deleted file mode 100644 index 2192fa39f8c6..000000000000 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSchemaResources.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2002-2017 "Neo Technology," - * Network Engine for Objects in Lund AB [http://neotechnology.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.kernel.impl.api.store; - -import java.util.function.Supplier; - -import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; -import org.neo4j.kernel.api.schema.index.IndexDescriptor; -import org.neo4j.kernel.impl.api.IndexReaderFactory; -import org.neo4j.storageengine.api.SchemaResources; -import org.neo4j.storageengine.api.schema.IndexReader; -import org.neo4j.storageengine.api.schema.LabelScanReader; - -/** - * Statement for store layer. This allows for acquisition of cursors on the store data. - *

- * The cursors call the release methods, so there is no need for manual release, only - * closing those cursor. - *

- */ -public class StoreSchemaResources implements SchemaResources -{ - private final Supplier indexReaderFactorySupplier; - private final Supplier labelScanStore; - - private IndexReaderFactory indexReaderFactory; - private LabelScanReader labelScanReader; - - public StoreSchemaResources( Supplier indexReaderFactory, - Supplier labelScanReaderSupplier ) - { - this.indexReaderFactorySupplier = indexReaderFactory; - this.labelScanStore = labelScanReaderSupplier; - } - - @Override - public void close() - { - if ( indexReaderFactory != null ) - { - indexReaderFactory.close(); - // we can actually keep this object around - } - if ( labelScanReader != null ) - { - labelScanReader.close(); - labelScanReader = null; - } - } - - @Override - public LabelScanReader getLabelScanReader() - { - return labelScanReader != null ? - labelScanReader : (labelScanReader = labelScanStore.get()); - } - - private IndexReaderFactory indexReaderFactory() - { - return indexReaderFactory != null ? - indexReaderFactory : (indexReaderFactory = indexReaderFactorySupplier.get()); - } - - @Override - public IndexReader getIndexReader( IndexDescriptor descriptor ) throws IndexNotFoundKernelException - { - return indexReaderFactory().newReader( descriptor ); - } - - @Override - public IndexReader getFreshIndexReader( IndexDescriptor descriptor ) throws IndexNotFoundKernelException - { - return indexReaderFactory().newUnCachedReader( descriptor ); - } -} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursor.java index 67fb4b2d7db7..6d72ee88c407 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursor.java @@ -19,10 +19,9 @@ */ package org.neo4j.kernel.impl.api.store; -import java.util.function.Consumer; - import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.store.RelationshipStore; +import org.neo4j.kernel.impl.util.InstanceCache; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import static org.neo4j.kernel.api.StatementConstants.NO_SUCH_NODE; @@ -35,15 +34,15 @@ */ public class StoreSingleRelationshipCursor extends StoreAbstractRelationshipCursor { - private final Consumer consumer; + private final InstanceCache instanceCache; private long relationshipId = NO_SUCH_RELATIONSHIP; private ReadableTransactionState state; StoreSingleRelationshipCursor( RelationshipStore relationshipStore, - Consumer consumer, LockService lockService ) + InstanceCache instanceCache, LockService lockService ) { super( relationshipStore, lockService ); - this.consumer = consumer; + this.instanceCache = instanceCache; } public StoreSingleRelationshipCursor init( long relId, ReadableTransactionState state ) @@ -92,6 +91,6 @@ public void close() { super.close(); relationshipId = NO_SUCH_RELATIONSHIP; - consumer.accept( this ); + instanceCache.accept( this ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreStatement.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreStatement.java new file mode 100644 index 000000000000..e64bcd4ff573 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/StoreStatement.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.api.store; + +import java.util.function.Supplier; + +import org.neo4j.cursor.Cursor; +import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; +import org.neo4j.kernel.api.schema.index.IndexDescriptor; +import org.neo4j.kernel.impl.api.IndexReaderFactory; +import org.neo4j.kernel.impl.locking.Lock; +import org.neo4j.kernel.impl.locking.LockService; +import org.neo4j.kernel.impl.store.NeoStores; +import org.neo4j.kernel.impl.util.InstanceCache; +import org.neo4j.storageengine.api.BatchingLongProgression; +import org.neo4j.storageengine.api.Direction; +import org.neo4j.storageengine.api.NodeItem; +import org.neo4j.storageengine.api.PropertyItem; +import org.neo4j.storageengine.api.RelationshipGroupItem; +import org.neo4j.storageengine.api.RelationshipItem; +import org.neo4j.storageengine.api.StorageStatement; +import org.neo4j.storageengine.api.schema.IndexReader; +import org.neo4j.storageengine.api.schema.LabelScanReader; +import org.neo4j.storageengine.api.txstate.NodeTransactionStateView; +import org.neo4j.storageengine.api.txstate.PropertyContainerState; +import org.neo4j.storageengine.api.txstate.ReadableTransactionState; + +/** + * Statement for store layer. This allows for acquisition of cursors on the store data. + *

+ * The cursors call the release methods, so there is no need for manual release, only + * closing those cursor. + *

+ */ +public class StoreStatement implements StorageStatement +{ + private final InstanceCache nodeCursor; + private final InstanceCache singleRelationshipCursor; + private final InstanceCache iteratorRelationshipCursor; + private final InstanceCache nodeRelationshipsCursor; + private final InstanceCache propertyCursorCache; + private final InstanceCache singlePropertyCursorCache; + private final InstanceCache relationshipGroupCursorCache; + private final InstanceCache degreeVisitableCache; + private final NeoStores neoStores; + private final Supplier indexReaderFactorySupplier; + private final Supplier labelScanStore; + private final LockService lockService; + + private IndexReaderFactory indexReaderFactory; + private LabelScanReader labelScanReader; + + private boolean acquired; + private boolean closed; + + public StoreStatement( NeoStores neoStores, Supplier indexReaderFactory, + Supplier labelScanReaderSupplier, LockService lockService ) + { + this.neoStores = neoStores; + this.indexReaderFactorySupplier = indexReaderFactory; + this.labelScanStore = labelScanReaderSupplier; + this.lockService = lockService; + + nodeCursor = new InstanceCache() + { + @Override + protected NodeCursor create() + { + return new NodeCursor( neoStores.getNodeStore(), this, lockService ); + } + }; + singleRelationshipCursor = new InstanceCache() + { + @Override + protected StoreSingleRelationshipCursor create() + { + return new StoreSingleRelationshipCursor( neoStores.getRelationshipStore(), this, lockService ); + } + }; + iteratorRelationshipCursor = new InstanceCache() + { + @Override + protected StoreIteratorRelationshipCursor create() + { + return new StoreIteratorRelationshipCursor( neoStores.getRelationshipStore(), this, lockService ); + } + }; + nodeRelationshipsCursor = new InstanceCache() + { + @Override + protected StoreNodeRelationshipCursor create() + { + return new StoreNodeRelationshipCursor( neoStores.getRelationshipStore(), + neoStores.getRelationshipGroupStore(), this, lockService ); + } + }; + propertyCursorCache = new InstanceCache() + { + @Override + protected StorePropertyCursor create() + { + return new StorePropertyCursor( neoStores.getPropertyStore(), this ); + } + }; + singlePropertyCursorCache = new InstanceCache() + { + @Override + protected StoreSinglePropertyCursor create() + { + return new StoreSinglePropertyCursor( neoStores.getPropertyStore(), this ); + } + }; + degreeVisitableCache = new InstanceCache() + { + @Override + protected DenseNodeDegreeCounter create() + { + return new DenseNodeDegreeCounter( neoStores.getRelationshipStore(), neoStores.getRelationshipGroupStore(), + this ); + } + }; + relationshipGroupCursorCache = new InstanceCache() + { + @Override + protected RelationshipGroupCursor create() + { + return new RelationshipGroupCursor( neoStores.getRelationshipGroupStore(), this ); + } + }; + } + + @Override + public void acquire() + { + assert !closed; + assert !acquired; + this.acquired = true; + } + + @Override + public Cursor acquireNewNodeCursor( BatchingLongProgression progression, + NodeTransactionStateView stateView ) + { + return new NodeCursor( neoStores.getNodeStore(), InstanceCache::noCache, lockService ) + .init( progression, stateView ); + } + + @Override + public Cursor acquireNodeCursor( BatchingLongProgression progression, NodeTransactionStateView stateView ) + { + neoStores.assertOpen(); + return nodeCursor.get().init( progression, stateView ); + } + + @Override + public Cursor acquireSingleRelationshipCursor( long relId, ReadableTransactionState state ) + { + neoStores.assertOpen(); + return singleRelationshipCursor.get().init( relId, state ); + } + + @Override + public Cursor acquireNodeRelationshipCursor( boolean isDense, long nodeId, long relationshipId, + Direction direction, int[] relTypes, ReadableTransactionState state ) + { + neoStores.assertOpen(); + return relTypes == null + ? nodeRelationshipsCursor.get().init( isDense, relationshipId, nodeId, direction, state ) + : nodeRelationshipsCursor.get().init( isDense, relationshipId, nodeId, direction, relTypes, state ); + } + + @Override + public Cursor relationshipsGetAllCursor( ReadableTransactionState state ) + { + neoStores.assertOpen(); + return iteratorRelationshipCursor.get().init( new AllIdIterator( neoStores.getRelationshipStore() ), state ); + } + + @Override + public Cursor acquirePropertyCursor( long propertyId, Lock lock, PropertyContainerState state ) + { + return propertyCursorCache.get().init( propertyId, lock, state ); + } + + @Override + public Cursor acquireSinglePropertyCursor( long propertyId, int propertyKeyId, Lock lock, + PropertyContainerState state ) + { + return singlePropertyCursorCache.get().init( propertyKeyId, propertyId, lock, state ); + } + + @Override + public Cursor acquireRelationshipGroupCursor( long relationshipGroupId ) + { + return relationshipGroupCursorCache.get().init( relationshipGroupId ); + } + + @Override + public NodeDegreeCounter acquireNodeDegreeCounter( long nodeId, long relationshipGroupId ) + { + return degreeVisitableCache.get().init( nodeId, relationshipGroupId ); + } + + @Override + public void release() + { + assert !closed; + assert acquired; + closeSchemaResources(); + acquired = false; + } + + @Override + public void close() + { + assert !closed; + closeSchemaResources(); + nodeCursor.close(); + singleRelationshipCursor.close(); + iteratorRelationshipCursor.close(); + nodeRelationshipsCursor.close(); + propertyCursorCache.close(); + singlePropertyCursorCache.close(); + relationshipGroupCursorCache.close(); + degreeVisitableCache.close(); + closed = true; + } + + private void closeSchemaResources() + { + if ( indexReaderFactory != null ) + { + indexReaderFactory.close(); + // we can actually keep this object around + } + if ( labelScanReader != null ) + { + labelScanReader.close(); + labelScanReader = null; + } + } + + @Override + public LabelScanReader getLabelScanReader() + { + return labelScanReader != null ? + labelScanReader : (labelScanReader = labelScanStore.get()); + } + + private IndexReaderFactory indexReaderFactory() + { + return indexReaderFactory != null ? + indexReaderFactory : (indexReaderFactory = indexReaderFactorySupplier.get()); + } + + @Override + public IndexReader getIndexReader( IndexDescriptor descriptor ) throws IndexNotFoundKernelException + { + return indexReaderFactory().newReader( descriptor ); + } + + @Override + public IndexReader getFreshIndexReader( IndexDescriptor descriptor ) throws IndexNotFoundKernelException + { + return indexReaderFactory().newUnCachedReader( descriptor ); + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java index f78f5e6be6ef..6c99340d7485 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataSnapshot.java @@ -45,6 +45,7 @@ import org.neo4j.storageengine.api.PropertyItem; import org.neo4j.storageengine.api.RelationshipItem; import org.neo4j.storageengine.api.StorageProperty; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.NodeState; import org.neo4j.storageengine.api.txstate.ReadableDiffSets; @@ -60,6 +61,7 @@ public class TxStateTransactionDataSnapshot implements TransactionData { private final ReadableTransactionState state; private final NodeProxy.NodeActions nodeActions; + private final StorageStatement storeStatement; private final RelationshipActions relationshipActions; private final StoreReadLayer store; private KernelTransaction transaction; @@ -73,12 +75,15 @@ public class TxStateTransactionDataSnapshot implements TransactionData private final Collection removedLabels = new ArrayList<>(); private final PrimitiveLongObjectMap relationshipsReadFromStore = Primitive.longObjectMap( 16 ); - public TxStateTransactionDataSnapshot( ReadableTransactionState state, NodeProxy.NodeActions nodeActions, - RelationshipActions relationshipActions, StoreReadLayer storeReadLayer, KernelTransaction transaction ) + public TxStateTransactionDataSnapshot( + ReadableTransactionState state, + NodeProxy.NodeActions nodeActions, RelationshipActions relationshipActions, + StoreReadLayer storeReadLayer, StorageStatement storageStatement, KernelTransaction transaction ) { this.state = state; this.nodeActions = nodeActions; this.relationshipActions = relationshipActions; + this.storeStatement = storageStatement; this.store = storeReadLayer; this.transaction = transaction; @@ -189,11 +194,12 @@ private void takeSnapshot() { for ( long nodeId : state.addedAndRemovedNodes().getRemoved() ) { - try ( Cursor node = store.nodeGetSingleCursor( nodeId, EMPTY ) ) + try ( Cursor node = store.nodeGetSingleCursor( storeStatement, nodeId, EMPTY ) ) { if ( node.next() ) { - try ( Cursor properties = store.nodeGetProperties( node.get(), NodeState.EMPTY ) ) + try ( Cursor properties = store + .nodeGetProperties( storeStatement, node.get(), NodeState.EMPTY ) ) { while ( properties.next() ) { @@ -214,12 +220,13 @@ private void takeSnapshot() for ( long relId : state.addedAndRemovedRelationships().getRemoved() ) { Relationship relationshipProxy = relationship( relId ); - try ( Cursor relationship = store.relationshipGetSingleCursor( relId, EMPTY ) ) + try ( Cursor relationship = store.relationshipCursor( storeStatement, relId, EMPTY ) ) { if ( relationship.next() ) { try ( Cursor properties = store - .relationshipGetProperties( relationship.get(), RelationshipState.EMPTY ) ) + .relationshipGetProperties( storeStatement, relationship.get(), + RelationshipState.EMPTY ) ) { while ( properties.next() ) { @@ -302,7 +309,7 @@ private Relationship relationship( long relId ) } // Get this relationship data from the store - try ( Cursor cursor = store.relationshipGetSingleCursor( relId, EMPTY ) ) + try ( Cursor cursor = store.relationshipCursor( storeStatement, relId, EMPTY ) ) { if ( !cursor.next() ) { @@ -348,14 +355,15 @@ private Object committedValue( NodeState nodeState, int property ) return null; } - try ( Cursor node = store.nodeGetSingleCursor( nodeState.getId(), EMPTY ) ) + try ( Cursor node = store.nodeGetSingleCursor( storeStatement, nodeState.getId(), EMPTY ) ) { if ( !node.next() ) { return null; } - try ( Cursor properties = store.nodeGetProperty( node.get(), property, NodeState.EMPTY ) ) + try ( Cursor properties = store + .nodeGetProperty( storeStatement, node.get(), property, NodeState.EMPTY ) ) { if ( properties.next() ) { @@ -374,7 +382,8 @@ private Object committedValue( RelationshipState relState, int property ) return null; } - try ( Cursor relationship = store.relationshipGetSingleCursor( relState.getId(), EMPTY ) ) + try ( Cursor relationship = store + .relationshipCursor( storeStatement, relState.getId(), EMPTY ) ) { if ( !relationship.next() ) { @@ -382,7 +391,8 @@ private Object committedValue( RelationshipState relState, int property ) } try ( Cursor properties = store - .relationshipGetProperty( relationship.get(), property, RelationshipState.EMPTY ) ) + .relationshipGetProperty( storeStatement, relationship.get(), property, + RelationshipState.EMPTY ) ) { if ( properties.next() ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java index 1f5fe5dfeafb..fced947d22a4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java @@ -37,6 +37,7 @@ import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.SchemaWriteGuard; import org.neo4j.kernel.impl.api.store.CommunityBatchingProgressionFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.constraints.ConstraintSemantics; import org.neo4j.kernel.impl.constraints.StandardConstraintSemantics; import org.neo4j.kernel.impl.core.DefaultLabelIdCreator; @@ -127,6 +128,8 @@ public CommunityEditionModule( PlatformModule platformModule ) constraintSemantics = createSchemaRuleVerifier(); + storageStatementFactory = StoreStatement::new; + progressionFactory = platformModule.dependencies.satisfyDependency( createProgressionFactory() ); coreAPIAvailabilityGuard = new CoreAPIAvailabilityGuard( platformModule.availabilityGuard, transactionStartTimeout ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java index 3d3a3389f761..0dceaaac7bb0 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java @@ -63,9 +63,9 @@ import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.core.TokenNotFoundException; import org.neo4j.kernel.impl.logging.LogService; +import org.neo4j.kernel.impl.proc.ProcedureTransactionProvider; import org.neo4j.kernel.impl.proc.ProcedureConfig; import org.neo4j.kernel.impl.proc.ProcedureGDSFactory; -import org.neo4j.kernel.impl.proc.ProcedureTransactionProvider; import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.kernel.impl.proc.TerminationGuardProvider; import org.neo4j.kernel.impl.proc.TypeMappers.SimpleConverter; @@ -213,6 +213,7 @@ public DataSourceModule( final PlatformModule platformModule, EditionModule edit autoIndexing, pageCache, editionModule.constraintSemantics, + editionModule.storageStatementFactory, platformModule.monitors, platformModule.tracers, procedures, diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java index 91e39bd4dc76..52211ed56092 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java @@ -44,6 +44,7 @@ import org.neo4j.kernel.impl.locking.StatementLocksFactory; import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.proc.Procedures; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.StorageStatementFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdReuseEligibility; import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; @@ -93,6 +94,8 @@ public abstract class EditionModule public ConstraintSemantics constraintSemantics; + public StorageStatementFactory storageStatementFactory; + public CoreAPIAvailabilityGuard coreAPIAvailabilityGuard; public AccessCapability accessCapability; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java index c6513963503c..c4bb7bd8066a 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java @@ -58,10 +58,8 @@ import org.neo4j.kernel.impl.api.index.IndexingUpdateService; import org.neo4j.kernel.impl.api.index.PropertyPhysicalToLogicalConverter; import org.neo4j.kernel.impl.api.scan.LabelScanStoreProvider; -import org.neo4j.kernel.impl.api.store.GlobalCursorPools; import org.neo4j.kernel.impl.api.store.SchemaCache; import org.neo4j.kernel.impl.api.store.StorageLayer; -import org.neo4j.kernel.impl.api.store.StoreSchemaResources; import org.neo4j.kernel.impl.cache.BridgingCacheAccess; import org.neo4j.kernel.impl.constraints.ConstraintSemantics; import org.neo4j.kernel.impl.core.CacheAccessBackDoor; @@ -111,12 +109,12 @@ import org.neo4j.kernel.lifecycle.Lifecycle; import org.neo4j.kernel.spi.legacyindex.IndexImplementation; import org.neo4j.logging.LogProvider; -import org.neo4j.storageengine.api.BatchingProgressionFactory; import org.neo4j.storageengine.api.CommandReaderFactory; import org.neo4j.storageengine.api.CommandsToApply; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.BatchingProgressionFactory; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreFileMetadata; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.TransactionApplicationMode; @@ -161,7 +159,9 @@ public class RecordStorageEngine implements StorageEngine, Lifecycle private final NeoStoreIndexStoreView indexStoreView; private final LegacyIndexProviderLookup legacyIndexProviderLookup; private final PropertyPhysicalToLogicalConverter indexUpdatesConverter; + private final Supplier storeStatementSupplier; private final IdController idController; + private final StorageStatementFactory storageStatementFactory; // Immutable state for creating/applying commands private final Loaders loaders; @@ -169,7 +169,6 @@ public class RecordStorageEngine implements StorageEngine, Lifecycle private final RelationshipDeleter relationshipDeleter; private final PropertyCreator propertyCreator; private final PropertyDeleter propertyDeleter; - private final GlobalCursorPools cursorsPool; public RecordStorageEngine( File storeDir, @@ -185,6 +184,7 @@ public RecordStorageEngine( RelationshipTypeTokenHolder relationshipTypeTokens, Runnable schemaStateChangeCallback, ConstraintSemantics constraintSemantics, + StorageStatementFactory storageStatementFactory, JobScheduler scheduler, TokenNameLookup tokenNameLookup, LockService lockService, @@ -208,6 +208,7 @@ public RecordStorageEngine( this.legacyIndexProviderLookup = legacyIndexProviderLookup; this.indexConfigStore = indexConfigStore; this.constraintSemantics = constraintSemantics; + this.storageStatementFactory = storageStatementFactory; this.legacyIndexTransactionOrdering = legacyIndexTransactionOrdering; this.idController = createStorageIdController( idGeneratorFactory, eligibleForReuse, @@ -234,10 +235,11 @@ public RecordStorageEngine( cacheAccess = new BridgingCacheAccess( schemaCache, schemaStateChangeCallback, propertyKeyTokenHolder, relationshipTypeTokens, labelTokens ); - cursorsPool = createCursorPool(); - Supplier schemaResourcesSupplier = createSchemaResources(); - storeLayer = new StorageLayer( propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, schemaStorage, - neoStores, indexingService, schemaResourcesSupplier, schemaCache, cursorsPool, progressionFactory ); + storeStatementSupplier = storeStatementSupplier( neoStores ); + storeLayer = new StorageLayer( + propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, + schemaStorage, neoStores, indexingService, + storeStatementSupplier, schemaCache, progressionFactory ); legacyIndexApplierLookup = new LegacyIndexApplierLookup.Direct( legacyIndexProviderLookup ); @@ -264,19 +266,6 @@ public RecordStorageEngine( } } - private Supplier createSchemaResources() - { - Supplier indexReaderFactorySupplier = - () -> new IndexReaderFactory.Caching( indexingService ); - return () -> new StoreSchemaResources( indexReaderFactorySupplier, labelScanStore::newReader ); - } - - private GlobalCursorPools createCursorPool() - { - return new GlobalCursorPools( neoStores, takePropertyReadLocks ? this.lockService : - NO_LOCK_SERVICE ); - } - private IdController createStorageIdController( IdGeneratorFactory idGeneratorFactory, IdReuseEligibility eligibleForReuse, IdTypeConfigurationProvider idTypeConfigurationProvider, @@ -288,6 +277,15 @@ private IdController createStorageIdController( IdGeneratorFactory idGeneratorFa new DefaultIdController( idGeneratorFactory ); } + private Supplier storeStatementSupplier( NeoStores neoStores ) + { + Supplier indexReaderFactory = () -> new IndexReaderFactory.Caching( indexingService ); + LockService lockService = takePropertyReadLocks ? this.lockService : NO_LOCK_SERVICE; + + return () -> storageStatementFactory.create( neoStores, indexReaderFactory, labelScanStore::newReader, + lockService ); + } + @Override public StoreReadLayer storeReadLayer() { @@ -305,7 +303,7 @@ public CommandReaderFactory commandReaderFactory() public void createCommands( Collection commands, ReadableTransactionState txState, - SchemaResources schemaResources, + StorageStatement storageStatement, ResourceLocker locks, long lastTransactionIdWhenStarted ) throws TransactionFailureException, CreateConstraintFailureException, ConstraintValidationException @@ -325,8 +323,8 @@ public void createCommands( storeLayer, txState, txStateVisitor ); - txStateVisitor = - new TransactionCountingStateVisitor( txStateVisitor, storeLayer, txState, countsRecordState ); + txStateVisitor = new TransactionCountingStateVisitor( + txStateVisitor, storeLayer, storageStatement, txState, countsRecordState ); try ( TxStateVisitor visitor = txStateVisitor ) { txState.accept( visitor ); @@ -471,7 +469,6 @@ public void shutdown() throws Throwable { labelScanStore.shutdown(); indexingService.shutdown(); - cursorsPool.dispose(); neoStores.close(); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/StorageStatementFactory.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/StorageStatementFactory.java new file mode 100644 index 000000000000..682a624656ae --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/StorageStatementFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.storageengine.impl.recordstorage; + +import java.util.function.Supplier; + +import org.neo4j.kernel.impl.api.IndexReaderFactory; +import org.neo4j.kernel.impl.locking.LockService; +import org.neo4j.kernel.impl.store.NeoStores; +import org.neo4j.storageengine.api.StorageStatement; +import org.neo4j.storageengine.api.schema.LabelScanReader; + +@FunctionalInterface +public interface StorageStatementFactory +{ + StorageStatement create( NeoStores neoStores, Supplier indexReaderFactory, + Supplier labelScanReaderSupplier, LockService lockService ); +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/util/InstanceCache.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/InstanceCache.java new file mode 100644 index 000000000000..9c9cb2655ee8 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/util/InstanceCache.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.util; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.neo4j.function.Disposable; + +/** + * Caches single instances. This is meant to be used within a single thread, where + * the usage pattern is such that it is likely that at any given time only one T is needed, but at times + * more than one T is used. This cache will for the majority of cases cache that single instance. + * + * @param + */ +public abstract class InstanceCache implements Supplier, Consumer, AutoCloseable +{ + private T instance; + + @Override + public T get() + { + if ( instance == null ) + { + return create(); + } + + try + { + return instance; + } + finally + { + instance = null; + } + } + + protected abstract T create(); + + @Override + public void accept( T instance ) + { + if ( this.instance == null ) + { + this.instance = instance; + } + else + { + instance.dispose(); + } + } + + @Override + public void close() + { + if ( instance != null ) + { + instance.dispose(); + } + } + + public static void noCache( T instance ) + { + + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/internal/TransactionEventHandlers.java b/community/kernel/src/main/java/org/neo4j/kernel/internal/TransactionEventHandlers.java index c04bea8a273c..b821212c162b 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/internal/TransactionEventHandlers.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/internal/TransactionEventHandlers.java @@ -39,7 +39,7 @@ import org.neo4j.kernel.impl.core.RelationshipProxy.RelationshipActions; import org.neo4j.kernel.impl.coreapi.TxStateTransactionDataSnapshot; import org.neo4j.kernel.lifecycle.Lifecycle; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -108,7 +108,7 @@ private T unregisterHandler( Collection setOfHandlers, T handler ) @Override public TransactionHandlerState beforeCommit( ReadableTransactionState state, KernelTransaction transaction, - StoreReadLayer storeReadLayer ) + StoreReadLayer storeReadLayer, StorageStatement statement ) { if ( transactionEventHandlers.isEmpty() ) { @@ -117,7 +117,7 @@ public TransactionHandlerState beforeCommit( ReadableTransactionState state, Ker TransactionData txData = state == null ? EMPTY_DATA : new TxStateTransactionDataSnapshot( state, nodeActions, relationshipActions, - storeReadLayer, transaction ); + storeReadLayer, statement, transaction ); TransactionHandlerState handlerStates = new TransactionHandlerState( txData ); for ( TransactionEventHandler handler : this.transactionEventHandlers ) diff --git a/community/kernel/src/main/java/org/neo4j/storageengine/api/SchemaResources.java b/community/kernel/src/main/java/org/neo4j/storageengine/api/SchemaResources.java deleted file mode 100644 index 39ad207d447c..000000000000 --- a/community/kernel/src/main/java/org/neo4j/storageengine/api/SchemaResources.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2002-2017 "Neo Technology," - * Network Engine for Objects in Lund AB [http://neotechnology.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.storageengine.api; - -import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; -import org.neo4j.kernel.api.schema.index.IndexDescriptor; -import org.neo4j.storageengine.api.schema.IndexReader; -import org.neo4j.storageengine.api.schema.LabelScanReader; - -/** - * Interface for accessing schema resources. - */ -public interface SchemaResources extends AutoCloseable -{ - /** - * Closes this statement so that the resources can be freed, the instance can still be reused. - */ - @Override - void close(); - - /** - * @return {@link LabelScanReader} capable of reading nodes for specific label ids. - */ - LabelScanReader getLabelScanReader(); - - /** - * Returns an {@link IndexReader} for searching entity ids given property values. One reader is allocated - * and kept per index throughout the life of a statement, making the returned reader repeatable-read isolation. - *

- * NOTE: - * Reader returned from this method should not be closed. All such readers will be closed during {@link #close()} - * of the current statement. - * - * @param index {@link IndexDescriptor} to get reader for. - * @return {@link IndexReader} capable of searching entity ids given property values. - * @throws IndexNotFoundKernelException if no such index exists. - */ - IndexReader getIndexReader( IndexDescriptor index ) throws IndexNotFoundKernelException; - - /** - * Returns an {@link IndexReader} for searching entity ids given property values. A new reader is allocated - * every call to this method, which means that newly committed data since the last call to this method - * will be visible in the returned reader. - *

- * NOTE: - * It is caller's responsibility to close the returned reader. - * - * @param index {@link IndexDescriptor} to get reader for. - * @return {@link IndexReader} capable of searching entity ids given property values. - * @throws IndexNotFoundKernelException if no such index exists. - */ - IndexReader getFreshIndexReader( IndexDescriptor index ) throws IndexNotFoundKernelException; -} diff --git a/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageCommand.java b/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageCommand.java index 6ac7834f1eb7..e846327e472c 100644 --- a/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageCommand.java +++ b/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageCommand.java @@ -27,7 +27,7 @@ /** * A command representing one unit of change to a {@link StorageEngine}. Commands are created by - * {@link StorageEngine#createCommands(Collection, ReadableTransactionState, SchemaResources, ResourceLocker, long)} + * {@link StorageEngine#createCommands(Collection, ReadableTransactionState, StorageStatement, ResourceLocker, long)} * and once created can be serialized onto a {@link WritableChannel} and/or passed back to * {@link StorageEngine#apply(CommandsToApply, TransactionApplicationMode)} for application where the * changes represented by the command are actually applied onto storage. diff --git a/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageEngine.java b/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageEngine.java index 0addb4e0752b..09846d0d03a2 100644 --- a/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageEngine.java +++ b/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageEngine.java @@ -51,7 +51,7 @@ public interface StorageEngine * * @param target {@link Collection} to put {@link StorageCommand commands} into. * @param state {@link ReadableTransactionState} representing logical store changes to generate commands for. - * @param schemaResources {@link SchemaResources} to use for reading store state during creation of commands. + * @param storageStatement {@link StorageStatement} to use for reading store state during creation of commands. * @param locks {@link ResourceLocker} can grab additional locks. * This locks client still have the potential to acquire more locks at this point. * TODO we should try to get rid of this locking mechanism during creation of commands @@ -70,7 +70,7 @@ public interface StorageEngine void createCommands( Collection target, ReadableTransactionState state, - SchemaResources schemaResources, + StorageStatement storageStatement, ResourceLocker locks, long lastTransactionIdWhenStarted ) throws TransactionFailureException, CreateConstraintFailureException, ConstraintValidationException; diff --git a/community/kernel/src/main/java/org/neo4j/storageengine/api/CursorPools.java b/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageStatement.java similarity index 55% rename from community/kernel/src/main/java/org/neo4j/storageengine/api/CursorPools.java rename to community/kernel/src/main/java/org/neo4j/storageengine/api/StorageStatement.java index 149438a61dab..24c3d639ab7c 100644 --- a/community/kernel/src/main/java/org/neo4j/storageengine/api/CursorPools.java +++ b/community/kernel/src/main/java/org/neo4j/storageengine/api/StorageStatement.java @@ -20,15 +20,55 @@ package org.neo4j.storageengine.api; import org.neo4j.cursor.Cursor; -import org.neo4j.function.Disposable; +import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; +import org.neo4j.kernel.api.schema.index.IndexDescriptor; import org.neo4j.kernel.impl.api.store.NodeDegreeCounter; import org.neo4j.kernel.impl.locking.Lock; +import org.neo4j.storageengine.api.schema.IndexReader; +import org.neo4j.storageengine.api.schema.LabelScanReader; import org.neo4j.storageengine.api.txstate.NodeTransactionStateView; import org.neo4j.storageengine.api.txstate.PropertyContainerState; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; -public interface CursorPools extends Disposable +/** + * A statement for accessing data from a {@link StoreReadLayer}. Most data about the entities of a graph + * are accessed through this statement interface as opposed to through the {@link StoreReadLayer} directly. + * One of the main reasons is that the access methods returns objects, like {@link Cursor cursors} which + * are valuable to reuse over a reasonably large window to reduce garbage churn in general. + *

+ * A {@link StorageStatement} must be {@link #acquire() acquired} before use. After use the statement + * should be {@link #release() released}. After released the statement can be acquired again. + * Creating and closing {@link StorageStatement} and there's also benefits keeping these statements opened + * during a longer period of time, with the assumption that it's still one thread at a time using each. + * With that in mind these statements should not be opened and closed for each operation, perhaps not even + * for each transaction. + *

+ * All cursors provided by this statement are views over data in the store. They do not interact with transaction + * state. + */ +public interface StorageStatement extends AutoCloseable { + /** + * Acquires this statement so that it can be used, should later be {@link #release() released}. + * Since a {@link StorageStatement} can be reused after {@link #release() released}, this call should + * do initialization/clearing of state whereas data structures can be kept between uses. + */ + void acquire(); + + /** + * Releases this statement so that it can later be {@link #acquire() acquired} again. + */ + void release(); + + /** + * Closes this statement so that it can no longer be used nor {@link #acquire() acquired}. + */ + @Override + void close(); + + // FIXME: this is a temporary workaround until we have a way to cache cursors thread safely in the transaction + Cursor acquireNewNodeCursor( BatchingLongProgression progression, NodeTransactionStateView stateView ); + /** * Acquires {@link Cursor} capable of {@link Cursor#get() serving} {@link NodeItem} for selected nodes. * No node is selected when this method returns, a call to {@link Cursor#next()} will have to be made @@ -88,4 +128,37 @@ Cursor acquireSinglePropertyCursor( long propertyId, int propertyK Cursor acquireRelationshipGroupCursor( long relationshipGroupId ); NodeDegreeCounter acquireNodeDegreeCounter( long nodeId, long relationshipGroupId ); + + /** + * @return {@link LabelScanReader} capable of reading nodes for specific label ids. + */ + LabelScanReader getLabelScanReader(); + + /** + * Returns an {@link IndexReader} for searching entity ids given property values. One reader is allocated + * and kept per index throughout the life of a statement, making the returned reader repeatable-read isolation. + *

+ * NOTE: + * Reader returned from this method should not be closed. All such readers will be closed during {@link #close()} + * of the current statement. + * + * @param index {@link IndexDescriptor} to get reader for. + * @return {@link IndexReader} capable of searching entity ids given property values. + * @throws IndexNotFoundKernelException if no such index exists. + */ + IndexReader getIndexReader( IndexDescriptor index ) throws IndexNotFoundKernelException; + + /** + * Returns an {@link IndexReader} for searching entity ids given property values. A new reader is allocated + * every call to this method, which means that newly committed data since the last call to this method + * will be visible in the returned reader. + *

+ * NOTE: + * It is caller's responsibility to close the returned reader. + * + * @param index {@link IndexDescriptor} to get reader for. + * @return {@link IndexReader} capable of searching entity ids given property values. + * @throws IndexNotFoundKernelException if no such index exists. + */ + IndexReader getFreshIndexReader( IndexDescriptor index ) throws IndexNotFoundKernelException; } diff --git a/community/kernel/src/main/java/org/neo4j/storageengine/api/StoreReadLayer.java b/community/kernel/src/main/java/org/neo4j/storageengine/api/StoreReadLayer.java index f45f0c8ab791..29a0313dbf52 100644 --- a/community/kernel/src/main/java/org/neo4j/storageengine/api/StoreReadLayer.java +++ b/community/kernel/src/main/java/org/neo4j/storageengine/api/StoreReadLayer.java @@ -51,7 +51,10 @@ */ public interface StoreReadLayer { - SchemaResources schemaResources(); + /** + * @return new {@link StorageStatement}, which can be used after a call to {@link StorageStatement#acquire()}. + */ + StorageStatement newStatement(); /** * @param labelId label to list indexes for. @@ -127,7 +130,7 @@ long indexGetCommittedId( IndexDescriptor index ) */ Iterator constraintsGetAll(); - PrimitiveLongIterator nodesGetForLabel( SchemaResources statement, int labelId ); + PrimitiveLongIterator nodesGetForLabel( StorageStatement statement, int labelId ); /** * Looks for a stored index by given {@code descriptor} @@ -163,9 +166,10 @@ long indexGetCommittedId( IndexDescriptor index ) */ String indexGetFailure( LabelSchemaDescriptor descriptor ) throws IndexNotFoundKernelException; - IndexReader indexGetReader( SchemaResources schemaResources, IndexDescriptor index ) throws IndexNotFoundKernelException; + IndexReader indexGetReader( StorageStatement statement, IndexDescriptor index ) + throws IndexNotFoundKernelException; - IndexReader indexGetFreshReader( SchemaResources schemaResources, IndexDescriptor index ) + IndexReader indexGetFreshReader( StorageStatement storeStatement, IndexDescriptor index ) throws IndexNotFoundKernelException; /** @@ -262,33 +266,37 @@ IndexReader indexGetFreshReader( SchemaResources schemaResources, IndexDescripto */ RelationshipIterator relationshipsGetAll(); - BatchingLongProgression parallelNodeScanProgression(); - - Cursor nodeGetCursor( BatchingLongProgression progression, NodeTransactionStateView stateView ); - - Cursor nodeGetAllCursor( NodeTransactionStateView stateView ); + BatchingLongProgression parallelNodeScanProgression( StorageStatement statement ); - Cursor nodeGetSingleCursor( long nodeId, NodeTransactionStateView stateView ); + Cursor nodeGetCursor( StorageStatement statement, BatchingLongProgression progression, + NodeTransactionStateView stateView ); - Cursor relationshipGetSingleCursor( long relationshipId, ReadableTransactionState state ); + Cursor nodeGetAllCursor( StorageStatement storeStatement, NodeTransactionStateView stateView ); - Cursor relationshipsGetAllCursor( ReadableTransactionState state ); + Cursor nodeGetSingleCursor( StorageStatement storeStatement, long nodeId, NodeTransactionStateView stateView ); - Cursor nodeGetRelationships( NodeItem nodeItem, Direction direction, + Cursor relationshipCursor( StorageStatement storeStatement, long relationshipId, ReadableTransactionState state ); - Cursor nodeGetRelationships( NodeItem nodeItem, Direction direction, int[] relTypes, + Cursor relationshipsGetAllCursor( StorageStatement storeStatement, ReadableTransactionState state ); + + Cursor nodeGetRelationships( StorageStatement statement, NodeItem nodeItem, Direction direction, ReadableTransactionState state ); - Cursor nodeGetProperties( NodeItem node, PropertyContainerState state ); + Cursor nodeGetRelationships( StorageStatement statement, NodeItem nodeItem, Direction direction, + int[] relTypes, ReadableTransactionState state ); - Cursor nodeGetProperty( NodeItem node, int propertyKeyId, PropertyContainerState state ); + Cursor nodeGetProperties( StorageStatement statement, NodeItem node, PropertyContainerState state ); - Cursor relationshipGetProperties( RelationshipItem relationship, PropertyContainerState state ); + Cursor nodeGetProperty( StorageStatement statement, NodeItem node, int propertyKeyId, + PropertyContainerState state ); - Cursor relationshipGetProperty( RelationshipItem relationshipItem, int propertyKeyId, + Cursor relationshipGetProperties( StorageStatement statement, RelationshipItem relationship, PropertyContainerState state ); + Cursor relationshipGetProperty( StorageStatement statement, RelationshipItem relationshipItem, + int propertyKeyId, PropertyContainerState state ); + /** * Reserves a node id for future use to store a node. The reason for it being exposed here is that * internal ids of nodes and relationships are publicly accessible all the way out to the user. @@ -380,13 +388,14 @@ DoubleLongRegister indexSample( LabelSchemaDescriptor descriptor, DoubleLongRegi boolean nodeExists( long id ); - PrimitiveIntSet relationshipTypes( NodeItem node ); + PrimitiveIntSet relationshipTypes( StorageStatement statement, NodeItem node ); - void degrees( NodeItem nodeItem, DegreeVisitor visitor ); + void degrees( StorageStatement statement, NodeItem nodeItem, DegreeVisitor visitor ); - int countDegrees( NodeItem node, Direction direction, ReadableTransactionState state ); + int countDegrees( StorageStatement statement, NodeItem node, Direction direction, ReadableTransactionState state ); - int countDegrees( NodeItem node, Direction direction, int relType, ReadableTransactionState state ); + int countDegrees( StorageStatement statement, NodeItem node, Direction direction, int relType, + ReadableTransactionState state ); T getOrCreateSchemaDependantState( Class type, Function factory ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/api/KernelTransactionFactory.java b/community/kernel/src/test/java/org/neo4j/kernel/api/KernelTransactionFactory.java index a17e5e93a85c..ba7e31113dea 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/api/KernelTransactionFactory.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/api/KernelTransactionFactory.java @@ -40,7 +40,7 @@ import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.transaction.TransactionMonitor; import org.neo4j.storageengine.api.StorageEngine; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.time.Clocks; @@ -55,15 +55,15 @@ public static class Instances public KernelTransactionImplementation transaction; public StorageEngine storageEngine; public StoreReadLayer storeReadLayer; - public SchemaResources schemaResources; + public StorageStatement storageStatement; public Instances( KernelTransactionImplementation transaction, StorageEngine storageEngine, - StoreReadLayer storeReadLayer, SchemaResources schemaResources ) + StoreReadLayer storeReadLayer, StorageStatement storageStatement ) { this.transaction = transaction; this.storageEngine = storageEngine; this.storeReadLayer = storeReadLayer; - this.schemaResources = schemaResources; + this.storageStatement = storageStatement; } } @@ -79,8 +79,8 @@ static Instances kernelTransactionWithInternals( SecurityContext securityContext StorageEngine storageEngine = mock( StorageEngine.class ); StoreReadLayer storeReadLayer = mock( StoreReadLayer.class ); - SchemaResources schemaResources = mock( SchemaResources.class ); - when( storeReadLayer.schemaResources() ).thenReturn( schemaResources ); + StorageStatement storageStatement = mock( StorageStatement.class ); + when( storeReadLayer.newStatement() ).thenReturn( storageStatement ); when( storageEngine.storeReadLayer() ).thenReturn( storeReadLayer ); KernelTransactionImplementation transaction = new KernelTransactionImplementation( @@ -101,7 +101,7 @@ static Instances kernelTransactionWithInternals( SecurityContext securityContext transaction.initialize( 0, 0, statementLocks, KernelTransaction.Type.implicit, securityContext, 0L ); - return new Instances( transaction, storageEngine, storeReadLayer, schemaResources ); + return new Instances( transaction, storageEngine, storeReadLayer, storageStatement ); } static KernelTransaction kernelTransaction( SecurityContext securityContext ) diff --git a/community/kernel/src/test/java/org/neo4j/kernel/api/TransactionStatementSharingTest.java b/community/kernel/src/test/java/org/neo4j/kernel/api/TransactionStatementSharingTest.java index 2acd3c2672bb..14623913325b 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/api/TransactionStatementSharingTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/api/TransactionStatementSharingTest.java @@ -24,6 +24,8 @@ import org.neo4j.kernel.api.security.AnonymousContext; import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import static org.neo4j.kernel.api.KernelTransactionFactory.kernelTransaction; import static org.neo4j.kernel.api.security.SecurityContext.AUTH_DISABLED; @@ -126,4 +128,25 @@ public void shouldShareStatementStateForConcurrentSchemaStatementAndSchemaStatem // then assertSame( stmt1, stmt2 ); } + + @Test + public void shouldNotShareStateForSequentialReadStatementAndReadStatement() throws Exception + { + // given + KernelTransactionFactory.Instances instances = + KernelTransactionFactory.kernelTransactionWithInternals( AnonymousContext.read() ); + KernelTransaction tx = instances.transaction; + Statement statement = tx.acquireStatement(); + ReadOperations ops1 = statement.readOperations(); + verify( instances.storageStatement ).acquire(); + statement.close(); + + // when + verify( instances.storageStatement ).release(); + reset( instances.storageStatement ); + ReadOperations ops2 = tx.acquireStatement().readOperations(); + + // then + verify( instances.storageStatement ).acquire(); + } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelStatementTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelStatementTest.java index 6d0fd5f024c0..e13d109b6a24 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelStatementTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelStatementTest.java @@ -31,7 +31,7 @@ import org.neo4j.kernel.impl.factory.CanWrite; import org.neo4j.kernel.impl.locking.LockTracer; import org.neo4j.kernel.impl.proc.Procedures; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -48,7 +48,7 @@ public void shouldThrowTerminateExceptionWhenTransactionTerminated() throws Exce when( transaction.securityContext() ).thenReturn( AUTH_DISABLED ); KernelStatementImplementation statement = - new KernelStatementImplementation( transaction, null, mock( SchemaResources.class ), null, + new KernelStatementImplementation( transaction, null, mock( StorageStatement.class ), null, new CanWrite(), LockTracer.NONE ); statement.acquire(); @@ -59,9 +59,9 @@ public void shouldThrowTerminateExceptionWhenTransactionTerminated() throws Exce public void shouldReleaseStorageStatementWhenForceClosed() throws Exception { // given - SchemaResources schemaResources = mock( SchemaResources.class ); + StorageStatement storeStatement = mock( StorageStatement.class ); KernelStatementImplementation statement = - new KernelStatementImplementation( mock( KernelTransactionImplementation.class ), null, schemaResources, + new KernelStatementImplementation( mock( KernelTransactionImplementation.class ), null, storeStatement, new Procedures(), new CanWrite(), LockTracer.NONE ); statement.acquire(); @@ -69,7 +69,7 @@ public void shouldReleaseStorageStatementWhenForceClosed() throws Exception statement.forceClose(); // then - verify( schemaResources ).close(); + verify( storeStatement ).release(); } @Test( expected = NotInTransactionException.class ) @@ -77,7 +77,7 @@ public void assertStatementIsNotOpenWhileAcquireIsNotInvoked() { KernelTransactionImplementation transaction = mock( KernelTransactionImplementation.class ); TxStateHolder txStateHolder = mock( TxStateHolder.class ); - SchemaResources storeStatement = mock( SchemaResources.class ); + StorageStatement storeStatement = mock( StorageStatement.class ); AccessCapability accessCapability = mock( AccessCapability.class ); Procedures procedures = mock( Procedures.class ); KernelStatement statement = new KernelStatementImplementation( transaction, txStateHolder, diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionImplementationTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionImplementationTest.java index c970734595b0..3fbfcce55e8c 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionImplementationTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionImplementationTest.java @@ -46,7 +46,7 @@ import org.neo4j.kernel.impl.transaction.TransactionMonitor; import org.neo4j.kernel.impl.transaction.command.Command; import org.neo4j.storageengine.api.StorageCommand; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.lock.ResourceLocker; import org.neo4j.test.DoubleLatch; @@ -394,7 +394,7 @@ public void shouldUseStartTimeAndTxIdFromWhenStartingTxAsHeader() throws Excepti } ).when( storageEngine ).createCommands( any( Collection.class ), any( TransactionState.class ), - any( SchemaResources.class ), + any( StorageStatement.class ), any( ResourceLocker.class ), anyLong() ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionTestBase.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionTestBase.java index 47c41ecaa7cd..54ae36c993b9 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionTestBase.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionTestBase.java @@ -32,7 +32,7 @@ import org.neo4j.kernel.api.security.SecurityContext; import org.neo4j.kernel.api.txstate.LegacyIndexTransactionState; import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.impl.api.store.StoreSchemaResources; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.factory.CanWrite; import org.neo4j.kernel.impl.locking.LockTracer; import org.neo4j.kernel.impl.locking.Locks; @@ -49,7 +49,7 @@ import org.neo4j.kernel.impl.transaction.tracing.TransactionTracer; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.TransactionApplicationMode; import org.neo4j.storageengine.api.lock.ResourceLocker; @@ -91,12 +91,12 @@ public void before() throws Exception { when( headerInformation.getAdditionalHeader() ).thenReturn( new byte[0] ); when( headerInformationFactory.create() ).thenReturn( headerInformation ); - when( readLayer.schemaResources() ).thenReturn( mock( StoreSchemaResources.class ) ); + when( readLayer.newStatement() ).thenReturn( mock( StoreStatement.class ) ); when( neoStores.getMetaDataStore() ).thenReturn( metaDataStore ); when( storageEngine.storeReadLayer() ).thenReturn( readLayer ); doAnswer( invocation -> ((Collection) invocation.getArguments()[0]).add( null ) ) .when( storageEngine ).createCommands( anyCollectionOf( StorageCommand.class ), - any( ReadableTransactionState.class ), any( SchemaResources.class ), + any( ReadableTransactionState.class ), any( StorageStatement.class ), any( ResourceLocker.class ), anyLong() ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionsTest.java index 39a16d43166d..31a239af1048 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionsTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTransactionsTest.java @@ -64,7 +64,7 @@ import org.neo4j.logging.NullLog; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.TransactionApplicationMode; import org.neo4j.storageengine.api.lock.ResourceLocker; @@ -316,9 +316,9 @@ public void disposeAllMarksAllTransactionsForTermination() throws Throwable @Test public void transactionClosesUnderlyingStoreStatementWhenDisposed() throws Throwable { - SchemaResources storeStatement1 = mock( SchemaResources.class ); - SchemaResources storeStatement2 = mock( SchemaResources.class ); - SchemaResources storeStatement3 = mock( SchemaResources.class ); + StorageStatement storeStatement1 = mock( StorageStatement.class ); + StorageStatement storeStatement2 = mock( StorageStatement.class ); + StorageStatement storeStatement3 = mock( StorageStatement.class ); KernelTransactions kernelTransactions = newKernelTransactions( mock( TransactionCommitProcess.class ), storeStatement1, storeStatement2, storeStatement3 ); @@ -480,29 +480,29 @@ private static KernelTransactions newKernelTransactions() throws Throwable private static KernelTransactions newTestKernelTransactions() throws Throwable { - return newKernelTransactions( true, mock( TransactionCommitProcess.class ), mock( SchemaResources.class ) ); + return newKernelTransactions( true, mock( TransactionCommitProcess.class ), mock( StorageStatement.class ) ); } private static KernelTransactions newKernelTransactions( TransactionCommitProcess commitProcess ) throws Throwable { - return newKernelTransactions( false, commitProcess, mock( SchemaResources.class ) ); + return newKernelTransactions( false, commitProcess, mock( StorageStatement.class ) ); } private static KernelTransactions newKernelTransactions( TransactionCommitProcess commitProcess, - SchemaResources firstStoreStatements, SchemaResources... otherSchemaResources ) throws Throwable + StorageStatement firstStoreStatements, StorageStatement... otherStorageStatements ) throws Throwable { - return newKernelTransactions( false, commitProcess, firstStoreStatements, otherSchemaResources ); + return newKernelTransactions( false, commitProcess, firstStoreStatements, otherStorageStatements ); } private static KernelTransactions newKernelTransactions( boolean testKernelTransactions, - TransactionCommitProcess commitProcess, SchemaResources firstStoreStatements, - SchemaResources... otherSchemaResources ) throws Throwable + TransactionCommitProcess commitProcess, StorageStatement firstStoreStatements, + StorageStatement... otherStorageStatements ) throws Throwable { Locks locks = mock( Locks.class ); when( locks.newClient() ).thenReturn( mock( Locks.Client.class ) ); StoreReadLayer readLayer = mock( StoreReadLayer.class ); - when( readLayer.schemaResources() ).thenReturn( firstStoreStatements, otherSchemaResources ); + when( readLayer.newStatement() ).thenReturn( firstStoreStatements, otherStorageStatements ); StorageEngine storageEngine = mock( StorageEngine.class ); when( storageEngine.storeReadLayer() ).thenReturn( readLayer ); @@ -513,7 +513,7 @@ private static KernelTransactions newKernelTransactions( boolean testKernelTrans } ).when( storageEngine ).createCommands( anyCollection(), any( ReadableTransactionState.class ), - any( SchemaResources.class ), + any( StorageStatement.class ), any( ResourceLocker.class ), anyLong() ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java index aebe058f7458..f22b21bfe06d 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/LockingStatementOperationsTest.java @@ -57,7 +57,7 @@ import org.neo4j.kernel.impl.locking.SimpleStatementLocks; import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.storageengine.api.RelationshipItem; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import org.neo4j.storageengine.api.txstate.WritableTransactionState; @@ -91,7 +91,7 @@ public class LockingStatementOperationsTest private final TxState txState = new TxState(); private final KernelStatementImplementation state = new KernelStatementImplementation( transaction, new SimpleTxStateHolder( txState ), - mock( SchemaResources.class ), new Procedures(), new CanWrite(), LockTracer.NONE ); + mock( StorageStatement.class ), new Procedures(), new CanWrite(), LockTracer.NONE ); private final SchemaStateOperations schemaStateOps; private final LabelSchemaDescriptor descriptor = SchemaDescriptorFactory.forLabel( 123, 456 ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementLifecycleTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementLifecycleTest.java new file mode 100644 index 000000000000..a4ee8207d069 --- /dev/null +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementLifecycleTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.api; + +import org.junit.Test; + +import org.neo4j.kernel.impl.factory.CanWrite; +import org.neo4j.kernel.impl.locking.LockTracer; +import org.neo4j.kernel.impl.proc.Procedures; +import org.neo4j.storageengine.api.StorageStatement; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +public class StatementLifecycleTest +{ + @Test + public void shouldReleaseStoreStatementOnlyWhenReferenceCountDownToZero() throws Exception + { + // given + KernelTransactionImplementation transaction = mock( KernelTransactionImplementation.class ); + StorageStatement storageStatement = mock( StorageStatement.class ); + KernelStatementImplementation statement = getKernelStatement( transaction, storageStatement ); + statement.acquire(); + verify( storageStatement ).acquire(); + statement.acquire(); + + // when + statement.close(); + verifyNoMoreInteractions( storageStatement ); + + // then + statement.close(); + verify( storageStatement ).release(); + } + + @Test + public void shouldReleaseStoreStatementWhenForceClosingStatements() throws Exception + { + // given + KernelTransactionImplementation transaction = mock( KernelTransactionImplementation.class ); + StorageStatement storageStatement = mock( StorageStatement.class ); + KernelStatementImplementation statement = getKernelStatement( transaction, storageStatement ); + statement.acquire(); + + // when + statement.forceClose(); + + // then + verify( storageStatement ).release(); + } + + private KernelStatementImplementation getKernelStatement( KernelTransactionImplementation transaction, + StorageStatement storageStatement ) + { + return new KernelStatementImplementation( transaction, null, storageStatement, new Procedures(), new CanWrite(), + LockTracer.NONE ); + } +} diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementOperationsTestHelper.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementOperationsTestHelper.java index c68a81ea6c22..f0a64f7c490e 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementOperationsTestHelper.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/StatementOperationsTestHelper.java @@ -41,7 +41,7 @@ import org.neo4j.kernel.impl.api.operations.SchemaWriteOperations; import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.locking.SimpleStatementLocks; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -79,11 +79,10 @@ public static KernelStatement mockedState( final TransactionState txState ) try { IndexReader indexReader = mock( IndexReader.class ); - when( indexReader.query( Matchers.isA( IndexQuery.ExactPredicate.class ) ) ) - .thenReturn( PrimitiveLongCollections.emptyIterator() ); - SchemaResources schemaResources = mock( SchemaResources.class ); - when( schemaResources.getIndexReader( Matchers.any() ) ).thenReturn( indexReader ); - when( state.schemaResources() ).thenReturn( schemaResources ); + when( indexReader.query( Matchers.isA( IndexQuery.ExactPredicate.class ) ) ).thenReturn( PrimitiveLongCollections.emptyIterator() ); + StorageStatement storageStatement = mock( StorageStatement.class ); + when( storageStatement.getIndexReader( Matchers.any() ) ).thenReturn( indexReader ); + when( state.storageStatement() ).thenReturn( storageStatement ); } catch ( IndexNotFoundKernelException | IndexNotApplicableKernelException e ) { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/TransactionHookIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/TransactionHookIT.java index d99b2ee49ccf..49949eee4c76 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/TransactionHookIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/integrationtest/TransactionHookIT.java @@ -24,6 +24,7 @@ import org.neo4j.kernel.api.DataWriteOperations; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.TransactionHook; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -52,7 +53,7 @@ public void shouldRecieveTxStateOnCommit() throws Exception // Then verify( hook ).beforeCommit( any( ReadableTransactionState.class ), any( KernelTransaction.class ), - any( StoreReadLayer.class ) ); + any( StoreReadLayer.class ), any( StorageStatement.class ) ); verify( hook ).afterCommit( any( ReadableTransactionState.class ), any( KernelTransaction.class ), any( TransactionHook.Outcome.class ) ); verifyNoMoreInteractions( hook ); @@ -65,7 +66,7 @@ public void shouldRollbackOnFailureInBeforeCommit() throws Exception TransactionHook hook = mock( TransactionHook.class ); final String message = "Original"; when( hook.beforeCommit( any( ReadableTransactionState.class ), any( KernelTransaction.class ), - any( StoreReadLayer.class ) ) ).thenReturn( new TransactionHook.Outcome() + any( StoreReadLayer.class ), any( StorageStatement.class ) ) ).thenReturn( new TransactionHook.Outcome() { @Override public boolean isSuccessful() @@ -97,7 +98,7 @@ public Throwable failure() } // Then verify( hook ).beforeCommit( any( ReadableTransactionState.class ), any( KernelTransaction.class ), - any( StoreReadLayer.class ) ); + any( StoreReadLayer.class ), any( StorageStatement.class ) ); verify( hook ).afterRollback( any( ReadableTransactionState.class ), any( KernelTransaction.class ), any( TransactionHook.Outcome.class ) ); verifyNoMoreInteractions( hook ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java index 8bfc52edf790..0d6f319b8e41 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/IndexQueryTransactionStateTest.java @@ -43,7 +43,7 @@ import org.neo4j.kernel.impl.constraints.StandardConstraintSemantics; import org.neo4j.kernel.impl.index.LegacyIndexStore; import org.neo4j.storageengine.api.NodeItem; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.txstate.PropertyContainerState; @@ -95,9 +95,9 @@ public void before() throws Exception when( store.indexGetForSchema( indexDescriptor.schema() ) ).thenReturn( indexDescriptor ); indexReader = mock( IndexReader.class ); - when( store.indexGetReader( any( SchemaResources.class ), eq( indexDescriptor ) ) ) + when( store.indexGetReader( any( StorageStatement.class ), eq( indexDescriptor ) ) ) .thenReturn( indexReader ); - when( store.indexGetFreshReader( any( SchemaResources.class ), eq( indexDescriptor ) ) ) + when( store.indexGetFreshReader( any( StorageStatement.class ), eq( indexDescriptor ) ) ) .thenReturn( indexReader ); StateHandlingStatementOperations stateHandlingOperations = new StateHandlingStatementOperations( @@ -116,7 +116,7 @@ public void shouldExcludeRemovedNodesFromIndexQuery() throws Exception long nodeId = 2L; when( indexReader.query( withValue ) ).then( answerAsPrimitiveLongIteratorFrom( asList( 1L, nodeId, 3L ) ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId ) ); txContext.nodeDelete( state, nodeId ); @@ -135,7 +135,7 @@ public void shouldExcludeRemovedNodeFromUniqueIndexQuery() throws Exception long nodeId = 1L; when( indexReader.query( withValue ) ).thenReturn( asPrimitiveResourceIterator( nodeId ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId ) ); txContext.nodeDelete( state, nodeId ); @@ -185,7 +185,7 @@ public void shouldIncludeCreatedNodesWithCorrectLabelAndProperty() throws Except long nodeId = 1L; state.writableTxState().nodeDoAddProperty( nodeId, stringProperty( propertyKeyId, value ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40L ) ); mockStoreProperty(); @@ -208,7 +208,7 @@ public void shouldIncludeUniqueCreatedNodeWithCorrectLabelAndProperty() throws E long nodeId = 1L; state.writableTxState().nodeDoAddProperty( nodeId, stringProperty( propertyKeyId, value ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40L ) ); mockStoreProperty(); @@ -230,7 +230,7 @@ public void shouldIncludeExistingNodesWithCorrectPropertyAfterAddingLabel() thro long nodeId = 1L; - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40L ) ); mockStoreProperty(); @@ -252,7 +252,7 @@ public void shouldIncludeExistingUniqueNodeWithCorrectPropertyAfterAddingLabel() long nodeId = 2L; - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40L ) ); mockStoreProperty(); @@ -273,7 +273,7 @@ public void shouldExcludeExistingNodesWithCorrectPropertyAfterRemovingLabel() th long nodeId = 1L; when( indexReader.query( withValue ) ).then( answerAsPrimitiveLongIteratorFrom( asList( nodeId, 2L, 3L ) ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40L, labels( labelId ) ) ); mockStoreProperty(); @@ -293,7 +293,7 @@ public void shouldExcludeExistingUniqueNodeWithCorrectPropertyAfterRemovingLabel long nodeId = 1L; when( indexReader.query( withValue ) ).thenReturn( asPrimitiveResourceIterator( nodeId ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40L, labels( labelId ) ) ); mockStoreProperty(); @@ -315,7 +315,7 @@ public void shouldExcludeNodesWithRemovedProperty() throws Exception long nodeId = 1L; state.writableTxState().nodeDoAddProperty( nodeId, intProperty( propertyKeyId, 10 ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, labels( labelId ) ) ); txContext.nodeAddLabel( state, nodeId, labelId ); @@ -334,7 +334,7 @@ public void shouldExcludeUniqueNodeWithRemovedProperty() throws Exception long nodeId = 1L; when( indexReader.query( withValue ) ).thenReturn( asPrimitiveResourceIterator( nodeId ) ); - when( store.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeId, 40, labels( labelId ) ) ); mockStoreProperty(); @@ -349,9 +349,11 @@ public void shouldExcludeUniqueNodeWithRemovedProperty() throws Exception private void mockStoreProperty() { - when( store.nodeGetProperties( any( NodeItem.class ), any( PropertyContainerState.class ) ) ) + when( store.nodeGetProperties( any( StorageStatement.class ), any( NodeItem.class ), + any( PropertyContainerState.class ) ) ) .thenReturn( asPropertyCursor( stringProperty( propertyKeyId, value ) ) ); - when( store.nodeGetProperty( any( NodeItem.class ), eq( propertyKeyId ), any( PropertyContainerState.class ) ) ) + when( store.nodeGetProperty( any( StorageStatement.class ), any( NodeItem.class ), eq( propertyKeyId ), + any( PropertyContainerState.class ) ) ) .thenReturn( asPropertyCursor( stringProperty( propertyKeyId, value ) ) ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/LabelTransactionStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/LabelTransactionStateTest.java index 04e2af368a85..df0a8e512e01 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/LabelTransactionStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/LabelTransactionStateTest.java @@ -40,7 +40,7 @@ import org.neo4j.kernel.impl.api.legacyindex.InternalAutoIndexing; import org.neo4j.kernel.impl.index.LegacyIndexStore; import org.neo4j.storageengine.api.NodeItem; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.PropertyContainerState; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -243,10 +243,10 @@ public void removingNonExistentLabelFromNodeShouldRespondFalse() throws Exceptio public void should_return_true_when_adding_new_label() throws Exception { // GIVEN - when( store.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( 1337L ) ); - when( store.nodeGetProperties( any( NodeItem.class ), any( PropertyContainerState.class ) ) ) - .thenReturn( asPropertyCursor() ); + when( store.nodeGetProperties( any( StorageStatement.class ), any( NodeItem.class ), + any( PropertyContainerState.class ) ) ).thenReturn( asPropertyCursor() ); // WHEN boolean added = txContext.nodeAddLabel( state, 1337L, 12 ); @@ -259,10 +259,10 @@ public void should_return_true_when_adding_new_label() throws Exception public void should_return_false_when_adding_existing_label() throws Exception { // GIVEN - when( store.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( 1337L, StubCursors.labels( 12 ) ) ); - when( store.nodeGetProperties( any( NodeItem.class ), any( PropertyContainerState.class ) ) ) - .thenReturn( asPropertyCursor() ); + when( store.nodeGetProperties( any( StorageStatement.class ), any( NodeItem.class ), + any( PropertyContainerState.class ) ) ).thenReturn( asPropertyCursor() ); // WHEN boolean added = txContext.nodeAddLabel( state, 1337L, 12 ); @@ -275,10 +275,10 @@ public void should_return_false_when_adding_existing_label() throws Exception public void should_return_true_when_removing_existing_label() throws Exception { // GIVEN - when( store.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( 1337L, StubCursors.labels( 12 ) ) ); - when( store.nodeGetProperties( any( NodeItem.class ), any( PropertyContainerState.class ) ) ) - .thenReturn( asPropertyCursor() ); + when( store.nodeGetProperties( any( StorageStatement.class ), any( NodeItem.class ), + any( PropertyContainerState.class ) ) ).thenReturn( asPropertyCursor() ); // WHEN boolean added = txContext.nodeRemoveLabel( state, 1337L, 12 ); @@ -291,7 +291,7 @@ public void should_return_true_when_removing_existing_label() throws Exception public void should_return_true_when_removing_non_existant_label() throws Exception { // GIVEN - when( store.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( 1337L ) ); // WHEN @@ -334,10 +334,11 @@ private void commitLabels( Labels... labels ) throws Exception Map> allLabels = new HashMap<>(); for ( Labels nodeLabels : labels ) { - when( store.nodeGetSingleCursor( eq( nodeLabels.nodeId ), any( ReadableTransactionState.class ) ) ) + when( store.nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeLabels.nodeId ), + any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( nodeLabels.nodeId, StubCursors.labels( nodeLabels.labelIds ) ) ); - when( store.nodeGetProperties( any( NodeItem.class ), any( PropertyContainerState.class ) ) ) - .thenReturn( asPropertyCursor() ); + when( store.nodeGetProperties( any( StorageStatement.class ), any( NodeItem.class ), + any( PropertyContainerState.class ) ) ).thenReturn( asPropertyCursor() ); for ( int label : nodeLabels.labelIds ) { @@ -348,7 +349,7 @@ private void commitLabels( Labels... labels ) throws Exception for ( Map.Entry> entry : allLabels.entrySet() ) { - when( store.nodesGetForLabel( state.schemaResources(), entry.getKey() ) ) + when( store.nodesGetForLabel( state.storageStatement(), entry.getKey() ) ) .then( answerAsPrimitiveLongIteratorFrom( entry.getValue() ) ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/SchemaTransactionStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/SchemaTransactionStateTest.java index 18fd1ff3ee31..e845c25c04a7 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/SchemaTransactionStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/SchemaTransactionStateTest.java @@ -39,7 +39,8 @@ import org.neo4j.kernel.impl.api.StateHandlingStatementOperations; import org.neo4j.kernel.impl.api.StatementOperationsTestHelper; import org.neo4j.kernel.impl.api.legacyindex.InternalAutoIndexing; -import org.neo4j.kernel.impl.api.store.StoreSchemaResources; +import org.neo4j.kernel.impl.api.store.SingleNodeFetch; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.index.LegacyIndexStore; import org.neo4j.storageengine.api.StoreReadLayer; @@ -233,7 +234,7 @@ public void shouldNotReturnExistentRuleDroppedInTransaction() throws Exception private TransactionState txState; private StateHandlingStatementOperations txContext; private KernelStatement state; - private StoreSchemaResources storeSchemaResources; + private StoreStatement storeStatement; @Before public void before() throws Exception @@ -249,8 +250,8 @@ public void before() throws Exception txContext = new StateHandlingStatementOperations( store, mock( InternalAutoIndexing.class ), mock( ConstraintIndexCreator.class ), mock( LegacyIndexStore.class ) ); - storeSchemaResources = mock( StoreSchemaResources.class ); - when( state.schemaResources() ).thenReturn( storeSchemaResources ); + storeStatement = mock( StoreStatement.class ); + when( state.storageStatement() ).thenReturn( storeStatement ); } private static class Labels @@ -275,7 +276,7 @@ private void commitLabels( Labels... labels ) throws Exception Map> allLabels = new HashMap<>(); for ( Labels nodeLabels : labels ) { - when( store.nodeGetSingleCursor( nodeLabels.nodeId, EMPTY ) ) + when( storeStatement.acquireNodeCursor( new SingleNodeFetch( nodeLabels.nodeId ), EMPTY ) ) .thenReturn( asNodeCursor( nodeLabels.nodeId, StubCursors.labels( nodeLabels.labelIds ) ) ); for ( int label : nodeLabels.labelIds ) @@ -288,7 +289,7 @@ private void commitLabels( Labels... labels ) throws Exception for ( Map.Entry> entry : allLabels.entrySet() ) { - when( store.nodesGetForLabel( state.schemaResources(), entry.getKey() ) ) + when( store.nodesGetForLabel( state.storageStatement(), entry.getKey() ) ) .then( invocation -> entry.getValue().iterator() ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java index 79624ad2aae1..8c707d9569b8 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateHandlingStatementOperationsTest.java @@ -47,13 +47,13 @@ import org.neo4j.kernel.impl.api.KernelStatement; import org.neo4j.kernel.impl.api.StateHandlingStatementOperations; import org.neo4j.kernel.impl.api.legacyindex.InternalAutoIndexing; -import org.neo4j.kernel.impl.api.store.StoreSchemaResources; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.index.LegacyIndexStore; import org.neo4j.kernel.impl.util.diffsets.DiffSets; import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.PropertyItem; import org.neo4j.storageengine.api.RelationshipItem; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.txstate.PropertyContainerState; @@ -95,11 +95,12 @@ public class StateHandlingStatementOperationsTest public void shouldNeverDelegateWrites() throws Exception { KernelStatement state = mockedState( new TxState() ); + when( inner.indexesGetForLabel( 0 ) ).thenReturn( iterator( IndexDescriptorFactory.forLabel( 0, 0 ) ) ); - when( inner.nodeGetSingleCursor( anyLong(), any( ReadableTransactionState.class ) ) ) + when( inner.nodeGetSingleCursor( any( StorageStatement.class ), anyLong(), any( ReadableTransactionState.class ) ) ) .thenReturn( asNodeCursor( 0 ) ); - when( inner.nodeGetProperties( any( NodeItem.class ), any( PropertyContainerState.class ) ) ) - .thenReturn( asPropertyCursor() ); + when( inner.nodeGetProperties( any( StorageStatement.class ), any( NodeItem.class ), + any( PropertyContainerState.class ) ) ).thenReturn( asPropertyCursor() ); StateHandlingStatementOperations ctx = newTxStateOps( inner ); @@ -111,7 +112,8 @@ public void shouldNeverDelegateWrites() throws Exception ctx.nodeRemoveLabel( state, 0, 0 ); // one for add and one for remove - verify( inner, times( 2 ) ).nodeGetSingleCursor( eq( 0L ), any( ReadableTransactionState.class ) ); + verify( inner, times( 2 ) ) + .nodeGetSingleCursor( any( StorageStatement.class ), eq( 0L ), any( ReadableTransactionState.class ) ); } @Test @@ -415,12 +417,13 @@ public void shouldConsiderTransactionStateDuringIndexBetweenRangeSeekByNumberWit IndexQuery.range( index.schema().getPropertyId(), lower, true, upper, false ); when( indexReader.query( indexQuery ) ).thenReturn( PrimitiveLongCollections.resourceIterator( PrimitiveLongCollections.iterator( 43L, 44L, 46L ), null ) ); - when( storeReadLayer.nodeGetSingleCursor( anyLong(), any( ReadableTransactionState.class ) ) ).thenAnswer( i -> + when( storeReadLayer.nodeGetSingleCursor( any( StorageStatement.class ), anyLong(), + any( ReadableTransactionState.class ) ) ).thenAnswer( invocationOnMock -> { - long nodeId = (long) i.getArguments()[0]; + long nodeId = (long) invocationOnMock.getArguments()[1]; when( storeReadLayer - .nodeGetProperty( any( NodeItem.class ), eq( propertyKey ), any( PropertyContainerState.class ) ) ) - .thenReturn( asPropertyCursor( intProperty( propertyKey, inRange ) ) ); + .nodeGetProperty( any( StorageStatement.class ), any( NodeItem.class ), eq( propertyKey ), + eq( null ) ) ).thenReturn( asPropertyCursor( intProperty( propertyKey, inRange ) ) ); return asNodeCursor( nodeId, nodeId + 20000 ); } ); @@ -473,7 +476,7 @@ public void indexQueryClosesIndexReader() throws Exception IndexReader indexReader = mock( IndexReader.class ); when( indexReader.query( any() ) ).thenReturn( PrimitiveLongCollections.emptyIterator() ); StoreReadLayer storeReadLayer = mock( StoreReadLayer.class ); - when( storeReadLayer.indexGetFreshReader( any( SchemaResources.class ), any( IndexDescriptor.class ) ) ) + when( storeReadLayer.indexGetFreshReader( any( StorageStatement.class ), any( IndexDescriptor.class ) ) ) .thenReturn( indexReader ); StateHandlingStatementOperations operations = newTxStateOps( storeReadLayer ); @@ -497,16 +500,16 @@ public void shouldNotRecordNodeSetPropertyOnSameValue() throws Exception StoreReadLayer storeReadLayer = mock( StoreReadLayer.class ); when( kernelStatement.readableTxState() ).thenReturn( ReadableTransactionState.EMPTY ); Cursor ourNode = nodeCursorWithProperty( propertyKeyId ); - when( storeReadLayer.nodeGetSingleCursor( eq( nodeId ), any( ReadableTransactionState.class ) ) ) + when( storeReadLayer + .nodeGetSingleCursor( any( StorageStatement.class ), eq( nodeId ), any( ReadableTransactionState.class ) ) ) .thenReturn( ourNode ); InternalAutoIndexing autoIndexing = mock( InternalAutoIndexing.class ); AutoIndexOperations autoIndexOps = mock( AutoIndexOperations.class ); when( autoIndexing.nodes() ).thenReturn( autoIndexOps ); when( autoIndexing.relationships() ).thenReturn( AutoIndexOperations.UNSUPPORTED ); Cursor propertyItemCursor = propertyCursor( propertyKeyId, value ); - when( storeReadLayer - .nodeGetProperty( any( NodeItem.class ), eq( propertyKeyId ), any( PropertyContainerState.class ) ) ) - .thenReturn( propertyItemCursor ); + when( storeReadLayer.nodeGetProperty( any( StorageStatement.class ), any( NodeItem.class ), eq( propertyKeyId ), + any( PropertyContainerState.class ) ) ).thenReturn( propertyItemCursor ); StateHandlingStatementOperations operations = newTxStateOps( storeReadLayer, autoIndexing ); // WHEN @@ -532,16 +535,15 @@ public void shouldNotRecordRelationshipSetPropertyOnSameValue() throws Exception when( kernelStatement.writableTxState() ).thenReturn( writableTransactionState ); StoreReadLayer storeReadLayer = mock( StoreReadLayer.class ); Cursor ourRelationship = relationshipCursorWithProperty( propertyKeyId ); - when( storeReadLayer - .relationshipGetSingleCursor( eq( relationshipId ), any( ReadableTransactionState.class ) ) ) - .thenReturn( ourRelationship ); + when( storeReadLayer.relationshipCursor( any( StorageStatement.class ), eq( relationshipId ), + any( ReadableTransactionState.class ) ) ).thenReturn( ourRelationship ); InternalAutoIndexing autoIndexing = mock( InternalAutoIndexing.class ); AutoIndexOperations autoIndexOps = mock( AutoIndexOperations.class ); when( autoIndexing.nodes() ).thenReturn( AutoIndexOperations.UNSUPPORTED ); when( autoIndexing.relationships() ).thenReturn( autoIndexOps ); Cursor propertyItemCursor = propertyCursor( propertyKeyId, value ); - when( storeReadLayer.relationshipGetProperty( any( RelationshipItem.class ), eq( propertyKeyId ), - any( PropertyContainerState.class ) ) ).thenReturn( propertyItemCursor ); + when( storeReadLayer.relationshipGetProperty( any( StorageStatement.class ), any( RelationshipItem.class ), + eq( propertyKeyId ), any( PropertyContainerState.class ) ) ).thenReturn( propertyItemCursor ); StateHandlingStatementOperations operations = newTxStateOps( storeReadLayer, autoIndexing ); // WHEN @@ -565,8 +567,8 @@ public void shouldNotRecordGraphSetPropertyOnSameValue() throws Exception when( kernelStatement.readableTxState() ).thenReturn( ReadableTransactionState.EMPTY ); WritableTransactionState writableTransactionState = mock( WritableTransactionState.class ); when( kernelStatement.writableTxState() ).thenReturn( writableTransactionState ); - StoreSchemaResources storeSchemaResources = mock( StoreSchemaResources.class ); - when( kernelStatement.schemaResources() ).thenReturn( storeSchemaResources ); + StoreStatement storeStatement = mock( StoreStatement.class ); + when( kernelStatement.storageStatement() ).thenReturn( storeStatement ); when( inner.graphGetAllProperties() ).thenReturn( iterator( Property.stringProperty( propertyKeyId, value ) ) ); StateHandlingStatementOperations operations = newTxStateOps( inner ); @@ -616,7 +618,7 @@ private IndexReader addMockedIndexReader( StoreReadLayer storeReadLayer ) throws IndexNotFoundKernelException { IndexReader indexReader = mock( IndexReader.class ); - when( storeReadLayer.indexGetReader( any( SchemaResources.class ), any( IndexDescriptor.class ) ) ) + when( storeReadLayer.indexGetReader( any( StorageStatement.class ), any( IndexDescriptor.class ) ) ) .thenReturn( indexReader ); return indexReader; } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateOperationsAutoIndexingTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateOperationsAutoIndexingTest.java index 3a2a256f6a27..5fd2f4bc3195 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateOperationsAutoIndexingTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/StateOperationsAutoIndexingTest.java @@ -36,6 +36,7 @@ import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.PropertyItem; import org.neo4j.storageengine.api.RelationshipItem; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.PropertyContainerState; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; @@ -74,7 +75,8 @@ public void setup() throws InvalidTransactionTypeKernelException public void shouldSignalNodeRemovedToAutoIndex() throws Exception { // Given - when( storeLayer.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( storeLayer + .nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( cursor( mock( NodeItem.class ) ) ); // When @@ -88,8 +90,8 @@ public void shouldSignalNodeRemovedToAutoIndex() throws Exception public void shouldSignalRelationshipRemovedToAutoIndex() throws Exception { // Given - when( storeLayer.relationshipGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) - .thenReturn( cursor( mock( RelationshipItem.class ) ) ); + when( storeLayer.relationshipCursor( any( StorageStatement.class ), eq( 1337L ), + any( ReadableTransactionState.class ) ) ).thenReturn( cursor( mock( RelationshipItem.class ) ) ); // When context.relationshipDelete( stmt, 1337 ); @@ -106,10 +108,12 @@ public void shouldSignalNodePropertyAddedToAutoIndex() throws Exception NodeItem node = mock( NodeItem.class ); when( node.labels() ).thenReturn( PrimitiveIntCollections.emptySet() ); - when( storeLayer.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( storeLayer + .nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( cursor( node ) ); - when( storeLayer.nodeGetProperty( any( NodeItem.class ), eq( property.propertyKeyId() ), - any( PropertyContainerState.class ) ) ).thenReturn( cursor() ); + when( storeLayer + .nodeGetProperty( any( StorageStatement.class ), any( NodeItem.class ), eq( property.propertyKeyId() ), + any( PropertyContainerState.class ) ) ).thenReturn( cursor() ); // When context.nodeSetProperty( stmt, 1337L, property ); @@ -126,10 +130,11 @@ public void shouldSignalRelationshipPropertyAddedToAutoIndex() throws Exception DefinedProperty property = property( propertyKeyId, "Hello!" ); RelationshipItem relationship = mock( RelationshipItem.class ); - when( storeLayer.relationshipGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( storeLayer.relationshipCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( cursor( relationship ) ); - when( storeLayer.relationshipGetProperty( eq( relationship ), eq( propertyKeyId ), - any( PropertyContainerState.class ) ) ).thenReturn( empty() ); + when( storeLayer + .relationshipGetProperty( any( StorageStatement.class ), eq( relationship ), eq( propertyKeyId ), + any( PropertyContainerState.class ) ) ).thenReturn( empty() ); // When context.relationshipSetProperty( stmt, 1337, property ); @@ -150,10 +155,12 @@ public void shouldSignalNodePropertyChangedToAutoIndex() throws Exception NodeItem node = mock( NodeItem.class ); when( node.labels() ).thenReturn( PrimitiveIntCollections.emptySet() ); - when( storeLayer.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( storeLayer + .nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( cursor( node ) ); - when( storeLayer.nodeGetProperty( any( NodeItem.class ), eq( property.propertyKeyId() ), - any( PropertyContainerState.class ) ) ).thenReturn( cursor( existingProperty ) ); + when( storeLayer + .nodeGetProperty( any( StorageStatement.class ), any( NodeItem.class ), eq( property.propertyKeyId() ), + any( PropertyContainerState.class ) ) ).thenReturn( cursor( existingProperty ) ); // When context.nodeSetProperty( stmt, 1337L, property ); @@ -174,10 +181,11 @@ public void shouldSignalRelationshipPropertyChangedToAutoIndex() throws Exceptio when(existingProperty.value()).thenReturn( "Goodbye!" ); RelationshipItem relationship = mock( RelationshipItem.class ); - when( storeLayer.relationshipGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) - .thenReturn( cursor( relationship ) ); - when( storeLayer.relationshipGetProperty( eq( relationship ), eq( propertyKeyId ), - any( PropertyContainerState.class ) ) ).thenReturn( cursor( existingProperty ) ); + when( storeLayer.relationshipCursor( any( StorageStatement.class ), eq( 1337L ), + any( ReadableTransactionState.class ) ) ).thenReturn( cursor( relationship ) ); + when( storeLayer + .relationshipGetProperty( any( StorageStatement.class ), eq( relationship ), eq( propertyKeyId ), + any( PropertyContainerState.class ) ) ).thenReturn( cursor( existingProperty ) ); // When context.relationshipSetProperty( stmt, 1337, property ); @@ -196,11 +204,12 @@ public void shouldSignalNodePropertyRemovedToAutoIndex() throws Exception int propertyKeyId = existingProperty.propertyKeyId(); NodeItem node = mock( NodeItem.class ); - when( storeLayer - .nodeGetProperty( any( NodeItem.class ), eq( propertyKeyId ), any( PropertyContainerState.class ) ) ) + when( storeLayer.nodeGetProperty( any( StorageStatement.class ), any( NodeItem.class ), eq( propertyKeyId ), + any( PropertyContainerState.class ) ) ) .thenReturn( cursor( existingProperty ) ); when( node.labels() ).thenReturn( PrimitiveIntCollections.emptySet() ); - when( storeLayer.nodeGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) + when( storeLayer + .nodeGetSingleCursor( any( StorageStatement.class ), eq( 1337L ), any( ReadableTransactionState.class ) ) ) .thenReturn( cursor( node ) ); // When @@ -221,10 +230,11 @@ public void shouldSignalRelationshipPropertyRemovedToAutoIndex() throws Exceptio when(existingProperty.value()).thenReturn( "Goodbye!" ); RelationshipItem relationship = mock( RelationshipItem.class ); - when( storeLayer.relationshipGetSingleCursor( eq( 1337L ), any( ReadableTransactionState.class ) ) ) - .thenReturn( cursor( relationship ) ); - when( storeLayer.relationshipGetProperty( eq( relationship ), eq( propertyKeyId ), - any( PropertyContainerState.class ) ) ).thenReturn( cursor( existingProperty ) ); + when( storeLayer.relationshipCursor( any( StorageStatement.class ), eq( 1337L ), + any( ReadableTransactionState.class ) ) ).thenReturn( cursor( relationship ) ); + when( storeLayer + .relationshipGetProperty( any( StorageStatement.class ), eq( relationship ), eq( propertyKeyId ), + any( PropertyContainerState.class ) ) ).thenReturn( cursor( existingProperty ) ); // When context.relationshipRemoveProperty( stmt, 1337, existingProperty.propertyKeyId() ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerLabelTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerLabelTest.java index 1d68927acd2d..3317fa1ef3a0 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerLabelTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerLabelTest.java @@ -21,6 +21,7 @@ import org.junit.Test; +import org.neo4j.collection.primitive.PrimitiveIntCollections; import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.graphdb.Node; @@ -28,7 +29,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.neo4j.collection.primitive.PrimitiveIntCollections.asSet; import static org.neo4j.helpers.collection.Iterators.asSet; import static org.neo4j.helpers.collection.MapUtil.map; import static org.neo4j.storageengine.api.txstate.ReadableTransactionState.EMPTY; @@ -58,8 +58,8 @@ public void should_be_able_to_list_labels_for_node() throws Exception } // THEN - disk.nodeGetSingleCursor( nodeId, EMPTY ) - .forAll( node -> assertEquals( asSet( new int[]{labelId1, labelId2} ), node.labels() ) ); + disk.newStatement().acquireNodeCursor( new SingleNodeFetch( nodeId ), EMPTY ).forAll( + node -> assertEquals( PrimitiveIntCollections.asSet( new int[]{labelId1, labelId2} ), node.labels() ) ); } @Test @@ -96,8 +96,8 @@ public void should_return_all_nodes_with_label() throws Exception int labelId2 = disk.labelGetForName( label2.name() ); // WHEN - PrimitiveLongIterator nodesForLabel1 = disk.nodesGetForLabel( state.schemaResources(), labelId1 ); - PrimitiveLongIterator nodesForLabel2 = disk.nodesGetForLabel( state.schemaResources(), labelId2 ); + PrimitiveLongIterator nodesForLabel1 = disk.nodesGetForLabel( state.storageStatement(), labelId1 ); + PrimitiveLongIterator nodesForLabel2 = disk.nodesGetForLabel( state.storageStatement(), labelId2 ); // THEN assertEquals( asSet( node1.getId(), node2.getId() ), PrimitiveLongCollections.toSet( nodesForLabel1 ) ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerNodeAndRelTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerNodeAndRelTest.java index 11aeaeee43cd..509ea756fce2 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerNodeAndRelTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerNodeAndRelTest.java @@ -25,6 +25,7 @@ import org.neo4j.graphdb.Transaction; import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.RelationshipItem; +import org.neo4j.storageengine.api.StorageStatement; import static junit.framework.Assert.assertFalse; import static junit.framework.TestCase.assertTrue; @@ -89,17 +90,23 @@ public void shouldTellIfRelExists() throws Exception private boolean nodeExists( long id ) { - try ( Cursor node = disk.nodeGetSingleCursor( id, EMPTY ) ) + try ( StorageStatement statement = disk.newStatement() ) { - return node.next(); + try ( Cursor node = statement.acquireNodeCursor( new SingleNodeFetch( id ), EMPTY ) ) + { + return node.next(); + } } } private boolean relationshipExists( long id ) { - try ( Cursor relationship = disk.relationshipGetSingleCursor( id, EMPTY ) ) + try ( StorageStatement statement = disk.newStatement() ) { - return relationship.next(); + try ( Cursor relationship = statement.acquireSingleRelationshipCursor( id, EMPTY ) ) + { + return relationship.next(); + } } } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerPropertyTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerPropertyTest.java index c661ce845f52..5ea222797729 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerPropertyTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerPropertyTest.java @@ -26,8 +26,10 @@ import org.neo4j.cursor.Cursor; import org.neo4j.kernel.api.properties.Property; import org.neo4j.kernel.impl.api.operations.KeyReadOperations; +import org.neo4j.kernel.impl.locking.Lock; import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.PropertyItem; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.txstate.NodeState; import static java.util.Collections.singletonMap; @@ -89,16 +91,21 @@ public void should_get_all_node_properties() throws Exception int propKey = disk.propertyKeyGetOrCreateForName( "prop" ); + StorageStatement statement = state.storageStatement(); for ( Object value : properties ) { // given long nodeId = createLabeledNode( db, singletonMap( "prop", value ), label1 ).getId(); // when - try ( Cursor node = disk.nodeGetSingleCursor( nodeId, EMPTY ) ) + try ( Cursor node = statement.acquireNodeCursor( new SingleNodeFetch( nodeId ), EMPTY ) ) { node.next(); - try ( Cursor props = disk.nodeGetProperty( node.get(), propKey, NodeState.EMPTY ) ) + + Lock lock = node.get().lock(); + try ( Cursor props = statement + .acquireSinglePropertyCursor( node.get().nextPropertyId(), propKey, lock, + NodeState.EMPTY ) ) { if ( props.next() ) { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerRelTypesAndDegreeTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerRelTypesAndDegreeTest.java index c83266c7a7c7..05b63c7f3efb 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerRelTypesAndDegreeTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerRelTypesAndDegreeTest.java @@ -241,12 +241,12 @@ private void testDegreeByDirectionForDenseNodeWithPartiallyDeletedRelChains( boo private int degreeForDirection( NodeCursor node, Direction direction ) { - return disk.countDegrees( node, direction, EMPTY ); + return disk.countDegrees( disk.newStatement(), node, direction, null ); } private int degreeForDirectionAndType( NodeCursor node, Direction direction, int relType ) { - return disk.countDegrees( node, direction, relType, EMPTY ); + return disk.countDegrees( disk.newStatement(), node, direction, relType, null ); } private void testDegreeByDirectionAndTypeForDenseNodeWithPartiallyDeletedRelGroupChain( @@ -375,7 +375,7 @@ private void testRelationshipTypesForDenseNode( LongConsumer nodeChanger, Set relTypes( NodeCursor cursor ) { - return mapToSet( disk.relationshipTypes( cursor.get() ).iterator(), this::relTypeForId ); + return mapToSet( disk.relationshipTypes( disk.newStatement(), cursor.get() ).iterator(), this::relTypeForId ); } private void testDegreesForDenseNodeWithPartiallyDeletedRelGroupChain( TestRelType... typesToDelete ) @@ -462,8 +462,8 @@ private void testDegreesForDenseNodeWithPartiallyDeletedRelChains( boolean modif private Set degrees( NodeItem nodeItem ) { Set degrees = new HashSet<>(); - disk.degrees( nodeItem, - ( type, outgoing, incoming ) -> degrees.add( new TestDegreeItem( type, outgoing, incoming ) ) ); + disk.degrees( disk.newStatement(), nodeItem, ( type, outgoing, incoming ) -> degrees + .add( new TestDegreeItem( type, outgoing, incoming ) ) ); return degrees; } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerTest.java index d42f684d9b1f..ac39f6dbe73b 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StorageLayerTest.java @@ -69,7 +69,7 @@ public void before() DependencyResolver resolver = db.getDependencyResolver(); this.disk = resolver.resolveDependency( StorageEngine.class ).storeReadLayer(); this.state = - new KernelStatementImplementation( null, null, disk.schemaResources(), new Procedures(), new CanWrite(), + new KernelStatementImplementation( null, null, disk.newStatement(), new Procedures(), new CanWrite(), LockTracer.NONE ); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursorTest.java index 94c31087f2c3..898621ac0db1 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreIteratorRelationshipCursorTest.java @@ -27,11 +27,13 @@ import org.neo4j.io.pagecache.PageCursor; import org.neo4j.kernel.impl.store.RelationshipStore; import org.neo4j.kernel.impl.store.record.RelationshipRecord; +import org.neo4j.kernel.impl.util.InstanceCache; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -87,11 +89,15 @@ private StoreIteratorRelationshipCursor createRelationshipCursor( boolean relati relationshipRecord.setId( RELATIONSHIP_ID ); return relationshipRecord; }); - return new StoreIteratorRelationshipCursor( relationshipStore, this::noCache, NO_LOCK_SERVICE ); + return new StoreIteratorRelationshipCursor( relationshipStore, new TestCursorCache(), NO_LOCK_SERVICE ); } - private void noCache( StoreIteratorRelationshipCursor c ) + private class TestCursorCache extends InstanceCache { - + @Override + protected StoreIteratorRelationshipCursor create() + { + return null; + } } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursorTest.java index 110b84f06bd5..ea4e9516eb24 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSingleRelationshipCursorTest.java @@ -25,10 +25,12 @@ import org.junit.Test; import org.junit.rules.RuleChain; +import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.store.NeoStores; import org.neo4j.kernel.impl.store.RelationshipStore; import org.neo4j.kernel.impl.store.StoreFactory; import org.neo4j.kernel.impl.store.record.RelationshipRecord; +import org.neo4j.kernel.impl.util.InstanceCache; import org.neo4j.logging.NullLogProvider; import org.neo4j.test.rule.PageCacheRule; import org.neo4j.test.rule.TestDirectory; @@ -37,7 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.neo4j.kernel.impl.locking.LockService.NO_LOCK_SERVICE; +import static org.mockito.Mockito.mock; import static org.neo4j.storageengine.api.txstate.ReadableTransactionState.EMPTY; public class StoreSingleRelationshipCursorTest @@ -112,10 +114,9 @@ private StoreFactory getStoreFactory() private StoreSingleRelationshipCursor createRelationshipCursor() { - return new StoreSingleRelationshipCursor( neoStores.getRelationshipStore(), this::noCache, NO_LOCK_SERVICE ); - } - - private void noCache( StoreSingleRelationshipCursor c ) - { + @SuppressWarnings( "unchecked" ) + InstanceCache instanceCache = mock(InstanceCache.class); + return new StoreSingleRelationshipCursor( neoStores.getRelationshipStore(), instanceCache, + LockService.NO_LOCK_SERVICE ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSchemaResourcesTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java similarity index 89% rename from community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSchemaResourcesTest.java rename to community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java index 692b8d9681c6..5e622e526419 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreSchemaResourcesTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java @@ -33,18 +33,19 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -public class StoreSchemaResourcesTest +public class StoreStatementTest { @Test public void shouldCloseOpenedLabelScanReader() throws Exception { // given - @SuppressWarnings( "unchecked" ) Supplier scanStore = mock( Supplier.class ); LabelScanReader scanReader = mock( LabelScanReader.class ); when( scanStore.get() ).thenReturn( scanReader ); - StoreSchemaResources statement = new StoreSchemaResources( null, scanStore ); + StoreStatement statement = new StoreStatement( MockedNeoStores.basicMockedNeoStores(), mock( Supplier.class ), + scanStore, LockService.NO_LOCK_SERVICE ); + statement.acquire(); // when LabelScanReader actualReader = statement.getLabelScanReader(); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java index e340ab19cd19..11de15779adc 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/coreapi/TxStateTransactionDataViewTest.java @@ -40,6 +40,7 @@ import org.neo4j.kernel.api.txstate.TransactionState; import org.neo4j.kernel.impl.api.KernelTransactionImplementation; import org.neo4j.kernel.impl.api.state.TxState; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.core.NodeProxy; import org.neo4j.kernel.impl.core.RelationshipProxy; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; @@ -74,6 +75,7 @@ public class TxStateTransactionDataViewTest private final ThreadToStatementContextBridge bridge = mock( ThreadToStatementContextBridge.class ); private final Statement stmt = mock( Statement.class ); private final StoreReadLayer ops = mock( StoreReadLayer.class ); + private final StoreStatement storeStatement = mock( StoreStatement.class ); private final KernelTransaction transaction = mock( KernelTransaction.class ); private final TransactionState state = new TxState(); @@ -82,6 +84,7 @@ public class TxStateTransactionDataViewTest public void setup() { when( bridge.get() ).thenReturn( stmt ); + when( ops.newStatement() ).thenReturn( storeStatement ); } @Test @@ -103,14 +106,14 @@ public void showsDeletedNodes() throws Exception state.nodeDoDelete( 2L ); NodeItem node1 = asNode( 2L, 20L, labels( 15 ) ); - when( ops.nodeGetSingleCursor( 2L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node1 ) ); + when( ops.nodeGetSingleCursor( storeStatement, 2L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node1 ) ); - when( ops.nodeGetProperties( node1, NodeState.EMPTY ) ) + when( ops.nodeGetProperties( storeStatement, node1, NodeState.EMPTY ) ) .thenReturn( asPropertyCursor( stringProperty( 1, "p" ) ) ); NodeItem node2 = asNode( 1L, 21L, labels() ); - when( ops.nodeGetSingleCursor( 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node2 ) ); - when( ops.nodeGetProperties( node2, NodeState.EMPTY ) ).thenReturn( asPropertyCursor() ); + when( ops.nodeGetSingleCursor( storeStatement, 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node2 ) ); + when( ops.nodeGetProperties( storeStatement, node2, NodeState.EMPTY ) ).thenReturn( asPropertyCursor() ); when( ops.propertyKeyGetName( 1 ) ).thenReturn( "key" ); when( ops.labelGetName( 15 ) ).thenReturn( "label" ); @@ -141,12 +144,15 @@ public void showsRemovedRelationships() throws Exception state.relationshipDoDelete( 2L, 1, 1L, 1L ); RelationshipItem rel1 = asRelationship( 1L, 1, 1L, 2L, -1L ); - when( ops.relationshipGetSingleCursor( 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( rel1 ) ); - when( ops.relationshipGetProperties( rel1, RelationshipState.EMPTY ) ).thenReturn( asPropertyCursor() ); + when( ops.relationshipCursor( storeStatement, 1L, ReadableTransactionState.EMPTY ) ) + .thenReturn( cursor( rel1 ) ); + when( ops.relationshipGetProperties( storeStatement, rel1, RelationshipState.EMPTY ) ) + .thenReturn( asPropertyCursor() ); RelationshipItem rel2 = asRelationship( 2L, 1, 1L, 1L, 40L ); - when( ops.relationshipGetSingleCursor( 2L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( rel2 ) ); - when( ops.relationshipGetProperties( rel2, RelationshipState.EMPTY ) ) + when( ops.relationshipCursor( storeStatement, 2L, ReadableTransactionState.EMPTY ) ) + .thenReturn( cursor( rel2 ) ); + when( ops.relationshipGetProperties( storeStatement, rel2, RelationshipState.EMPTY ) ) .thenReturn( asPropertyCursor( stringProperty( 1, "p" ) ) ); when( ops.propertyKeyGetName( 1 ) ).thenReturn( "key" ); @@ -165,8 +171,8 @@ public void correctlySaysNodeIsDeleted() throws Exception Node node = mock( Node.class ); when( node.getId() ).thenReturn( 1L ); NodeItem nodeItem = asNode( 1 ); - when( ops.nodeGetSingleCursor( 1, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( nodeItem ) ); - when( ops.nodeGetProperties( nodeItem, NodeState.EMPTY ) ).thenReturn( asPropertyCursor() ); + when( ops.nodeGetSingleCursor( storeStatement, 1, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( nodeItem ) ); + when( ops.nodeGetProperties( storeStatement, nodeItem, NodeState.EMPTY ) ).thenReturn( asPropertyCursor() ); // When & Then assertThat( snapshot().isDeleted( node ), equalTo( true ) ); @@ -181,9 +187,10 @@ public void correctlySaysRelIsDeleted() throws Exception Relationship rel = mock( Relationship.class ); when( rel.getId() ).thenReturn( 1L ); RelationshipItem relationship = asRelationship( 1L, 1, 1L, 2L, -1L ); - when( ops.relationshipGetSingleCursor( 1L, ReadableTransactionState.EMPTY ) ) + when( ops.relationshipCursor( storeStatement, 1L, ReadableTransactionState.EMPTY ) ) .thenReturn( cursor( relationship ) ); - when( ops.relationshipGetProperties( relationship, RelationshipState.EMPTY ) ).thenReturn( asPropertyCursor() ); + when( ops.relationshipGetProperties( storeStatement, relationship, RelationshipState.EMPTY ) ) + .thenReturn( asPropertyCursor() ); // When & Then assertThat( snapshot().isDeleted( rel ), equalTo( true ) ); @@ -199,8 +206,9 @@ public void shouldListAddedNodePropertiesProperties() throws Exception when( ops.propertyKeyGetName( propertyKeyId ) ).thenReturn( "theKey" ); long propertyId = 20L; NodeItem node = asNode( 1L, propertyId, labels() ); - when( ops.nodeGetSingleCursor( 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node ) ); - when( ops.nodeGetProperty( node, propertyKeyId, NodeState.EMPTY ) ).thenReturn( asPropertyCursor( prevProp ) ); + when( ops.nodeGetSingleCursor( storeStatement, 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node ) ); + when( ops.nodeGetProperty( storeStatement, node, propertyKeyId, NodeState.EMPTY ) ) + .thenReturn( asPropertyCursor( prevProp ) ); // When Iterable> propertyEntries = snapshot().assignedNodeProperties(); @@ -223,8 +231,9 @@ public void shouldListRemovedNodeProperties() throws Exception when( ops.propertyKeyGetName( propertyKeyId ) ).thenReturn( "theKey" ); long propertyId = 20L; NodeItem node = asNode( 1L, propertyId, labels() ); - when( ops.nodeGetSingleCursor( 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node ) ); - when( ops.nodeGetProperty( node, propertyKeyId, NodeState.EMPTY ) ).thenReturn( asPropertyCursor( prevProp ) ); + when( ops.nodeGetSingleCursor( storeStatement, 1L, ReadableTransactionState.EMPTY ) ).thenReturn( cursor( node ) ); + when( ops.nodeGetProperty( storeStatement, node, propertyKeyId, NodeState.EMPTY ) ) + .thenReturn( asPropertyCursor( prevProp ) ); // When Iterable> propertyEntries = snapshot().removedNodeProperties(); @@ -246,9 +255,9 @@ public void shouldListRemovedRelationshipProperties() throws Exception when( ops.propertyKeyGetName( propertyKeyId ) ).thenReturn( "theKey" ); long propertyId = 40L; RelationshipItem relationshipItem = asRelationship( 1, 0, 0, 0, propertyId ); - when( ops.relationshipGetSingleCursor( 1, ReadableTransactionState.EMPTY ) ) + when( ops.relationshipCursor( storeStatement, 1, ReadableTransactionState.EMPTY ) ) .thenReturn( cursor( relationshipItem ) ); - when( ops.relationshipGetProperty( relationshipItem, propertyKeyId, RelationshipState.EMPTY ) ) + when( ops.relationshipGetProperty( storeStatement, relationshipItem, propertyKeyId, RelationshipState.EMPTY ) ) .thenReturn( asPropertyCursor( prevValue ) ); // When @@ -272,9 +281,9 @@ public void shouldListAddedRelationshipProperties() throws Exception when( ops.propertyKeyGetName( propertyKeyId ) ).thenReturn( "theKey" ); long propertyId = 40L; RelationshipItem relationshipItem = asRelationship( 1, 0, 0, 0, propertyId ); - when( ops.relationshipGetSingleCursor( 1, ReadableTransactionState.EMPTY ) ) + when( ops.relationshipCursor( storeStatement, 1, ReadableTransactionState.EMPTY ) ) .thenReturn( cursor( relationshipItem ) ); - when( ops.relationshipGetProperty( relationshipItem, propertyKeyId, RelationshipState.EMPTY ) ) + when( ops.relationshipGetProperty( storeStatement, relationshipItem, propertyKeyId, RelationshipState.EMPTY ) ) .thenReturn( asPropertyCursor( prevProp ) ); // When @@ -294,7 +303,7 @@ public void shouldListAddedLabels() throws Exception // Given state.nodeDoAddLabel( 2, 1L ); when( ops.labelGetName( 2 ) ).thenReturn( "theLabel" ); - when( ops.nodeGetCursor( any( BatchingLongProgression.class ), any( NodeTransactionStateView.class ) ) ) + when( storeStatement.acquireNodeCursor( any( BatchingLongProgression.class ), any( NodeTransactionStateView.class ) ) ) .thenReturn( asNodeCursor( 1 ) ); // When @@ -371,7 +380,7 @@ public void shouldAccessExampleMetaData() final KernelTransactionImplementation transaction = mock( KernelTransactionImplementation.class ); when( transaction.getUserMetaData() ).thenReturn( genericMap( "username", "Igor" ) ); TxStateTransactionDataSnapshot transactionDataSnapshot = - new TxStateTransactionDataSnapshot( state, nodeActions, relActions, ops, transaction ); + new TxStateTransactionDataSnapshot( state, nodeActions, relActions, ops, storeStatement, transaction ); assertEquals( 1, transactionDataSnapshot.metaData().size() ); assertThat( "Expected metadata map to contain defined username", transactionDataSnapshot.metaData(), equalTo( genericMap( "username", "Igor" ) ) ); @@ -391,6 +400,6 @@ private TxStateTransactionDataSnapshot snapshot() { NodeProxy.NodeActions nodeActions = mock( NodeProxy.NodeActions.class ); final RelationshipProxy.RelationshipActions relActions = mock( RelationshipProxy.RelationshipActions.class ); - return new TxStateTransactionDataSnapshot( state, nodeActions, relActions, ops, transaction ); + return new TxStateTransactionDataSnapshot( state, nodeActions, relActions, ops, storeStatement, transaction ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/store/NeoStoresTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/store/NeoStoresTest.java index d324876ca010..481eb5be6a43 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/store/NeoStoresTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/store/NeoStoresTest.java @@ -54,8 +54,10 @@ import org.neo4j.kernel.api.properties.DefinedProperty; import org.neo4j.kernel.api.properties.Property; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.api.KernelStatement; import org.neo4j.kernel.impl.api.KernelTransactionImplementation; import org.neo4j.kernel.impl.api.RelationshipVisitor; +import org.neo4j.kernel.impl.api.store.SingleNodeFetch; import org.neo4j.kernel.impl.core.RelationshipTypeToken; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; import org.neo4j.kernel.impl.store.MetaDataStore.Position; @@ -76,6 +78,7 @@ import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.PropertyItem; import org.neo4j.storageengine.api.RelationshipItem; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.Token; import org.neo4j.storageengine.api.txstate.NodeState; @@ -106,6 +109,7 @@ import static org.neo4j.kernel.api.properties.DefinedProperty.NO_SUCH_PROPERTY; import static org.neo4j.kernel.api.security.SecurityContext.AUTH_DISABLED; import static org.neo4j.kernel.configuration.Config.embeddedDefaults; +import static org.neo4j.kernel.impl.locking.LockService.NO_LOCK; import static org.neo4j.kernel.impl.store.RecordStore.getRecord; import static org.neo4j.kernel.impl.store.format.standard.MetaDataRecordFormat.FIELD_NOT_PRESENT; import static org.neo4j.kernel.impl.store.record.RecordLoad.NORMAL; @@ -297,14 +301,19 @@ private DefinedProperty nodeAddProperty( long nodeId, int key, Object value ) { DefinedProperty property = Property.property( key, value ); DefinedProperty oldProperty = NO_SUCH_PROPERTY; - try ( Cursor cursor = storeLayer.nodeGetSingleCursor( nodeId, EMPTY ) ) + try ( StorageStatement statement = storeLayer.newStatement(); + Cursor cursor = statement.acquireNodeCursor( new SingleNodeFetch( nodeId ), EMPTY ) ) { if ( cursor.next() ) { - DefinedProperty fetched = getProperty( key, cursor.get(), NodeState.EMPTY ); - if ( fetched != null ) + if ( cursor.next() ) { - oldProperty = fetched; + DefinedProperty fetched = + getProperty( key, statement, cursor.get().nextPropertyId(), NodeState.EMPTY ); + if ( fetched != null ) + { + oldProperty = fetched; + } } } } @@ -324,12 +333,13 @@ private DefinedProperty relAddProperty( long relationshipId, int key, Object val { DefinedProperty property = Property.property( key, value ); Property oldProperty = Property.noRelationshipProperty( relationshipId, key ); - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( relationshipId, EMPTY ) ) + try ( StorageStatement statement = storeLayer.newStatement(); + Cursor cursor = statement.acquireSingleRelationshipCursor( relationshipId, EMPTY ) ) { if ( cursor.next() ) { Property fetched = - getProperty( key, cursor.get(), RelationshipState.EMPTY ); + getProperty( key, statement, cursor.get().nextPropertyId(), RelationshipState.EMPTY ); if ( fetched != null ) { oldProperty = fetched; @@ -341,29 +351,19 @@ private DefinedProperty relAddProperty( long relationshipId, int key, Object val return property; } - private DefinedProperty getProperty( int key, NodeItem node, PropertyContainerState state ) - { - try ( Cursor propertyCursor = storeLayer.nodeGetProperty( node, key, state ) ) - { - return fetchProperty( key, propertyCursor ); - } - } - private DefinedProperty getProperty( int key, RelationshipItem relationshipItem, PropertyContainerState state ) - { - try ( Cursor propertyCursor = storeLayer.relationshipGetProperty( relationshipItem, key, state ) ) - { - return fetchProperty( key, propertyCursor ); - } - } - - private DefinedProperty fetchProperty( int key, Cursor propertyCursor ) + private DefinedProperty getProperty( int key, StorageStatement statement, long propertyId, + PropertyContainerState state ) { - if ( propertyCursor.next() ) + try ( Cursor propertyCursor = statement + .acquireSinglePropertyCursor( propertyId, key, NO_LOCK, state ) ) { - Object oldValue = propertyCursor.get().value(); - if ( oldValue != null ) + if ( propertyCursor.next() ) { - return Property.property( key, oldValue ); + Object oldValue = propertyCursor.get().value(); + if ( oldValue != null ) + { + return Property.property( key, oldValue ); + } } } return null; @@ -406,7 +406,8 @@ private void relDelete( long id ) transaction.relationshipDoDelete( relId, type, startNode, endNode ); if ( !readableTransactionState.relationshipVisit( id, visitor ) ) { - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( id, EMPTY ) ) + try ( Cursor cursor = storeLayer + .relationshipCursor( storeLayer.newStatement(), id, EMPTY ) ) { if ( !cursor.next() ) { @@ -1029,11 +1030,15 @@ private int validateAndCountRelationships( long node, long rel1, long rel2, int throws IOException { int count = 0; - try ( Cursor nodeCursor = storeLayer.nodeGetSingleCursor( node, EMPTY ) ) + try ( KernelStatement statement = (KernelStatement) tx.acquireStatement(); + Cursor nodeCursor = statement.storageStatement() + .acquireNodeCursor( new SingleNodeFetch( node ), EMPTY ) ) { nodeCursor.next(); - try ( Cursor relationships = storeLayer - .nodeGetRelationships( nodeCursor.get(), BOTH, EMPTY ) ) + + NodeItem nodeItem = nodeCursor.get(); + try ( Cursor relationships = statement.storageStatement().acquireNodeRelationshipCursor( + nodeItem.isDense(), nodeItem.id(), nodeItem.nextRelationshipId(), BOTH, null, EMPTY ) ) { while ( relationships.next() ) { @@ -1110,11 +1115,14 @@ else if ( data.propertyKeyId() == prop3.propertyKeyId() ) assertEquals( 3, count ); count = 0; - try ( Cursor nodeCursor = storeLayer.nodeGetSingleCursor( node, EMPTY ) ) + try ( KernelStatement statement = (KernelStatement) tx.acquireStatement(); + Cursor nodeCursor = statement.storageStatement() + .acquireNodeCursor( new SingleNodeFetch( node ), EMPTY ) ) { nodeCursor.next(); - try ( Cursor relationships = storeLayer - .nodeGetRelationships( nodeCursor.get(), BOTH, EMPTY ) ) + NodeItem nodeItem = nodeCursor.get(); + try ( Cursor relationships = statement.storageStatement().acquireNodeRelationshipCursor( + nodeItem.isDense(), nodeItem.id(), nodeItem.nextRelationshipId(), BOTH, null, EMPTY ) ) { while ( relationships.next() ) { @@ -1143,9 +1151,12 @@ else if ( rel == rel2 ) private boolean nodeExists( long nodeId ) { - try ( Cursor node = storeLayer.nodeGetSingleCursor( nodeId, EMPTY ) ) + try ( StorageStatement statement = storeLayer.newStatement() ) { - return node.next(); + try ( Cursor node = statement.acquireNodeCursor( new SingleNodeFetch( nodeId ), EMPTY ) ) + { + return node.next(); + } } } @@ -1196,7 +1207,7 @@ else if ( data.propertyKeyId() == prop3.propertyKeyId() ) private void assertRelationshipData( long rel, final long firstNode, final long secondNode, final int relType ) { - try ( Cursor cursor = storeLayer.relationshipGetSingleCursor( rel, EMPTY ) ) + try ( Cursor cursor = storeLayer.relationshipCursor( storeLayer.newStatement(), rel, EMPTY ) ) { if ( !cursor.next() ) { @@ -1398,11 +1409,14 @@ else if ( data.propertyKeyId() == prop3.propertyKeyId() ) private void assertHasRelationships( long node ) { - try ( Cursor nodeCursor = storeLayer.nodeGetSingleCursor( node, EMPTY ) ) + try ( KernelStatement statement = (KernelStatement) tx.acquireStatement(); + Cursor nodeCursor = statement.storageStatement() + .acquireNodeCursor( new SingleNodeFetch( node ), EMPTY ) ) { nodeCursor.next(); - try ( Cursor relationships = storeLayer - .nodeGetRelationships( nodeCursor.get(), BOTH, EMPTY ) ) + NodeItem nodeItem = nodeCursor.get(); + try ( Cursor relationships = statement.storageStatement().acquireNodeRelationshipCursor( + nodeItem.isDense(), nodeItem.id(), nodeItem.nextRelationshipId(), BOTH, null, EMPTY ) ) { assertTrue( relationships.next() ); } @@ -1505,21 +1519,29 @@ else if ( data.propertyKeyId() == prop3.propertyKeyId() ) private void testGetRels( long[] relIds ) { - for ( long relId : relIds ) + try ( StorageStatement statement = storeLayer.newStatement() ) { - try ( Cursor relationship = storeLayer.relationshipGetSingleCursor( relId, EMPTY ) ) + for ( long relId : relIds ) { - assertFalse( relationship.next() ); + try ( Cursor relationship = statement.acquireSingleRelationshipCursor( relId, EMPTY ) ) + { + assertFalse( relationship.next() ); + } } } } private void deleteRelationships( long nodeId ) throws Exception { - try ( Cursor nodeCursor = storeLayer.nodeGetSingleCursor( nodeId, EMPTY ) ) + try ( KernelStatement statement = (KernelStatement) tx.acquireStatement(); + Cursor nodeCursor = statement.storageStatement() + .acquireNodeCursor( new SingleNodeFetch( nodeId ), EMPTY ) ) { assertTrue( nodeCursor.next() ); - storeLayer.nodeGetRelationships( nodeCursor.get(), BOTH, EMPTY ).forAll( rel -> relDelete( rel.id() ) ); + NodeItem nodeItem = nodeCursor.get(); + statement.storageStatement() + .acquireNodeRelationshipCursor( nodeItem.isDense(), nodeItem.id(), nodeItem.nextRelationshipId(), + BOTH, null, EMPTY ).forAll( rel -> relDelete( rel.id() ) ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/IndexWorkSyncTransactionApplicationStressIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/IndexWorkSyncTransactionApplicationStressIT.java index 9f62e91d4944..ebba7edfc388 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/IndexWorkSyncTransactionApplicationStressIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/transaction/command/IndexWorkSyncTransactionApplicationStressIT.java @@ -49,7 +49,7 @@ import org.neo4j.kernel.impl.transaction.command.Command.NodeCommand; import org.neo4j.kernel.impl.util.Dependencies; import org.neo4j.storageengine.api.StorageCommand; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.TransactionApplicationMode; import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.test.rule.PageCacheRule; @@ -194,7 +194,7 @@ private TransactionToApply createNodeAndProperty( int progress ) throws Exceptio txState.nodeDoAddLabel( descriptor.getLabelId(), nodeId ); txState.nodeDoAddProperty( nodeId, property( descriptor.getPropertyId(), propertyValue( id, progress ) ) ); Collection commands = new ArrayList<>(); - try ( SchemaResources statement = storageEngine.storeReadLayer().schemaResources() ) + try ( StorageStatement statement = storageEngine.storeReadLayer().newStatement() ) { storageEngine.createCommands( commands, txState, statement, null, 0 ); } diff --git a/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java b/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java index 57bd24c7831e..fdf55191ea19 100644 --- a/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java +++ b/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java @@ -40,6 +40,7 @@ import org.neo4j.kernel.impl.api.scan.LabelScanStoreProvider; import org.neo4j.kernel.impl.api.scan.NativeLabelScanStoreExtension; import org.neo4j.kernel.impl.api.store.CommunityBatchingProgressionFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.constraints.StandardConstraintSemantics; import org.neo4j.kernel.impl.core.DatabasePanicEventGenerator; import org.neo4j.kernel.impl.core.LabelTokenHolder; @@ -139,7 +140,7 @@ idConfigurationProvider, logService, mock( JobScheduler.class, RETURNS_MOCKS ), mock( TransactionMonitor.class ), databaseHealth, mock( PhysicalLogFile.Monitor.class ), TransactionHeaderInformationFactory.DEFAULT, new StartupStatisticsProvider(), null, new CommunityCommitProcessFactory(), mock( InternalAutoIndexing.class ), pageCache, - new StandardConstraintSemantics(), monitors, + new StandardConstraintSemantics(), StoreStatement::new, monitors, new Tracers( "null", NullLog.getInstance(), monitors, jobScheduler ), mock( Procedures.class ), IOLimiter.unlimited(), new AvailabilityGuard( clock, NullLog.getInstance() ), clock, new CanWrite(), new StoreCopyCheckPointMutex(), new CommunityBatchingProgressionFactory(), diff --git a/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java b/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java index dcdfe03f51bf..acb6bdb8f1b1 100644 --- a/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java +++ b/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java @@ -36,6 +36,7 @@ import org.neo4j.kernel.impl.api.index.IndexingService; import org.neo4j.kernel.impl.api.scan.LabelScanStoreProvider; import org.neo4j.kernel.impl.api.store.CommunityBatchingProgressionFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.constraints.ConstraintSemantics; import org.neo4j.kernel.impl.constraints.StandardConstraintSemantics; import org.neo4j.kernel.impl.core.DatabasePanicEventGenerator; @@ -46,6 +47,7 @@ import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.locking.ReentrantLockService; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.StorageStatementFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdReuseEligibility; import org.neo4j.kernel.impl.store.id.configuration.CommunityIdTypeConfigurationProvider; @@ -117,7 +119,7 @@ IdReuseEligibility.ALWAYS, new CommunityIdTypeConfigurationProvider(), pageCache NullLogProvider.getInstance(), mock( PropertyKeyTokenHolder.class ), mock( LabelTokenHolder.class ), mock( RelationshipTypeTokenHolder.class ), () -> {}, new StandardConstraintSemantics(), - scheduler, mock( TokenNameLookup.class ), new ReentrantLockService(), + StoreStatement::new, scheduler, mock( TokenNameLookup.class ), new ReentrantLockService(), schemaIndexProvider, IndexingService.NO_MONITOR, databaseHealth, labelScanStoreProvider, legacyIndexProviderLookup, indexConfigStore, new SynchronizedArrayIdOrderingQueue( 20 ), txSnapshotSupplier, transactionApplierTransformer ) ); @@ -200,19 +202,21 @@ private class ExtendedRecordStorageEngine extends RecordStorageEngine PageCache pageCache, FileSystemAbstraction fs, LogProvider logProvider, PropertyKeyTokenHolder propertyKeyTokenHolder, LabelTokenHolder labelTokens, RelationshipTypeTokenHolder relationshipTypeTokens, Runnable schemaStateChangeCallback, - ConstraintSemantics constraintSemantics, JobScheduler scheduler, TokenNameLookup tokenNameLookup, - LockService lockService, SchemaIndexProvider indexProvider, - IndexingService.Monitor indexingServiceMonitor, DatabaseHealth databaseHealth, - LabelScanStoreProvider labelScanStoreProvider, LegacyIndexProviderLookup legacyIndexProviderLookup, - IndexConfigStore indexConfigStore, IdOrderingQueue legacyIndexTransactionOrdering, + ConstraintSemantics constraintSemantics, StorageStatementFactory storageStatementFactory, + JobScheduler scheduler, TokenNameLookup tokenNameLookup, LockService lockService, + SchemaIndexProvider indexProvider, IndexingService.Monitor indexingServiceMonitor, + DatabaseHealth databaseHealth, LabelScanStoreProvider labelScanStoreProvider, + LegacyIndexProviderLookup legacyIndexProviderLookup, IndexConfigStore indexConfigStore, + IdOrderingQueue legacyIndexTransactionOrdering, Supplier transactionsSnapshotSupplier, Function transactionApplierTransformer ) { super( storeDir, config, idGeneratorFactory, eligibleForReuse, idTypeConfigurationProvider, pageCache, fs, logProvider, propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, schemaStateChangeCallback, - constraintSemantics, scheduler, tokenNameLookup, lockService, indexProvider, indexingServiceMonitor, - databaseHealth, labelScanStoreProvider, legacyIndexProviderLookup, indexConfigStore, - legacyIndexTransactionOrdering, transactionsSnapshotSupplier, new CommunityBatchingProgressionFactory() ); + constraintSemantics, storageStatementFactory, scheduler, tokenNameLookup, lockService, + indexProvider, indexingServiceMonitor, databaseHealth, labelScanStoreProvider, + legacyIndexProviderLookup, indexConfigStore, legacyIndexTransactionOrdering, + transactionsSnapshotSupplier, new CommunityBatchingProgressionFactory() ); this.transactionApplierTransformer = transactionApplierTransformer; } diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java index 9160e63b8fb3..0220d3efd040 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java @@ -71,6 +71,7 @@ import org.neo4j.kernel.impl.api.SchemaWriteGuard; import org.neo4j.kernel.impl.api.TransactionHeaderInformation; import org.neo4j.kernel.impl.api.store.EnterpriseBatchingProgressionFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.enterprise.EnterpriseConstraintSemantics; import org.neo4j.kernel.impl.enterprise.EnterpriseEditionModule; @@ -282,6 +283,8 @@ private void editionInvariants( PlatformModule platformModule, Dependencies depe constraintSemantics = new EnterpriseConstraintSemantics(); + storageStatementFactory = StoreStatement::new; + progressionFactory = dependencies.satisfyDependency( new EnterpriseBatchingProgressionFactory() ); coreAPIAvailabilityGuard = diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolder.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolder.java index bbae171d698d..6debcd3e7df4 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolder.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolder.java @@ -40,7 +40,7 @@ import org.neo4j.kernel.impl.util.Dependencies; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.Token; import org.neo4j.storageengine.api.lock.ResourceLocker; @@ -116,7 +116,7 @@ private byte[] createCommands( String tokenName ) TransactionState txState = new TxState(); int tokenId = Math.toIntExact( idGeneratorFactory.get( tokenIdType ).nextId() ); createToken( txState, tokenName, tokenId ); - try ( SchemaResources statement = storageEngine.storeReadLayer().schemaResources() ) + try ( StorageStatement statement = storageEngine.storeReadLayer().newStatement() ) { storageEngine.createCommands( commands, txState, statement, ResourceLocker.NONE, Long.MAX_VALUE ); } diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/readreplica/EnterpriseReadReplicaEditionModule.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/readreplica/EnterpriseReadReplicaEditionModule.java index 1fc863a148b7..68fc51e2c898 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/readreplica/EnterpriseReadReplicaEditionModule.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/readreplica/EnterpriseReadReplicaEditionModule.java @@ -64,6 +64,7 @@ import org.neo4j.kernel.impl.api.TransactionCommitProcess; import org.neo4j.kernel.impl.api.TransactionRepresentationCommitProcess; import org.neo4j.kernel.impl.api.store.EnterpriseBatchingProgressionFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.core.DelegatingLabelTokenHolder; import org.neo4j.kernel.impl.core.DelegatingPropertyKeyTokenHolder; import org.neo4j.kernel.impl.core.DelegatingRelationshipTypeTokenHolder; @@ -165,6 +166,8 @@ public class EnterpriseReadReplicaEditionModule extends EditionModule constraintSemantics = new EnterpriseConstraintSemantics(); + storageStatementFactory = StoreStatement::new; + progressionFactory = dependencies.satisfyDependency( new EnterpriseBatchingProgressionFactory() ); coreAPIAvailabilityGuard = diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolderTest.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolderTest.java index 8ad05eaf27bf..7f35a59bf657 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolderTest.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/token/ReplicatedTokenHolderTest.java @@ -32,7 +32,7 @@ import org.neo4j.kernel.impl.util.Dependencies; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; -import org.neo4j.storageengine.api.SchemaResources; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.Token; import org.neo4j.storageengine.api.lock.ResourceLocker; @@ -137,10 +137,10 @@ public void visitCreatedLabelToken( String name, int id ) } ); return null; } ).when( storageEngine ).createCommands( anyCollection(), any( ReadableTransactionState.class ), - any( SchemaResources.class ), any( ResourceLocker.class ), anyLong() ); + any( StorageStatement.class ), any( ResourceLocker.class ), anyLong() ); StoreReadLayer readLayer = mock( StoreReadLayer.class ); - when( readLayer.schemaResources() ).thenReturn( mock( SchemaResources.class ) ); + when( readLayer.newStatement() ).thenReturn( mock( StorageStatement.class ) ); when( storageEngine.storeReadLayer() ).thenReturn( readLayer ); return storageEngine; } diff --git a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/factory/HighlyAvailableEditionModule.java b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/factory/HighlyAvailableEditionModule.java index 238ce596e40e..bbc6df8d9249 100644 --- a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/factory/HighlyAvailableEditionModule.java +++ b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/factory/HighlyAvailableEditionModule.java @@ -129,6 +129,7 @@ import org.neo4j.kernel.impl.api.TransactionCommitProcess; import org.neo4j.kernel.impl.api.TransactionHeaderInformation; import org.neo4j.kernel.impl.api.store.EnterpriseBatchingProgressionFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.core.DelegatingLabelTokenHolder; import org.neo4j.kernel.impl.core.DelegatingPropertyKeyTokenHolder; import org.neo4j.kernel.impl.core.DelegatingRelationshipTypeTokenHolder; @@ -524,6 +525,8 @@ public void elected( String role, InstanceId instanceId, URI electedMember ) constraintSemantics = new EnterpriseConstraintSemantics(); + storageStatementFactory = StoreStatement::new; + progressionFactory = dependencies.satisfyDependency( new EnterpriseBatchingProgressionFactory() ); coreAPIAvailabilityGuard = new CoreAPIAvailabilityGuard( platformModule.availabilityGuard, transactionStartTimeout ); diff --git a/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/PropertyExistenceEnforcer.java b/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/PropertyExistenceEnforcer.java index 28ee964faa19..e5bb2821e3f3 100644 --- a/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/PropertyExistenceEnforcer.java +++ b/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/PropertyExistenceEnforcer.java @@ -38,11 +38,13 @@ import org.neo4j.kernel.api.schema.RelationTypeSchemaDescriptor; import org.neo4j.kernel.api.schema.SchemaProcessor; import org.neo4j.kernel.api.schema.constaints.ConstraintDescriptor; +import org.neo4j.kernel.impl.api.store.SingleNodeFetch; +import org.neo4j.kernel.impl.locking.Lock; import org.neo4j.storageengine.api.NodeItem; import org.neo4j.storageengine.api.PropertyItem; import org.neo4j.storageengine.api.RelationshipItem; -import org.neo4j.storageengine.api.SchemaResources; import org.neo4j.storageengine.api.StorageProperty; +import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.txstate.ReadableTransactionState; import org.neo4j.storageengine.api.txstate.TxStateVisitor; @@ -149,7 +151,7 @@ private class Decorator extends TxStateVisitor.Delegator private final ReadableTransactionState txState; private final StoreReadLayer storeLayer; private final PrimitiveIntSet propertyKeyIds = Primitive.intSet(); - private SchemaResources schemaResources; + private StorageStatement storageStatement; Decorator( TxStateVisitor next, ReadableTransactionState txState, StoreReadLayer storeLayer ) { @@ -196,9 +198,9 @@ public void visitRelPropertyChanges( public void close() { super.close(); - if ( schemaResources != null ) + if ( storageStatement != null ) { - schemaResources.close(); + storageStatement.close(); } } @@ -210,7 +212,8 @@ private void validateNode( long nodeId ) throws NodePropertyExistenceException } PrimitiveIntSet labelIds; - try ( Cursor node = storeLayer.nodeGetSingleCursor( nodeId, txState ) ) + try ( Cursor node = storeStatement() + .acquireNodeCursor( new SingleNodeFetch( nodeId ), txState ) ) { if ( node.next() ) { @@ -220,8 +223,7 @@ private void validateNode( long nodeId ) throws NodePropertyExistenceException return; } propertyKeyIds.clear(); - try ( Cursor properties = storeLayer - .nodeGetProperties( node.get(), txState.getNodeState( nodeId ) ) ) + try ( Cursor properties = properties( node.get() ) ) { while ( properties.next() ) { @@ -247,7 +249,8 @@ private void validateRelationship( long id ) throws RelationshipPropertyExistenc int relationshipType; int[] required; - try ( Cursor relationship = storeLayer.relationshipGetSingleCursor( id, txState ) ) + try ( Cursor relationship = storeStatement() + .acquireSingleRelationshipCursor( id, txState ) ) { if ( relationship.next() ) { @@ -258,8 +261,7 @@ private void validateRelationship( long id ) throws RelationshipPropertyExistenc return; } propertyKeyIds.clear(); - try ( Cursor properties = storeLayer.relationshipGetProperties( relationship.get(), - txState.getRelationshipState( id ) ) ) + try ( Cursor properties = properties( relationship.get() ) ) { while ( properties.next() ) { @@ -272,6 +274,7 @@ private void validateRelationship( long id ) throws RelationshipPropertyExistenc throw new IllegalStateException( format( "Relationship %d with changes should exist.", id ) ); } } + for ( int mandatory : required ) { if ( !propertyKeyIds.contains( mandatory ) ) @@ -280,6 +283,24 @@ private void validateRelationship( long id ) throws RelationshipPropertyExistenc } } } + + private Cursor properties( NodeItem node ) + { + Lock lock = node.lock(); + return storeStatement().acquirePropertyCursor( node.nextPropertyId(), lock, txState.getNodeState( node.id() ) ); + } + + private Cursor properties( RelationshipItem relationship ) + { + Lock lock = relationship.lock(); + return storeStatement().acquirePropertyCursor( relationship.nextPropertyId(), + lock, txState.getRelationshipState( relationship.id() ) ); + } + + private StorageStatement storeStatement() + { + return storageStatement == null ? storageStatement = storeLayer.newStatement() : storageStatement; + } } private void validateNodeProperties( long id, PrimitiveIntSet labelIds, PrimitiveIntSet propertyKeyIds ) diff --git a/enterprise/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreParallelNodeScanIntegrationTest.java b/enterprise/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreParallelNodeScanIntegrationTest.java index 69a938724ea3..888bc245d393 100644 --- a/enterprise/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreParallelNodeScanIntegrationTest.java +++ b/enterprise/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreParallelNodeScanIntegrationTest.java @@ -33,6 +33,7 @@ import org.neo4j.helpers.Exceptions; import org.neo4j.kernel.impl.api.state.TxState; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; +import org.neo4j.kernel.impl.store.NeoStores; import org.neo4j.kernel.impl.store.NodeStore; import org.neo4j.kernel.internal.GraphDatabaseAPI; import org.neo4j.storageengine.api.BatchingLongProgression; @@ -59,19 +60,20 @@ public class StoreParallelNodeScanIntegrationTest public void parallelScanShouldProvideTheSameResultAsANormalScan() throws Throwable { GraphDatabaseAPI db = databaseRule.getGraphDatabaseAPI(); - - BatchingProgressionFactory progressionFactory = progressionFactory( db ); - NodeStore nodeStore = nodeStore( db ); - int nodes = randomNodes( nodeStore ); + BatchingProgressionFactory progressionFactory = + db.getDependencyResolver().resolveDependency( BatchingProgressionFactory.class ); + NeoStores neoStores = + db.getDependencyResolver().resolveDependency( RecordStorageEngine.class ).testAccessNeoStores(); + int nodes = randomNodes( neoStores.getNodeStore() ); createNodes( db, nodes ); - Set expected = singleThreadExecution( nodeStore, progressionFactory, EMPTY ); + Set expected = singleThreadExecution( neoStores, progressionFactory, EMPTY ); int threads = random.nextInt( 2, 6 ); ExecutorService executor = Executors.newCachedThreadPool(); try { - Set parallelResult = parallelExecution( nodeStore, executor, threads, progressionFactory, EMPTY ); + Set parallelResult = parallelExecution( neoStores, executor, threads, progressionFactory, EMPTY ); assertEquals( expected, parallelResult ); } finally @@ -85,20 +87,22 @@ public void parallelScanWithTxStateChangesShouldProvideTheSameResultAsANormalSca throws Throwable { GraphDatabaseAPI db = databaseRule.getGraphDatabaseAPI(); - BatchingProgressionFactory progressionFactory = progressionFactory( db ); - NodeStore nodeStore = nodeStore( db ); - int nodes = randomNodes( nodeStore ); + BatchingProgressionFactory progressionFactory = + db.getDependencyResolver().resolveDependency( BatchingProgressionFactory.class ); + NeoStores neoStores = + db.getDependencyResolver().resolveDependency( RecordStorageEngine.class ).testAccessNeoStores(); + int nodes = randomNodes( neoStores.getNodeStore() ); long lastNodeId = createNodes( db, nodes ); TxState txState = crateTxStateWithRandomAddedAndDeletedNodes( nodes, lastNodeId ); - Set expected = singleThreadExecution( nodeStore, progressionFactory, txState ); + Set expected = singleThreadExecution( neoStores, progressionFactory, txState ); ExecutorService executor = Executors.newCachedThreadPool(); try { int threads = random.nextInt( 2, 6 ); - Set parallelResult = parallelExecution( nodeStore, executor, threads, progressionFactory, txState ); + Set parallelResult = parallelExecution( neoStores, executor, threads, progressionFactory, txState ); assertEquals( expected, parallelResult ); } finally @@ -107,16 +111,16 @@ public void parallelScanWithTxStateChangesShouldProvideTheSameResultAsANormalSca } } - private Set parallelExecution( NodeStore nodeStore, ExecutorService executorService, int threads, + private Set parallelExecution( NeoStores neoStores, ExecutorService executorService, int threads, BatchingProgressionFactory progressionFactory, NodeTransactionStateView stateView ) throws Throwable { - NodeCursor[] nodeCursors = new NodeCursor[threads]; + StoreStatement[] localStatements = new StoreStatement[threads]; for ( int i = 0; i < threads; i++ ) { - nodeCursors[i] = new NodeCursor( nodeStore, this::noCache, NO_LOCK_SERVICE ); + localStatements[i] = new StoreStatement( neoStores, null, null, NO_LOCK_SERVICE ); } // use any of the local statements to build the shared progression - BatchingLongProgression progression = progressionFactory.parallelAllNodeScan( nodeStore ); + BatchingLongProgression progression = progressionFactory.parallelAllNodeScan( neoStores.getNodeStore() ); @SuppressWarnings( "unchecked" ) Future>[] futures = new Future[threads]; @@ -126,7 +130,7 @@ private Set parallelExecution( NodeStore nodeStore, ExecutorService execut futures[i] = executorService.submit( () -> { HashSet ids = new HashSet<>(); - try ( Cursor cursor = nodeCursors[id].init( progression, stateView ) ) + try ( Cursor cursor = localStatements[id].acquireNodeCursor( progression, stateView ) ) { while ( cursor.next() ) { @@ -163,12 +167,13 @@ private Set parallelExecution( NodeStore nodeStore, ExecutorService execut return parallelResult; } - private Set singleThreadExecution( NodeStore nodeStore, BatchingProgressionFactory progressionFactory, + private Set singleThreadExecution( NeoStores neoStores, BatchingProgressionFactory progressionFactory, NodeTransactionStateView stateView ) { Set expected = new HashSet<>(); - try ( Cursor cursor = new NodeCursor( nodeStore, this::noCache, NO_LOCK_SERVICE ) - .init( progressionFactory.allNodeScan( nodeStore ), stateView ) ) + StoreStatement statement = new StoreStatement( neoStores, null, null, NO_LOCK_SERVICE ); + try ( Cursor cursor = statement + .acquireNodeCursor( progressionFactory.allNodeScan( neoStores.getNodeStore() ), stateView ) ) { while ( cursor.next() ) { @@ -217,19 +222,4 @@ private long createNodes( GraphDatabaseAPI db, int nodes ) return nodeId; } } - - private BatchingProgressionFactory progressionFactory( GraphDatabaseAPI db ) - { - return db.getDependencyResolver().resolveDependency( BatchingProgressionFactory.class ); - } - - private NodeStore nodeStore( GraphDatabaseAPI db ) - { - return db.getDependencyResolver().resolveDependency( RecordStorageEngine.class ).testAccessNeoStores() - .getNodeStore(); - } - - private void noCache( NodeCursor c ) - { - } }