Skip to content

Commit

Permalink
Add check method into Neo4jTransactionalContext for cypher to perform…
Browse files Browse the repository at this point in the history
… kernel call independent checks.

Introduced guard interface and introduce default empty implementation instead of null.
  • Loading branch information
MishaDemianenko committed Aug 16, 2016
1 parent 621b40b commit 79ea243
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 74 deletions.
Expand Up @@ -20,11 +20,7 @@
package org.neo4j.cypher.internal.compiler.v3_0.planner.logical.idp

import org.mockito.Mockito.{spy, verify, verifyNoMoreInteractions}
import org.neo4j.cypher.internal.compiler.v3_0.planner.logical.Metrics.CardinalityModel
import org.neo4j.cypher.internal.compiler.v3_0.planner.logical.steps.LogicalPlanProducer
import org.neo4j.cypher.internal.compiler.v3_0.planner.logical.{LogicalPlanningContext, Metrics, ProjectingSelector, QueryGraphSolver}
import org.neo4j.cypher.internal.compiler.v3_0.spi.PlanContext
import org.neo4j.cypher.internal.frontend.v3_0.SemanticTable
import org.neo4j.cypher.internal.compiler.v3_0.planner.logical.ProjectingSelector
import org.neo4j.cypher.internal.frontend.v3_0.test_helpers.CypherFunSuite

import scala.collection.immutable.BitSet
Expand Down Expand Up @@ -146,7 +142,6 @@ class IDPSolverTest extends CypherFunSuite {
solver(seed, result)

monitor.maxStartIteration should equal(monitor.foundPlanIteration)
println(monitor.maxStartIteration)
monitor.maxStartIteration
}

Expand Down
Expand Up @@ -57,7 +57,7 @@ class TransactionBoundQueryContextTest extends CypherFunSuite {
outerTx = mock[InternalTransaction]
val kernelTransaction = mock[KernelTransactionImplementation]
when(kernelTransaction.mode()).thenReturn(AccessMode.Static.FULL)
statement = new KernelStatement(kernelTransaction, null, null, null, new Procedures(), Clock.SYSTEM_CLOCK, timeoutMillis)
statement = new KernelStatement(kernelTransaction, null, null, null, new Procedures(), Clock.SYSTEM_CLOCK, 1L)
}

