4949import com .google .common .base .Supplier ;
5050import com .google .common .collect .ImmutableList ;
5151import com .google .common .collect .ImmutableMap ;
52+ import com .google .common .collect .ImmutableSet ;
5253import com .google .common .util .concurrent .ListenableFuture ;
5354import com .google .common .util .concurrent .MoreExecutors ;
5455import com .google .common .util .concurrent .SettableFuture ;
@@ -102,6 +103,17 @@ final class SessionPool {
102103 private static final Logger logger = Logger .getLogger (SessionPool .class .getName ());
103104 private static final Tracer tracer = Tracing .getTracer ();
104105 static final String WAIT_FOR_SESSION = "SessionPool.WaitForSession" ;
106+ static final ImmutableSet <ErrorCode > SHOULD_STOP_PREPARE_SESSIONS_ERROR_CODES =
107+ ImmutableSet .of (
108+ ErrorCode .UNKNOWN ,
109+ ErrorCode .INVALID_ARGUMENT ,
110+ ErrorCode .PERMISSION_DENIED ,
111+ ErrorCode .UNAUTHENTICATED ,
112+ ErrorCode .RESOURCE_EXHAUSTED ,
113+ ErrorCode .FAILED_PRECONDITION ,
114+ ErrorCode .OUT_OF_RANGE ,
115+ ErrorCode .UNIMPLEMENTED ,
116+ ErrorCode .INTERNAL );
105117
106118 /**
107119 * Wrapper around current time so that we can fake it in tests. TODO(user): Replace with Java 8
@@ -1114,6 +1126,9 @@ private static enum Position {
11141126 @ GuardedBy ("lock" )
11151127 private ResourceNotFoundException resourceNotFoundException ;
11161128
1129+ @ GuardedBy ("lock" )
1130+ private boolean stopAutomaticPrepare ;
1131+
11171132 @ GuardedBy ("lock" )
11181133 private final LinkedList <PooledSession > readSessions = new LinkedList <>();
11191134
@@ -1348,8 +1363,9 @@ private boolean isDatabaseOrInstanceNotFound(SpannerException e) {
13481363 return e instanceof DatabaseNotFoundException || e instanceof InstanceNotFoundException ;
13491364 }
13501365
1351- private boolean isPermissionDenied (SpannerException e ) {
1352- return e .getErrorCode () == ErrorCode .PERMISSION_DENIED ;
1366+ private boolean shouldStopPrepareSessions (SpannerException e ) {
1367+ return isDatabaseOrInstanceNotFound (e )
1368+ || SHOULD_STOP_PREPARE_SESSIONS_ERROR_CODES .contains (e .getErrorCode ());
13531369 }
13541370
13551371 private void invalidateSession (PooledSession session ) {
@@ -1477,7 +1493,7 @@ PooledSession getReadWriteSession() {
14771493 // session.
14781494 while (true ) {
14791495 Waiter waiter = null ;
1480- boolean inProcessPrepare = false ;
1496+ boolean inProcessPrepare = stopAutomaticPrepare ;
14811497 synchronized (lock ) {
14821498 if (closureFuture != null ) {
14831499 span .addAnnotation ("Pool has been closed" );
@@ -1494,7 +1510,7 @@ PooledSession getReadWriteSession() {
14941510 }
14951511 sess = writePreparedSessions .poll ();
14961512 if (sess == null ) {
1497- if (numSessionsBeingPrepared <= prepareThreadPoolSize ) {
1513+ if (! inProcessPrepare && numSessionsBeingPrepared <= prepareThreadPoolSize ) {
14981514 if (numSessionsBeingPrepared <= readWriteWaiters .size ()) {
14991515 PooledSession readSession = readSessions .poll ();
15001516 if (readSession != null ) {
@@ -1550,12 +1566,16 @@ PooledSession getReadWriteSession() {
15501566 if (inProcessPrepare ) {
15511567 try {
15521568 sess .prepareReadWriteTransaction ();
1569+ // Session prepare succeeded, restart automatic prepare if it had been stopped.
1570+ synchronized (lock ) {
1571+ stopAutomaticPrepare = false ;
1572+ }
15531573 } catch (Throwable t ) {
1554- sess = null ;
15551574 SpannerException e = newSpannerException (t );
15561575 if (!isClosed ()) {
15571576 handlePrepareSessionFailure (e , sess , false );
15581577 }
1578+ sess = null ;
15591579 if (!isSessionNotFound (e )) {
15601580 throw e ;
15611581 }
@@ -1696,25 +1716,30 @@ private void handlePrepareSessionFailure(
16961716 synchronized (lock ) {
16971717 if (isSessionNotFound (e )) {
16981718 invalidateSession (session );
1699- } else if (isDatabaseOrInstanceNotFound (e ) || isPermissionDenied (e )) {
1700- // Database has been deleted or the user has no permission to write to this database. We
1701- // should stop trying to prepare any transactions. Also propagate the error to all waiters,
1702- // as any further waiting is pointless.
1719+ } else if (shouldStopPrepareSessions (e )) {
1720+ // Database has been deleted or the user has no permission to write to this database, or
1721+ // there is some other semi-permanent error. We should stop trying to prepare any
1722+ // transactions. Also propagate the error to all waiters if the database or instance has
1723+ // been deleted, as any further waiting is pointless.
1724+ stopAutomaticPrepare = true ;
17031725 while (readWriteWaiters .size () > 0 ) {
17041726 readWriteWaiters .poll ().put (e );
17051727 }
17061728 while (readWaiters .size () > 0 ) {
17071729 readWaiters .poll ().put (e );
17081730 }
1709- // Remove the session from the pool.
1710- allSessions .remove (session );
1711- if (isClosed ()) {
1712- decrementPendingClosures (1 );
1731+ if (isDatabaseOrInstanceNotFound (e )) {
1732+ // Remove the session from the pool.
1733+ if (isClosed ()) {
1734+ decrementPendingClosures (1 );
1735+ }
1736+ allSessions .remove (session );
1737+ this .resourceNotFoundException =
1738+ MoreObjects .firstNonNull (
1739+ this .resourceNotFoundException , (ResourceNotFoundException ) e );
1740+ } else {
1741+ releaseSession (session , Position .FIRST );
17131742 }
1714- this .resourceNotFoundException =
1715- MoreObjects .firstNonNull (
1716- this .resourceNotFoundException ,
1717- isDatabaseOrInstanceNotFound (e ) ? (ResourceNotFoundException ) e : null );
17181743 } else if (informFirstWaiter && readWriteWaiters .size () > 0 ) {
17191744 releaseSession (session , Position .FIRST );
17201745 readWriteWaiters .poll ().put (e );
@@ -1809,6 +1834,9 @@ private boolean shouldUnblockReader() {
18091834
18101835 private boolean shouldPrepareSession () {
18111836 synchronized (lock ) {
1837+ if (stopAutomaticPrepare ) {
1838+ return false ;
1839+ }
18121840 int preparedSessions = writePreparedSessions .size () + numSessionsBeingPrepared ;
18131841 return preparedSessions < Math .floor (options .getWriteSessionsFraction () * totalSessions ());
18141842 }
0 commit comments