diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/IndexReaderFactory.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/IndexReaderFactory.java index 369b74a44f9ee..183f3befa2db4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/IndexReaderFactory.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/IndexReaderFactory.java @@ -63,6 +63,7 @@ public IndexReader newReader( IndexDescriptor descriptor ) throws IndexNotFoundK return reader; } + @Override public IndexReader newUnCachedReader( IndexDescriptor descriptor ) throws IndexNotFoundKernelException { IndexProxy index = indexingService.getIndexProxy( descriptor ); @@ -78,6 +79,7 @@ public void close() { indexReader.close(); } + indexReaders.clear(); } } } 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 6ef9621a9fff9..7387a79d026a2 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 @@ -243,7 +243,7 @@ public KernelStatement acquireStatement() if ( currentStatement == null ) { currentStatement = new KernelStatement( this, this, locks, operations, - storageEngine.storeReadLayer().acquireStatement(), procedures ); + storeLayer.acquireStatement(), procedures ); } currentStatement.acquire(); return currentStatement; 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 index 0eb93fbeef13a..a27bd43777504 100644 --- 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 @@ -21,6 +21,7 @@ import java.util.function.Supplier; +import org.neo4j.collection.pool.Pool; import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.cursor.Cursor; @@ -63,14 +64,16 @@ public class StoreStatement implements StorageStatement private final Supplier labelScanStore; private LabelScanReader labelScanReader; private boolean closed; + private final Pool pool; public StoreStatement( final NeoStores neoStores, final LockService lockService, Supplier indexReaderFactory, - Supplier labelScanReaderSupplier ) + Supplier labelScanReaderSupplier, Pool pool ) { this.neoStores = neoStores; this.indexReaderFactorySupplier = indexReaderFactory; this.labelScanStore = labelScanReaderSupplier; + this.pool = pool; this.nodeStore = neoStores.getNodeStore(); this.relationshipStore = neoStores.getRelationshipStore(); @@ -112,6 +115,12 @@ protected StoreIteratorRelationshipCursor create() }; } + public StoreStatement initialize() + { + this.closed = false; + return this; + } + @Override public Cursor acquireSingleNodeCursor( long nodeId ) { @@ -163,8 +172,10 @@ public void close() if ( labelScanReader != null ) { labelScanReader.close(); + labelScanReader = null; } closed = true; + pool.release( this ); } private class AllStoreIdIterator extends PrimitiveLongCollections.PrimitiveLongBaseIterator 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 9b78b43689b3a..2360820ff3b85 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 @@ -57,7 +57,6 @@ import org.neo4j.kernel.impl.api.store.CacheLayer; import org.neo4j.kernel.impl.api.store.DiskLayer; import org.neo4j.kernel.impl.api.store.SchemaCache; -import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.cache.BridgingCacheAccess; import org.neo4j.kernel.impl.constraints.ConstraintSemantics; import org.neo4j.kernel.impl.core.CacheAccessBackDoor; @@ -103,7 +102,6 @@ import org.neo4j.storageengine.api.CommandsToApply; import org.neo4j.storageengine.api.StorageCommand; import org.neo4j.storageengine.api.StorageEngine; -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; @@ -151,6 +149,7 @@ public class RecordStorageEngine implements StorageEngine, Lifecycle private final NeoStoreIndexStoreView indexStoreView; private final LegacyIndexProviderLookup legacyIndexProviderLookup; private final PropertyPhysicalToLogicalConverter indexUpdatesConverter; + private final StoreStatements storeStatementSupplier; // Immutable state for creating/applying commands private final Loaders loaders; @@ -216,10 +215,11 @@ public RecordStorageEngine( propertyKeyTokenHolder, relationshipTypeTokens, labelTokens ); labelScanStore = labelScanStoreProvider.getLabelScanStore(); + storeStatementSupplier = storeStatementSupplier( neoStores, config, lockService ); DiskLayer diskLayer = new DiskLayer( propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, schemaStorage, neoStores, indexingService, - storeStatementSupplier( neoStores, config, lockService ) ); + storeStatementSupplier ); storeLayer = new CacheLayer( diskLayer, schemaCache ); legacyIndexApplierLookup = new LegacyIndexApplierLookup.Direct( legacyIndexProviderLookup ); @@ -247,18 +247,14 @@ public RecordStorageEngine( } } - private Supplier storeStatementSupplier( + private StoreStatements storeStatementSupplier( NeoStores neoStores, Config config, LockService lockService ) { final LockService currentLockService = config.get( use_read_locks_on_property_reads ) ? lockService : NO_LOCK_SERVICE; - final Supplier indexReaderFactory = () -> { - return new IndexReaderFactory.Caching( indexingService ); - }; + final Supplier indexReaderFactory = () -> new IndexReaderFactory.Caching( indexingService ); - return () -> { - return new StoreStatement( neoStores, currentLockService, indexReaderFactory, labelScanStore::newReader ); - }; + return new StoreStatements( neoStores, currentLockService, indexReaderFactory, labelScanStore::newReader ); } @Override @@ -432,6 +428,7 @@ public void stop() throws Throwable @Override public void shutdown() throws Throwable { + storeStatementSupplier.close(); labelScanStore.shutdown(); indexingService.shutdown(); neoStores.close(); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/StoreStatements.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/StoreStatements.java new file mode 100644 index 0000000000000..fdbfbdd85d0c8 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/StoreStatements.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002-2016 "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.collection.pool.MarshlandPool; +import org.neo4j.function.Factory; +import org.neo4j.kernel.impl.api.IndexReaderFactory; +import org.neo4j.kernel.impl.api.store.StoreStatement; +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; + +/** + * {@link Supplier} of {@link StoreStatement} instances for {@link RecordStorageEngine}. + * Internally uses pooling to reduce need for actual instantiation. + */ +public class StoreStatements implements Supplier, AutoCloseable +{ + private final NeoStores neoStores; + private final LockService lockService; + private final Supplier indexReaderFactory; + private final Supplier labelScanReader; + private final Factory factory = new Factory() + { + @Override + public StoreStatement newInstance() + { + return new StoreStatement( neoStores, lockService, indexReaderFactory, labelScanReader, pool ); + } + }; + private final MarshlandPool pool = new MarshlandPool<>( factory ); + + public StoreStatements( NeoStores neoStores, LockService lockService, + Supplier indexReaderFactory, Supplier labelScanReader ) + { + this.neoStores = neoStores; + this.lockService = lockService; + this.indexReaderFactory = indexReaderFactory; + this.labelScanReader = labelScanReader; + } + + @Override + public StorageStatement get() + { + return pool.acquire().initialize(); + } + + @Override + public void close() + { + pool.close(); + } +} 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 7d6f485d0db38..accd59736fbc3 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 @@ -24,19 +24,14 @@ import org.mockito.stubbing.Answer; import java.util.Collection; -import java.util.function.Supplier; - import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.exceptions.TransactionFailureException; -import org.neo4j.kernel.impl.api.store.StoreStatement; import org.neo4j.kernel.impl.locking.Locks; -import org.neo4j.kernel.impl.locking.ReentrantLockService; import org.neo4j.kernel.impl.proc.Procedures; -import org.neo4j.kernel.impl.store.MetaDataStore; -import org.neo4j.kernel.impl.store.NeoStores; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.transaction.TransactionMonitor; import org.neo4j.kernel.impl.transaction.TransactionRepresentation; +import org.neo4j.kernel.impl.transaction.log.TransactionIdStore; import org.neo4j.kernel.impl.transaction.tracing.CommitEvent; import org.neo4j.kernel.impl.util.JobScheduler; import org.neo4j.kernel.lifecycle.LifeSupport; @@ -191,17 +186,13 @@ private static KernelTransactions newKernelTransactions( TransactionCommitProces Locks locks = mock( Locks.class ); when( locks.newClient() ).thenReturn( mock( Locks.Client.class ) ); - MetaDataStore metaDataStore = mock( MetaDataStore.class ); - NeoStores neoStores = mock( NeoStores.class ); - StoreReadLayer readLayer = mock( StoreReadLayer.class ); when( readLayer.acquireStatement() ).thenAnswer( new Answer() { @Override public StorageStatement answer( InvocationOnMock invocation ) throws Throwable { - return new StoreStatement( neoStores, new ReentrantLockService(), - mock( Supplier.class ), null ); + return mock( StorageStatement.class ); } } ); @@ -227,7 +218,7 @@ public Void answer( InvocationOnMock invocation ) throws Throwable null, null, null, TransactionHeaderInformationFactory.DEFAULT, commitProcess, null, null, new TransactionHooks(), mock( TransactionMonitor.class ), life, - tracers, storageEngine, new Procedures(), metaDataStore ); + tracers, storageEngine, new Procedures(), mock( TransactionIdStore.class ) ); } private static TransactionCommitProcess newRememberingCommitProcess( final TransactionRepresentation[] slot ) 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 b7a287f0eb833..159f27dcb9fcf 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 @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.Set; +import org.neo4j.collection.pool.Pool; import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.cursor.Cursor; @@ -450,7 +451,7 @@ private static class StoreStatementWithSingleFreshIndexReader extends StoreState StoreStatementWithSingleFreshIndexReader( IndexReader reader ) { super( mock( NeoStores.class ), new ReentrantLockService(), () -> mock( IndexReaderFactory.class ), - () -> mock( LabelScanReader.class ) ); + () -> mock( LabelScanReader.class ), mock( Pool.class ) ); this.reader = reader; } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java index 75d900a3d601b..cfa40be7033fc 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/store/StoreStatementTest.java @@ -23,6 +23,7 @@ import java.util.function.Supplier; +import org.neo4j.collection.pool.Pool; import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.store.NeoStores; import org.neo4j.storageengine.api.schema.LabelScanReader; @@ -45,7 +46,7 @@ public void shouldCloseOpenedLabelScanReader() throws Exception when( scanStore.get() ).thenReturn( scanReader ); StoreStatement statement = new StoreStatement( mock( NeoStores.class ), LockService.NO_LOCK_SERVICE, - mock( Supplier.class ), scanStore ); + mock( Supplier.class ), scanStore, mock( Pool.class ) ); // when LabelScanReader actualReader = statement.getLabelScanReader();