Skip to content

Commit db3a0e9

Browse files
committed
trigger failover when connected instance turns into read-only mode
1 parent efd6c12 commit db3a0e9

11 files changed

+141
-4
lines changed

wrapper/src/main/java/software/amazon/jdbc/PartialPluginService.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,22 @@ public boolean isLoginException(final String sqlState) {
562562
return this.exceptionManager.isLoginException(this.dbDialect, sqlState);
563563
}
564564

565+
@Override
566+
public boolean isReadOnlyConnectionException(@Nullable String sqlState, @Nullable Integer errorCode) {
567+
if (this.exceptionHandler != null) {
568+
return this.exceptionHandler.isReadOnlyConnectionException(sqlState, errorCode);
569+
}
570+
return this.exceptionManager.isReadOnlyConnectionException(this.dbDialect, sqlState, errorCode);
571+
}
572+
573+
@Override
574+
public boolean isReadOnlyConnectionException(Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect) {
575+
if (this.exceptionHandler != null) {
576+
return this.exceptionHandler.isReadOnlyConnectionException(throwable, targetDriverDialect);
577+
}
578+
return this.exceptionManager.isReadOnlyConnectionException(this.dbDialect, throwable, targetDriverDialect);
579+
}
580+
565581
@Override
566582
public Dialect getDialect() {
567583
return this.dbDialect;

wrapper/src/main/java/software/amazon/jdbc/PluginServiceImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,22 @@ public boolean isLoginException(final String sqlState) {
690690
return this.exceptionManager.isLoginException(this.dialect, sqlState);
691691
}
692692

693+
@Override
694+
public boolean isReadOnlyConnectionException(@Nullable String sqlState, @Nullable Integer errorCode) {
695+
if (this.exceptionHandler != null) {
696+
return this.exceptionHandler.isReadOnlyConnectionException(sqlState, errorCode);
697+
}
698+
return this.exceptionManager.isReadOnlyConnectionException(this.dialect, sqlState, errorCode);
699+
}
700+
701+
@Override
702+
public boolean isReadOnlyConnectionException(Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect) {
703+
if (this.exceptionHandler != null) {
704+
return this.exceptionHandler.isReadOnlyConnectionException(throwable, targetDriverDialect);
705+
}
706+
return this.exceptionManager.isReadOnlyConnectionException(this.dialect, throwable, targetDriverDialect);
707+
}
708+
693709
@Override
694710
public Dialect getDialect() {
695711
return this.dialect;

wrapper/src/main/java/software/amazon/jdbc/exceptions/AbstractPgExceptionHandler.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,36 @@ public boolean isLoginException(final String sqlState) {
9595
}
9696
return getAccessErrors().contains(sqlState);
9797
}
98+
99+
@Override
100+
public boolean isReadOnlyConnectionException(
101+
final @Nullable String sqlState, final @Nullable Integer errorCode) {
102+
return "25006".equals(sqlState);
103+
}
104+
105+
@Override
106+
public boolean isReadOnlyConnectionException(
107+
final Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect) {
108+
109+
Throwable exception = throwable;
110+
111+
while (exception != null) {
112+
String sqlState = null;
113+
Integer errorCode = null;
114+
if (exception instanceof SQLException) {
115+
sqlState = ((SQLException) exception).getSQLState();
116+
errorCode = ((SQLException) exception).getErrorCode();
117+
} else if (targetDriverDialect != null) {
118+
sqlState = targetDriverDialect.getSQLState(exception);
119+
}
120+
121+
if (isReadOnlyConnectionException(sqlState, errorCode)) {
122+
return true;
123+
}
124+
125+
exception = exception.getCause();
126+
}
127+
128+
return false;
129+
}
98130
}

wrapper/src/main/java/software/amazon/jdbc/exceptions/ExceptionHandler.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ public interface ExceptionHandler {
2828
boolean isLoginException(String sqlState);
2929

3030
boolean isLoginException(Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect);
31+
32+
boolean isReadOnlyConnectionException(final @Nullable String sqlState, final @Nullable Integer errorCode);
33+
34+
boolean isReadOnlyConnectionException(Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect);
3135
}

wrapper/src/main/java/software/amazon/jdbc/exceptions/ExceptionManager.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package software.amazon.jdbc.exceptions;
1818

19+
import org.checkerframework.checker.nullness.qual.Nullable;
1920
import software.amazon.jdbc.Driver;
2021
import software.amazon.jdbc.dialect.Dialect;
2122
import software.amazon.jdbc.targetdriverdialect.TargetDriverDialect;
@@ -44,6 +45,18 @@ public boolean isNetworkException(final Dialect dialect, final String sqlState)
4445
return handler.isNetworkException(sqlState);
4546
}
4647

