Skip to content

Commit

Permalink
Allow to start transaction with custom timeout from GraphDatabaseFacade.
Browse files Browse the repository at this point in the history
Rename property for timeout of idle transactions in the REST endpoint from 'dbms.transaction_timeout' to 'dbms.rest.transaction.idle_timeout'.
  • Loading branch information
MishaDemianenko committed Sep 7, 2016
1 parent 3165dab commit 67ed213
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 23 deletions.
Expand Up @@ -237,6 +237,22 @@ public interface GraphDatabaseService
*/ */
Transaction beginTx(); Transaction beginTx();


/**
* Starts a new {@link Transaction transaction} with custom timeout and associates it with the current thread.
* Timeout will be taken into account <b>only</b> when execution guard is enabled.
* <p>
* <em>All database operations must be wrapped in a transaction.</em>
* <p>
* If you attempt to access the graph outside of a transaction, those operations will throw
* {@link NotInTransactionException}.
* <p>
* Please ensure that any returned {@link ResourceIterable} is closed correctly and as soon as possible
* inside your transaction to avoid potential blocking of write operations.
*
* @return a new transaction instance
*/
Transaction beginTx( long timeout );

/** /**
* Executes a query and returns an iterable that contains the result set. * Executes a query and returns an iterable that contains the result set.
* *
Expand Down
Expand Up @@ -343,6 +343,12 @@ public Transaction beginTx()
return beginTransaction( KernelTransaction.Type.explicit, AccessMode.Static.FULL ); return beginTransaction( KernelTransaction.Type.explicit, AccessMode.Static.FULL );
} }


@Override
public Transaction beginTx( long timeout )
{
return beginTransaction( KernelTransaction.Type.explicit, AccessMode.Static.FULL, timeout );
}

public InternalTransaction beginTransaction( KernelTransaction.Type type, AccessMode accessMode ) public InternalTransaction beginTransaction( KernelTransaction.Type type, AccessMode accessMode )
{ {
return beginTransaction( () -> spi.beginTransaction( type, accessMode ) ); return beginTransaction( () -> spi.beginTransaction( type, accessMode ) );
Expand Down
Expand Up @@ -147,6 +147,12 @@ public Transaction beginTx()
return getGraphDatabaseAPI().beginTx(); return getGraphDatabaseAPI().beginTx();
} }


@Override
public Transaction beginTx( long timeout)
{
return getGraphDatabaseAPI().beginTx( timeout );
}

@Override @Override
public Node createNode( Label... labels ) public Node createNode( Label... labels )
{ {
Expand Down
Expand Up @@ -265,7 +265,7 @@ private TransactionFacade createTransactionalActions()
*/ */
private long getTransactionTimeoutMillis() private long getTransactionTimeoutMillis()
{ {
final long timeout = config.get( ServerSettings.transaction_timeout ); final long timeout = config.get( ServerSettings.transaction_idle_timeout );
return Math.max( timeout, MINIMUM_TIMEOUT + ROUNDING_SECOND ); return Math.max( timeout, MINIMUM_TIMEOUT + ROUNDING_SECOND );
} }


