Skip to content

Commit c47aa01

Browse files
author
Zhen Li
authored
Merge pull request #325 from lutovich/1.2-new-api
API updates
2 parents 378ae43 + 2714f6a commit c47aa01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3104
-260
lines changed

driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
import org.neo4j.driver.internal.net.SocketConnector;
2929
import org.neo4j.driver.internal.net.pooling.PoolSettings;
3030
import org.neo4j.driver.internal.net.pooling.SocketConnectionPool;
31+
import org.neo4j.driver.internal.retry.ExponentialBackoff;
32+
import org.neo4j.driver.internal.retry.RetryDecision;
33+
import org.neo4j.driver.internal.retry.RetryLogic;
34+
import org.neo4j.driver.internal.retry.RetrySettings;
3135
import org.neo4j.driver.internal.security.SecurityPlan;
3236
import org.neo4j.driver.internal.spi.ConnectionPool;
3337
import org.neo4j.driver.internal.spi.ConnectionProvider;
@@ -47,15 +51,18 @@
4751

4852
public class DriverFactory
4953
{
50-
public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings routingSettings, Config config )
54+
public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings routingSettings,
55+
RetrySettings retrySettings, Config config )
5156
{
5257
BoltServerAddress address = BoltServerAddress.from( uri );
5358
SecurityPlan securityPlan = createSecurityPlan( address, config );
5459
ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, config );
60+
RetryLogic<RetryDecision> retryLogic = createRetryLogic( retrySettings );
5561

5662
try
5763
{
58-
return createDriver( address, uri.getScheme(), connectionPool, config, routingSettings, securityPlan );
64+
return createDriver( address, uri.getScheme(), connectionPool, config, routingSettings, securityPlan,
65+
retryLogic );
5966
}
6067
catch ( Throwable driverError )
6168
{
@@ -73,14 +80,15 @@ public final Driver newInstance( URI uri, AuthToken authToken, RoutingSettings r
7380
}
7481

7582
private Driver createDriver( BoltServerAddress address, String scheme, ConnectionPool connectionPool,
76-
Config config, RoutingSettings routingSettings, SecurityPlan securityPlan )
83+
Config config, RoutingSettings routingSettings, SecurityPlan securityPlan,
84+
RetryLogic<RetryDecision> retryLogic )
7785
{
7886
switch ( scheme.toLowerCase() )
7987
{
8088
case "bolt":
81-
return createDirectDriver( address, connectionPool, config, securityPlan );
89+
return createDirectDriver( address, connectionPool, config, securityPlan, retryLogic );
8290
case "bolt+routing":
83-
return createRoutingDriver( address, connectionPool, config, routingSettings, securityPlan );
91+
return createRoutingDriver( address, connectionPool, config, routingSettings, securityPlan, retryLogic );
8492
default:
8593
throw new ClientException( format( "Unsupported URI scheme: %s", scheme ) );
8694
}
@@ -92,10 +100,10 @@ private Driver createDriver( BoltServerAddress address, String scheme, Connectio
92100
* <b>This method is protected only for testing</b>
93101
*/
94102
protected Driver createDirectDriver( BoltServerAddress address, ConnectionPool connectionPool, Config config,
95-
SecurityPlan securityPlan )
103+
SecurityPlan securityPlan, RetryLogic<RetryDecision> retryLogic )
96104
{
97105
ConnectionProvider connectionProvider = new DirectConnectionProvider( address, connectionPool );
98-
SessionFactory sessionFactory = createSessionFactory( connectionProvider, config );
106+
SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config );
99107
return createDriver( config, securityPlan, sessionFactory );
100108
}
101109