48+
public boolean isReadOnlyConnectionException(
49+
final Dialect dialect, final Throwable throwable, final TargetDriverDialect targetDriverDialect) {
50+
final ExceptionHandler handler = getHandler(dialect);
51+
return handler.isReadOnlyConnectionException(throwable, targetDriverDialect);
52+
}
53+
54+
public boolean isReadOnlyConnectionException(
55+
final Dialect dialect, final @Nullable String sqlState, final @Nullable Integer errorCode) {
56+
final ExceptionHandler handler = getHandler(dialect);
57+
return handler.isReadOnlyConnectionException(sqlState, errorCode);
58+
}
59+
4760
private ExceptionHandler getHandler(final Dialect dialect) {
4861
final ExceptionHandler customHandler = Driver.getCustomExceptionHandler();
4962
return customHandler != null ? customHandler : dialect.getExceptionHandler();

wrapper/src/main/java/software/amazon/jdbc/exceptions/GenericExceptionHandler.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public boolean isLoginException(final Throwable throwable, TargetDriverDialect t
8686
if (exception instanceof SQLException) {
8787
sqlState = ((SQLException) exception).getSQLState();
8888
} else if (targetDriverDialect != null) {
89-
sqlState = targetDriverDialect.getSQLState(throwable);
89+
sqlState = targetDriverDialect.getSQLState(exception);
9090
}
9191

9292
if (isLoginException(sqlState)) {
@@ -103,4 +103,15 @@ public boolean isLoginException(final Throwable throwable, TargetDriverDialect t
103103
public boolean isLoginException(final String sqlState) {
104104
return ACCESS_ERRORS.contains(sqlState);
105105
}
106+
107+
@Override
108+
public boolean isReadOnlyConnectionException(@Nullable String sqlState, @Nullable Integer errorCode) {
109+
return false;
110+
}
111+
112+
@Override
113+
public boolean isReadOnlyConnectionException(
114+
Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect) {
115+
return false;
116+
}
106117
}

wrapper/src/main/java/software/amazon/jdbc/exceptions/MultiAzDbClusterPgExceptionHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020
import java.util.Collections;
2121
import java.util.List;
22+
import org.checkerframework.checker.nullness.qual.Nullable;
2223

2324
public class MultiAzDbClusterPgExceptionHandler extends AbstractPgExceptionHandler {
2425

wrapper/src/main/java/software/amazon/jdbc/exceptions/MySQLExceptionHandler.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public boolean isLoginException(final Throwable throwable, @Nullable TargetDrive
8181
if (exception instanceof SQLException) {
8282
sqlState = ((SQLException) exception).getSQLState();
8383
} else if (targetDriverDialect != null) {
84-
sqlState = targetDriverDialect.getSQLState(throwable);
84+
sqlState = targetDriverDialect.getSQLState(exception);
8585
}
8686

8787
if (isLoginException(sqlState)) {
@@ -103,6 +103,38 @@ public boolean isLoginException(final String sqlState) {
103103
return SQLSTATE_ACCESS_ERROR.equals(sqlState);
104104
}
105105

106+
@Override
107+
public boolean isReadOnlyConnectionException(
108+
final @Nullable String sqlState, final @Nullable Integer errorCode) {
109+
return "HY000".equals(sqlState) && errorCode != null && (errorCode == 1290 || errorCode == 1836);
110+
}
111+
112+
@Override
113+
public boolean isReadOnlyConnectionException(
114+
final Throwable throwable, @Nullable TargetDriverDialect targetDriverDialect) {
115+
116+
Throwable exception = throwable;
117+
118+
while (exception != null) {
119+
String sqlState = null;
120+
Integer errorCode = null;
121+
if (exception instanceof SQLException) {
122+
sqlState = ((SQLException) exception).getSQLState();
123+
errorCode = ((SQLException) exception).getErrorCode();
124+
} else if (targetDriverDialect != null) {
125+
sqlState = targetDriverDialect.getSQLState(exception);
126+
}
127+
128+
if (isReadOnlyConnectionException(sqlState, errorCode)) {
129+
return true;
130+
}
131+
132+
exception = exception.getCause();
133+
}
134+
135+
return false;
136+
}
137+
106138
private boolean isHikariMariaDbNetworkException(final SQLException sqlException) {
107139
return sqlException.getSQLState().equals(SQLSTATE_SYNTAX_ERROR_OR_ACCESS_VIOLATION)
108140
&& sqlException.getMessage().contains(SET_NETWORK_TIMEOUT_ON_CLOSED_CONNECTION);

wrapper/src/main/java/software/amazon/jdbc/exceptions/PgExceptionHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
package software.amazon.jdbc.exceptions;
1818

1919
import java.util.Arrays;
20+
import java.util.Collections;
2021
import java.util.List;
22+
import org.checkerframework.checker.nullness.qual.Nullable;
2123

2224
public class PgExceptionHandler extends AbstractPgExceptionHandler {
2325

wrapper/src/main/java/software/amazon/jdbc/plugin/failover/FailoverConnectionPlugin.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,12 @@ protected boolean shouldExceptionTriggerConnectionSwitch(final Throwable t) {
890890
return false;
891891
}
892892

893-
return this.pluginService.isNetworkException(t, this.pluginService.getTargetDriverDialect());
893+
if (this.pluginService.isNetworkException(t, this.pluginService.getTargetDriverDialect())) {
894+
return true;
895+
}
896+
897+
return this.failoverMode == FailoverMode.STRICT_WRITER
898+
&& this.pluginService.isReadOnlyConnectionException(t, this.pluginService.getTargetDriverDialect());
894899
}
895900

896901
/**

0 commit comments

Comments
 (0)