1818 */
1919package org .neo4j .driver .internal ;
2020
21+ import java .util .ArrayList ;
22+ import java .util .List ;
2123import java .util .Map ;
2224import java .util .concurrent .atomic .AtomicBoolean ;
2325
26+ import org .neo4j .driver .internal .retry .RetryDecision ;
27+ import org .neo4j .driver .internal .retry .RetryLogic ;
2428import org .neo4j .driver .internal .spi .Connection ;
2529import org .neo4j .driver .internal .spi .ConnectionProvider ;
2630import org .neo4j .driver .internal .spi .PooledConnection ;
3741import org .neo4j .driver .v1 .Values ;
3842import org .neo4j .driver .v1 .exceptions .ClientException ;
3943import org .neo4j .driver .v1 .types .TypeSystem ;
44+ import org .neo4j .driver .v1 .util .Function ;
4045
4146import static org .neo4j .driver .v1 .Values .value ;
4247
4348public 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}
0 commit comments