@@ -105,14 +113,15 @@ protected Driver createDirectDriver( BoltServerAddress address, ConnectionPool c
105113
* <b>This method is protected only for testing</b>
106114
*/
107115
protected Driver createRoutingDriver( BoltServerAddress address, ConnectionPool connectionPool,
108-
Config config, RoutingSettings routingSettings, SecurityPlan securityPlan )
116+
Config config, RoutingSettings routingSettings, SecurityPlan securityPlan,
117+
RetryLogic<RetryDecision> retryLogic )
109118
{
110119
if ( !securityPlan.isRoutingCompatible() )
111120
{
112121
throw new IllegalArgumentException( "The chosen security plan is not compatible with a routing driver" );
113122
}
114123
ConnectionProvider connectionProvider = createLoadBalancer( address, connectionPool, config, routingSettings );
115-
SessionFactory sessionFactory = createSessionFactory( connectionProvider, config );
124+
SessionFactory sessionFactory = createSessionFactory( connectionProvider, retryLogic, config );
116125
return createDriver( config, securityPlan, sessionFactory );
117126
}
118127

@@ -180,9 +189,20 @@ protected Connector createConnector( ConnectionSettings connectionSettings, Secu
180189
* <p>
181190
* <b>This method is protected only for testing</b>
182191
*/
183-
protected SessionFactory createSessionFactory( ConnectionProvider connectionProvider, Config config )
192+
protected SessionFactory createSessionFactory( ConnectionProvider connectionProvider,
193+
RetryLogic<RetryDecision> retryLogic, Config config )
184194
{
185-
return new SessionFactoryImpl( connectionProvider, config, config.logging() );
195+
return new SessionFactoryImpl( connectionProvider, retryLogic, config );
196+
}
197+
198+
/**
199+
* Creates new {@link RetryLogic<RetryDecision>}.
200+
* <p>
201+
* <b>This method is protected only for testing</b>
202+
*/
203+
protected RetryLogic<RetryDecision> createRetryLogic( RetrySettings settings )
204+
{
205+
return ExponentialBackoff.create( settings, createClock() );
186206
}
187207

188208
private static SecurityPlan createSecurityPlan( BoltServerAddress address, Config config )

driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,21 @@ public final Session session()
6161

6262
@Override
6363
public final Session session( AccessMode mode )
64+
{
65+
return session( mode, null );
66+
}
67+
68+
@Override
69+
public final Session session( String bookmark )
70+
{
71+
return session( AccessMode.WRITE, bookmark );
72+
}
73+
74+
@Override
75+
public final Session session( AccessMode mode, String bookmark )
6476
{
6577
assertOpen();
66-
Session session = sessionFactory.newInstance( mode );
78+
Session session = sessionFactory.newInstance( mode, bookmark );
6779
if ( closed.get() )
6880
{
6981
// the driver is already closed and we either 1. obtain this session from the old session pool

driver/src/main/java/org/neo4j/driver/internal/LeakLoggingNetworkSession.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
package org.neo4j.driver.internal;
2020

21+
import org.neo4j.driver.internal.retry.RetryDecision;
22+
import org.neo4j.driver.internal.retry.RetryLogic;
2123
import org.neo4j.driver.internal.spi.ConnectionProvider;
2224
import org.neo4j.driver.v1.AccessMode;
2325
import org.neo4j.driver.v1.Logging;
@@ -28,9 +30,10 @@ class LeakLoggingNetworkSession extends NetworkSession
2830
{
2931
private final String stackTrace;
3032

31-
LeakLoggingNetworkSession( ConnectionProvider connectionProvider, AccessMode mode, Logging logging )
33+
LeakLoggingNetworkSession( ConnectionProvider connectionProvider, AccessMode mode,
34+
RetryLogic<RetryDecision> retryLogic, Logging logging )
3235
{
33-
super( connectionProvider, mode, logging );
36+
super( connectionProvider, mode, retryLogic, logging );
3437
this.stackTrace = captureStackTrace();
3538
}
3639

driver/src/main/java/org/neo4j/driver/internal/NetworkSession.java

Lines changed: 108 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@
1818
*/
1919
package org.neo4j.driver.internal;
2020

21+
import java.util.ArrayList;
22+
import java.util.List;
2123
import java.util.Map;
2224
import java.util.concurrent.atomic.AtomicBoolean;
2325

26+
import org.neo4j.driver.internal.retry.RetryDecision;
27+
import org.neo4j.driver.internal.retry.RetryLogic;
2428
import org.neo4j.driver.internal.spi.Connection;
2529
import org.neo4j.driver.internal.spi.ConnectionProvider;
2630
import org.neo4j.driver.internal.spi.PooledConnection;
@@ -37,13 +41,15 @@
3741
import org.neo4j.driver.v1.Values;
3842
import org.neo4j.driver.v1.exceptions.ClientException;
3943
import org.neo4j.driver.v1.types.TypeSystem;
44+
import org.neo4j.driver.v1.util.Function;
4045

4146
import static org.neo4j.driver.v1.Values.value;
4247

4348
public class NetworkSession implements Session, SessionResourcesHandler
4449
{
4550
private final ConnectionProvider connectionProvider;
4651
private final AccessMode mode;
52+
private final RetryLogic<RetryDecision> retryLogic;
4753
protected final Logger logger;
4854

4955
private String lastBookmark;
@@ -52,10 +58,12 @@ public class NetworkSession implements Session, SessionResourcesHandler
5258

5359
private final AtomicBoolean isOpen = new AtomicBoolean( true );
5460

55-
public NetworkSession( ConnectionProvider connectionProvider, AccessMode mode, Logging logging )
61+
public NetworkSession( ConnectionProvider connectionProvider, AccessMode mode, RetryLogic<RetryDecision> retryLogic,
62+
Logging logging )
5663
{
5764
this.connectionProvider = connectionProvider;
5865
this.mode = mode;
66+
this.retryLogic = retryLogic;
5967
this.logger = logging.getLog( "Session-" + hashCode() );
6068
}
6169

@@ -92,12 +100,13 @@ public StatementResult run( Statement statement )
92100
ensureNoOpenTransactionBeforeRunningSession();
93101

94102
syncAndCloseCurrentConnection();
95-
currentConnection = acquireConnection();
103+
currentConnection = acquireConnection( mode );
96104

97105
return run( currentConnection, statement, this );
98106
}
99107

100-
public static StatementResult run( Connection connection, Statement statement, SessionResourcesHandler resourcesHandler )
108+
public static StatementResult run( Connection connection, Statement statement,
109+
SessionResourcesHandler resourcesHandler )
101110
{
102111
InternalStatementResult result = new InternalStatementResult( connection, resourcesHandler, null, statement );
103112
connection.run( statement.text(), statement.parameters().asMap( Values.ofValue() ),
@@ -116,7 +125,7 @@ public synchronized void reset()
116125
if ( currentTransaction != null )
117126
{
118127
currentTransaction.markToClose();
119-
lastBookmark = currentTransaction.bookmark();
128+
updateLastBookmarkFrom( currentTransaction );
120129
currentTransaction = null;
121130
}
122131
if ( currentConnection != null )
@@ -155,28 +164,38 @@ public void close()
155164
}
156165
}
157166
}
158-
167+
159168
syncAndCloseCurrentConnection();
160169
}
161170

162171
@Override
163-
public Transaction beginTransaction()
172+
public synchronized Transaction beginTransaction()
164173
{
165-
return beginTransaction( null );
174+
return beginTransaction( mode );
166175
}
167176

168177
@Override
169178
public synchronized Transaction beginTransaction( String bookmark )
170179
{
171-
ensureSessionIsOpen();
172-
ensureNoOpenTransactionBeforeOpeningTransaction();
180+
lastBookmark = bookmark;
181+
return beginTransaction();
182+
}
173183

174-
syncAndCloseCurrentConnection();
175-
currentConnection = acquireConnection();
184+
@Override
185+
public <T> T readTransaction( Function<Transaction,T> work )
186+
{
187+
return transaction( AccessMode.READ, work );
188+
}
176189

177-
currentTransaction = new ExplicitTransaction( currentConnection, this, bookmark );
178-
currentConnection.setResourcesHandler( this );
179-
return currentTransaction;
190+
@Override
191+
public <T> T writeTransaction( Function<Transaction,T> work )
192+
{
193+
return transaction( AccessMode.WRITE, work );
194+
}
195+
196+
void setLastBookmark( String bookmark )
197+
{
198+
lastBookmark = bookmark;
180199
}
181200

182201
@Override
@@ -203,7 +222,7 @@ public synchronized void onTransactionClosed( ExplicitTransaction tx )
203222
if ( currentTransaction != null && currentTransaction == tx )
204223
{
205224
closeCurrentConnection();
206-
lastBookmark = currentTransaction.bookmark();
225+
updateLastBookmarkFrom( currentTransaction );
207226
currentTransaction = null;
208227
}
209228
}
@@ -225,6 +244,47 @@ public synchronized void onConnectionError( boolean recoverable )
225244
}
226245
}
227246