override def afterEach() {
Expand Down
Expand Up @@ -48,6 +48,7 @@
import org.neo4j.kernel.api.legacyindex.AutoIndexing;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.extension.dependency.HighestSelectionStrategy;
import org.neo4j.kernel.guard.EmptyGuard;
import org.neo4j.kernel.guard.Guard;
import org.neo4j.kernel.impl.api.CommitProcessFactory;
import org.neo4j.kernel.impl.api.ConstraintEnforcingEntityOperations;
Expand Down Expand Up @@ -1004,7 +1005,7 @@ private StatementOperationParts buildStatementOperations(
parts = parts.override( null, null, null, lockingContext, lockingContext, lockingContext, lockingContext,
lockingContext, null, null, null );
// + Guard
if ( guard != null )
if ( !EmptyGuard.EMPTY_GUARD.equals( guard ) )
{
GuardingStatementOperations guardingOperations = new GuardingStatementOperations(
parts.entityWriteOperations(), parts.entityReadOperations(), guard );
Expand Down
@@ -0,0 +1,37 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.guard;

import org.neo4j.kernel.impl.api.KernelStatement;

public class EmptyGuard implements Guard
{
public static final EmptyGuard EMPTY_GUARD = new EmptyGuard();

private EmptyGuard()
{
}

@Override
public void check( KernelStatement statement )
{
// empty
}
}
59 changes: 2 additions & 57 deletions community/kernel/src/main/java/org/neo4j/kernel/guard/Guard.java
Expand Up @@ -19,64 +19,9 @@
*/
package org.neo4j.kernel.guard;

import java.util.function.Supplier;

import org.neo4j.helpers.Clock;
import org.neo4j.kernel.impl.api.KernelStatement;
import org.neo4j.kernel.impl.api.KernelTransactionImplementation;
import org.neo4j.logging.Log;

public class Guard
public interface Guard
{
private final Log log;
private Clock clock;

public Guard( final Log log, Clock clock )
{
this.log = log;
this.clock = clock;
}

public void check( KernelStatement statement)
{
check( maxStatementCompletionTimeSupplier( statement ), "Statement timeout." );
check( statement.getTransaction() );
}

public void check (KernelTransactionImplementation transaction)
{
check( maxTransactionCompletionTimeSupplier( transaction ), "Transaction timeout." );
}

private void check( Supplier<Long> completionTimeSupplier, String timeoutDescription )
{
long now = clock.currentTimeMillis();
long transactionCompletionTime = completionTimeSupplier.get();
if ( transactionCompletionTime < now )
{
final long overtime = now - transactionCompletionTime;
log.warn( timeoutDescription + " ( Overtime: " + overtime + " ms)." );
throw new GuardTimeoutException( overtime );
}
}

private static Supplier<Long> maxTransactionCompletionTimeSupplier( KernelTransactionImplementation transaction )
{
return () -> getMaxTransactionCompletionTime( transaction );
}

private static Supplier<Long> maxStatementCompletionTimeSupplier( KernelStatement statement )
{
return () -> getMaxStatementCompletionTime( statement );
}

private static long getMaxStatementCompletionTime( KernelStatement statement )
{
return statement.startTime() + statement.timeout();
}

private static long getMaxTransactionCompletionTime( KernelTransactionImplementation transaction )
{
return transaction.startTime() + transaction.timeout();
}
void check( KernelStatement statement );
}
@@ -0,0 +1,83 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.guard;

import java.util.function.Supplier;

import org.neo4j.helpers.Clock;
import org.neo4j.kernel.impl.api.KernelStatement;
import org.neo4j.kernel.impl.api.KernelTransactionImplementation;
import org.neo4j.logging.Log;

public class TimeoutGuard implements Guard
{
private final Log log;
private Clock clock;

public TimeoutGuard( final Log log, Clock clock )
{
this.log = log;
this.clock = clock;
}

@Override
public void check( KernelStatement statement )
{
check( maxStatementCompletionTimeSupplier( statement ), "Statement timeout." );
check( statement.getTransaction() );
}

private void check (KernelTransactionImplementation transaction)
{
check( maxTransactionCompletionTimeSupplier( transaction ), "Transaction timeout." );
}

private void check( Supplier<Long> completionTimeSupplier, String timeoutDescription )
{
long now = clock.currentTimeMillis();
long transactionCompletionTime = completionTimeSupplier.get();
if ( transactionCompletionTime < now )
{
final long overtime = now - transactionCompletionTime;
log.warn( timeoutDescription + " ( Overtime: " + overtime + " ms)." );
throw new GuardTimeoutException( overtime );
}
}

private static Supplier<Long> maxTransactionCompletionTimeSupplier( KernelTransactionImplementation transaction )
{
return () -> getMaxTransactionCompletionTime( transaction );
}

private static Supplier<Long> maxStatementCompletionTimeSupplier( KernelStatement statement )
{
return () -> getMaxStatementCompletionTime( statement );
}

private static long getMaxStatementCompletionTime( KernelStatement statement )
{
return statement.startTime() + statement.timeout();
}

private static long getMaxTransactionCompletionTime( KernelTransactionImplementation transaction )
{
return transaction.startTime() + transaction.timeout();
}
}
Expand Up @@ -44,7 +44,9 @@
import org.neo4j.kernel.api.legacyindex.AutoIndexing;
import org.neo4j.kernel.builtinprocs.BuiltInProcedures;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.guard.EmptyGuard;
import org.neo4j.kernel.guard.Guard;
import org.neo4j.kernel.guard.TimeoutGuard;
import org.neo4j.kernel.impl.api.NonTransactionalTokenNameLookup;
import org.neo4j.kernel.impl.api.SchemaWriteGuard;
import org.neo4j.kernel.impl.api.dbms.NonTransactionalDbmsOperations;
Expand All @@ -69,6 +71,7 @@
import org.neo4j.kernel.impl.store.StoreId;
import org.neo4j.kernel.impl.transaction.log.PhysicalLogFile;
import org.neo4j.kernel.impl.transaction.state.DataSourceManager;
import org.neo4j.kernel.impl.util.Dependencies;
import org.neo4j.kernel.info.DiagnosticsManager;
import org.neo4j.kernel.internal.DatabaseHealth;
import org.neo4j.kernel.internal.GraphDatabaseAPI;
Expand Down Expand Up @@ -149,7 +152,7 @@ public DataSourceModule( final GraphDatabaseFacadeFactory.Dependencies dependenc

SchemaWriteGuard schemaWriteGuard = deps.satisfyDependency( editionModule.schemaWriteGuard );

Guard guard = buildGuard( config, logging );
Guard guard = buildGuard( deps, config, logging );

kernelEventHandlers = new KernelEventHandlers( logging.getInternalLog( KernelEventHandlers.class ) );

Expand Down Expand Up @@ -250,10 +253,17 @@ public void unregistered( NeoStoreDataSource dataSource )
this.kernelAPI = neoStoreDataSource::getKernel;
}

private Guard buildGuard( Config config, LogService logging )
private Guard buildGuard( Dependencies deps, Config config, LogService logging )
{
Boolean isGuardEnabled = config.get( GraphDatabaseSettings.execution_guard_enabled );
return isGuardEnabled ? new Guard( logging.getInternalLog( Guard.class ), Clock.SYSTEM_CLOCK ) : null;
Guard guard = isGuardEnabled ? createTimeoutGuard( logging ) : EmptyGuard.EMPTY_GUARD;
deps.satisfyDependency( guard );
return guard;
}

private TimeoutGuard createTimeoutGuard( LogService logging )
{
return new TimeoutGuard( logging.getInternalLog( TimeoutGuard.class ), Clock.SYSTEM_CLOCK );
}

protected RelationshipProxy.RelationshipActions createRelationshipActions(
Expand Down
Expand Up @@ -19,15 +19,17 @@
*/
package org.neo4j.kernel.impl.query;

import org.neo4j.graphdb.DependencyResolver;
import org.neo4j.graphdb.Lock;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.kernel.GraphDatabaseQueryService;
import org.neo4j.kernel.api.dbms.DbmsOperations;
import org.neo4j.kernel.api.KernelTransaction;
import org.neo4j.kernel.api.ReadOperations;
import org.neo4j.kernel.api.Statement;
import org.neo4j.kernel.api.dbms.DbmsOperations;
import org.neo4j.kernel.api.security.AccessMode;
import org.neo4j.kernel.api.txstate.TxStateHolder;
import org.neo4j.kernel.guard.Guard;
import org.neo4j.kernel.impl.api.KernelStatement;
import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge;
import org.neo4j.kernel.impl.coreapi.InternalTransaction;
Expand All @@ -39,12 +41,13 @@ public class Neo4jTransactionalContext implements TransactionalContext
private final ThreadToStatementContextBridge txBridge;
private final KernelTransaction.Type transactionType;
private final AccessMode mode;
private final DbmsOperations dbmsOperations;
private final Guard guard;

private final DbmsOperations dbmsOperations;
private InternalTransaction transaction;
private Statement statement;
private PropertyContainerLocker locker;

private PropertyContainerLocker locker;
private boolean isOpen = true;

public Neo4jTransactionalContext( GraphDatabaseQueryService graph, InternalTransaction initialTransaction,
Expand All @@ -56,8 +59,10 @@ public Neo4jTransactionalContext( GraphDatabaseQueryService graph, InternalTrans
this.mode = initialTransaction.mode();
this.statement = initialStatement;
this.locker = locker;
this.txBridge = graph.getDependencyResolver().resolveDependency( ThreadToStatementContextBridge.class );
this.dbmsOperations = graph.getDependencyResolver().resolveDependency( DbmsOperations.class );
DependencyResolver dependencyResolver = graph.getDependencyResolver();
this.txBridge = dependencyResolver.resolveDependency( ThreadToStatementContextBridge.class );
this.dbmsOperations = dependencyResolver.resolveDependency( DbmsOperations.class );
this.guard = dependencyResolver.resolveDependency( Guard.class );
}

@Override
Expand Down Expand Up @@ -159,6 +164,12 @@ public Statement statement()
return statement;
}

@Override
public void check()
{
guard.check( (KernelStatement) statement );
}

@Override
public TxStateHolder stateView()
{
Expand Down
Expand Up @@ -22,10 +22,10 @@
import org.neo4j.graphdb.Lock;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.kernel.GraphDatabaseQueryService;
import org.neo4j.kernel.api.dbms.DbmsOperations;
import org.neo4j.kernel.api.KernelTransaction;
import org.neo4j.kernel.api.ReadOperations;
import org.neo4j.kernel.api.Statement;
import org.neo4j.kernel.api.dbms.DbmsOperations;
import org.neo4j.kernel.api.security.AccessMode;
import org.neo4j.kernel.api.txstate.TxStateHolder;

Expand All @@ -51,6 +51,8 @@ public interface TransactionalContext

Statement statement();

void check();

TxStateHolder stateView();

Lock acquireWriteLock( PropertyContainer p );
Expand Down

0 comments on commit 79ea243

Please sign in to comment.