diff --git a/community/bolt/src/main/java/org/neo4j/bolt/BoltKernelExtension.java b/community/bolt/src/main/java/org/neo4j/bolt/BoltKernelExtension.java index 46e4c8c7cc828..34349fb6b11e3 100644 --- a/community/bolt/src/main/java/org/neo4j/bolt/BoltKernelExtension.java +++ b/community/bolt/src/main/java/org/neo4j/bolt/BoltKernelExtension.java @@ -19,6 +19,11 @@ */ package org.neo4j.bolt; +import io.netty.channel.Channel; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import org.bouncycastle.operator.OperatorCreationException; + import java.io.File; import java.io.IOException; import java.security.GeneralSecurityException; @@ -27,11 +32,6 @@ import java.util.function.BiFunction; import java.util.function.Function; -import io.netty.channel.Channel; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import org.bouncycastle.operator.OperatorCreationException; - import org.neo4j.bolt.security.ssl.Certificates; import org.neo4j.bolt.security.ssl.KeyStoreFactory; import org.neo4j.bolt.security.ssl.KeyStoreInformation; @@ -90,8 +90,7 @@ public static class Settings @Description( "Set the encryption level for Neo4j Bolt protocol ports" ) public static final Setting tls_level = - setting( "tls.level", options( EncryptionLevel.class ), - OPTIONAL.name() ); + setting( "tls.level", options( EncryptionLevel.class ), OPTIONAL.name() ); @Description( "Host and port for the Neo4j Bolt Protocol" ) public static final Setting socket_address = diff --git a/community/bolt/src/main/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachine.java b/community/bolt/src/main/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachine.java index 853fd9583dafd..9da301351ca72 100644 --- a/community/bolt/src/main/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachine.java +++ b/community/bolt/src/main/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachine.java @@ -26,7 +26,8 @@ import org.neo4j.bolt.v1.runtime.spi.RecordStream; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Transaction; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.logging.LogService; @@ -80,7 +81,8 @@ public State beginTransaction( SessionStateMachine ctx ) { assert ctx.currentTransaction == null; ctx.implicitTransaction = false; - ctx.currentTransaction = ctx.db.beginTx(); + ctx.db.beginTx(); + ctx.currentTransaction = ctx.txBridge.getKernelTransactionBoundToThisThread( false ); return IN_TRANSACTION; } @@ -104,7 +106,8 @@ public State beginImplicitTransaction( SessionStateMachine ctx ) { assert ctx.currentTransaction == null; ctx.implicitTransaction = true; - ctx.currentTransaction = ctx.db.beginTx(); + ctx.db.beginTx(); + ctx.currentTransaction = ctx.txBridge.getKernelTransactionBoundToThisThread( false ); return IN_TRANSACTION; } @@ -153,7 +156,7 @@ public State rollbackTransaction( SessionStateMachine ctx ) { try { - Transaction tx = ctx.currentTransaction; + KernelTransaction tx = ctx.currentTransaction; ctx.currentTransaction = null; tx.failure(); @@ -427,7 +430,7 @@ public String[] fieldNames() private RecordStream currentResult; /** The current transaction, if present */ - private Transaction currentTransaction; + private KernelTransaction currentTransaction; /** Callback poised to receive the next response */ private Callback currentCallback; @@ -584,7 +587,7 @@ private void before( Object attachment, Callback cb ) { if ( hasTransaction() ) { - txBridge.bindTransactionToCurrentThread( (TopLevelTransaction) currentTransaction ); + txBridge.bindTransactionToCurrentThread( currentTransaction ); } assert this.currentCallback == null; assert this.currentAttachment == null; diff --git a/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachineTest.java b/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachineTest.java index 88b4d3d5338be..bd4399b1b6194 100644 --- a/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachineTest.java +++ b/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/SessionStateMachineTest.java @@ -31,7 +31,8 @@ import org.neo4j.bolt.v1.runtime.spi.StatementRunner; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Transaction; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.logging.NullLogService; @@ -53,6 +54,7 @@ public class SessionStateMachineTest private final GraphDatabaseService db = mock( GraphDatabaseService.class ); private final ThreadToStatementContextBridge txBridge = mock( ThreadToStatementContextBridge.class ); private final Transaction tx = mock( TopLevelTransaction.class ); + private final KernelTransaction ktx = mock( KernelTransaction.class ); private final UsageData usageData = new UsageData(); private final StatementRunner runner = mock( StatementRunner.class ); private final SessionStateMachine machine = new SessionStateMachine( @@ -82,8 +84,8 @@ public void shouldRollbackOpenTransactionOnRollbackInducingError() throws Throwa // Then assertThat( machine.state(), CoreMatchers.equalTo( SessionStateMachine.State.ERROR ) ); - verify( tx ).failure(); - verify( tx ).close(); + verify( ktx ).failure(); + verify( ktx ).close(); // And when machine.reset( null, Session.Callback.NO_OP ); @@ -109,8 +111,8 @@ public void shouldNotLeaveTransactionOpenOnClientErrors() throws Throwable // Then assertThat( machine.state(), equalTo( SessionStateMachine.State.ERROR ) ); - verify(tx).failure(); - verify(tx).close(); + verify( ktx ).failure(); + verify( ktx ).close(); // And when machine.reset( null, Session.Callback.NO_OP ); @@ -130,7 +132,7 @@ public void shouldStopRunningTxOnHalt() throws Throwable // Then assertThat( machine.state(), CoreMatchers.equalTo( SessionStateMachine.State.STOPPED ) ); verify( db ).beginTx(); - verify( tx ).close(); + verify( ktx ).close(); } @Test @@ -236,6 +238,7 @@ public void shouldResetToIdleOnError() throws Throwable public void setup() { when( db.beginTx() ).thenReturn( tx ); + when( txBridge.getKernelTransactionBoundToThisThread( false ) ).thenReturn( ktx ); } static class TestCallback extends Session.Callback.Adapter diff --git a/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/StateMachineErrorTest.java b/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/StateMachineErrorTest.java index 69544bc724b6e..1d3990f84424d 100644 --- a/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/StateMachineErrorTest.java +++ b/community/bolt/src/test/java/org/neo4j/bolt/v1/runtime/internal/StateMachineErrorTest.java @@ -36,7 +36,7 @@ import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.TransactionFailureException; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.logging.NullLogService; diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/ExecutionEngine.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/ExecutionEngine.scala index b36cab558d108..af6ec1c7c0159 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/ExecutionEngine.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/ExecutionEngine.scala @@ -30,6 +30,7 @@ import org.neo4j.cypher.internal.{CypherCompiler, _} import org.neo4j.graphdb.GraphDatabaseService import org.neo4j.graphdb.config.Setting import org.neo4j.graphdb.factory.GraphDatabaseSettings +import org.neo4j.kernel.configuration.Config import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge import org.neo4j.kernel.impl.factory.GraphDatabaseFacade import org.neo4j.kernel.impl.query.{QueryEngineProvider, QueryExecutionMonitor, QuerySession} @@ -251,7 +252,9 @@ class ExecutionEngine(graph: GraphDatabaseService, logProvider: LogProvider = Nu } optGraphAs[GraphDatabaseFacade] .andThen(g => { - Option(g.platformModule.config.get(setting)) + // TODO: Config should be passed in as a dependency to Cypher, not pulled out of casted interfaces + val config: Config = g.getDependencyResolver.resolveDependency(classOf[Config]) + Option(config.get(setting)) }) .andThen(_.getOrElse(defaultValue)) .applyOrElse(graph, (_: GraphDatabaseService) => defaultValue) diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CypherCompiler.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CypherCompiler.scala index 50017588e2606..c9f9ba58ae529 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CypherCompiler.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/CypherCompiler.scala @@ -25,7 +25,9 @@ import org.neo4j.cypher.{InvalidArgumentException, SyntaxException, _} import org.neo4j.graphdb.GraphDatabaseService import org.neo4j.graphdb.factory.GraphDatabaseSettings import org.neo4j.helpers.Clock +import org.neo4j.kernel.GraphDatabaseAPI import org.neo4j.kernel.api.KernelAPI +import org.neo4j.kernel.configuration.Config import org.neo4j.kernel.impl.factory.GraphDatabaseFacade import org.neo4j.kernel.monitoring.{Monitors => KernelMonitors} import org.neo4j.logging.{Log, LogProvider} @@ -132,29 +134,30 @@ class CypherCompiler(graph: GraphDatabaseService, } } - private def getQueryCacheSize : Int = - optGraphAs[GraphDatabaseFacade] - .andThen(_.platformModule.config.get(GraphDatabaseSettings.query_cache_size).intValue()) - .applyOrElse(graph, (_: GraphDatabaseService) => DEFAULT_QUERY_CACHE_SIZE) + private def getQueryCacheSize : Int = { + val setting: (Config) => Int = config => config.get(GraphDatabaseSettings.query_cache_size).intValue() + getSetting(graph, setting, DEFAULT_QUERY_CACHE_SIZE) + } - private def getStatisticsDivergenceThreshold : Double = - optGraphAs[GraphDatabaseFacade] - .andThen(_.platformModule.config.get(GraphDatabaseSettings.query_statistics_divergence_threshold).doubleValue()) - .applyOrElse(graph, (_: GraphDatabaseService) => DEFAULT_STATISTICS_DIVERGENCE_THRESHOLD) + private def getStatisticsDivergenceThreshold : Double = { + val setting: (Config) => Double = config => config.get(GraphDatabaseSettings.query_statistics_divergence_threshold).doubleValue() + getSetting(graph, setting, DEFAULT_STATISTICS_DIVERGENCE_THRESHOLD) + } - private def getNonIndexedLabelWarningThreshold: Long = - optGraphAs[GraphDatabaseFacade] - .andThen(_.platformModule.config.get(GraphDatabaseSettings.query_non_indexed_label_warning_threshold).longValue()) - .applyOrElse(graph, (_: GraphDatabaseService) => DEFAULT_NON_INDEXED_LABEL_WARNING_THRESHOLD) + private def getNonIndexedLabelWarningThreshold: Long = { + val setting: (Config) => Long = config => config.get(GraphDatabaseSettings.query_non_indexed_label_warning_threshold).longValue() + getSetting(graph, setting, DEFAULT_NON_INDEXED_LABEL_WARNING_THRESHOLD) + } private def getMinimumTimeBeforeReplanning: Long = { - optGraphAs[GraphDatabaseFacade] - .andThen(_.platformModule.config.get(GraphDatabaseSettings.cypher_min_replan_interval).longValue()) - .applyOrElse(graph, (_: GraphDatabaseService) => DEFAULT_QUERY_PLAN_TTL) + val setting: (Config) => Long = config => config.get(GraphDatabaseSettings.cypher_min_replan_interval).longValue() + getSetting(graph, setting, DEFAULT_QUERY_PLAN_TTL) } - private def optGraphAs[T <: GraphDatabaseService : Manifest]: PartialFunction[GraphDatabaseService, T] = { - case (db: T) => db + private def getSetting[A](gds: GraphDatabaseService, configLookup: Config => A, default: A): A = gds match { + // TODO: Cypher should not be pulling out components from casted interfaces, it should ask for Config as a dep + case (gdbApi:GraphDatabaseAPI) => configLookup(gdbApi.getDependencyResolver.resolveDependency(classOf[Config])) + case _ => default } } diff --git a/community/cypher/cypher/src/test/java/org/neo4j/cypher/javacompat/ExecutionResultTest.java b/community/cypher/cypher/src/test/java/org/neo4j/cypher/javacompat/ExecutionResultTest.java index 56e0100cf88ce..04c667fb8f268 100644 --- a/community/cypher/cypher/src/test/java/org/neo4j/cypher/javacompat/ExecutionResultTest.java +++ b/community/cypher/cypher/src/test/java/org/neo4j/cypher/javacompat/ExecutionResultTest.java @@ -33,7 +33,9 @@ import org.neo4j.graphdb.Result; import org.neo4j.graphdb.Transaction; import org.neo4j.helpers.collection.Iterables; +import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.test.ImpermanentDatabaseRule; import static org.hamcrest.MatcherAssert.assertThat; @@ -226,11 +228,11 @@ private void createNode() } } - private org.neo4j.kernel.TopLevelTransaction activeTransaction() + private TopLevelTransaction activeTransaction() { ThreadToStatementContextBridge bridge = db.getDependencyResolver().resolveDependency( ThreadToStatementContextBridge.class ); - return bridge.getTopLevelTransactionBoundToThisThread( false ); + KernelTransaction kernelTransaction = bridge.getTopLevelTransactionBoundToThisThread( false ); + return kernelTransaction == null ? null : new TopLevelTransaction( kernelTransaction, null ); } - } diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala index f3e74ac695766..7fd399b30de7b 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala @@ -30,8 +30,11 @@ import org.neo4j.graphdb._ import org.neo4j.graphdb.config.Setting import org.neo4j.graphdb.factory.GraphDatabaseSettings import org.neo4j.io.fs.FileUtils -import org.neo4j.kernel.{NeoStoreDataSource, TopLevelTransaction} +import org.neo4j.kernel.{NeoStoreDataSource} import org.neo4j.test.TestGraphDatabaseFactory +import org.neo4j.kernel.NeoStoreDataSource +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction +import org.neo4j.test.{ImpermanentGraphDatabase, TestGraphDatabaseFactory} import scala.collection.JavaConverters._ import scala.collection.mutable diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_0/LazyTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_0/LazyTest.scala index cae8501b4c8dc..5e29ce0ec32b3 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_0/LazyTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiler/v3_0/LazyTest.scala @@ -42,6 +42,7 @@ import org.neo4j.graphdb._ import org.neo4j.helpers.collection.Iterables.asResourceIterable import org.neo4j.kernel.GraphDatabaseAPI import org.neo4j.kernel.api.{ReadOperations, Statement} +import org.neo4j.kernel.configuration.Config import org.neo4j.kernel.impl.api.OperationsFacade import org.neo4j.kernel.impl.core.{NodeManager, NodeProxy, ThreadToStatementContextBridge} import org.neo4j.kernel.impl.transaction.log.TransactionIdStore @@ -190,6 +191,7 @@ class LazyTest extends ExecutionEngineFunSuite { val dependencies = mock[DependencyResolver] val bridge = mock[ThreadToStatementContextBridge] val monitors = new org.neo4j.kernel.monitoring.Monitors() + val config = new Config() val fakeDataStatement = mock[OperationsFacade] val fakeReadStatement = mock[ReadOperations] @@ -208,6 +210,7 @@ class LazyTest extends ExecutionEngineFunSuite { when(dependencies.resolveDependency(classOf[NodeManager])).thenReturn(nodeManager) when(dependencies.resolveDependency(classOf[TransactionIdStore])).thenReturn(idStore) when(dependencies.resolveDependency(classOf[org.neo4j.kernel.monitoring.Monitors])).thenReturn(monitors) + when(dependencies.resolveDependency(classOf[Config])).thenReturn(config) when(fakeGraph.beginTx()).thenReturn(tx) val n0 = mock[Node] val n1 = mock[Node] diff --git a/community/graph-algo/src/main/java/org/neo4j/graphalgo/impl/path/ShortestPath.java b/community/graph-algo/src/main/java/org/neo4j/graphalgo/impl/path/ShortestPath.java index 1cac6640e2b5a..03291b0ca37b1 100644 --- a/community/graph-algo/src/main/java/org/neo4j/graphalgo/impl/path/ShortestPath.java +++ b/community/graph-algo/src/main/java/org/neo4j/graphalgo/impl/path/ShortestPath.java @@ -129,7 +129,7 @@ private void resolveMonitor( Node node ) GraphDatabaseService service = node.getGraphDatabase(); if ( service instanceof GraphDatabaseFacade ) { - Monitors monitors = ((GraphDatabaseFacade) service).platformModule.monitors; + Monitors monitors = ((GraphDatabaseFacade) service).getDependencyResolver().resolveDependency( Monitors.class ); dataMonitor = monitors.newMonitor( DataMonitor.class ); } } diff --git a/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java b/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java index 6627a29b8e063..58ffff6d0f079 100644 --- a/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java +++ b/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java @@ -47,6 +47,7 @@ import static org.neo4j.kernel.configuration.Settings.NO_DEFAULT; import static org.neo4j.kernel.configuration.Settings.PATH; import static org.neo4j.kernel.configuration.Settings.STRING; +import static org.neo4j.kernel.configuration.Settings.STRING_LIST; import static org.neo4j.kernel.configuration.Settings.TRUE; import static org.neo4j.kernel.configuration.Settings.illegalValueMessage; import static org.neo4j.kernel.configuration.Settings.list; @@ -200,7 +201,7 @@ public abstract class GraphDatabaseSettings "only.") @Internal @Deprecated - public static final Setting node_keys_indexable = setting("node_keys_indexable", STRING, NO_DEFAULT, illegalValueMessage( "must be a comma-separated list of keys to be indexed", matches( ANY ) ) ); + public static final Setting> node_keys_indexable = setting("node_keys_indexable", STRING_LIST, "" ); @Description("Controls the auto indexing feature for relationships. Setting it to `false` shuts it down, " + "while `true` enables it by default for properties " @@ -214,7 +215,7 @@ public abstract class GraphDatabaseSettings "_relationships_ only." ) @Internal @Deprecated - public static final Setting relationship_keys_indexable = setting("relationship_keys_indexable", STRING, NO_DEFAULT, illegalValueMessage( "must be a comma-separated list of keys to be indexed", matches( ANY ) ) ); + public static final Setting> relationship_keys_indexable = setting("relationship_keys_indexable", STRING_LIST, "" ); // Index sampling @Description("Enable or disable background index sampling") diff --git a/community/kernel/src/main/java/org/neo4j/kernel/AvailabilityGuard.java b/community/kernel/src/main/java/org/neo4j/kernel/AvailabilityGuard.java index 41214f499b27e..750c9a5f38af8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/AvailabilityGuard.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/AvailabilityGuard.java @@ -206,7 +206,7 @@ public void notify( AvailabilityListener listener ) } } - private static enum Availability + private enum Availability { AVAILABLE, UNAVAILABLE, @@ -223,6 +223,15 @@ public boolean isAvailable() return availability() == Availability.AVAILABLE; } + + /** + * Check if the database has been shut down. + */ + public boolean isShutdown() + { + return availability() == Availability.SHUTDOWN; + } + /** * Check if the database is available for transactions to use. * diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java index 8ae9c10f78f2d..e46c36a75ff2e 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java @@ -29,11 +29,8 @@ import org.neo4j.graphdb.RelationshipType; import org.neo4j.kernel.PropertyTracker; import org.neo4j.kernel.api.Statement; -import org.neo4j.kernel.api.exceptions.EntityNotFoundException; import org.neo4j.kernel.lifecycle.LifecycleAdapter; -import static java.lang.System.currentTimeMillis; - public class NodeManager extends LifecycleAdapter implements EntityFactory { private final ThreadToStatementContextBridge threadToTransactionBridge; @@ -43,7 +40,6 @@ public class NodeManager extends LifecycleAdapter implements EntityFactory private final List> nodePropertyTrackers; private final List> relationshipPropertyTrackers; - private long epoch; private final GraphDatabaseService graphDatabaseService; private final RelationshipTypeTokenHolder relationshipTypeTokenHolder; @@ -63,17 +59,6 @@ public NodeManager( GraphDatabaseService graphDatabaseService, this.relationshipPropertyTrackers = new CopyOnWriteArrayList<>(); } - @Override - public void init() - { // Nothing to initialize - } - - @Override - public void start() throws Throwable - { - epoch = currentTimeMillis(); - } - @Override public NodeProxy newNodeProxyById( long id ) { @@ -87,21 +72,6 @@ public RelationshipProxy newRelationshipProxyById( long id ) return new RelationshipProxy( relationshipActions, id ); } - /** Returns a fully initialized proxy. */ - public RelationshipProxy newRelationshipProxy( long id ) - { - try ( Statement statement = threadToTransactionBridge.get() ) - { - RelationshipProxy proxy = new RelationshipProxy( relationshipActions, id ); - statement.readOperations().relationshipVisit( id, proxy ); - return proxy; - } - catch ( EntityNotFoundException e ) - { - throw new NotFoundException( e ); - } - } - /** Returns a fully initialized proxy. */ public RelationshipProxy newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId ) { @@ -171,18 +141,6 @@ public void failTransaction() threadToTransactionBridge.getKernelTransactionBoundToThisThread( true ).failure(); } - @Override - public Relationship lazyRelationshipProxy( long id ) - { - return NodeManager.this.newRelationshipProxyById( id ); - } - - @Override - public Relationship newRelationshipProxy( long id ) - { - return NodeManager.this.newRelationshipProxy( id ); - } - @Override public Relationship newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java index 82cc7a2fc5a4b..230c5fd3f0cdf 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/NodeProxy.java @@ -78,10 +78,6 @@ public interface NodeActions void failTransaction(); - Relationship lazyRelationshipProxy( long id ); - - Relationship newRelationshipProxy( long id ); - Relationship newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java index a7e80df7c6aa2..dbc77a8850001 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipProxy.java @@ -28,9 +28,11 @@ import org.neo4j.collection.primitive.PrimitiveIntIterator; import org.neo4j.cursor.Cursor; import org.neo4j.graphdb.ConstraintViolationException; +import org.neo4j.graphdb.DatabaseShutdownException; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.NotFoundException; +import org.neo4j.graphdb.NotInTransactionException; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; import org.neo4j.kernel.api.Statement; @@ -477,8 +479,18 @@ public int hashCode() @Override public String toString() { - return format( "(%d)-[%s,%d]->(%d)", - sourceId(), actions.getRelationshipTypeById( typeId() ).name(), getId(), targetId() ); + String relType; + try + { + relType = actions.getRelationshipTypeById( typeId() ).name(); + } + catch( NotInTransactionException | DatabaseShutdownException e ) + { + // We don't keep the rel-name lookup if the database is shut down. However, failing on toString would be uncomfortably evil, so we fall + // back to noting the relationship type id. + relType = "RELTYPE(" + typeId() + ")"; + } + return format( "(%d)-[%s,%d]->(%d)", sourceId(), relType, getId(), targetId() ); } private void assertInUnterminatedTransaction() diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/ThreadToStatementContextBridge.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/ThreadToStatementContextBridge.java index c9dddb475029d..dc14bcb9e8d57 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/core/ThreadToStatementContextBridge.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/core/ThreadToStatementContextBridge.java @@ -24,7 +24,6 @@ import org.neo4j.graphdb.DatabaseShutdownException; import org.neo4j.graphdb.NotInTransactionException; import org.neo4j.graphdb.TransactionTerminatedException; -import org.neo4j.kernel.TopLevelTransaction; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.lifecycle.LifecycleAdapter; @@ -35,7 +34,7 @@ */ public class ThreadToStatementContextBridge extends LifecycleAdapter implements Supplier { - private final ThreadLocal threadToTransactionMap = new ThreadLocal<>(); + private final ThreadLocal threadToTransactionMap = new ThreadLocal<>(); private boolean isShutdown; public boolean hasTransaction() @@ -44,7 +43,7 @@ public boolean hasTransaction() return threadToTransactionMap.get() != null; } - public void bindTransactionToCurrentThread( TopLevelTransaction transaction ) + public void bindTransactionToCurrentThread( KernelTransaction transaction ) { if ( threadToTransactionMap.get() != null ) { @@ -65,13 +64,13 @@ public Statement get() return getKernelTransactionBoundToThisThread( true ).acquireStatement(); } - private void assertInUnterminatedTransaction( TopLevelTransaction transaction ) + private void assertInUnterminatedTransaction( KernelTransaction transaction ) { if ( transaction == null ) { throw new NotInTransactionException(); } - if ( transaction.getTransaction().shouldBeTerminated() ) + if ( transaction.shouldBeTerminated() ) { throw new TransactionTerminatedException(); } @@ -97,9 +96,9 @@ private void checkIfShutdown() } } - public TopLevelTransaction getTopLevelTransactionBoundToThisThread( boolean strict ) + public KernelTransaction getTopLevelTransactionBoundToThisThread( boolean strict ) { - TopLevelTransaction transaction = threadToTransactionMap.get(); + KernelTransaction transaction = threadToTransactionMap.get(); if ( strict ) { assertInUnterminatedTransaction( transaction ); @@ -109,7 +108,7 @@ public TopLevelTransaction getTopLevelTransactionBoundToThisThread( boolean stri public KernelTransaction getKernelTransactionBoundToThisThread( boolean strict ) { - TopLevelTransaction tx = getTopLevelTransactionBoundToThisThread( strict ); - return tx != null ? tx.getTransaction() : null; + checkIfShutdown(); + return getTopLevelTransactionBoundToThisThread( strict ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/AbstractAutoIndexerImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/AbstractAutoIndexerImpl.java index 28751f42f0bb8..61d33f75423c5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/AbstractAutoIndexerImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/AbstractAutoIndexerImpl.java @@ -22,7 +22,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; -import java.util.StringTokenizer; + import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.AutoIndexer; @@ -30,7 +30,6 @@ import org.neo4j.graphdb.index.IndexHits; import org.neo4j.graphdb.index.ReadableIndex; import org.neo4j.kernel.PropertyTracker; -import org.neo4j.kernel.lifecycle.Lifecycle; /** * Default implementation of the AutoIndexer, binding to the beforeCommit hook @@ -39,9 +38,9 @@ * @param The database primitive type auto indexed/** */ abstract class AbstractAutoIndexerImpl implements - PropertyTracker, AutoIndexer, Lifecycle + PropertyTracker, AutoIndexer { - protected final Set propertyKeysToInclude = new HashSet(); + protected final Set propertyKeysToInclude = new HashSet<>(); private volatile boolean enabled; @@ -124,27 +123,6 @@ public Set getAutoIndexedProperties() */ protected abstract Index getIndexInternal(); - protected Set parseConfigList(String list) - { - if ( list == null ) - { - return Collections.emptySet(); - } - - Set toReturn = new HashSet(); - StringTokenizer tokenizer = new StringTokenizer(list, "," ); - String currentToken; - while ( tokenizer.hasMoreTokens() ) - { - currentToken = tokenizer.nextToken(); - if ( ( currentToken = currentToken.trim() ).length() > 0 ) - { - toReturn.add( currentToken ); - } - } - return toReturn; - } - /** * Simple implementation of the AutoIndex interface, as a wrapper around a * normal Index that exposes the read-only operations. diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexManagerImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexManagerImpl.java index 179918120f6c3..578cb804985b8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexManagerImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexManagerImpl.java @@ -20,6 +20,7 @@ package org.neo4j.kernel.impl.coreapi; import java.util.Map; +import java.util.function.Supplier; import org.neo4j.graphdb.ConstraintViolationException; import org.neo4j.graphdb.Node; @@ -34,17 +35,15 @@ import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.exceptions.InvalidTransactionTypeKernelException; import org.neo4j.kernel.api.exceptions.legacyindex.LegacyIndexNotFoundKernelException; -import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; public class IndexManagerImpl implements IndexManager { - - private final ThreadToStatementContextBridge transactionBridge; + private final Supplier transactionBridge; private final IndexProvider provider; private final AutoIndexer nodeAutoIndexer; private final RelationshipAutoIndexer relAutoIndexer; - public IndexManagerImpl( ThreadToStatementContextBridge bridge, + public IndexManagerImpl( Supplier bridge, IndexProvider provider, AutoIndexer nodeAutoIndexer, RelationshipAutoIndexer relAutoIndexer ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexProviderImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexProviderImpl.java index e2561673449a4..0719bad04b226 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexProviderImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/IndexProviderImpl.java @@ -20,23 +20,24 @@ package org.neo4j.kernel.impl.coreapi; import java.util.Map; +import java.util.function.Supplier; import org.neo4j.graphdb.ConstraintViolationException; +import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.index.RelationshipIndex; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.exceptions.InvalidTransactionTypeKernelException; -import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; public class IndexProviderImpl implements IndexProvider { - private final LegacyIndexProxy.Lookup lookup; - private final ThreadToStatementContextBridge transactionBridge; + private final Supplier transactionBridge; + private final GraphDatabaseService gds; - public IndexProviderImpl( LegacyIndexProxy.Lookup lookup, ThreadToStatementContextBridge transactionBridge ) + public IndexProviderImpl( GraphDatabaseService gds, Supplier transactionBridge ) { - this.lookup = lookup; + this.gds = gds; this.transactionBridge = transactionBridge; } @@ -49,7 +50,7 @@ public Index getOrCreateNodeIndex( String indexName, Map cu // and the index will itself share the same IndexConfigStore as us and pick up and use // that. We should pass along config somehow with calls. statement.dataWriteOperations().nodeLegacyIndexCreateLazily( indexName, customConfiguration ); - return new LegacyIndexProxy<>( indexName, LegacyIndexProxy.Type.NODE, lookup, transactionBridge ); + return new LegacyIndexProxy<>( indexName, LegacyIndexProxy.Type.NODE, gds, transactionBridge ); } catch ( InvalidTransactionTypeKernelException e ) { @@ -67,7 +68,7 @@ public RelationshipIndex getOrCreateRelationshipIndex( String indexName, Map implements Index { - public static enum Type + public enum Type { NODE { @@ -250,15 +250,15 @@ public interface Lookup protected final String name; protected final Type type; - protected final ThreadToStatementContextBridge statementContextBridge; - private final Lookup lookup; + protected final Supplier statementContextBridge; + private final GraphDatabaseService gds; - public LegacyIndexProxy( String name, Type type, Lookup lookup, - ThreadToStatementContextBridge statementContextBridge ) + public LegacyIndexProxy( String name, Type type, GraphDatabaseService gds, + Supplier statementContextBridge ) { this.name = name; this.type = type; - this.lookup = lookup; + this.gds = gds; this.statementContextBridge = statementContextBridge; } @@ -312,7 +312,7 @@ public float currentScore() @Override protected T fetchNextOrNull() { - statementContextBridge.assertInUnterminatedTransaction(); + statementContextBridge.get(); while ( ids.hasNext() ) { long id = ids.next(); @@ -341,7 +341,7 @@ protected T fetchNextOrNull() private T entityOf( long id ) { - return type.entity( id, lookup.getGraphDatabaseService() ); + return type.entity( id, gds ); } @Override @@ -379,7 +379,7 @@ public boolean isWriteable() @Override public GraphDatabaseService getGraphDatabase() { - return lookup.getGraphDatabaseService(); + return gds; } @Override diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/NodeAutoIndexerImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/NodeAutoIndexerImpl.java index 4c3e2e5487ba1..de1298e6bf844 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/NodeAutoIndexerImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/NodeAutoIndexerImpl.java @@ -19,12 +19,11 @@ */ package org.neo4j.kernel.impl.coreapi; +import java.util.Collection; + import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.config.Setting; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.graphdb.index.Index; -import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.impl.core.NodeManager; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; /** * Implementation of an AutoIndexer for Node primitives. It @@ -34,55 +33,23 @@ */ public class NodeAutoIndexerImpl extends AbstractAutoIndexerImpl { - public static abstract class Configuration - { - public static final Setting node_auto_indexing = GraphDatabaseSettings.node_auto_indexing; - public static final Setting node_keys_indexable = GraphDatabaseSettings.node_keys_indexable; - } - static final String NODE_AUTO_INDEX = "node_auto_index"; - private Config config; - private IndexProvider indexProvider; - private NodeManager nodeManager; + private final IndexProvider indexProvider; + private final GraphDatabaseFacade.SPI spi; - public NodeAutoIndexerImpl( Config config, IndexProvider indexProvider, NodeManager nodeManager ) + public NodeAutoIndexerImpl( boolean enabled, Collection propertiesToIndex, IndexProvider indexProvider, GraphDatabaseFacade.SPI spi ) { super(); - this.config = config; this.indexProvider = indexProvider; - this.nodeManager = nodeManager; - } - - @Override - public void init() - throws Throwable - { - } - - @Override - public void start() - { - setEnabled( config.get( Configuration.node_auto_indexing ) ); - propertyKeysToInclude.addAll( parseConfigList( config.get( Configuration.node_keys_indexable ) ) ); - } - - @Override - public void stop() - throws Throwable - { - } - - @Override - public void shutdown() - throws Throwable - { + this.spi = spi; + setEnabled( enabled ); + propertyKeysToInclude.addAll( propertiesToIndex ); } @Override protected Index getIndexInternal() { - return indexProvider.getOrCreateNodeIndex( - NODE_AUTO_INDEX, null ); + return indexProvider.getOrCreateNodeIndex( NODE_AUTO_INDEX, null ); } @Override @@ -91,13 +58,11 @@ public void setEnabled( boolean enabled ) super.setEnabled( enabled ); if ( enabled ) { - nodeManager.addNodePropertyTracker( - this ); + spi.addNodePropertyTracker( this ); } else { - nodeManager.removeNodePropertyTracker( - this ); + spi.removeNodePropertyTracker( this ); } } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/PlaceboTransaction.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/PlaceboTransaction.java similarity index 64% rename from community/kernel/src/main/java/org/neo4j/kernel/PlaceboTransaction.java rename to community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/PlaceboTransaction.java index 9d07229b5c433..b8b3854d50ca7 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/PlaceboTransaction.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/PlaceboTransaction.java @@ -17,36 +17,39 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.neo4j.kernel; +package org.neo4j.kernel.impl.coreapi; + +import java.util.function.Supplier; import org.neo4j.graphdb.Lock; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.Transaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.Statement; -/** - * @deprecated This will be moved to internal packages in the next major release. - */ -@Deprecated public class PlaceboTransaction implements Transaction { - private final TopLevelTransaction parentTransaction; + private final static PropertyContainerLocker locker = new PropertyContainerLocker(); + private final Supplier stmt; + private final Supplier currentTransaction; private boolean success; - public PlaceboTransaction( TopLevelTransaction parentTransaction ) + public PlaceboTransaction( Supplier currentTransaction, Supplier stmt ) { - this.parentTransaction = parentTransaction; + this.stmt = stmt; + this.currentTransaction = currentTransaction; } @Override public void terminate() { - parentTransaction.terminate(); + currentTransaction.get().markForTermination(); } @Override public void failure() { - parentTransaction.failure(); + currentTransaction.get().failure(); } @Override @@ -58,9 +61,9 @@ public void success() @Override public void close() { - if ( !success && !parentTransaction.failureCalled() ) + if ( !success ) { - parentTransaction.failure(); + currentTransaction.get().failure(); } } @@ -73,12 +76,12 @@ public void finish() @Override public Lock acquireWriteLock( PropertyContainer entity ) { - return parentTransaction.acquireWriteLock( entity ); + return locker.exclusiveLock( stmt, entity ); } @Override public Lock acquireReadLock( PropertyContainer entity ) { - return parentTransaction.acquireReadLock( entity ); + return locker.sharedLock( stmt, entity ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipAutoIndexerImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipAutoIndexerImpl.java index 2e029dce0d8f4..078e9da9edb1c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipAutoIndexerImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipAutoIndexerImpl.java @@ -19,65 +19,31 @@ */ package org.neo4j.kernel.impl.coreapi; +import java.util.Collection; + import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; -import org.neo4j.graphdb.config.Setting; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.graphdb.index.IndexHits; import org.neo4j.graphdb.index.ReadableRelationshipIndex; import org.neo4j.graphdb.index.RelationshipAutoIndexer; import org.neo4j.graphdb.index.RelationshipIndex; -import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.impl.core.NodeManager; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; public class RelationshipAutoIndexerImpl extends AbstractAutoIndexerImpl implements RelationshipAutoIndexer { - public static abstract class Configuration - { - public static final Setting relationship_auto_indexing = GraphDatabaseSettings - .relationship_auto_indexing; - public static final Setting relationship_keys_indexable = GraphDatabaseSettings - .relationship_keys_indexable; - } - static final String RELATIONSHIP_AUTO_INDEX = "relationship_auto_index"; - private Config config; private IndexProvider indexProvider; - private NodeManager nodeManager; + private GraphDatabaseFacade.SPI spi; - public RelationshipAutoIndexerImpl( Config config, IndexProvider indexProvider, - NodeManager nodeManager ) + public RelationshipAutoIndexerImpl( boolean enabled, Collection propertiesToIndex, IndexProvider indexProvider, + GraphDatabaseFacade.SPI spi ) { super(); - this.config = config; this.indexProvider = indexProvider; - this.nodeManager = nodeManager; - } - - @Override - public void init() - throws Throwable - { - } - - @Override - public void start() - { - setEnabled( config.get( Configuration.relationship_auto_indexing ) ); - propertyKeysToInclude.addAll( parseConfigList( config.get( Configuration.relationship_keys_indexable ) ) ); - } - - @Override - public void stop() - throws Throwable - { - } - - @Override - public void shutdown() - throws Throwable - { + this.spi = spi; + setEnabled( enabled ); + propertyKeysToInclude.addAll( propertiesToIndex ); } @Override @@ -99,13 +65,11 @@ public void setEnabled( boolean enabled ) super.setEnabled( enabled ); if ( enabled ) { - nodeManager.addRelationshipPropertyTracker( - this ); + spi.addRelationshipPropertyTracker( this ); } else { - nodeManager.removeRelationshipPropertyTracker( - this ); + spi.removeRelationshipPropertyTracker( this ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipLegacyIndexProxy.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipLegacyIndexProxy.java index d0de90eb5c30b..40e548ee6b494 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipLegacyIndexProxy.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/RelationshipLegacyIndexProxy.java @@ -19,6 +19,9 @@ */ package org.neo4j.kernel.impl.coreapi; +import java.util.function.Supplier; + +import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.NotFoundException; import org.neo4j.graphdb.Relationship; @@ -26,14 +29,13 @@ import org.neo4j.graphdb.index.RelationshipIndex; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.exceptions.legacyindex.LegacyIndexNotFoundKernelException; -import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; public class RelationshipLegacyIndexProxy extends LegacyIndexProxy implements RelationshipIndex { - public RelationshipLegacyIndexProxy( String name, LegacyIndexProxy.Lookup lookup, - ThreadToStatementContextBridge statementContextBridge ) + public RelationshipLegacyIndexProxy( String name, GraphDatabaseService gds, + Supplier statementContextBridge ) { - super( name, Type.RELATIONSHIP, lookup, statementContextBridge ); + super( name, Type.RELATIONSHIP, gds, statementContextBridge ); } @Override diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/StandardNodeActions.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/StandardNodeActions.java new file mode 100644 index 0000000000000..44cb6919c6edc --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/StandardNodeActions.java @@ -0,0 +1,82 @@ +/* + * 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.coreapi; + +import java.util.function.Supplier; + +import org.neo4j.function.ThrowingAction; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Relationship; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.impl.core.NodeProxy; +import org.neo4j.kernel.impl.core.RelationshipProxy; + +public class StandardNodeActions implements NodeProxy.NodeActions +{ + private final Supplier stmt; + private final Supplier currentTx; + private final ThrowingAction assertInOpenTransaction; + private final RelationshipProxy.RelationshipActions relationshipActions; + private final GraphDatabaseService gds; + + public StandardNodeActions( Supplier stmt, + Supplier currentTx, + ThrowingAction assertTransactionOpen, + RelationshipProxy.RelationshipActions relationshipActions, + GraphDatabaseService gds ) + { + this.stmt = stmt; + this.currentTx = currentTx; + this.assertInOpenTransaction = assertTransactionOpen; + this.relationshipActions = relationshipActions; + this.gds = gds; + } + + @Override + public Statement statement() + { + return stmt.get(); + } + + @Override + public GraphDatabaseService getGraphDatabase() + { + return gds; + } + + @Override + public void assertInUnterminatedTransaction() + { + assertInOpenTransaction.apply(); + } + + @Override + public void failTransaction() + { + currentTx.get().failure(); + } + + @Override + public Relationship newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId ) + { + return new RelationshipProxy( relationshipActions, id, startNodeId, typeId, endNodeId ); + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/StandardRelationshipActions.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/StandardRelationshipActions.java new file mode 100644 index 0000000000000..0e44db1941f52 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/StandardRelationshipActions.java @@ -0,0 +1,95 @@ +/* + * 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.coreapi; + +import java.util.function.LongFunction; +import java.util.function.Supplier; + +import org.neo4j.function.ThrowingAction; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.RelationshipType; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.exceptions.RelationshipTypeIdNotFoundKernelException; +import org.neo4j.kernel.impl.core.RelationshipProxy.RelationshipActions; + +public class StandardRelationshipActions implements RelationshipActions +{ + private final Supplier stmt; + private final Supplier currentTransaction; + private final ThrowingAction assertInOpenTransaction; + private final LongFunction newNodeProxy; + private final GraphDatabaseService gds; + + public StandardRelationshipActions( Supplier stmt, Supplier currentTransaction, + ThrowingAction assertInOpenTransaction, + LongFunction newNodeProxy, GraphDatabaseService gds ) + { + this.stmt = stmt; + this.currentTransaction = currentTransaction; + this.assertInOpenTransaction = assertInOpenTransaction; + this.newNodeProxy = newNodeProxy; + this.gds = gds; + } + + @Override + public Statement statement() + { + return stmt.get(); + } + + @Override + public Node newNodeProxy( long nodeId ) + { + return newNodeProxy.apply( nodeId ); + } + + @Override + public RelationshipType getRelationshipTypeById( int type ) + { + try + { + return RelationshipType.withName( statement().readOperations().relationshipTypeGetName( type ) ); + } + catch ( RelationshipTypeIdNotFoundKernelException e ) + { + throw new IllegalStateException( "Kernel API returned non-existent relationship type: " + type ); + } + } + + @Override + public GraphDatabaseService getGraphDatabaseService() + { + return gds; + } + + @Override + public void failTransaction() + { + currentTransaction.get().failure(); + } + + @Override + public void assertInUnterminatedTransaction() + { + assertInOpenTransaction.apply(); + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/TopLevelTransaction.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TopLevelTransaction.java similarity index 83% rename from community/kernel/src/main/java/org/neo4j/kernel/TopLevelTransaction.java rename to community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TopLevelTransaction.java index 174a9f37e04ab..00c30f7710f56 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/TopLevelTransaction.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/TopLevelTransaction.java @@ -17,7 +17,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.neo4j.kernel; +package org.neo4j.kernel.impl.coreapi; + +import java.util.function.Supplier; import org.neo4j.graphdb.ConstraintViolationException; import org.neo4j.graphdb.Lock; @@ -27,30 +29,23 @@ import org.neo4j.graphdb.TransientFailureException; import org.neo4j.graphdb.TransientTransactionFailureException; import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.api.exceptions.ConstraintViolationTransactionFailureException; import org.neo4j.kernel.api.exceptions.KernelException; import org.neo4j.kernel.api.exceptions.Status.Classification; -import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; -import org.neo4j.kernel.impl.coreapi.PropertyContainerLocker; -/** - * @deprecated This will be moved to internal packages in the next major release. - */ -@Deprecated public class TopLevelTransaction implements Transaction { private final static PropertyContainerLocker locker = new PropertyContainerLocker(); - private final ThreadToStatementContextBridge stmtProvider; private boolean successCalled; private boolean failureCalled; + private final Supplier stmt; private final KernelTransaction transaction; - public TopLevelTransaction( KernelTransaction transaction, - final ThreadToStatementContextBridge stmtProvider ) + public TopLevelTransaction( KernelTransaction transaction, Supplier stmt ) { + this.stmt = stmt; this.transaction = transaction; - this.stmtProvider = stmtProvider; - this.transaction.registerCloseListener( success -> stmtProvider.unbindTransactionFromCurrentThread() ); } @Override @@ -117,13 +112,13 @@ public void close() @Override public Lock acquireWriteLock( PropertyContainer entity ) { - return locker.exclusiveLock( stmtProvider, entity ); + return locker.exclusiveLock( stmt, entity ); } @Override public Lock acquireReadLock( PropertyContainer entity ) { - return locker.sharedLock(stmtProvider, entity); + return locker.sharedLock(stmt, entity); } @Deprecated diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/AbstractConstraintCreator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/AbstractConstraintCreator.java index 705fdafda6205..7091eec75b43c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/AbstractConstraintCreator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/AbstractConstraintCreator.java @@ -38,6 +38,6 @@ public ConstraintDefinition create() protected final void assertInUnterminatedTransaction() { - actions.assertInUnterminatedTransaction(); + actions.assertInOpenTransaction(); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexCreatorImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexCreatorImpl.java index 0cd147e50ee40..02e51af30e5de 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexCreatorImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexCreatorImpl.java @@ -78,6 +78,6 @@ public IndexDefinition create() throws ConstraintViolationException protected void assertInUnterminatedTransaction() { - actions.assertInUnterminatedTransaction(); + actions.assertInOpenTransaction(); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexDefinitionImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexDefinitionImpl.java index 57959b29fe786..71cbc5712730f 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexDefinitionImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/IndexDefinitionImpl.java @@ -114,6 +114,6 @@ public String toString() protected void assertInUnterminatedTransaction() { - actions.assertInUnterminatedTransaction(); + actions.assertInOpenTransaction(); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/InternalSchemaActions.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/InternalSchemaActions.java index 25ad5642cba7c..ea27abc2f1425 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/InternalSchemaActions.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/InternalSchemaActions.java @@ -59,5 +59,5 @@ ConstraintDefinition createPropertyExistenceConstraint( RelationshipType type, S String getUserMessage( KernelException e ); - void assertInUnterminatedTransaction(); + void assertInOpenTransaction(); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java index 911c734172f68..5643268a53e9b 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/PropertyConstraintDefinition.java @@ -64,6 +64,6 @@ public boolean isConstraintType( ConstraintType type ) protected void assertInUnterminatedTransaction() { - actions.assertInUnterminatedTransaction(); + actions.assertInOpenTransaction(); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java index e1b095b11c84a..3fd3dcd73de26 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.function.Supplier; import org.neo4j.graphdb.ConstraintViolationException; import org.neo4j.graphdb.InvalidTransactionTypeException; @@ -78,10 +79,10 @@ public class SchemaImpl implements Schema { - private final ThreadToStatementContextBridge statementContextSupplier; + private final Supplier statementContextSupplier; private final InternalSchemaActions actions; - public SchemaImpl( ThreadToStatementContextBridge statementContextSupplier ) + public SchemaImpl( Supplier statementContextSupplier ) { this.statementContextSupplier = statementContextSupplier; this.actions = new GDBSchemaActions( statementContextSupplier ); @@ -90,16 +91,12 @@ public SchemaImpl( ThreadToStatementContextBridge statementContextSupplier ) @Override public IndexCreator indexFor( Label label ) { - assertInUnterminatedTransaction(); - return new IndexCreatorImpl( actions, label ); } @Override public Iterable getIndexes( final Label label ) { - assertInUnterminatedTransaction(); - try ( Statement statement = statementContextSupplier.get() ) { List definitions = new ArrayList<>(); @@ -117,8 +114,6 @@ public Iterable getIndexes( final Label label ) @Override public Iterable getIndexes() { - assertInUnterminatedTransaction(); - try ( Statement statement = statementContextSupplier.get() ) { List definitions = new ArrayList<>(); @@ -148,8 +143,7 @@ private void addDefinitions( List definitions, final ReadOperat @Override public void awaitIndexOnline( IndexDefinition index, long duration, TimeUnit unit ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); long timeout = System.currentTimeMillis() + unit.toMillis( duration ); do { @@ -177,8 +171,7 @@ public void awaitIndexOnline( IndexDefinition index, long duration, TimeUnit uni @Override public void awaitIndexesOnline( long duration, TimeUnit unit ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); long millisLeft = TimeUnit.MILLISECONDS.convert( duration, unit ); Collection onlineIndexes = new ArrayList<>(); @@ -203,8 +196,7 @@ public void awaitIndexesOnline( long duration, TimeUnit unit ) @Override public IndexState getIndexState( final IndexDefinition index ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); String propertyKey = single( index.getPropertyKeys() ); try ( Statement statement = statementContextSupplier.get() ) { @@ -245,8 +237,7 @@ public IndexState getIndexState( final IndexDefinition index ) @Override public IndexPopulationProgress getIndexPopulationProgress( IndexDefinition index ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); String propertyKey = single( index.getPropertyKeys() ); try ( Statement statement = statementContextSupplier.get() ) { @@ -278,8 +269,7 @@ public IndexPopulationProgress getIndexPopulationProgress( IndexDefinition index @Override public String getIndexFailure( IndexDefinition index ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); String propertyKey = single( index.getPropertyKeys() ); try ( Statement statement = statementContextSupplier.get() ) { @@ -309,16 +299,14 @@ public String getIndexFailure( IndexDefinition index ) @Override public ConstraintCreator constraintFor( Label label ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); return new BaseNodeConstraintCreator( actions, label ); } @Override public Iterable getConstraints() { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); try ( Statement statement = statementContextSupplier.get() ) { Iterator constraints = statement.readOperations().constraintsGetAll(); @@ -329,7 +317,7 @@ public Iterable getConstraints() @Override public Iterable getConstraints( final Label label ) { - assertInUnterminatedTransaction(); + actions.assertInOpenTransaction(); try ( Statement statement = statementContextSupplier.get() ) { @@ -346,8 +334,7 @@ public Iterable getConstraints( final Label label ) @Override public Iterable getConstraints( RelationshipType type ) { - assertInUnterminatedTransaction(); - + actions.assertInOpenTransaction(); try ( Statement statement = statementContextSupplier.get() ) { int typeId = statement.readOperations().relationshipTypeGetForName( type.name() ); @@ -410,8 +397,8 @@ else if ( constraint instanceof RelationshipPropertyExistenceConstraint ) private static class GDBSchemaActions implements InternalSchemaActions { - private final ThreadToStatementContextBridge ctxSupplier; - public GDBSchemaActions( ThreadToStatementContextBridge ctxSupplier ) + private final Supplier ctxSupplier; + public GDBSchemaActions( Supplier ctxSupplier ) { this.ctxSupplier = ctxSupplier; } @@ -654,14 +641,9 @@ public String getUserMessage( KernelException e ) } @Override - public void assertInUnterminatedTransaction() + public void assertInOpenTransaction() { - ctxSupplier.assertInUnterminatedTransaction(); + ctxSupplier.get(); } } - - private void assertInUnterminatedTransaction() - { - statementContextSupplier.assertInUnterminatedTransaction(); - } } 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 new file mode 100644 index 0000000000000..d21215ae6d414 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/ClassicCoreSPI.java @@ -0,0 +1,235 @@ +/* + * 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.factory; + +import java.net.URL; +import java.util.Map; + +import org.neo4j.graphdb.DatabaseShutdownException; +import org.neo4j.graphdb.DependencyResolver; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.NotInTransactionException; +import org.neo4j.graphdb.Relationship; +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.PropertyTracker; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.Statement; +import org.neo4j.kernel.api.exceptions.TransactionFailureException; +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; + +/** + * 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. + * @see org.neo4j.kernel.impl.factory.GraphDatabaseFacade.SPI + */ +class ClassicCoreSPI implements GraphDatabaseFacade.SPI +{ + private final PlatformModule platform; + private final DataSourceModule dataSource; + private final Logger msgLog; + private final EditionModule edition; + + public ClassicCoreSPI( PlatformModule platform, DataSourceModule dataSource, Logger msgLog, EditionModule edition ) + { + this.platform = platform; + this.dataSource = dataSource; + this.msgLog = msgLog; + this.edition = edition; + } + + @Override + public boolean databaseIsAvailable( long timeout ) + { + return platform.availabilityGuard.isAvailable( timeout ); + } + + @Override + public Result executeQuery( String query, Map parameters, QuerySession querySession ) + { + try + { + assertDatabaseAvailable(); + return dataSource.queryExecutor.get().executeQuery( query, parameters, querySession ); + } + catch ( QueryExecutionKernelException e ) + { + throw e.asUserException(); + } + } + + @Override + public DependencyResolver resolver() + { + return platform.dependencies; + } + + @Override + public void registerKernelEventHandler( KernelEventHandler handler ) + { + dataSource.kernelEventHandlers.registerKernelEventHandler( handler ); + } + + @Override + public void unregisterKernelEventHandler( KernelEventHandler handler ) + { + dataSource.kernelEventHandlers.unregisterKernelEventHandler( handler ); + } + + @Override + public void registerTransactionEventHandler( TransactionEventHandler handler ) + { + dataSource.transactionEventHandlers.registerTransactionEventHandler( handler ); + } + + @Override + public void unregisterTransactionEventHandler( TransactionEventHandler handler ) + { + dataSource.transactionEventHandlers.unregisterTransactionEventHandler( handler ); + } + + @Override + public StoreId storeId() + { + return dataSource.storeId.get(); + } + + @Override + public String storeDir() + { + return platform.storeDir.getAbsolutePath(); + } + + @Override + public void addNodePropertyTracker( PropertyTracker tracker ) + { + dataSource.nodeManager.addNodePropertyTracker( tracker ); + } + + @Override + public void removeNodePropertyTracker( PropertyTracker tracker ) + { + dataSource.nodeManager.removeNodePropertyTracker( tracker ); + } + + @Override + public void addRelationshipPropertyTracker( PropertyTracker tracker ) + { + dataSource.nodeManager.addRelationshipPropertyTracker( tracker ); + } + + @Override + public void removeRelationshipPropertyTracker( PropertyTracker tracker ) + { + dataSource.nodeManager.removeRelationshipPropertyTracker( tracker ); + } + + @Override + public URL validateURLAccess( URL url ) throws URLAccessValidationError + { + return platform.urlAccessRule.validate( platform.config, url ); + } + + @Override + public String name() + { + return platform.databaseInfo.toString(); + } + + @Override + public void shutdown() + { + try + { + msgLog.log( "Shutdown started" ); + platform.availabilityGuard.shutdown(); + platform.life.shutdown(); + } + catch ( LifecycleException throwable ) + { + msgLog.log( "Shutdown failed", throwable ); + throw throwable; + } + } + + @Override + public KernelTransaction beginTransaction() + { + try + { + assertDatabaseAvailable(); + KernelTransaction kernelTx = dataSource.kernelAPI.get().newTransaction(); + kernelTx.registerCloseListener( (s) -> dataSource.threadToTransactionBridge.unbindTransactionFromCurrentThread() ); + dataSource.threadToTransactionBridge.bindTransactionToCurrentThread( kernelTx ); + return kernelTx; + } + catch ( TransactionFailureException e ) + { + throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage(), e ); + } + } + + @Override + public KernelTransaction currentTransaction() + { + assertDatabaseAvailable(); + KernelTransaction tx = dataSource.threadToTransactionBridge.getKernelTransactionBoundToThisThread( false ); + if( tx == null ) + { + throw new NotInTransactionException(); + } + return tx; + } + + @Override + public boolean isInOpenTransaction() + { + return dataSource.threadToTransactionBridge.hasTransaction(); + } + + @Override + 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/DataSourceModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java index c7d957727bf01..eaa21bb21730b 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 @@ -28,9 +28,6 @@ import org.neo4j.graphdb.NotFoundException; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; -import org.neo4j.graphdb.index.IndexManager; -import org.neo4j.graphdb.index.RelationshipAutoIndexer; -import org.neo4j.graphdb.schema.Schema; import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.io.pagecache.PageCache; import org.neo4j.kernel.AvailabilityGuard; @@ -54,13 +51,6 @@ import org.neo4j.kernel.impl.core.StartupStatisticsProvider; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.core.TokenNotFoundException; -import org.neo4j.kernel.impl.coreapi.IndexManagerImpl; -import org.neo4j.kernel.impl.coreapi.IndexProvider; -import org.neo4j.kernel.impl.coreapi.IndexProviderImpl; -import org.neo4j.kernel.impl.coreapi.LegacyIndexProxy; -import org.neo4j.kernel.impl.coreapi.NodeAutoIndexerImpl; -import org.neo4j.kernel.impl.coreapi.RelationshipAutoIndexerImpl; -import org.neo4j.kernel.impl.coreapi.schema.SchemaImpl; import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.query.QueryEngineProvider; import org.neo4j.kernel.impl.query.QueryExecutionEngine; @@ -89,10 +79,6 @@ public class DataSourceModule public final NeoStoreDataSource neoStoreDataSource; - public final IndexManager indexManager; - - public final Schema schema; - public final Supplier kernelAPI; public final Supplier queryExecutor; @@ -135,24 +121,6 @@ public DataSourceModule( final GraphDatabaseFacadeFactory.Dependencies dependenc life.add( platformModule.kernelExtensions ); - schema = new SchemaImpl( threadToTransactionBridge ); - - final LegacyIndexProxy.Lookup indexLookup = new LegacyIndexProxy.Lookup() - { - @Override - public GraphDatabaseService getGraphDatabaseService() - { - return graphDatabaseFacade; - } - }; - - final IndexProvider indexProvider = new IndexProviderImpl( indexLookup, threadToTransactionBridge ); - NodeAutoIndexerImpl nodeAutoIndexer = life.add( new NodeAutoIndexerImpl( config, indexProvider, nodeManager ) ); - RelationshipAutoIndexer relAutoIndexer = life.add( new RelationshipAutoIndexerImpl( config, indexProvider, - nodeManager ) ); - indexManager = new IndexManagerImpl( - threadToTransactionBridge, indexProvider, nodeAutoIndexer, relAutoIndexer ); - // Factories for things that needs to be created later PageCache pageCache = platformModule.pageCache; @@ -338,18 +306,6 @@ public void failTransaction() threadToStatementContextBridge.getKernelTransactionBoundToThisThread( true ).failure(); } - @Override - public Relationship lazyRelationshipProxy( long id ) - { - return nodeManager.newRelationshipProxyById( id ); - } - - @Override - public Relationship newRelationshipProxy( long id ) - { - return nodeManager.newRelationshipProxy( id ); - } - @Override public Relationship newRelationshipProxy( long id, long startNodeId, int typeId, long endNodeId ) { 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 bccdd2a521902..735d19aa566be 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 @@ -19,12 +19,9 @@ */ package org.neo4j.kernel.impl.factory; -import java.io.File; import java.net.URL; import java.util.Collections; import java.util.Map; -import java.util.function.LongFunction; -import java.util.function.Supplier; import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongIterator; @@ -41,7 +38,7 @@ import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.Result; import org.neo4j.graphdb.Transaction; -import org.neo4j.graphdb.TransactionFailureException; +import org.neo4j.graphdb.TransactionTerminatedException; import org.neo4j.graphdb.event.KernelEventHandler; import org.neo4j.graphdb.event.TransactionEventHandler; import org.neo4j.graphdb.index.IndexManager; @@ -49,17 +46,10 @@ import org.neo4j.graphdb.security.URLAccessValidationError; import org.neo4j.graphdb.traversal.BidirectionalTraversalDescription; import org.neo4j.graphdb.traversal.TraversalDescription; -import org.neo4j.helpers.collection.IteratorUtil; import org.neo4j.helpers.collection.PrefetchingResourceIterator; import org.neo4j.helpers.collection.ResourceClosingIterator; -import org.neo4j.kernel.AvailabilityGuard; import org.neo4j.kernel.GraphDatabaseAPI; -import org.neo4j.kernel.impl.store.id.IdType; -import org.neo4j.kernel.KernelEventHandlers; -import org.neo4j.kernel.PlaceboTransaction; -import org.neo4j.kernel.TopLevelTransaction; -import org.neo4j.kernel.TransactionEventHandlers; -import org.neo4j.kernel.api.KernelAPI; +import org.neo4j.kernel.PropertyTracker; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.ReadOperations; import org.neo4j.kernel.api.Statement; @@ -72,34 +62,41 @@ import org.neo4j.kernel.api.index.IndexDescriptor; import org.neo4j.kernel.api.index.InternalIndexState; import org.neo4j.kernel.api.properties.Property; +import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.TokenAccess; import org.neo4j.kernel.impl.api.operations.KeyReadOperations; -import org.neo4j.kernel.impl.core.NodeManager; -import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; +import org.neo4j.kernel.impl.core.NodeProxy; +import org.neo4j.kernel.impl.core.RelationshipProxy; +import org.neo4j.kernel.impl.coreapi.IndexManagerImpl; +import org.neo4j.kernel.impl.coreapi.IndexProviderImpl; +import org.neo4j.kernel.impl.coreapi.NodeAutoIndexerImpl; +import org.neo4j.kernel.impl.coreapi.PlaceboTransaction; +import org.neo4j.kernel.impl.coreapi.RelationshipAutoIndexerImpl; +import org.neo4j.kernel.impl.coreapi.StandardNodeActions; +import org.neo4j.kernel.impl.coreapi.StandardRelationshipActions; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; +import org.neo4j.kernel.impl.coreapi.schema.SchemaImpl; import org.neo4j.kernel.impl.query.QueryEngineProvider; -import org.neo4j.kernel.impl.query.QueryExecutionEngine; -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.impl.store.id.IdType; import org.neo4j.kernel.impl.traversal.BidirectionalTraversalDescriptionImpl; import org.neo4j.kernel.impl.traversal.MonoDirectionalTraversalDescription; -import org.neo4j.kernel.lifecycle.LifeSupport; -import org.neo4j.kernel.lifecycle.LifecycleException; -import org.neo4j.logging.Log; import org.neo4j.storageengine.api.EntityType; import static java.lang.String.format; import static org.neo4j.collection.primitive.PrimitiveLongCollections.map; +import static org.neo4j.graphdb.factory.GraphDatabaseSettings.node_auto_indexing; +import static org.neo4j.graphdb.factory.GraphDatabaseSettings.node_keys_indexable; +import static org.neo4j.graphdb.factory.GraphDatabaseSettings.relationship_auto_indexing; +import static org.neo4j.graphdb.factory.GraphDatabaseSettings.relationship_keys_indexable; import static org.neo4j.helpers.collection.IteratorUtil.emptyIterator; import static org.neo4j.kernel.impl.api.operations.KeyReadOperations.NO_SUCH_LABEL; import static org.neo4j.kernel.impl.api.operations.KeyReadOperations.NO_SUCH_PROPERTY_KEY; /** - * Implementation of the GraphDatabaseService/GraphDatabaseService interfaces. This delegates to the - * services created by the {@link org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory}. - * - * To make a custom GraphDatabaseFacade, the best option is to subclass an existing GraphDatabaseFacadeFactory. Another - * alternative, used by legacy database implementations, is to subclass this class and call - * {@link org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory#newFacade(java.io.File, java.util.Map, org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.Dependencies, GraphDatabaseFacade)} in the constructor. + * Implementation of the GraphDatabaseService/GraphDatabaseService interfaces - the "Core API". Given an {@link SPI} implementation, this provides users with + * a clean facade to interact with the database. */ public class GraphDatabaseFacade implements GraphDatabaseAPI @@ -107,71 +104,100 @@ public class GraphDatabaseFacade private static final long MAX_NODE_ID = IdType.NODE.getMaxValue(); private static final long MAX_RELATIONSHIP_ID = IdType.RELATIONSHIP.getMaxValue(); - private boolean initialized = false; - - private ThreadToStatementContextBridge threadToTransactionBridge; - private NodeManager nodeManager; - private IndexManager indexManager; private Schema schema; - private AvailabilityGuard availabilityGuard; - private Log msgLog; - private LifeSupport life; - private Supplier kernel; - private Supplier queryExecutor; - private KernelEventHandlers kernelEventHandlers; - private TransactionEventHandlers transactionEventHandlers; - - private long transactionStartTimeout; - private DependencyResolver dependencies; - private Supplier storeId; - protected File storeDir; - - public PlatformModule platformModule; - public EditionModule editionModule; - public DataSourceModule dataSourceModule; + private IndexManager indexManager; + private NodeProxy.NodeActions nodeActions; + private RelationshipProxy.RelationshipActions relActions; + private Config config; + private SPI spi; + + /** + * This is what you need to implemenent to get your very own {@link GraphDatabaseFacade}. This SPI exists as a thin layer to make it easy to provide + * alternate {@link org.neo4j.graphdb.GraphDatabaseService} instances without having to re-implement this whole API implementation. + */ + public interface SPI + { + /** Check if database is available, waiting up to {@code timeout} if it isn't. If the timeout expires before database available, this returns false */ + boolean databaseIsAvailable( long timeout ); + + DependencyResolver resolver(); + + StoreId storeId(); + String storeDir(); + + /** Eg. Neo4j Enterprise HA, Neo4j Community Standalone.. */ + String name(); + + void shutdown(); + + /** + * Begin a new kernel transaction. If a transaction is already associated to the current context + * (meaning, non-null is returned from {@link #currentTransaction()}), this should fail. + * @throws org.neo4j.graphdb.TransactionFailureException if unable to begin, or a transaction already exists. + */ + KernelTransaction beginTransaction(); + + /** + * Retrieve the transaction associated with the current context. For the classic implementation of the Core API, the context is the current thread. + * Must not return null, and must return the underlying transaction even if it has been terminated. + * + * @throws org.neo4j.graphdb.NotInTransactionException if no transaction present + * @throws org.neo4j.graphdb.DatabaseShutdownException if the database has been shut down + */ + KernelTransaction currentTransaction(); + + /** true if {@link #currentTransaction()} would return a transaction. */ + boolean isInOpenTransaction(); + + /** Acquire a statement to perform work with */ + Statement currentStatement(); + + /** Execute a cypher statement */ + Result executeQuery( String query, Map parameters, QuerySession querySession ); + + // Methods below smell a bit - at least the property trackers should go to kernel API somewhere, probably the others as well + void addNodePropertyTracker( PropertyTracker tracker ); + void removeNodePropertyTracker( PropertyTracker tracker ); + void addRelationshipPropertyTracker( PropertyTracker tracker ); + void removeRelationshipPropertyTracker( PropertyTracker tracker ); + + void registerKernelEventHandler( KernelEventHandler handler ); + void unregisterKernelEventHandler( KernelEventHandler handler ); + + void registerTransactionEventHandler( TransactionEventHandler handler ); + void unregisterTransactionEventHandler( TransactionEventHandler handler ); + + URL validateURLAccess( URL url ) throws URLAccessValidationError; + } protected GraphDatabaseFacade() { } /** - * When {@link org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory#newFacade(java.io.File, java.util.Map, org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.Dependencies, GraphDatabaseFacade)} has created the different - * modules of a database, it calls this method so that the facade can get access to the created services. - * - * @param platformModule - * @param editionModule - * @param dataSourceModule + * Create a new Core API facade, backed by the given SPI. */ - public void init(PlatformModule platformModule, EditionModule editionModule, DataSourceModule dataSourceModule) - { - this.platformModule = platformModule; - this.editionModule = editionModule; - this.dataSourceModule = dataSourceModule; - this.threadToTransactionBridge = dataSourceModule.threadToTransactionBridge; - this.nodeManager = dataSourceModule.nodeManager; - this.indexManager = dataSourceModule.indexManager; - this.schema = dataSourceModule.schema; - this.availabilityGuard = platformModule.availabilityGuard; - this.msgLog = platformModule.logging.getInternalLog( getClass() ); - this.life = platformModule.life; - this.kernel = dataSourceModule.kernelAPI; - this.queryExecutor = dataSourceModule.queryExecutor; - this.kernelEventHandlers = dataSourceModule.kernelEventHandlers; - this.transactionEventHandlers = dataSourceModule.transactionEventHandlers; - this.transactionStartTimeout = editionModule.transactionStartTimeout; - this.dependencies = platformModule.dependencies; - this.storeId = dataSourceModule.storeId; - this.storeDir = platformModule.storeDir; - - initialized = true; + public void init( Config config, SPI spi ) + { + IndexProviderImpl idxProvider = new IndexProviderImpl( this, spi::currentStatement ); + + this.spi = spi; + this.config = config; + this.relActions = new StandardRelationshipActions( spi::currentStatement, spi::currentTransaction, + this::assertTransactionOpen, (id) -> new NodeProxy( nodeActions, id ), this ); + this.nodeActions = new StandardNodeActions( spi::currentStatement, spi::currentTransaction, this::assertTransactionOpen, relActions, this ); + this.schema = new SchemaImpl( spi::currentStatement ); + this.indexManager = new IndexManagerImpl( spi::currentStatement, idxProvider, + new NodeAutoIndexerImpl( config.get( node_auto_indexing ), config.get( node_keys_indexable ), idxProvider, spi ), + new RelationshipAutoIndexerImpl( config.get( relationship_auto_indexing ), config.get( relationship_keys_indexable ), idxProvider, spi ) ); } @Override public Node createNode() { - try ( Statement statement = threadToTransactionBridge.get() ) + try ( Statement statement = spi.currentStatement() ) { - return nodeManager.newNodeProxyById( statement.dataWriteOperations().nodeCreate() ); + return new NodeProxy( nodeActions, statement.dataWriteOperations().nodeCreate() ); } catch ( InvalidTransactionTypeKernelException e ) { @@ -182,7 +208,7 @@ public Node createNode() @Override public Node createNode( Label... labels ) { - try ( Statement statement = threadToTransactionBridge.get() ) + try ( Statement statement = spi.currentStatement() ) { long nodeId = statement.dataWriteOperations().nodeCreate(); for ( Label label : labels ) @@ -197,7 +223,7 @@ public Node createNode( Label... labels ) throw new NotFoundException( "No node with id " + nodeId + " found.", e ); } } - return nodeManager.newNodeProxyById( nodeId ); + return new NodeProxy( nodeActions, nodeId ); } catch ( ConstraintValidationKernelException e ) { @@ -221,7 +247,7 @@ public Node getNodeById( long id ) throw new NotFoundException( format( "Node %d not found", id ), new EntityNotFoundException( EntityType.NODE, id ) ); } - try ( Statement statement = threadToTransactionBridge.get() ) + try ( Statement statement = spi.currentStatement() ) { if ( !statement.readOperations().nodeExists( id ) ) { @@ -229,7 +255,7 @@ public Node getNodeById( long id ) new EntityNotFoundException( EntityType.NODE, id ) ); } - return nodeManager.newNodeProxyById( id ); + return new NodeProxy( nodeActions, id ); } } @@ -241,7 +267,7 @@ public Relationship getRelationshipById( long id ) throw new NotFoundException( format( "Relationship %d not found", id ), new EntityNotFoundException( EntityType.RELATIONSHIP, id )); } - try ( Statement statement = threadToTransactionBridge.get() ) + try ( Statement statement = spi.currentStatement() ) { if ( !statement.readOperations().relationshipExists( id ) ) { @@ -249,72 +275,45 @@ public Relationship getRelationshipById( long id ) new EntityNotFoundException( EntityType.RELATIONSHIP, id )); } - return nodeManager.newRelationshipProxy( id ); + return new RelationshipProxy( relActions, id ); } } @Override public IndexManager index() { - // TODO: txManager.assertInUnterminatedTransaction(); return indexManager; } @Override public Schema schema() { - threadToTransactionBridge.assertInUnterminatedTransaction(); + assertTransactionOpen(); return schema; } @Override public boolean isAvailable( long timeout ) { - return availabilityGuard.isAvailable( timeout ); + return spi.databaseIsAvailable( timeout ); } @Override public void shutdown() { - if (initialized) - { - try - { - msgLog.info( "Shutdown started" ); - availabilityGuard.shutdown(); - life.shutdown(); - } - catch ( LifecycleException throwable ) - { - msgLog.warn( "Shutdown failed", throwable ); - throw throwable; - } - } + spi.shutdown(); } @Override - public Transaction beginTx() - { - checkAvailability(); - - TopLevelTransaction topLevelTransaction = - threadToTransactionBridge.getTopLevelTransactionBoundToThisThread( false ); - if ( topLevelTransaction != null ) - { - return new PlaceboTransaction( topLevelTransaction ); - } - - try - { - KernelTransaction transaction = kernel.get().newTransaction(); - topLevelTransaction = new TopLevelTransaction( transaction, threadToTransactionBridge ); - threadToTransactionBridge.bindTransactionToCurrentThread( topLevelTransaction ); - return topLevelTransaction; - } - catch ( org.neo4j.kernel.api.exceptions.TransactionFailureException e ) - { - throw new TransactionFailureException( "Failure to begin transaction", e ); - } + public Transaction beginTx() + { + if( spi.isInOpenTransaction() ) + { + return new PlaceboTransaction( spi::currentTransaction, spi::currentStatement ); + } + + KernelTransaction kernelTx = spi.beginTransaction(); + return new TopLevelTransaction( kernelTx, spi::currentStatement ); } @Override @@ -326,36 +325,15 @@ public Result execute( String query ) throws QueryExecutionException @Override public Result execute( String query, Map parameters ) throws QueryExecutionException { - checkAvailability(); - - try - { - return queryExecutor.get().executeQuery( query, parameters, QueryEngineProvider.embeddedSession() ); - } - catch ( QueryExecutionKernelException e ) - { - throw e.asUserException(); - } - } - - private void checkAvailability() - { - try - { - availabilityGuard.await( transactionStartTimeout ); - } - catch ( AvailabilityGuard.UnavailableException e ) - { - throw new TransactionFailureException( e.getMessage() ); - } + return spi.executeQuery( query, parameters, QueryEngineProvider.embeddedSession() ); } @Override public ResourceIterable getAllNodes() { - threadToTransactionBridge.assertInUnterminatedTransaction(); + assertTransactionOpen(); return () -> { - Statement statement = threadToTransactionBridge.get(); + Statement statement = spi.currentStatement(); return map2nodes( statement.readOperations().nodesGetAll(), statement ); }; } @@ -363,9 +341,9 @@ public ResourceIterable getAllNodes() @Override public ResourceIterable getAllRelationships() { - threadToTransactionBridge.assertInUnterminatedTransaction(); + assertTransactionOpen(); return () -> { - final Statement statement = threadToTransactionBridge.get(); + final Statement statement = spi.currentStatement(); final PrimitiveLongIterator ids = statement.readOperations().relationshipsGetAll(); return new PrefetchingResourceIterator() { @@ -378,7 +356,7 @@ public void close() @Override protected Relationship fetchNextOrNull() { - return ids.hasNext() ? nodeManager.newRelationshipProxy( ids.next() ) : null; + return ids.hasNext() ? new RelationshipProxy( relActions, ids.next() ) : null; } }; }; @@ -404,36 +382,40 @@ public ResourceIterable getAllPropertyKeys() private ResourceIterable all( final TokenAccess tokens ) { - threadToTransactionBridge.assertInUnterminatedTransaction(); - return () -> tokens.inUse( threadToTransactionBridge.get() ); + assertTransactionOpen(); + return () -> tokens.inUse( spi.currentStatement() ); } @Override public KernelEventHandler registerKernelEventHandler( KernelEventHandler handler ) { - return kernelEventHandlers.registerKernelEventHandler( handler ); + spi.registerKernelEventHandler( handler ); + return handler; } @Override public TransactionEventHandler registerTransactionEventHandler( TransactionEventHandler handler ) { - return transactionEventHandlers.registerTransactionEventHandler( handler ); + spi.registerTransactionEventHandler( handler ); + return handler; } @Override public KernelEventHandler unregisterKernelEventHandler( KernelEventHandler handler ) { - return kernelEventHandlers.unregisterKernelEventHandler( handler ); + spi.unregisterKernelEventHandler( handler ); + return handler; } @Override public TransactionEventHandler unregisterTransactionEventHandler( TransactionEventHandler handler ) { - return transactionEventHandlers.unregisterTransactionEventHandler( handler ); + spi.unregisterTransactionEventHandler( handler ); + return handler; } @Override @@ -475,7 +457,7 @@ public ResourceIterable findNodesByLabelAndProperty( final Label myLabel, private ResourceIterator nodesByLabelAndProperty( Label myLabel, String key, Object value ) { - Statement statement = threadToTransactionBridge.get(); + Statement statement = spi.currentStatement(); ReadOperations readOps = statement.readOperations(); int propertyId = readOps.propertyKeyGetForName( key ); @@ -484,7 +466,7 @@ private ResourceIterator nodesByLabelAndProperty( Label myLabel, String ke if ( propertyId == NO_SUCH_PROPERTY_KEY || labelId == NO_SUCH_LABEL ) { statement.close(); - return IteratorUtil.emptyIterator(); + return emptyIterator(); } IndexDescriptor descriptor = findAnyIndexByLabelAndProperty( readOps, propertyId, labelId ); @@ -535,7 +517,7 @@ private ResourceIterator getNodesByLabelAndPropertyWithoutIndex( int prope private ResourceIterator allNodesWithLabel( final Label myLabel ) { - Statement statement = threadToTransactionBridge.get(); + Statement statement = spi.currentStatement(); int labelId = statement.readOperations().labelGetForName( myLabel.name() ); if ( labelId == KeyReadOperations.NO_SUCH_LABEL ) @@ -545,57 +527,55 @@ private ResourceIterator allNodesWithLabel( final Label myLabel ) } final PrimitiveLongIterator nodeIds = statement.readOperations().nodesGetForLabel( labelId ); - return ResourceClosingIterator.newResourceIterator( statement, map( - (LongFunction) nodeId -> nodeManager.newNodeProxyById( nodeId ), nodeIds ) ); + return ResourceClosingIterator.newResourceIterator( statement, map( nodeId -> new NodeProxy( nodeActions, nodeId ), nodeIds ) ); } private ResourceIterator map2nodes( PrimitiveLongIterator input, Statement statement ) { - return ResourceClosingIterator.newResourceIterator( statement, map( - (LongFunction) id -> nodeManager.newNodeProxyById( id ), input ) ); + return ResourceClosingIterator.newResourceIterator( statement, map( id -> new NodeProxy( nodeActions, id ), input ) ); } @Override public TraversalDescription traversalDescription() { - return new MonoDirectionalTraversalDescription( threadToTransactionBridge ); + return new MonoDirectionalTraversalDescription( spi::currentStatement ); } @Override public BidirectionalTraversalDescription bidirectionalTraversalDescription() { - return new BidirectionalTraversalDescriptionImpl( threadToTransactionBridge ); + return new BidirectionalTraversalDescriptionImpl( spi::currentStatement ); } // GraphDatabaseAPI @Override public DependencyResolver getDependencyResolver() { - return dependencies; + return spi.resolver(); } @Override public StoreId storeId() { - return storeId.get(); + return spi.storeId(); } @Override public URL validateURLAccess( URL url ) throws URLAccessValidationError { - return platformModule.urlAccessRule.validate( platformModule.config, url ); + return spi.validateURLAccess( url ); } @Override public String getStoreDir() { - return storeDir.toString(); + return spi.storeDir(); } @Override public String toString() { - return platformModule.databaseInfo + " ["+storeDir+"]"; + return spi.name() + " ["+getStoreDir()+"]"; } private static class PropertyValueFilteringNodeIdIterator extends PrimitiveLongCollections.PrimitiveLongBaseIterator @@ -639,4 +619,12 @@ protected boolean fetchNext() return false; } } + + private void assertTransactionOpen() + { + if( spi.currentTransaction().shouldBeTerminated() ) + { + throw new TransactionTerminatedException(); + } + } } 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 3e515e7ce15a7..fd2efc71400c4 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 @@ -125,12 +125,12 @@ public GraphDatabaseFacade newFacade( File storeDir, Map params, PlatformModule platform = createPlatform( storeDir, params, dependencies, graphDatabaseFacade ); EditionModule edition = createEdition( platform ); final DataSourceModule dataSource = createDataSource( dependencies, platform, edition ); + Logger msgLog = platform.logging.getInternalLog( getClass() ).infoLogger(); // Start it - graphDatabaseFacade.init( platform, edition, dataSource ); + graphDatabaseFacade.init( platform.config, new ClassicCoreSPI( platform, dataSource, msgLog, edition ) ); Throwable error = null; - Logger msgLog = platform.logging.getInternalLog( getClass() ).infoLogger(); try { // Done after create to avoid a redundant diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java b/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java index db9aba1fde5cb..b6c7dd7b86427 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/batchinsert/BatchInserterImpl.java @@ -1223,7 +1223,7 @@ public String getUserMessage( KernelException e ) } @Override - public void assertInUnterminatedTransaction() + public void assertInOpenTransaction() { // BatchInserterImpl always is expected to be running in one big single "transaction" } diff --git a/community/kernel/src/test/java/org/neo4j/graphdb/GraphDatabaseServiceTest.java b/community/kernel/src/test/java/org/neo4j/graphdb/GraphDatabaseServiceTest.java index 76ee02e35d71c..19a12299ee04d 100644 --- a/community/kernel/src/test/java/org/neo4j/graphdb/GraphDatabaseServiceTest.java +++ b/community/kernel/src/test/java/org/neo4j/graphdb/GraphDatabaseServiceTest.java @@ -60,7 +60,7 @@ public void givenShutdownDatabaseWhenBeginTxThenExceptionIsThrown() throws Excep catch ( Exception e ) { // Then - assertThat( e.getClass().getName(), CoreMatchers.equalTo( TransactionFailureException.class.getName() ) ); + assertThat( e.getClass().getName(), CoreMatchers.equalTo( DatabaseShutdownException.class.getName() ) ); } } @@ -246,7 +246,7 @@ public void run() } } - assertThat( result.get().getClass(), CoreMatchers.equalTo( TransactionFailureException.class ) ); + assertThat( result.get().getClass(), CoreMatchers.equalTo( DatabaseShutdownException.class ) ); } @Test diff --git a/community/kernel/src/test/java/org/neo4j/graphdb/LabelsAcceptanceTest.java b/community/kernel/src/test/java/org/neo4j/graphdb/LabelsAcceptanceTest.java index 29774c51d5d95..a65dbb87c1882 100644 --- a/community/kernel/src/test/java/org/neo4j/graphdb/LabelsAcceptanceTest.java +++ b/community/kernel/src/test/java/org/neo4j/graphdb/LabelsAcceptanceTest.java @@ -37,7 +37,7 @@ import org.neo4j.kernel.GraphDatabaseDependencies; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdType; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.impl.factory.CommunityEditionModule; import org.neo4j.kernel.impl.factory.CommunityFacadeFactory; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/NodeAutoIndexerImplTest.java b/community/kernel/src/test/java/org/neo4j/kernel/NodeAutoIndexerImplTest.java index 680f02994e869..ceffacb584e96 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/NodeAutoIndexerImplTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/NodeAutoIndexerImplTest.java @@ -21,11 +21,12 @@ import org.junit.Test; +import java.util.Collections; + import org.neo4j.graphdb.Node; -import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.impl.core.NodeManager; import org.neo4j.kernel.impl.coreapi.IndexProvider; import org.neo4j.kernel.impl.coreapi.NodeAutoIndexerImpl; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; import static org.mockito.Mockito.RETURNS_MOCKS; import static org.mockito.Mockito.mock; @@ -33,16 +34,16 @@ public class NodeAutoIndexerImplTest { + + private final IndexProvider indexProvider = mock( IndexProvider.class, RETURNS_MOCKS ); + private final NodeAutoIndexerImpl index = new NodeAutoIndexerImpl( true, Collections.emptyList(), indexProvider, mock( GraphDatabaseFacade.SPI.class ) ); + @Test public void shouldNotRemoveFromIndexForNonAutoIndexedProperty() throws Exception { // Given String indexedPropertyName = "someProperty"; String nonIndexedPropertyName = "someOtherProperty"; - - IndexProvider indexProvider = mock( IndexProvider.class, RETURNS_MOCKS ); - NodeAutoIndexerImpl index = new NodeAutoIndexerImpl( mock( Config.class ), indexProvider, - mock( NodeManager.class ) ); index.startAutoIndexingProperty( indexedPropertyName ); // When @@ -58,10 +59,6 @@ public void shouldNotAddToIndexForNonAutoIndexedProperty() throws Exception // Given String indexedPropertyName = "someProperty"; String nonIndexedPropertyName = "someOtherProperty"; - - IndexProvider indexProvider = mock( IndexProvider.class, RETURNS_MOCKS ); - NodeAutoIndexerImpl index = new NodeAutoIndexerImpl( mock( Config.class ), indexProvider, - mock( NodeManager.class ) ); index.startAutoIndexingProperty( indexedPropertyName ); // When @@ -77,10 +74,6 @@ public void shouldNotAddOrRemoveFromIndexForNonAutoIndexedProperty() throws Exce // Given String indexedPropertyName = "someProperty"; String nonIndexedPropertyName = "someOtherProperty"; - - IndexProvider indexProvider = mock( IndexProvider.class, RETURNS_MOCKS ); - NodeAutoIndexerImpl index = new NodeAutoIndexerImpl( mock( Config.class ), indexProvider, - mock( NodeManager.class ) ); index.startAutoIndexingProperty( indexedPropertyName ); // When diff --git a/community/kernel/src/test/java/org/neo4j/kernel/TestPlaceboTransaction.java b/community/kernel/src/test/java/org/neo4j/kernel/TestPlaceboTransaction.java index 77f3fe1eb0d57..093fc50ff4c90 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/TestPlaceboTransaction.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/TestPlaceboTransaction.java @@ -28,6 +28,8 @@ import org.neo4j.kernel.api.ReadOperations; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; +import org.neo4j.kernel.impl.coreapi.PlaceboTransaction; +import org.neo4j.kernel.impl.locking.ResourceTypes; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -37,23 +39,22 @@ public class TestPlaceboTransaction { - private TopLevelTransaction mockTopLevelTx; private Transaction placeboTx; private Node resource; + private KernelTransaction kernelTransaction; + private ReadOperations readOps; @Before public void before() throws Exception { ThreadToStatementContextBridge bridge = mock (ThreadToStatementContextBridge.class ); when( bridge.get() ).thenReturn( mock( Statement.class ) ); - KernelTransaction kernelTransaction = mock( KernelTransaction.class ); + kernelTransaction = spy( KernelTransaction.class ); Statement statement = mock( Statement.class ); - ReadOperations readOperations = mock( ReadOperations.class ); - when( statement.readOperations() ).thenReturn( readOperations ); + readOps = mock( ReadOperations.class ); + when( statement.readOperations() ).thenReturn( readOps ); when( bridge.get() ).thenReturn( statement ); - mockTopLevelTx = spy( new TopLevelTransaction( kernelTransaction, bridge ) ); - - placeboTx = new PlaceboTransaction( mockTopLevelTx ); + placeboTx = new PlaceboTransaction( () -> kernelTransaction, bridge ); resource = mock( Node.class ); when( resource.getId() ).thenReturn( 1l ); } @@ -65,7 +66,7 @@ public void shouldRollbackParentByDefault() placeboTx.close(); // Then - verify( mockTopLevelTx ).failure(); + verify( kernelTransaction ).failure(); } @Test @@ -76,7 +77,7 @@ public void shouldRollbackParentIfFailureCalled() placeboTx.close(); // Then - verify( mockTopLevelTx ).failure(); + verify( kernelTransaction, times(2) ).failure(); // We accept two calls to failure, since KernelTX#failure is idempotent } @Test @@ -87,7 +88,7 @@ public void shouldNotRollbackParentIfSuccessCalled() placeboTx.close(); // Then - verify( mockTopLevelTx, times( 0 ) ).failure(); + verify( kernelTransaction, times( 0 ) ).failure(); } @Test @@ -99,8 +100,8 @@ public void successCannotOverrideFailure() placeboTx.close(); // Then - verify( mockTopLevelTx ).failure(); - verify( mockTopLevelTx, times( 0 ) ).success(); + verify( kernelTransaction ).failure(); + verify( kernelTransaction, times( 0 ) ).success(); } @Test @@ -110,7 +111,7 @@ public void canAcquireReadLock() throws Exception placeboTx.acquireReadLock( resource ); // then - verify( mockTopLevelTx ).acquireReadLock( resource ); + verify( readOps ).acquireShared( ResourceTypes.NODE, resource.getId() ); } @Test @@ -120,6 +121,6 @@ public void canAcquireWriteLock() throws Exception placeboTx.acquireWriteLock( resource ); // then - verify( mockTopLevelTx ).acquireWriteLock( resource ); + verify( readOps ).acquireExclusive( ResourceTypes.NODE, resource.getId() ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/TopLevelTransactionTest.java b/community/kernel/src/test/java/org/neo4j/kernel/TopLevelTransactionTest.java index c19c3d546457f..33fc938da1e77 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/TopLevelTransactionTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/TopLevelTransactionTest.java @@ -28,6 +28,7 @@ import org.neo4j.kernel.api.exceptions.Status; import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import static org.junit.Assert.fail; import static org.mockito.Mockito.doThrow; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/api/index/UniqueConstraintCompatibility.java b/community/kernel/src/test/java/org/neo4j/kernel/api/index/UniqueConstraintCompatibility.java index 15fafa6410dd2..4b0dbd693f41e 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/api/index/UniqueConstraintCompatibility.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/api/index/UniqueConstraintCompatibility.java @@ -44,7 +44,7 @@ import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Transaction; import org.neo4j.kernel.GraphDatabaseAPI; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.extension.KernelExtensionFactory; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.locking.Lock; @@ -945,7 +945,7 @@ private String reprNode( Node node ) // -- Set Up: Advanced transaction handling - private final Map txMap = new IdentityHashMap<>(); + private final Map txMap = new IdentityHashMap<>(); private void suspend( Transaction tx ) throws Exception { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeManagerTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeManagerTest.java index ed0bf4a8b1f08..ce1bd6e6f3393 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeManagerTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeManagerTest.java @@ -31,7 +31,7 @@ import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.Transaction; import org.neo4j.kernel.GraphDatabaseAPI; -import org.neo4j.kernel.PlaceboTransaction; +import org.neo4j.kernel.impl.coreapi.PlaceboTransaction; import org.neo4j.kernel.PropertyTracker; import org.neo4j.test.TestGraphDatabaseFactory; diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeProxySingleRelationshipTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeProxySingleRelationshipTest.java index 45669ca293cc4..c38ba6c2358cd 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeProxySingleRelationshipTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/NodeProxySingleRelationshipTest.java @@ -105,14 +105,6 @@ private NodeProxy mockNodeWithRels( final long ... relIds) throws EntityNotFound { NodeProxy.NodeActions nodeActions = mock( NodeProxy.NodeActions.class ); final RelationshipProxy.RelationshipActions relActions = mock( RelationshipProxy.RelationshipActions.class ); - when( nodeActions.newRelationshipProxy( anyLong() ) ).thenAnswer( new Answer() - { - @Override - public RelationshipProxy answer( InvocationOnMock invocation ) throws Throwable - { - return new RelationshipProxy( relActions, (Long)invocation.getArguments()[0] ); - } - } ); when( nodeActions.newRelationshipProxy( anyLong(), anyLong(), anyInt(), anyLong() ) ).then( new Answer() { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/RelationshipProxyTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/RelationshipProxyTest.java index b72fe1e6b356c..c99c3a1ce1fce 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/RelationshipProxyTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/RelationshipProxyTest.java @@ -119,14 +119,14 @@ public void shouldPrintCypherEsqueRelationshipToString() throws Exception end = db.createNode(); relationship = start.createRelationshipTo( end, type ); tx.success(); - } - // WHEN - String toString = relationship.toString(); + // WHEN + String toString = relationship.toString(); - // THEN - assertEquals( "(" + start.getId() + ")-[" + type + "," + relationship.getId() + "]->(" + end.getId() + ")", - toString ); + // THEN + assertEquals( "(" + start.getId() + ")-[" + type + "," + relationship.getId() + "]->(" + end.getId() + ")", + toString ); + } } private void verifyIds( RelationshipActions actions, long relationshipId, long nodeId1, int typeId, long nodeId2 ) diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/TestNeo4jApiExceptions.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/TestNeo4jApiExceptions.java index 36282886612e4..743babeb11962 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/core/TestNeo4jApiExceptions.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/core/TestNeo4jApiExceptions.java @@ -22,6 +22,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; + import org.neo4j.graphdb.DatabaseShutdownException; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.GraphDatabaseService; @@ -34,7 +35,8 @@ import org.neo4j.test.TestGraphDatabaseFactory; import static java.util.Arrays.asList; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; public class TestNeo4jApiExceptions { 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 f0e445401e2f5..ede5c1a1f1b12 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 @@ -19,13 +19,11 @@ */ package org.neo4j.kernel.impl.coreapi; -import java.util.ArrayList; -import java.util.List; - import org.junit.Before; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; + +import java.util.ArrayList; +import java.util.List; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.PropertyContainer; @@ -45,13 +43,10 @@ import org.neo4j.storageengine.api.StoreReadLayer; import static java.util.Arrays.asList; - import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; - import static org.neo4j.helpers.collection.Iterables.single; import static org.neo4j.kernel.api.properties.Property.stringProperty; import static org.neo4j.kernel.impl.api.state.StubCursors.asLabelCursor; @@ -302,14 +297,6 @@ private TxStateTransactionDataSnapshot snapshot() { NodeProxy.NodeActions nodeActions = mock( NodeProxy.NodeActions.class ); final RelationshipProxy.RelationshipActions relActions = mock( RelationshipProxy.RelationshipActions.class ); - when( nodeActions.lazyRelationshipProxy( anyLong() ) ).thenAnswer( new Answer() - { - @Override - public RelationshipProxy answer( InvocationOnMock invocation ) throws Throwable - { - return new RelationshipProxy( relActions, (Long) invocation.getArguments()[0] ); - } - } ); return new TxStateTransactionDataSnapshot( state, nodeActions, relActions, ops ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/store/RelationshipGroupStoreTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/store/RelationshipGroupStoreTest.java index 976e16e452a8c..59c6b1f325bc8 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/store/RelationshipGroupStoreTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/store/RelationshipGroupStoreTest.java @@ -128,7 +128,7 @@ public void createDenseNodeWithLowThreshold() throws Exception private void newDb( int denseNodeThreshold ) { db = new ImpermanentGraphDatabase( MapUtil.stringMap( "dense_node_threshold", "" + denseNodeThreshold ) ); - fs = db.platformModule.fileSystem; + fs = db.getDependencyResolver().resolveDependency( FileSystemAbstraction.class ); } private void createAndVerify( Integer customThreshold ) diff --git a/community/server/src/main/java/org/neo4j/server/rest/transactional/TransitionalTxManagementKernelTransaction.java b/community/server/src/main/java/org/neo4j/server/rest/transactional/TransitionalTxManagementKernelTransaction.java index fe9f82592a010..dbf22b3bb081a 100644 --- a/community/server/src/main/java/org/neo4j/server/rest/transactional/TransitionalTxManagementKernelTransaction.java +++ b/community/server/src/main/java/org/neo4j/server/rest/transactional/TransitionalTxManagementKernelTransaction.java @@ -19,7 +19,7 @@ */ package org.neo4j.server.rest.transactional; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; @@ -29,7 +29,7 @@ class TransitionalTxManagementKernelTransaction private final TransactionTerminator txTerminator; private final ThreadToStatementContextBridge bridge; - private TopLevelTransaction suspendedTransaction; + private KernelTransaction suspendedTransaction; TransitionalTxManagementKernelTransaction( TransactionTerminator txTerminator, ThreadToStatementContextBridge bridge ) { diff --git a/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java b/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java index 108e0ba01920f..5ab2344da77aa 100644 --- a/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java +++ b/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java @@ -28,7 +28,8 @@ import org.neo4j.graphdb.factory.GraphDatabaseFactory; import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.kernel.GraphDatabaseAPI; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.api.Statement; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.shell.Output; @@ -52,7 +53,7 @@ public class GraphDatabaseShellServer extends AbstractAppServer { private final GraphDatabaseAPI graphDb; private boolean graphDbCreatedHere; - protected final Map clients = new ConcurrentHashMap<>(); + protected final Map clients = new ConcurrentHashMap<>(); /** * @param path the path to the directory where the database should be created @@ -111,10 +112,10 @@ public Response interpretLine( Serializable clientId, String line, Output out ) @Override public void terminate( Serializable clientId ) { - TopLevelTransaction tx = clients.get( clientId ); + KernelTransaction tx = clients.get( clientId ); if ( tx != null ) { - tx.terminate(); + tx.markForTermination(); } } @@ -123,7 +124,7 @@ public void registerTopLevelTransactionInProgress( Serializable clientId ) throw if ( !clients.containsKey( clientId ) ) { ThreadToStatementContextBridge threadToStatementContextBridge = getThreadToStatementContextBridge(); - TopLevelTransaction tx = threadToStatementContextBridge.getTopLevelTransactionBoundToThisThread( false ); + KernelTransaction tx = threadToStatementContextBridge.getTopLevelTransactionBoundToThisThread( false ); clients.put( clientId, tx ); } } @@ -143,7 +144,7 @@ public void unbindAndRegisterTransaction( Serializable clientId ) throws ShellEx try { ThreadToStatementContextBridge threadToStatementContextBridge = getThreadToStatementContextBridge(); - TopLevelTransaction tx = threadToStatementContextBridge.getTopLevelTransactionBoundToThisThread( false ); + KernelTransaction tx = threadToStatementContextBridge.getTopLevelTransactionBoundToThisThread( false ); threadToStatementContextBridge.unbindTransactionFromCurrentThread(); if ( tx == null ) { @@ -162,7 +163,7 @@ public void unbindAndRegisterTransaction( Serializable clientId ) throws ShellEx public void bindTransaction( Serializable clientId ) throws ShellException { - TopLevelTransaction tx = clients.get( clientId ); + KernelTransaction tx = clients.get( clientId ); if ( tx != null ) { try diff --git a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Begin.java b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Begin.java index 96d39403a328e..a344a2e27fea3 100644 --- a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Begin.java +++ b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Begin.java @@ -21,8 +21,9 @@ import java.rmi.RemoteException; +import org.neo4j.graphdb.Transaction; import org.neo4j.helpers.Service; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.shell.App; import org.neo4j.shell.AppCommandParser; @@ -52,7 +53,7 @@ protected Continuation exec( AppCommandParser parser, Session session, Output ou return Continuation.INPUT_COMPLETE; } - TopLevelTransaction tx = currentTransaction( getServer() ); + KernelTransaction tx = currentTransaction( getServer() ); // This is a "begin" app so it will leave a transaction open. Don't close it in here getServer().getDb().beginTx(); @@ -95,7 +96,7 @@ private boolean acceptableText( String line ) return substring.equals( line.toUpperCase() ); } - public static TopLevelTransaction currentTransaction( GraphDatabaseShellServer server ) + public static KernelTransaction currentTransaction( GraphDatabaseShellServer server ) { return server.getDb().getDependencyResolver().resolveDependency( ThreadToStatementContextBridge.class ) .getTopLevelTransactionBoundToThisThread( false ); diff --git a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Commit.java b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Commit.java index b68f31c7d87e4..3f600a17a06b3 100644 --- a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Commit.java +++ b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Commit.java @@ -22,7 +22,8 @@ import java.rmi.RemoteException; import org.neo4j.helpers.Service; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.shell.App; import org.neo4j.shell.AppCommandParser; import org.neo4j.shell.Continuation; @@ -52,7 +53,7 @@ protected Continuation exec( AppCommandParser parser, Session session, Output ou Integer txCount = session.getCommitCount(); - TopLevelTransaction tx = Begin.currentTransaction( getServer() ); + KernelTransaction tx = Begin.currentTransaction( getServer() ); if ( txCount == null || txCount.equals( 0 ) ) { if ( tx != null ) diff --git a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Rollback.java b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Rollback.java index 6e16e70a5be1f..1cd42aef0aceb 100644 --- a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Rollback.java +++ b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/Rollback.java @@ -21,9 +21,9 @@ import java.rmi.RemoteException; -import org.neo4j.graphdb.TransactionFailureException; import org.neo4j.helpers.Service; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.shell.App; import org.neo4j.shell.AppCommandParser; import org.neo4j.shell.Continuation; @@ -51,7 +51,7 @@ protected Continuation exec( AppCommandParser parser, Session session, Output ou return Continuation.INPUT_COMPLETE; } - TopLevelTransaction tx = Begin.currentTransaction( getServer() ); + KernelTransaction tx = Begin.currentTransaction( getServer() ); if ( tx == null ) { throw Commit.fail( session, "Not in a transaction" ); diff --git a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/cypher/Using.java b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/cypher/Using.java index d32c33d4f4e6c..d260bf9a7a66c 100644 --- a/community/shell/src/main/java/org/neo4j/shell/kernel/apps/cypher/Using.java +++ b/community/shell/src/main/java/org/neo4j/shell/kernel/apps/cypher/Using.java @@ -24,7 +24,8 @@ import org.neo4j.graphdb.Result; import org.neo4j.helpers.Service; import org.neo4j.kernel.GraphDatabaseAPI; -import org.neo4j.kernel.TopLevelTransaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.query.QueryExecutionEngine; import org.neo4j.kernel.impl.query.QueryExecutionKernelException; @@ -45,7 +46,7 @@ protected Result getResult( String query, final Session session ) { ThreadToStatementContextBridge manager = graphDatabaseAPI.getDependencyResolver().resolveDependency( ThreadToStatementContextBridge.class ); - TopLevelTransaction tx = manager.getTopLevelTransactionBoundToThisThread( true ); + KernelTransaction tx = manager.getTopLevelTransactionBoundToThisThread( true ); manager.unbindTransactionFromCurrentThread(); try diff --git a/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/core/CoreGraphDatabase.java b/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/core/CoreGraphDatabase.java index 4cfc43c12f48f..277b3ced9e8fb 100644 --- a/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/core/CoreGraphDatabase.java +++ b/enterprise/core-edge/src/main/java/org/neo4j/coreedge/server/core/CoreGraphDatabase.java @@ -22,25 +22,27 @@ import java.io.File; import java.util.Map; -import org.neo4j.coreedge.server.EnterpriseCoreFacadeFactory; import org.neo4j.coreedge.discovery.DiscoveryServiceFactory; import org.neo4j.coreedge.discovery.HazelcastDiscoveryServiceFactory; +import org.neo4j.coreedge.raft.RaftInstance; import org.neo4j.coreedge.raft.roles.Role; -import org.neo4j.kernel.impl.factory.DataSourceModule; -import org.neo4j.kernel.impl.factory.EditionModule; +import org.neo4j.coreedge.server.CoreMember; +import org.neo4j.coreedge.server.EnterpriseCoreFacadeFactory; import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory; -import org.neo4j.kernel.impl.factory.PlatformModule; public class CoreGraphDatabase extends GraphDatabaseFacade { - private EnterpriseCoreEditionModule coreEditionModule; + private RaftInstance raft; public CoreGraphDatabase( File storeDir, Map params, GraphDatabaseFacadeFactory.Dependencies dependencies, DiscoveryServiceFactory discoveryServiceFactory ) { new EnterpriseCoreFacadeFactory( discoveryServiceFactory ).newFacade( storeDir, params, dependencies, this ); + + // See same thing in HighlyAvailableGraphDatabase for details + raft = getDependencyResolver().resolveDependency( RaftInstance.class ); } public CoreGraphDatabase( File storeDir, Map params, @@ -49,15 +51,8 @@ public CoreGraphDatabase( File storeDir, Map params, this( storeDir, params, dependencies, new HazelcastDiscoveryServiceFactory() ); } - @Override - public void init( PlatformModule platformModule, EditionModule editionModule, DataSourceModule dataSourceModule ) - { - super.init( platformModule, editionModule, dataSourceModule ); - this.coreEditionModule = (EnterpriseCoreEditionModule) editionModule; - } - public Role getRole() { - return coreEditionModule.raft().currentRole(); + return raft.currentRole(); } } diff --git a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/HighlyAvailableGraphDatabase.java b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/HighlyAvailableGraphDatabase.java index 1e0589eed17de..e17d5b870e311 100644 --- a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/HighlyAvailableGraphDatabase.java +++ b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/HighlyAvailableGraphDatabase.java @@ -22,21 +22,13 @@ import java.io.File; import java.util.Map; -import org.neo4j.cluster.ClusterSettings; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; -import org.neo4j.kernel.extension.KernelExtensionFactory; import org.neo4j.kernel.ha.cluster.HighAvailabilityMemberState; +import org.neo4j.kernel.ha.cluster.HighAvailabilityMemberStateMachine; +import org.neo4j.kernel.ha.cluster.member.ClusterMembers; import org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher; -import org.neo4j.kernel.ha.factory.HighlyAvailableEditionModule; import org.neo4j.kernel.ha.factory.HighlyAvailableFacadeFactory; -import org.neo4j.kernel.impl.factory.DataSourceModule; -import org.neo4j.kernel.impl.factory.EditionModule; 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.monitoring.Monitors; - -import static org.neo4j.kernel.GraphDatabaseDependencies.newDependencies; /** * This has all the functionality of an embedded database, with the addition of services @@ -44,50 +36,19 @@ */ public class HighlyAvailableGraphDatabase extends GraphDatabaseFacade { - private HighlyAvailableEditionModule highlyAvailableEditionModule; - - public HighlyAvailableGraphDatabase( File storeDir, Map params, - Iterable> kernelExtensions, - Monitors monitors ) - { - this( storeDir, params, newDependencies() - .settingsClasses( GraphDatabaseSettings.class, ClusterSettings.class, HaSettings.class ) - .kernelExtensions( kernelExtensions ).monitors( monitors ) ); - } - - public HighlyAvailableGraphDatabase( File storeDir, Map params, - Iterable> kernelExtensions ) - { - this( storeDir, params, newDependencies() - .settingsClasses( GraphDatabaseSettings.class, ClusterSettings.class, HaSettings.class ) - .kernelExtensions( kernelExtensions ) ); - } - public HighlyAvailableGraphDatabase( File storeDir, Map params, GraphDatabaseFacadeFactory.Dependencies dependencies ) { - newHighlyAvailableFacadeFactory().newFacade( storeDir, params, dependencies, this ); - } - - protected HighlyAvailableFacadeFactory newHighlyAvailableFacadeFactory() - { - return new HighlyAvailableFacadeFactory(); - } - - @Override - public void init( PlatformModule platformModule, EditionModule editionModule, DataSourceModule dataSourceModule ) - { - super.init( platformModule, editionModule, dataSourceModule ); - this.highlyAvailableEditionModule = (HighlyAvailableEditionModule) editionModule; + new HighlyAvailableFacadeFactory().newFacade( storeDir, params, dependencies, this ); } public HighAvailabilityMemberState getInstanceState() { - return highlyAvailableEditionModule.memberStateMachine.getCurrentState(); + return getDependencyResolver().resolveDependency( HighAvailabilityMemberStateMachine.class ).getCurrentState(); } public String role() { - return highlyAvailableEditionModule.members.getCurrentMemberRole(); + return getDependencyResolver().resolveDependency( ClusterMembers.class ).getCurrentMemberRole(); } public boolean isMaster() @@ -97,6 +58,6 @@ public boolean isMaster() public File getStoreDirectory() { - return storeDir; + return new File( getStoreDir() ); } } 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 fabcaff021a25..ba5895e784608 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 @@ -19,6 +19,8 @@ */ package org.neo4j.kernel.ha.factory; +import org.jboss.netty.logging.InternalLoggerFactory; + import java.io.File; import java.lang.reflect.Proxy; import java.net.URI; @@ -27,8 +29,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import org.jboss.netty.logging.InternalLoggerFactory; - import org.neo4j.cluster.ClusterSettings; import org.neo4j.cluster.InstanceId; import org.neo4j.cluster.client.ClusterClient; @@ -139,7 +139,6 @@ import org.neo4j.kernel.impl.store.stats.IdBasedStoreEntityCounters; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.transaction.log.LogicalTransactionStore; -import org.neo4j.kernel.impl.transaction.log.ReadableClosableChannel; import org.neo4j.kernel.impl.transaction.log.ReadableClosablePositionAwareChannel; import org.neo4j.kernel.impl.transaction.log.TransactionIdStore; import org.neo4j.kernel.impl.transaction.log.checkpoint.CheckPointer; @@ -309,13 +308,14 @@ public void elected( String role, InstanceId instanceId, URI electedMember ) ObservedClusterMembers observedMembers = new ObservedClusterMembers( logging.getInternalLogProvider(), clusterClient, clusterClient, clusterEvents, config.get( ClusterSettings.server_id ) ); - HighAvailabilityMemberStateMachine stateMachine = new HighAvailabilityMemberStateMachine( memberContext, + memberStateMachine = new HighAvailabilityMemberStateMachine( memberContext, platformModule.availabilityGuard, observedMembers, clusterEvents, clusterClient, logging.getInternalLogProvider() ); - members = dependencies.satisfyDependency( new ClusterMembers( observedMembers, stateMachine ) ); + members = dependencies.satisfyDependency( new ClusterMembers( observedMembers, memberStateMachine ) ); - memberStateMachine = paxosLife.add( stateMachine ); + dependencies.satisfyDependency( memberStateMachine ); + paxosLife.add( memberStateMachine ); electionProviderRef.set( memberStateMachine ); HighAvailabilityLogger highAvailabilityLogger = new HighAvailabilityLogger( logging.getUserLogProvider(), diff --git a/enterprise/ha/src/test/java/org/neo4j/ha/UpdatePullerSwitchIT.java b/enterprise/ha/src/test/java/org/neo4j/ha/UpdatePullerSwitchIT.java index a5b39749c346a..617365af2db0e 100644 --- a/enterprise/ha/src/test/java/org/neo4j/ha/UpdatePullerSwitchIT.java +++ b/enterprise/ha/src/test/java/org/neo4j/ha/UpdatePullerSwitchIT.java @@ -33,6 +33,7 @@ import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.Transaction; import org.neo4j.helpers.collection.Iterables; +import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.ha.HaSettings; import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; import org.neo4j.kernel.ha.SlaveUpdatePuller; @@ -43,7 +44,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - import static org.neo4j.kernel.ha.HaSettings.tx_push_factor; public class UpdatePullerSwitchIT @@ -109,8 +109,8 @@ public void updatePullerSwitchOnNodeModeSwitch() throws Throwable private void verifyUpdatePullerThreads() { - InstanceId masterId = managedCluster.getMaster().platformModule.config.get( ClusterSettings.server_id ); - InstanceId slaveId = managedCluster.getAnySlave().platformModule.config.get( ClusterSettings.server_id ); + InstanceId masterId = managedCluster.getMaster().getDependencyResolver().resolveDependency( Config.class ).get( ClusterSettings.server_id ); + InstanceId slaveId = managedCluster.getAnySlave().getDependencyResolver().resolveDependency( Config.class ).get( ClusterSettings.server_id ); Map allStackTraces = Thread.getAllStackTraces(); Set threads = allStackTraces.keySet(); assertFalse( "Master should not have any puller threads", findThreadWithPrefix( threads, diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/LabelIT.java b/enterprise/ha/src/test/java/org/neo4j/kernel/LabelIT.java index d134e6c3dc111..c0e14d453aa35 100644 --- a/enterprise/ha/src/test/java/org/neo4j/kernel/LabelIT.java +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/LabelIT.java @@ -25,8 +25,11 @@ import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Transaction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; +import org.neo4j.kernel.impl.coreapi.TopLevelTransaction; import org.neo4j.kernel.impl.ha.ClusterManager; import org.neo4j.test.ha.ClusterRule; @@ -99,7 +102,7 @@ private static ThreadToStatementContextBridge threadToStatementContextBridgeFrom private static class TransactionContinuation { private final HighlyAvailableGraphDatabase db; - private TopLevelTransaction graphDbTx; + private KernelTransaction graphDbTx; private final ThreadToStatementContextBridge bridge; private TransactionContinuation( HighlyAvailableGraphDatabase db ) @@ -110,12 +113,13 @@ private TransactionContinuation( HighlyAvailableGraphDatabase db ) public void begin() { - graphDbTx = (TopLevelTransaction) db.beginTx(); + db.beginTx(); + graphDbTx = bridge.getKernelTransactionBoundToThisThread( false ); } public void suspend() { - graphDbTx = bridge.getTopLevelTransactionBoundToThisThread( true ); + graphDbTx = bridge.getKernelTransactionBoundToThisThread( true ); bridge.unbindTransactionFromCurrentThread(); } @@ -126,7 +130,14 @@ public void resume() throws Exception public void commit() { - graphDbTx.close(); + try + { + graphDbTx.close(); + } + catch ( TransactionFailureException e ) + { + throw new org.neo4j.graphdb.TransactionFailureException( e.getMessage(), e ); + } } } } 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 716899c75b272..302beac9cc009 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 @@ -40,7 +40,7 @@ import org.neo4j.graphdb.schema.ConstraintType; import org.neo4j.graphdb.schema.IndexDefinition; import org.neo4j.helpers.Exceptions; -import org.neo4j.kernel.TopLevelTransaction; +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; @@ -416,7 +416,7 @@ public void shouldNotAllowOldUncommittedTransactionsToResumeAndViolateConstraint // And given that I begin a transaction that will create a constraint violation slave.beginTx(); createConstraintViolation( slave, type, key, "Foo" ); - TopLevelTransaction slaveTx = txBridge.getTopLevelTransactionBoundToThisThread( true ); + KernelTransaction slaveTx = txBridge.getTopLevelTransactionBoundToThisThread( true ); txBridge.unbindTransactionFromCurrentThread(); // When I create a constraint