247+
private synchronized <T> T transaction( AccessMode mode, Function<Transaction,T> work )
248+
{
249+
RetryDecision decision = null;
250+
List<Throwable> errors = null;
251+
252+
while ( true )
253+
{
254+
try ( Transaction tx = beginTransaction( mode ) )
255+
{
256+
return work.apply( tx );
257+
}
258+
catch ( Throwable newError )
259+
{
260+
decision = retryLogic.apply( newError, decision );
261+
262+
if ( decision.shouldRetry() )
263+
{
264+
errors = recordError( newError, errors );
265+
}
266+
else
267+
{
268+
addSuppressed( newError, errors );
269+
throw newError;
270+
}
271+
}
272+
}
273+
}
274+
275+
private synchronized Transaction beginTransaction( AccessMode mode )
276+
{
277+
ensureSessionIsOpen();
278+
ensureNoOpenTransactionBeforeOpeningTransaction();
279+
280+
syncAndCloseCurrentConnection();
281+
currentConnection = acquireConnection( mode );
282+
283+
currentTransaction = new ExplicitTransaction( currentConnection, this, lastBookmark );
284+
currentConnection.setResourcesHandler( this );
285+
return currentTransaction;
286+
}
287+
228288
private void ensureNoUnrecoverableError()
229289
{
230290
if ( currentConnection != null && currentConnection.hasUnrecoverableErrors() )
@@ -268,7 +328,7 @@ private void ensureSessionIsOpen()
268328
}
269329
}
270330