Expand Down
Expand Up @@ -232,7 +232,7 @@ private ThirdPartyJaxRsPackage createThirdPartyJaxRsPackage( String packageAndMo
Setting<File> lib_directory = pathSetting( "dbms.directories.lib", "lib" ); Setting<File> lib_directory = pathSetting( "dbms.directories.lib", "lib" );


@Description("Timeout for idle transactions in the REST endpoint.") @Description("Timeout for idle transactions in the REST endpoint.")
Setting<Long> transaction_timeout = setting( "dbms.transaction_timeout", DURATION, "60s" ); Setting<Long> transaction_idle_timeout = setting( "dbms.rest.transaction.idle_timeout", DURATION, "60s" );


@Internal @Internal
Setting<URI> rest_api_path = setting( "unsupported.dbms.uris.rest", NORMALIZED_RELATIVE_URI, "/db/data" ); Setting<URI> rest_api_path = setting( "unsupported.dbms.uris.rest", NORMALIZED_RELATIVE_URI, "/db/data" );
Expand Down
Expand Up @@ -19,12 +19,12 @@
*/ */
package org.neo4j.server; package org.neo4j.server;


import java.util.List;
import java.util.Map;

import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;


import java.util.List;
import java.util.Map;

import org.neo4j.server.configuration.ServerSettings; import org.neo4j.server.configuration.ServerSettings;
import org.neo4j.test.server.ExclusiveServerTestBase; import org.neo4j.test.server.ExclusiveServerTestBase;
import org.neo4j.test.server.HTTP; import org.neo4j.test.server.HTTP;
Expand All @@ -50,7 +50,7 @@ public void stopTheServer()
public void shouldHonorReallyLowSessionTimeout() throws Exception public void shouldHonorReallyLowSessionTimeout() throws Exception
{ {
// Given // Given
server = server().withProperty( ServerSettings.transaction_timeout.name(), "1" ).build(); server = server().withProperty( ServerSettings.transaction_idle_timeout.name(), "1" ).build();
server.start(); server.start();


String tx = HTTP.POST( txURI(), asList( map( "statement", "CREATE (n)" ) ) ).location(); String tx = HTTP.POST( txURI(), asList( map( "statement", "CREATE (n)" ) ) ).location();
Expand All @@ -62,7 +62,7 @@ public void shouldHonorReallyLowSessionTimeout() throws Exception
// Then // Then
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Map<String, Object>> errors = (List<Map<String, Object>>) response.get( "errors" ); List<Map<String, Object>> errors = (List<Map<String, Object>>) response.get( "errors" );
assertThat( (String) errors.get( 0 ).get( "code" ), equalTo( TransactionNotFound.code().serialize() ) ); assertThat( errors.get( 0 ).get( "code" ), equalTo( TransactionNotFound.code().serialize() ) );
} }


private String txURI() private String txURI()
Expand Down
Expand Up @@ -48,7 +48,7 @@ public class ExtensionInitializerTest
@Test @Test
public void testPluginInitialization() public void testPluginInitialization()
{ {
Config config = new Config( stringMap( ServerSettings.transaction_timeout.name(), "600" ) ); Config config = new Config( stringMap( ServerSettings.transaction_idle_timeout.name(), "600" ) );
NeoServer neoServer = Mockito.mock( NeoServer.class, Mockito.RETURNS_DEEP_STUBS ); NeoServer neoServer = Mockito.mock( NeoServer.class, Mockito.RETURNS_DEEP_STUBS );
Mockito.when( neoServer.getConfig() ).thenReturn( config ); Mockito.when( neoServer.getConfig() ).thenReturn( config );
ExtensionInitializer extensionInitializer = new ExtensionInitializer( neoServer ); ExtensionInitializer extensionInitializer = new ExtensionInitializer( neoServer );
Expand All @@ -58,7 +58,7 @@ public void testPluginInitialization()


assertThat( injectableProperties, Matchers.hasSize( 1 ) ); assertThat( injectableProperties, Matchers.hasSize( 1 ) );
assertThat( injectableProperties, Matchers.contains( new InjectableMatcher<>( ServerSettings assertThat( injectableProperties, Matchers.contains( new InjectableMatcher<>( ServerSettings
.transaction_timeout.name() ) ) ); .transaction_idle_timeout.name() ) ) );
} }


private class InjectableMatcher<T> extends BaseMatcher<Injectable<?>> private class InjectableMatcher<T> extends BaseMatcher<Injectable<?>>
Expand Down
Expand Up @@ -19,17 +19,16 @@
*/ */
package org.neo4j.server.plugins; package org.neo4j.server.plugins;


import org.junit.Test;

import java.net.URI; import java.net.URI;
import java.util.HashMap; import java.util.HashMap;


import org.junit.Test;

import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.server.configuration.ServerSettings; import org.neo4j.server.configuration.ServerSettings;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;

import static org.neo4j.helpers.collection.MapUtil.stringMap; import static org.neo4j.helpers.collection.MapUtil.stringMap;


public class ConfigAdapterTest public class ConfigAdapterTest
Expand Down Expand Up @@ -82,15 +81,15 @@ public void shouldAbleToAccessRegisteredPropertyByName()
Config config = new Config( new HashMap<>(), ServerSettings.class ); Config config = new Config( new HashMap<>(), ServerSettings.class );
ConfigAdapter wrappingConfiguration = new ConfigAdapter( config ); ConfigAdapter wrappingConfiguration = new ConfigAdapter( config );


assertEquals( 60000L, wrappingConfiguration.getProperty( ServerSettings.transaction_timeout.name() ) ); assertEquals( 60000L, wrappingConfiguration.getProperty( ServerSettings.transaction_idle_timeout.name() ) );
} }


@Test @Test
public void shouldAbleToAccessNonRegisteredPropertyByName() public void shouldAbleToAccessNonRegisteredPropertyByName()
{ {
Config config = new Config( stringMap( ServerSettings.transaction_timeout.name(), "600" ) ); Config config = new Config( stringMap( ServerSettings.transaction_idle_timeout.name(), "600" ) );
ConfigAdapter wrappingConfiguration = new ConfigAdapter( config ); ConfigAdapter wrappingConfiguration = new ConfigAdapter( config );


assertEquals( "600", wrappingConfiguration.getProperty( ServerSettings.transaction_timeout.name() ) ); assertEquals( "600", wrappingConfiguration.getProperty( ServerSettings.transaction_idle_timeout.name() ) );
} }
} }
Expand Up @@ -59,8 +59,8 @@
import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.KernelTransaction;
import org.neo4j.kernel.api.security.AccessMode; import org.neo4j.kernel.api.security.AccessMode;
import org.neo4j.kernel.impl.coreapi.InternalTransaction; import org.neo4j.kernel.impl.coreapi.InternalTransaction;
import org.neo4j.kernel.internal.GraphDatabaseAPI;
import org.neo4j.kernel.impl.store.StoreId; import org.neo4j.kernel.impl.store.StoreId;
import org.neo4j.kernel.internal.GraphDatabaseAPI;


