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 new file mode 100644 index 0000000000000..b808a952ec307 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/CoreAPIAvailabilityGuard.java @@ -0,0 +1,61 @@ +package org.neo4j.kernel.impl.coreapi; + +/* + * 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 . + */ + +import org.neo4j.graphdb.DatabaseShutdownException; +import org.neo4j.kernel.AvailabilityGuard; + +/** + * This is a simple wrapper around {@link AvailabilityGuard} that augments its behavior to match how + * availability errors and timeouts are handled in the Core API. + */ +public class CoreAPIAvailabilityGuard +{ + private final AvailabilityGuard guard; + private final long timeout; + + public CoreAPIAvailabilityGuard( AvailabilityGuard guard, long timeout ) + { + this.guard = guard; + this.timeout = timeout; + } + + public boolean isAvailable( long timeoutMillis ) + { + return guard.isAvailable( timeoutMillis ); + } + + public void assertDatabaseAvailable() + { + try + { + guard.await( timeout ); + } + catch ( AvailabilityGuard.UnavailableException e ) + { + if( guard.isShutdown()) + { + throw new DatabaseShutdownException(); + } + throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage() ); + } + } +} 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 6f236c3079a2d..c52c4b041bc98 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 @@ -19,27 +19,26 @@ */ package org.neo4j.kernel.impl.factory; -import java.net.URL; -import java.util.Map; - -import org.neo4j.graphdb.DatabaseShutdownException; import org.neo4j.graphdb.DependencyResolver; import org.neo4j.graphdb.NotInTransactionException; import org.neo4j.graphdb.Result; import org.neo4j.graphdb.event.KernelEventHandler; import org.neo4j.graphdb.event.TransactionEventHandler; import org.neo4j.graphdb.security.URLAccessValidationError; -import org.neo4j.kernel.AvailabilityGuard; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.impl.api.AutoIndexing; +import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.query.QueryExecutionKernelException; import org.neo4j.kernel.impl.query.QuerySession; import org.neo4j.kernel.impl.store.StoreId; import org.neo4j.kernel.lifecycle.LifecycleException; import org.neo4j.logging.Logger; +import java.net.URL; +import java.util.Map; + /** * This implements the backend for the "classic" Core API - meaning the surface-layer-of-the-database, thread bound API. It's a thin veneer to wire the * various components the kernel and related utilities expose in a way that {@link GraphDatabaseFacade} likes. @@ -50,14 +49,14 @@ class ClassicCoreSPI implements GraphDatabaseFacade.SPI private final PlatformModule platform; private final DataSourceModule dataSource; private final Logger msgLog; - private final EditionModule edition; + private final CoreAPIAvailabilityGuard availability; - public ClassicCoreSPI( PlatformModule platform, DataSourceModule dataSource, Logger msgLog, EditionModule edition ) + public ClassicCoreSPI(PlatformModule platform, DataSourceModule dataSource, Logger msgLog, CoreAPIAvailabilityGuard availability ) { this.platform = platform; this.dataSource = dataSource; this.msgLog = msgLog; - this.edition = edition; + this.availability = availability; } @Override @@ -71,7 +70,7 @@ public Result executeQuery( String query, Map parameters, QuerySe { try { - assertDatabaseAvailable(); + availability.assertDatabaseAvailable(); return dataSource.queryExecutor.get().executeQuery( query, parameters, querySession ); } catch ( QueryExecutionKernelException e ) @@ -161,7 +160,7 @@ public KernelTransaction beginTransaction() { try { - assertDatabaseAvailable(); + availability.assertDatabaseAvailable(); KernelTransaction kernelTx = dataSource.kernelAPI.get().newTransaction(); kernelTx.registerCloseListener( (s) -> dataSource.threadToTransactionBridge.unbindTransactionFromCurrentThread() ); dataSource.threadToTransactionBridge.bindTransactionToCurrentThread( kernelTx ); @@ -176,7 +175,7 @@ public KernelTransaction beginTransaction() @Override public KernelTransaction currentTransaction() { - assertDatabaseAvailable(); + availability.assertDatabaseAvailable(); KernelTransaction tx = dataSource.threadToTransactionBridge.getKernelTransactionBoundToThisThread( false ); if( tx == null ) { @@ -196,20 +195,4 @@ public Statement currentStatement() { return dataSource.threadToTransactionBridge.get(); } - - private void assertDatabaseAvailable() - { - try - { - platform.availabilityGuard.await( edition.transactionStartTimeout ); - } - catch ( AvailabilityGuard.UnavailableException e ) - { - if( platform.availabilityGuard.isShutdown()) - { - throw new DatabaseShutdownException(); - } - throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage() ); - } - } } 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 7cac8101fe85a..e9cf9636162ec 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 @@ -45,6 +45,7 @@ import org.neo4j.kernel.impl.core.DelegatingRelationshipTypeTokenHolder; import org.neo4j.kernel.impl.core.ReadOnlyTokenCreator; import org.neo4j.kernel.impl.core.TokenCreator; +import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.locking.ResourceTypes; import org.neo4j.kernel.impl.locking.community.CommunityLockManger; @@ -105,6 +106,8 @@ public CommunityEditionModule( PlatformModule platformModule ) constraintSemantics = createSchemaRuleVerifier(); + coreAPIAvailabilityGuard = new CoreAPIAvailabilityGuard( platformModule.availabilityGuard, transactionStartTimeout ); + registerRecovery( platformModule.databaseInfo, life, dependencies ); publishEditionInfo( dependencies.resolveDependency( UsageData.class ), platformModule.databaseInfo, config ); 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 24a2e91bf6bff..c1bad368ff1bf 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 @@ -29,6 +29,7 @@ import org.neo4j.kernel.impl.core.LabelTokenHolder; import org.neo4j.kernel.impl.core.PropertyKeyTokenHolder; import org.neo4j.kernel.impl.core.RelationshipTypeTokenHolder; +import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.Configuration; import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; @@ -65,6 +66,8 @@ public abstract class EditionModule public ConstraintSemantics constraintSemantics; + public CoreAPIAvailabilityGuard coreAPIAvailabilityGuard; + protected void doAfterRecoveryAndStartup( DatabaseInfo databaseInfo, DependencyResolver dependencyResolver) { DiagnosticsManager diagnosticsManager = dependencyResolver.resolveDependency( DiagnosticsManager.class ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacadeFactory.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacadeFactory.java index fd2efc71400c4..ecf6dad4537cc 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacadeFactory.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/GraphDatabaseFacadeFactory.java @@ -29,6 +29,7 @@ import org.neo4j.kernel.AvailabilityGuard; import org.neo4j.kernel.configuration.Settings; import org.neo4j.kernel.extension.KernelExtensionFactory; +import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.query.QueryEngineProvider; import org.neo4j.kernel.monitoring.Monitors; import org.neo4j.logging.LogProvider; @@ -126,9 +127,10 @@ public GraphDatabaseFacade newFacade( File storeDir, Map params, EditionModule edition = createEdition( platform ); final DataSourceModule dataSource = createDataSource( dependencies, platform, edition ); Logger msgLog = platform.logging.getInternalLog( getClass() ).infoLogger(); + CoreAPIAvailabilityGuard coreAPIAvailabilityGuard = edition.coreAPIAvailabilityGuard; // Start it - graphDatabaseFacade.init( platform.config, new ClassicCoreSPI( platform, dataSource, msgLog, edition ) ); + graphDatabaseFacade.init( platform.config, new ClassicCoreSPI( platform, dataSource, msgLog, coreAPIAvailabilityGuard ) ); Throwable error = null; try diff --git a/community/kernel/src/test/java/org/neo4j/kernel/GraphDatabaseFacadeFactoryTest.java b/community/kernel/src/test/java/org/neo4j/kernel/GraphDatabaseFacadeFactoryTest.java index ccb798da7054b..71fab4b78b357 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/GraphDatabaseFacadeFactoryTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/GraphDatabaseFacadeFactoryTest.java @@ -22,6 +22,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -143,7 +144,7 @@ public LifeSupport createLife() @Override protected EditionModule createEdition( PlatformModule platformModule ) { - return null; + return Mockito.mock( EditionModule.class, Mockito.RETURNS_DEEP_STUBS ); } @Override diff --git a/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/edge/EnterpriseEdgeEditionModule.java b/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/edge/EnterpriseEdgeEditionModule.java index b0e74e6e01b62..845fb86d2d97a 100644 --- a/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/edge/EnterpriseEdgeEditionModule.java +++ b/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/edge/EnterpriseEdgeEditionModule.java @@ -60,6 +60,7 @@ import org.neo4j.kernel.impl.core.DelegatingPropertyKeyTokenHolder; import org.neo4j.kernel.impl.core.DelegatingRelationshipTypeTokenHolder; import org.neo4j.kernel.impl.core.ReadOnlyTokenCreator; +import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.factory.DatabaseInfo; import org.neo4j.kernel.impl.factory.EditionModule; import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; @@ -129,6 +130,8 @@ public void assertSchemaWritesAllowed() throws InvalidTransactionTypeKernelExcep constraintSemantics = new StandardConstraintSemantics(); + coreAPIAvailabilityGuard = new CoreAPIAvailabilityGuard( platformModule.availabilityGuard, transactionStartTimeout ); + registerRecovery( platformModule.databaseInfo, life, dependencies ); publishEditionInfo( dependencies.resolveDependency( UsageData.class ), platformModule.databaseInfo, config ); 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 ba5895e784608..e459943250e5c 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 @@ -126,6 +126,7 @@ import org.neo4j.kernel.impl.core.LastTxIdGetter; import org.neo4j.kernel.impl.core.ReadOnlyTokenCreator; import org.neo4j.kernel.impl.core.TokenCreator; +import org.neo4j.kernel.impl.coreapi.CoreAPIAvailabilityGuard; import org.neo4j.kernel.impl.enterprise.EnterpriseConstraintSemantics; import org.neo4j.kernel.impl.enterprise.EnterpriseEditionModule; import org.neo4j.kernel.impl.factory.CommunityEditionModule; @@ -492,6 +493,8 @@ public void elected( String role, InstanceId instanceId, URI electedMember ) constraintSemantics = new EnterpriseConstraintSemantics(); + coreAPIAvailabilityGuard = new CoreAPIAvailabilityGuard( platformModule.availabilityGuard, transactionStartTimeout ); + registerRecovery( platformModule.databaseInfo, dependencies, logging ); UsageData usageData = dependencies.resolveDependency( UsageData.class ); diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/api/ConstraintHaIT.java b/enterprise/ha/src/test/java/org/neo4j/kernel/api/ConstraintHaIT.java index 302beac9cc009..6788cc1415c0d 100644 --- a/enterprise/ha/src/test/java/org/neo4j/kernel/api/ConstraintHaIT.java +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/api/ConstraintHaIT.java @@ -19,28 +19,18 @@ */ package org.neo4j.kernel.api; +import java.io.File; + import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; - -import java.io.File; - -import org.neo4j.graphdb.DependencyResolver; -import org.neo4j.graphdb.DynamicLabel; -import org.neo4j.graphdb.DynamicRelationshipType; -import org.neo4j.graphdb.GraphDatabaseService; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.QueryExecutionException; -import org.neo4j.graphdb.Relationship; -import org.neo4j.graphdb.ResourceIterator; -import org.neo4j.graphdb.Transaction; +import org.neo4j.graphdb.*; import org.neo4j.graphdb.schema.ConstraintDefinition; import org.neo4j.graphdb.schema.ConstraintType; import org.neo4j.graphdb.schema.IndexDefinition; import org.neo4j.helpers.Exceptions; -import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.ConstraintHaIT.NodePropertyExistenceConstraintHaIT; import org.neo4j.kernel.api.ConstraintHaIT.RelationshipPropertyExistenceConstraintHaIT; import org.neo4j.kernel.api.ConstraintHaIT.UniquenessConstraintHaIT;