271-
private PooledConnection acquireConnection()
331+
private PooledConnection acquireConnection( AccessMode mode )
272332
{
273333
PooledConnection connection = connectionProvider.acquireConnection( mode );
274334
logger.debug( "Acquired connection " + connection.hashCode() );
@@ -312,4 +372,36 @@ private void closeCurrentConnection( boolean sync )
312372
logger.debug( "Released connection " + connection.hashCode() );
313373
}
314374
}
375+
376+
private void updateLastBookmarkFrom( ExplicitTransaction tx )
377+
{
378+
if ( tx.bookmark() != null )
379+
{
380+
lastBookmark = tx.bookmark();
381+
}
382+
}
383+
384+
private static List<Throwable> recordError( Throwable error, List<Throwable> errors )
385+
{
386+
if ( errors == null )
387+
{
388+
errors = new ArrayList<>();
389+
}
390+
errors.add( error );
391+
return errors;
392+
}
393+
394+
private static void addSuppressed( Throwable error, List<Throwable> suppressedErrors )
395+
{
396+
if ( suppressedErrors != null )
397+
{
398+
for ( Throwable suppressedError : suppressedErrors )
399+
{
400+
if ( error != suppressedError )
401+
{
402+
error.addSuppressed( suppressedError );
403+
}
404+
}
405+
}
406+
}
315407
}

driver/src/main/java/org/neo4j/driver/internal/SessionFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@
2323

2424
public interface SessionFactory extends AutoCloseable
2525
{
26-
Session newInstance( AccessMode mode );
26+
Session newInstance( AccessMode mode, String bookmark );
2727
}

0 commit comments

Comments
 (0)