From b5ff11e0d30d488a87cc5fc0e25ecd443a854a0a Mon Sep 17 00:00:00 2001 From: Ragnar Mellbin Date: Fri, 7 Jul 2017 17:03:59 +0200 Subject: [PATCH] Revert "Fixes race between starting transaction and shutdown" This reverts commit 2c4d7505efe4a0e93ea9c1256d59c9ffa577ddbe. --- .../neo4j/kernel/DatabaseAvailability.java | 4 +- .../org/neo4j/kernel/NeoStoreDataSource.java | 2 +- .../org/neo4j/kernel/impl/api/Kernel.java | 26 +- .../kernel/impl/api/KernelTransactions.java | 4 +- .../coreapi/CoreAPIAvailabilityGuard.java | 15 +- .../kernel/impl/factory/ClassicCoreSPI.java | 5 +- .../impl/factory/GraphDatabaseFacade.java | 1 - .../kernel/impl/factory/PlatformModule.java | 8 +- .../impl/proc/ProcedureGDBFacadeSPI.java | 3 +- .../org/neo4j/kernel/impl/api/KernelTest.java | 55 +--- ...ransactionCompletionAndShutdownRaceIT.java | 262 ------------------ .../neo4j/test/TestGraphDatabaseFactory.java | 31 +-- 12 files changed, 36 insertions(+), 380 deletions(-) delete mode 100644 community/kernel/src/test/java/org/neo4j/kernel/impl/api/TransactionCompletionAndShutdownRaceIT.java diff --git a/community/kernel/src/main/java/org/neo4j/kernel/DatabaseAvailability.java b/community/kernel/src/main/java/org/neo4j/kernel/DatabaseAvailability.java index 39f37ee5c1f3..7e97504d85b4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/DatabaseAvailability.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/DatabaseAvailability.java @@ -21,14 +21,13 @@ import java.time.Clock; -import org.neo4j.kernel.AvailabilityGuard.AvailabilityRequirement; import org.neo4j.kernel.impl.transaction.TransactionStats; import org.neo4j.kernel.lifecycle.Lifecycle; import org.neo4j.time.Clocks; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.locks.LockSupport.parkNanos; - +import static org.neo4j.kernel.AvailabilityGuard.AvailabilityRequirement; import static org.neo4j.kernel.AvailabilityGuard.availabilityRequirement; /** @@ -93,5 +92,6 @@ private void awaitTransactionsClosedWithinTimeout() public void shutdown() throws Throwable { + // TODO: Starting database. Make sure none can access it through lock or CAS } } 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 801ca19a1086..e96d72f14305 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java @@ -735,7 +735,7 @@ private NeoStoreKernelModule buildKernel( TransactionAppender appender, availabilityGuard, tracers, storageEngine, procedures, transactionIdStore, clock, accessCapability ) ); final Kernel kernel = new Kernel( kernelTransactions, hooks, databaseHealth, transactionMonitor, procedures, - config, availabilityGuard ); + config ); kernel.registerTransactionHook( transactionEventHandlers ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/Kernel.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/Kernel.java index f8b04d68ff8a..4a2888b0c9f5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/Kernel.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/Kernel.java @@ -20,13 +20,10 @@ package org.neo4j.kernel.impl.api; import org.neo4j.graphdb.factory.GraphDatabaseSettings; -import org.neo4j.kernel.AvailabilityGuard; -import org.neo4j.kernel.AvailabilityGuard.UnavailableException; import org.neo4j.kernel.api.KernelAPI; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.TransactionHook; import org.neo4j.kernel.api.exceptions.ProcedureException; -import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.api.proc.CallableProcedure; import org.neo4j.kernel.api.proc.CallableUserAggregationFunction; @@ -67,22 +64,17 @@ public class Kernel extends LifecycleAdapter implements KernelAPI private final DatabaseHealth health; private final TransactionMonitor transactionMonitor; private final Procedures procedures; - private final AvailabilityGuard availabilityGuard; private final long defaultTransactionTimeout; - private final long transactionStartTimeout; public Kernel( KernelTransactions transactionFactory, TransactionHooks hooks, DatabaseHealth health, - TransactionMonitor transactionMonitor, Procedures procedures, Config config, - AvailabilityGuard availabilityGuard ) + TransactionMonitor transactionMonitor, Procedures procedures, Config config ) { this.transactions = transactionFactory; this.hooks = hooks; this.health = health; this.transactionMonitor = transactionMonitor; this.procedures = procedures; - this.availabilityGuard = availabilityGuard; this.defaultTransactionTimeout = config.get( GraphDatabaseSettings.transaction_timeout ).toMillis(); - this.transactionStartTimeout = config.get( GraphDatabaseSettings.transaction_start_timeout ).toMillis(); } @Override @@ -96,21 +88,9 @@ public KernelTransaction newTransaction( KernelTransaction.Type type, SecurityCo TransactionFailureException { health.assertHealthy( TransactionFailureException.class ); - - // Increment transaction monitor before checking the availability guard (which needs to be checked - // before starting the transaction). This is because the DatabaseAvailability does this in the other - // order, where it closes the availability guard and then awaits started transactions to finish. + KernelTransaction transaction = transactions.newInstance( type, securityContext, timeout ); transactionMonitor.transactionStarted(); - try - { - availabilityGuard.await( transactionStartTimeout ); - } - catch ( UnavailableException e ) - { - transactionMonitor.transactionFinished( false, false ); - throw new TransactionFailureException( e.status(), e, e.getMessage() ); - } - return transactions.newInstance( type, securityContext, timeout ); + return transaction; } @Override 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 3bcb329a2d8e..8da15226542e 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 @@ -322,7 +322,7 @@ private void assertCurrentThreadIsNotBlockingNewTransactions() private class KernelTransactionImplementationFactory implements Factory { - private final Set transactions; + private Set transactions; KernelTransactionImplementationFactory( Set transactions ) { @@ -345,7 +345,7 @@ public KernelTransactionImplementation newInstance() private class GlobalKernelTransactionPool extends LinkedQueuePool { - private final Set transactions; + private Set transactions; GlobalKernelTransactionPool( Set transactions, Factory factory ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/CoreAPIAvailabilityGuard.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/CoreAPIAvailabilityGuard.java index 6270fc48613c..98c0af3c40a2 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/CoreAPIAvailabilityGuard.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/CoreAPIAvailabilityGuard.java @@ -50,16 +50,11 @@ public void assertDatabaseAvailable() } catch ( AvailabilityGuard.UnavailableException e ) { - throw convertUnavailabilityException( e ); + if ( guard.isShutdown() ) + { + throw new DatabaseShutdownException(); + } + throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage() ); } } - - public RuntimeException convertUnavailabilityException( Exception e ) - { - if ( guard.isShutdown() ) - { - return new DatabaseShutdownException(); - } - return new org.neo4j.graphdb.TransactionFailureException( e.getMessage(), e ); - } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/ClassicCoreSPI.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/ClassicCoreSPI.java index 19151844fe0f..bbfc99e7b23d 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/ClassicCoreSPI.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/ClassicCoreSPI.java @@ -154,8 +154,8 @@ public void shutdown() { try { - platform.availabilityGuard.shutdown(); msgLog.log( "Shutdown started" ); + platform.availabilityGuard.shutdown(); platform.life.shutdown(); } catch ( LifecycleException throwable ) @@ -170,6 +170,7 @@ public KernelTransaction beginTransaction( KernelTransaction.Type type, Security { try { + availability.assertDatabaseAvailable(); KernelTransaction kernelTx = dataSource.kernelAPI.get().newTransaction( type, securityContext, timeout ); kernelTx.registerCloseListener( (txId) -> dataSource.threadToTransactionBridge.unbindTransactionFromCurrentThread() ); @@ -178,7 +179,7 @@ public KernelTransaction beginTransaction( KernelTransaction.Type type, Security } catch ( TransactionFailureException e ) { - throw availability.convertUnavailabilityException( e ); + throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage(), e ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacade.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacade.java index c648577bce10..5a49b14e82cc 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacade.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacade.java @@ -105,7 +105,6 @@ import org.neo4j.storageengine.api.EntityType; import static java.lang.String.format; - import static org.neo4j.collection.primitive.PrimitiveLongCollections.map; import static org.neo4j.helpers.collection.Iterators.emptyIterator; import static org.neo4j.kernel.api.security.SecurityContext.AUTH_DISABLED; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/PlatformModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/PlatformModule.java index 19400606c9d9..d64798c71548 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/PlatformModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/PlatformModule.java @@ -183,7 +183,8 @@ public PlatformModule( File providedStoreDir, Config config, DatabaseInfo databa // Anyways please fix this. dependencies.satisfyDependency( dataSourceManager ); - availabilityGuard = dependencies.satisfyDependency( createAvailabilityGuard() ); + availabilityGuard = dependencies.satisfyDependency( + new AvailabilityGuard( clock, logging.getInternalLog( AvailabilityGuard.class ) ) ); transactionMonitor = dependencies.satisfyDependency( createTransactionStats() ); @@ -199,11 +200,6 @@ public PlatformModule( File providedStoreDir, Config config, DatabaseInfo databa publishPlatformInfo( dependencies.resolveDependency( UsageData.class ) ); } - protected AvailabilityGuard createAvailabilityGuard() - { - return new AvailabilityGuard( clock, logging.getInternalLog( AvailabilityGuard.class ) ); - } - protected SystemNanoClock createClock() { return Clocks.nanoClock(); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ProcedureGDBFacadeSPI.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ProcedureGDBFacadeSPI.java index c9ae258a2753..ec97e2ebaa53 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ProcedureGDBFacadeSPI.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ProcedureGDBFacadeSPI.java @@ -186,6 +186,7 @@ public KernelTransaction beginTransaction( KernelTransaction.Type type, Security { try { + availability.assertDatabaseAvailable(); KernelTransaction kernelTx = sourceModule.kernelAPI.get().newTransaction( type, this.securityContext, timeout ); kernelTx.registerCloseListener( ( txId ) -> sourceModule.threadToTransactionBridge.unbindTransactionFromCurrentThread() ); @@ -194,7 +195,7 @@ public KernelTransaction beginTransaction( KernelTransaction.Type type, Security } catch ( TransactionFailureException e ) { - throw availability.convertUnavailabilityException( e ); + throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage(), e ); } } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java index cb34730bf263..db62d976a1d9 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/KernelTest.java @@ -19,21 +19,13 @@ */ package org.neo4j.kernel.impl.api; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; -import org.mockito.InOrder; import java.io.File; -import java.time.Clock; import java.util.Map; import java.util.function.Function; import org.neo4j.graphdb.Transaction; -import org.neo4j.kernel.AvailabilityGuard; -import org.neo4j.kernel.NeoStoreDataSource; -import org.neo4j.kernel.api.KernelAPI; -import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.exceptions.InvalidTransactionTypeKernelException; import org.neo4j.kernel.configuration.Config; @@ -44,34 +36,16 @@ import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory; import org.neo4j.kernel.impl.factory.PlatformModule; -import org.neo4j.kernel.impl.transaction.TransactionMonitor; -import org.neo4j.kernel.impl.util.Dependencies; import org.neo4j.kernel.internal.GraphDatabaseAPI; -import org.neo4j.logging.NullLog; import org.neo4j.test.ImpermanentGraphDatabase; -import org.neo4j.test.rule.NeoStoreDataSourceRule; -import org.neo4j.test.rule.PageCacheAndDependenciesRule; + import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; - import static org.neo4j.kernel.api.schema.SchemaDescriptorFactory.forLabel; -import static org.neo4j.kernel.api.security.SecurityContext.AUTH_DISABLED; -import static org.neo4j.kernel.api.KernelTransaction.Type.explicit; public class KernelTest { - private final PageCacheAndDependenciesRule pageCacheRule = new PageCacheAndDependenciesRule(); - private final NeoStoreDataSourceRule neoStoreRule = new NeoStoreDataSourceRule(); - - @Rule - public final RuleChain rules = RuleChain.outerRule( pageCacheRule ).around( neoStoreRule ); - @Test public void shouldNotAllowCreationOfConstraintsWhenInHA() throws Exception { @@ -98,29 +72,6 @@ public void shouldNotAllowCreationOfConstraintsWhenInHA() throws Exception db.shutdown(); } - @Test - public void shouldIncrementTransactionMonitorBeforeCheckingDatabaseAvailability() throws Exception - { - // GIVEN - AvailabilityGuard availabilityGuard = spy( new AvailabilityGuard( Clock.systemUTC(), NullLog.getInstance() ) ); - TransactionMonitor transactionMonitor = mock( TransactionMonitor.class ); - Dependencies dependencies = new Dependencies(); - dependencies.satisfyDependencies( availabilityGuard, transactionMonitor ); - NeoStoreDataSource dataSource = neoStoreRule.getDataSource( pageCacheRule.directory().absolutePath(), - pageCacheRule.fileSystem(), pageCacheRule.pageCache(), dependencies ); - dataSource.start(); - KernelAPI kernel = dataSource.getKernel(); - - // WHEN - try ( KernelTransaction tx = kernel.newTransaction( explicit, AUTH_DISABLED ) ) - { - // THEN - InOrder order = inOrder( transactionMonitor, availabilityGuard ); - order.verify( transactionMonitor, times( 1 ) ).transactionStarted(); - order.verify( availabilityGuard, times( 1 ) ).await( anyLong() ); - } - } - @SuppressWarnings("deprecation") class FakeHaDatabase extends ImpermanentGraphDatabase { @@ -145,8 +96,8 @@ protected SchemaWriteGuard createSchemaWriteGuard() new GraphDatabaseFacadeFactory( DatabaseInfo.COMMUNITY, factory ) { @Override - protected PlatformModule createPlatform( File storeDir, Config config, - GraphDatabaseFacadeFactory.Dependencies dependencies, GraphDatabaseFacade graphDatabaseFacade ) + protected PlatformModule createPlatform( File storeDir, Config config, Dependencies dependencies, + GraphDatabaseFacade graphDatabaseFacade ) { return new ImpermanentPlatformModule( storeDir, config, databaseInfo, dependencies, graphDatabaseFacade ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/TransactionCompletionAndShutdownRaceIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/TransactionCompletionAndShutdownRaceIT.java deleted file mode 100644 index d0c4fcc4cdfd..000000000000 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/TransactionCompletionAndShutdownRaceIT.java +++ /dev/null @@ -1,262 +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; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.File; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.neo4j.graphdb.DatabaseShutdownException; -import org.neo4j.graphdb.GraphDatabaseService; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.Transaction; -import org.neo4j.kernel.AvailabilityGuard; -import org.neo4j.kernel.DatabaseAvailability; -import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; -import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory; -import org.neo4j.kernel.impl.factory.PlatformModule; -import org.neo4j.kernel.impl.transaction.TransactionMonitor; -import org.neo4j.logging.NullLog; -import org.neo4j.test.Barrier; -import org.neo4j.test.TestGraphDatabaseFactory; -import org.neo4j.test.TestGraphDatabaseFactoryState; -import org.neo4j.test.rule.TestDirectory; -import org.neo4j.test.rule.concurrent.OtherThreadRule; - -import static org.hamcrest.core.Is.isA; -import static org.junit.Assert.assertNotNull; -import static org.neo4j.helpers.collection.Iterables.single; - -/** - * In its essence this test is about a race in mainly {@link DatabaseAvailability} and - * {@link TransactionMonitor#transactionStarted()} where a transaction thread (starting the transaction) - * would race with shutdown ({@link DatabaseAvailability#stop()}) where a transaction would get passed - * the availability check, the shutdown would think that no transactions were running and start the shutdown, - * leaving the transaction executing straight in the middle of dead or dying components. - * - * This will still be the case for transactions that live longer than the shutdown timeout in - * {@link DatabaseAvailability#stop()}, but at least that's deterministic and configurable. - */ -public class TransactionCompletionAndShutdownRaceIT -{ - @Rule - public final TestDirectory directory = TestDirectory.testDirectory(); - @Rule - public final OtherThreadRule transactor = new OtherThreadRule<>( "Transactor" ); - @Rule - public final OtherThreadRule shutter = new OtherThreadRule<>( "Shutter" ); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void shouldAlwaysAwaitTransactionCompletionBeforeShuttingDown() throws Exception - { - // GIVEN - Barrier.Control barrier = new Barrier.Control(); - AtomicBoolean barrierInstalled = new AtomicBoolean(); - File storeDir = directory.absolutePath(); - TestGraphDatabaseFactory dbFactory = - dbFactoryWithBarrierControlledTransactionStats( barrier, barrierInstalled ); - - { - GraphDatabaseService db = dbFactory.newImpermanentDatabase( storeDir ); - barrierInstalled.set( true ); - - // WHEN - Future transactionFuture = transactor.execute( state -> doTransaction( db, barrier ) ); - Future shutterFuture = shutter.execute( state -> doShutdown( db, barrier ) ); - - // THEN - shutterFuture.get(); - transactionFuture.get(); - barrierInstalled.set( false ); - } - - // Now assert that the node was created - GraphDatabaseService db = dbFactory.newImpermanentDatabase( storeDir ); - try ( Transaction tx = db.beginTx() ) - { - Node node = single( db.getAllNodes() ); - assertNotNull( node ); - tx.success(); - } - finally - { - db.shutdown(); - } - } - - private TestGraphDatabaseFactory dbFactoryWithBarrierControlledTransactionStats( Barrier.Control barrier, - AtomicBoolean barrierInstaller ) - { - return new TestGraphDatabaseFactory() - { - @Override - protected GraphDatabaseFacadeFactory newTestGraphDatabaseFacadeFactory( - File storeDir, Config config, TestGraphDatabaseFactoryState state ) - { - return new TestGraphDatabaseFacadeFactory( state, true ) - { - @Override - protected PlatformModule createPlatform( File storeDir, Config config, Dependencies dependencies, - GraphDatabaseFacade graphDatabaseFacade ) - { - return new TestGraphDatabaseFacadeFactory.TestDatabasePlatformModule( - storeDir, config, databaseInfo, dependencies, graphDatabaseFacade ) - { - @Override - protected AvailabilityGuard createAvailabilityGuard() - { - return new AvailabilityGuard( clock, NullLog.getInstance() ) - { - @Override - public void require( AvailabilityRequirement requirement ) - { - super.require( requirement ); - if ( barrierInstaller.get() ) - { - barrier.release(); - } - } - - @Override - public void await( long millis ) throws UnavailableException - { - super.await( millis ); - } - }; - } - }; - } - }; - } - }; - } - - private Object doShutdown( GraphDatabaseService db, Barrier.Control barrier ) - { - barrier.awaitUninterruptibly(); - db.shutdown(); - return null; - } - - private Object doTransaction( GraphDatabaseService db, Barrier.Control barrier ) - { - try ( Transaction tx = db.beginTx() ) - { - barrier.reached(); - db.createNode(); - tx.success(); - } - return null; - } - - @Test - public void shouldNotStartTransactoinOnDatabaseThatIsKnownToBeShuttingDown() throws Exception - { - // GIVEN - Barrier.Control barrier = new Barrier.Control(); - AtomicBoolean barrierInstalled = new AtomicBoolean(); - File storeDir = directory.absolutePath(); - TestGraphDatabaseFactory dbFactory = dbFactoryWithBarrierControlledTransactionStats2( barrier, - barrierInstalled ); - - { - GraphDatabaseService db = dbFactory.newImpermanentDatabase( storeDir ); - barrierInstalled.set( true ); - - // WHEN - Future transactionFuture = transactor.execute( state -> doTransaction( db ) ); - Future shutterFuture = shutter.execute( state -> doShutdown( db, barrier ) ); - - // THEN - shutterFuture.get(); - expectedException.expectCause( isA( DatabaseShutdownException.class ) ); - transactionFuture.get(); - barrierInstalled.set( false ); - } - } - - private TestGraphDatabaseFactory dbFactoryWithBarrierControlledTransactionStats2( Barrier.Control barrier, - AtomicBoolean barrierInstaller ) - { - return new TestGraphDatabaseFactory() - { - @Override - protected GraphDatabaseFacadeFactory newTestGraphDatabaseFacadeFactory( File storeDir, Config config, - TestGraphDatabaseFactoryState state ) - { - return new TestGraphDatabaseFacadeFactory( state, true ) - { - @Override - protected PlatformModule createPlatform( File storeDir, Config config, Dependencies dependencies, - GraphDatabaseFacade graphDatabaseFacade ) - { - return new TestGraphDatabaseFacadeFactory.TestDatabasePlatformModule( storeDir, config, - databaseInfo, dependencies, graphDatabaseFacade ) - { - @Override - protected AvailabilityGuard createAvailabilityGuard() - { - return new AvailabilityGuard( clock, NullLog.getInstance() ) - { - @Override - public void require( AvailabilityRequirement requirement ) - { - super.require( requirement ); - if ( barrierInstaller.get() ) - { - barrier.release(); - } - } - - @Override - public void await( long millis ) throws UnavailableException - { - super.await( millis ); - if ( barrierInstaller.get() ) - { - barrier.reached(); - } - } - }; - } - }; - } - }; - } - }; - } - - private Object doTransaction( GraphDatabaseService db ) - { - try ( Transaction tx = db.beginTx() ) - { - db.createNode(); - tx.success(); - } - return null; - } -} diff --git a/community/kernel/src/test/java/org/neo4j/test/TestGraphDatabaseFactory.java b/community/kernel/src/test/java/org/neo4j/test/TestGraphDatabaseFactory.java index b177d93e94ab..112e61c801cf 100644 --- a/community/kernel/src/test/java/org/neo4j/test/TestGraphDatabaseFactory.java +++ b/community/kernel/src/test/java/org/neo4j/test/TestGraphDatabaseFactory.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.Map; import java.util.function.Function; - import javax.annotation.Nonnull; import org.neo4j.graphdb.GraphDatabaseService; @@ -205,6 +204,7 @@ protected GraphDatabaseService newEmbeddedDatabase( File storeDir, Config config protected GraphDatabaseBuilder.DatabaseCreator createImpermanentDatabaseCreator( final File storeDir, final TestGraphDatabaseFactoryState state ) { + return new GraphDatabaseBuilder.DatabaseCreator() { @Override @@ -216,29 +216,23 @@ public GraphDatabaseService newDatabase( Map config ) @Override public GraphDatabaseService newDatabase( @Nonnull Config config ) { - return newTestGraphDatabaseFacadeFactory( storeDir, config, state ).newFacade( storeDir, config, + return new TestGraphDatabaseFacadeFactory( state, true ).newFacade( storeDir, config, GraphDatabaseDependencies.newDependencies( state.databaseDependencies() ) ); } }; } - protected GraphDatabaseFacadeFactory newTestGraphDatabaseFacadeFactory( File storeDir, - Config config, TestGraphDatabaseFactoryState state ) - { - return new TestGraphDatabaseFacadeFactory( state, true ); - } - - protected static class TestGraphDatabaseFacadeFactory extends GraphDatabaseFacadeFactory + static class TestGraphDatabaseFacadeFactory extends GraphDatabaseFacadeFactory { private final TestGraphDatabaseFactoryState state; private final boolean impermanent; - protected TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state, boolean impermanent ) + TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state, boolean impermanent ) { this( state, impermanent, DatabaseInfo.COMMUNITY, CommunityEditionModule::new ); } - protected TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state, boolean impermanent, + TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state, boolean impermanent, DatabaseInfo databaseInfo, Function editionFactory ) { super(databaseInfo, editionFactory); @@ -246,7 +240,7 @@ protected TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state, b this.impermanent = impermanent; } - protected TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state ) + TestGraphDatabaseFacadeFactory( TestGraphDatabaseFactoryState state ) { this(state, false); } @@ -258,14 +252,15 @@ protected PlatformModule createPlatform( File storeDir, Config config, return impermanent ? new ImpermanentTestDatabasePlatformModule( storeDir, config.with( stringMap( ephemeral.name(), TRUE ) ), dependencies, graphDatabaseFacade, this.databaseInfo ) : - new TestDatabasePlatformModule( storeDir, config, this - .databaseInfo, dependencies, graphDatabaseFacade ); + new TestDatabasePlatformModule( storeDir, config, dependencies, graphDatabaseFacade, this + .databaseInfo ); } - protected class TestDatabasePlatformModule extends PlatformModule + class TestDatabasePlatformModule extends PlatformModule { - protected TestDatabasePlatformModule( File storeDir, Config config, DatabaseInfo databaseInfo, - Dependencies dependencies, GraphDatabaseFacade graphDatabaseFacade ) + + TestDatabasePlatformModule( File storeDir, Config config, Dependencies dependencies, + GraphDatabaseFacade graphDatabaseFacade, DatabaseInfo databaseInfo ) { super( storeDir, config, databaseInfo, dependencies, graphDatabaseFacade ); @@ -312,7 +307,7 @@ private class ImpermanentTestDatabasePlatformModule extends TestDatabasePlatform ImpermanentTestDatabasePlatformModule( File storeDir, Config config, Dependencies dependencies, GraphDatabaseFacade graphDatabaseFacade, DatabaseInfo databaseInfo ) { - super( storeDir, config, databaseInfo, dependencies, graphDatabaseFacade ); + super( storeDir, config, dependencies, graphDatabaseFacade, databaseInfo ); } @Override