public class ReadOnlyGraphDatabaseProxy implements GraphDatabaseService, GraphDatabaseAPI, IndexManager public class ReadOnlyGraphDatabaseProxy implements GraphDatabaseService, GraphDatabaseAPI, IndexManager
{ {
Expand Down Expand Up @@ -103,10 +103,16 @@ public Transaction beginTx()
return actual.beginTx(); return actual.beginTx();
} }


@Override
public Transaction beginTx( long timeout )
{
return actual.beginTx( timeout );
}

@Override @Override
public Result execute( String query ) public Result execute( String query )
{ {
return execute( query, Collections.<String, Object>emptyMap() ); return execute( query, Collections.emptyMap() );
} }


@Override @Override
Expand Down
Expand Up @@ -45,8 +45,9 @@
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.configuration.Settings; import org.neo4j.kernel.configuration.Settings;
import org.neo4j.kernel.guard.GuardTimeoutException; import org.neo4j.kernel.guard.GuardTimeoutException;
import org.neo4j.kernel.impl.factory.CommunityFacadeFactory; import org.neo4j.kernel.impl.factory.CommunityEditionModule;
import org.neo4j.kernel.impl.factory.DataSourceModule; import org.neo4j.kernel.impl.factory.DataSourceModule;
import org.neo4j.kernel.impl.factory.DatabaseInfo;
import org.neo4j.kernel.impl.factory.EditionModule; import org.neo4j.kernel.impl.factory.EditionModule;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; import org.neo4j.kernel.impl.factory.GraphDatabaseFacade;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory; import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory;
Expand All @@ -63,9 +64,9 @@
import org.neo4j.shell.impl.CollectingOutput; import org.neo4j.shell.impl.CollectingOutput;
import org.neo4j.shell.impl.SameJvmClient; import org.neo4j.shell.impl.SameJvmClient;
import org.neo4j.shell.kernel.GraphDatabaseShellServer; import org.neo4j.shell.kernel.GraphDatabaseShellServer;
import org.neo4j.test.CleanupRule;
import org.neo4j.test.TestGraphDatabaseFactory; import org.neo4j.test.TestGraphDatabaseFactory;
import org.neo4j.test.TestGraphDatabaseFactoryState; import org.neo4j.test.TestGraphDatabaseFactoryState;
import org.neo4j.test.rule.CleanupRule;
import org.neo4j.test.server.HTTP; import org.neo4j.test.server.HTTP;
import org.neo4j.time.FakeClock; import org.neo4j.time.FakeClock;


Expand Down Expand Up @@ -227,7 +228,6 @@ private Map<Setting<?>,String> getSettingsMap()
GraphDatabaseSettings.auth_enabled, "false" ); GraphDatabaseSettings.auth_enabled, "false" );
} }



private String transactionUri(CommunityNeoServer neoServer) private String transactionUri(CommunityNeoServer neoServer)
{ {
return neoServer.baseUri().toString() + "db/data/transaction"; return neoServer.baseUri().toString() + "db/data/transaction";
Expand Down Expand Up @@ -306,9 +306,9 @@ private class GuardTestServer extends CommunityNeoServer
private class GuardTestGraphDatabaseFactory extends TestGraphDatabaseFactory private class GuardTestGraphDatabaseFactory extends TestGraphDatabaseFactory
{ {


private CommunityFacadeFactory customFacadeFactory; private GraphDatabaseFacadeFactory customFacadeFactory;


GuardTestGraphDatabaseFactory( CommunityFacadeFactory customFacadeFactory ) GuardTestGraphDatabaseFactory( GraphDatabaseFacadeFactory customFacadeFactory )
{ {
this.customFacadeFactory = customFacadeFactory; this.customFacadeFactory = customFacadeFactory;
} }
Expand All @@ -322,13 +322,14 @@ protected GraphDatabaseBuilder.DatabaseCreator createImpermanentDatabaseCreator(
} }
} }


private class GuardCommunityFacadeFactory extends CommunityFacadeFactory private class GuardCommunityFacadeFactory extends GraphDatabaseFacadeFactory
{ {


private Clock clock; private Clock clock;


GuardCommunityFacadeFactory( Clock clock ) GuardCommunityFacadeFactory( Clock clock )
{ {
super( DatabaseInfo.COMMUNITY, CommunityEditionModule::new);
this.clock = clock; this.clock = clock;
} }


Expand Down

0 comments on commit 67ed213

Please sign in to comment.