Skip to content

Commit 420b9da

Browse files
committed
blue new connections
add RDS PG support; fixes fix IAM and routing green change node name APG support switchover rollback fix unit tests codestyle tags separate host list provider per monitor review todo fixes for Aurora refactoring IAM fixes; summary fixes; BG switchover summary; IAM node changed name resources tier down fix integration test suite bgdId smart waiting routing verified bg monitors IAM reroute to IP and a proper token useBlueNode flag in BG status iam, dialect identification Blue/Green Deployments for MultiAz clusters
1 parent 73208b6 commit 420b9da

File tree

74 files changed

+6945
-331
lines changed

Some content is hidden

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

74 files changed

+6945
-331
lines changed

wrapper/build.gradle.kts

Lines changed: 155 additions & 17 deletions
Large diffs are not rendered by default.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import software.amazon.jdbc.plugin.DriverMetaDataConnectionPluginFactory;
3636
import software.amazon.jdbc.plugin.ExecutionTimeConnectionPluginFactory;
3737
import software.amazon.jdbc.plugin.LogQueryConnectionPluginFactory;
38+
import software.amazon.jdbc.plugin.bluegreen.BlueGreenConnectionPluginFactory;
3839
import software.amazon.jdbc.plugin.customendpoint.CustomEndpointPluginFactory;
3940
import software.amazon.jdbc.plugin.dev.DeveloperConnectionPluginFactory;
4041
import software.amazon.jdbc.plugin.efm.HostMonitoringConnectionPluginFactory;
@@ -82,6 +83,7 @@ public class ConnectionPluginChainBuilder {
8283
put("fastestResponseStrategy", FastestResponseStrategyPluginFactory.class);
8384
put("initialConnection", AuroraInitialConnectionStrategyPluginFactory.class);
8485
put("limitless", LimitlessConnectionPluginFactory.class);
86+
put("bg", BlueGreenConnectionPluginFactory.class);
8587
}
8688
};
8789

@@ -99,6 +101,7 @@ public class ConnectionPluginChainBuilder {
99101
put(AuroraInitialConnectionStrategyPluginFactory.class, 390);
100102
put(AuroraConnectionTrackerPluginFactory.class, 400);
101103
put(AuroraStaleDnsPluginFactory.class, 500);
104+
put(BlueGreenConnectionPluginFactory.class, 550);
102105
put(ReadWriteSplittingPluginFactory.class, 600);
103106
put(FailoverConnectionPluginFactory.class, 700);
104107
put(software.amazon.jdbc.plugin.failover2.FailoverConnectionPluginFactory.class, 710);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ protected <T, E extends Exception> T executeWithSubscribedPlugins(
221221
throw new IllegalArgumentException("jdbcMethodFunc");
222222
}
223223

224-
// noinspection unchecked
224+
@SuppressWarnings({"unchecked", "noinspection"})
225225
PluginChainJdbcCallable<T, E> pluginChainFunc = this.pluginChainFuncMap.get(methodName);
226226

227227
if (pluginChainFunc == null) {
@@ -641,7 +641,7 @@ public boolean isWrapperFor(Class<?> iface) throws SQLException {
641641
return false;
642642
}
643643

644-
public ConnectionProvider getDefaultConnProvider() {
644+
public @NonNull ConnectionProvider getDefaultConnProvider() {
645645
return this.defaultConnProvider;
646646
}
647647

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ EnumSet<NodeChangeOptions> setCurrentConnection(
8080

8181
HostSpec getInitialConnectionHostSpec();
8282

83+
String getOriginalUrl();
84+
8385
/**
8486
* Set the collection of hosts that should be allowed and/or blocked for connections.
8587
*
@@ -249,4 +251,14 @@ Connection forceConnect(
249251
@NonNull SessionStateService getSessionStateService();
250252

251253
<T> T getPlugin(final Class<T> pluginClazz);
254+
255+
<T> void setStatus(final Class<T> clazz, final @Nullable T status, final boolean clusterBound);
256+
257+
<T> void setStatus(final Class<T> clazz, final @Nullable T status, final String key);
258+
259+
<T> T getStatus(final @NonNull Class<T> clazz, final boolean clusterBound);
260+
261+
<T> T getStatus(final @NonNull Class<T> clazz, final String key);
262+
263+
boolean isPluginInUse(final Class<? extends ConnectionPlugin> pluginClazz);
252264
}

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

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public class PluginServiceImpl implements PluginService, CanReleaseResources,
6363
protected static final long DEFAULT_HOST_AVAILABILITY_CACHE_EXPIRE_NANO = TimeUnit.MINUTES.toNanos(5);
6464

6565
protected static final CacheMap<String, HostAvailability> hostAvailabilityExpiringCache = new CacheMap<>();
66+
67+
protected static final CacheMap<String, Object> statusesExpiringCache = new CacheMap<>();
68+
protected static final long DEFAULT_STATUS_CACHE_EXPIRE_NANO = TimeUnit.MINUTES.toNanos(60);
69+
6670
protected final ConnectionPluginManager pluginManager;
6771
private final Properties props;
6872
private final String originalUrl;
@@ -205,6 +209,11 @@ public HostSpec getInitialConnectionHostSpec() {
205209
return this.initialConnectionHostSpec;
206210
}
207211

212+
@Override
213+
public String getOriginalUrl() {
214+
return this.originalUrl;
215+
}
216+
208217
@Override
209218
public void setAllowedAndBlockedHosts(AllowedAndBlockedHosts allowedAndBlockedHosts) {
210219
this.allowedAndBlockedHosts.set(allowedAndBlockedHosts);
@@ -716,6 +725,7 @@ public void updateDialect(final @NonNull Connection connection) throws SQLExcept
716725

717726
final HostListProviderSupplier supplier = this.dialect.getHostListProvider();
718727
this.setHostListProvider(supplier.getProvider(props, this.originalUrl, this, this));
728+
this.refreshHostList(connection);
719729
}
720730

721731
@Override
@@ -790,4 +800,53 @@ public <T> T getPlugin(final Class<T> pluginClazz) {
790800
public static void clearCache() {
791801
hostAvailabilityExpiringCache.clear();
792802
}
803+
804+
public <T> void setStatus(final Class<T> clazz, final @Nullable T status, final boolean clusterBound) {
805+
String clusterId = null;
806+
if (clusterBound) {
807+
try {
808+
clusterId = this.hostListProvider.getClusterId();
809+
} catch (Exception ex) {
810+
// do nothing
811+
}
812+
}
813+
this.setStatus(clazz, status, clusterId);
814+
}
815+
816+
public <T> void setStatus(final Class<T> clazz, final @Nullable T status, final String key) {
817+
final String cacheKey = this.getStatusCacheKey(clazz, key);
818+
if (status == null) {
819+
statusesExpiringCache.remove(cacheKey);
820+
} else {
821+
statusesExpiringCache.put(cacheKey, status, DEFAULT_STATUS_CACHE_EXPIRE_NANO);
822+
}
823+
}
824+
825+
public <T> T getStatus(final @NonNull Class<T> clazz, final boolean clusterBound) {
826+
String clusterId = null;
827+
if (clusterBound) {
828+
try {
829+
clusterId = this.hostListProvider.getClusterId();
830+
} catch (Exception ex) {
831+
// do nothing
832+
}
833+
}
834+
return this.getStatus(clazz, clusterId);
835+
}
836+
837+
public <T> T getStatus(final @NonNull Class<T> clazz, String key) {
838+
return clazz.cast(statusesExpiringCache.get(this.getStatusCacheKey(clazz, key)));
839+
}
840+
841+
protected <T> String getStatusCacheKey(final Class<T> clazz, final String key) {
842+
return String.format("%s::%s", key == null ? "" : key.trim().toLowerCase(), clazz.getName());
843+
}
844+
845+
public boolean isPluginInUse(final Class<? extends ConnectionPlugin> pluginClazz) {
846+
try {
847+
return this.pluginManager.isWrapperFor(pluginClazz);
848+
} catch (SQLException e) {
849+
return false;
850+
}
851+
}
793852
}

wrapper/src/main/java/software/amazon/jdbc/dialect/AuroraMysqlDialect.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import software.amazon.jdbc.hostlistprovider.monitoring.MonitoringRdsHostListProvider;
2727
import software.amazon.jdbc.plugin.failover2.FailoverConnectionPlugin;
2828

29-
public class AuroraMysqlDialect extends MysqlDialect {
29+
public class AuroraMysqlDialect extends MysqlDialect implements SupportBlueGreen {
3030

3131
private static final String TOPOLOGY_QUERY =
3232
"SELECT SERVER_ID, CASE WHEN SESSION_ID = 'MASTER_SESSION_ID' THEN TRUE ELSE FALSE END, "
@@ -42,6 +42,13 @@ public class AuroraMysqlDialect extends MysqlDialect {
4242
private static final String NODE_ID_QUERY = "SELECT @@aurora_server_id";
4343
private static final String IS_READER_QUERY = "SELECT @@innodb_read_only";
4444

45+
private static final String BG_STATUS_QUERY =
46+
"SELECT * FROM mysql.rds_topology";
47+
48+
private static final String TOPOLOGY_TABLE_EXIST_QUERY =
49+
"SELECT 1 AS tmp FROM information_schema.tables WHERE"
50+
+ " table_schema = 'mysql' AND table_name = 'rds_topology'";
51+
4552
@Override
4653
public boolean isDialect(final Connection connection) {
4754
Statement stmt = null;
@@ -105,5 +112,23 @@ public HostListProviderSupplier getHostListProvider() {
105112
IS_READER_QUERY);
106113
};
107114
}
115+
116+
@Override
117+
public String getBlueGreenStatusQuery() {
118+
return BG_STATUS_QUERY;
119+
}
120+
121+
@Override
122+
public boolean isStatusAvailable(final Connection connection) {
123+
try {
124+
try (Statement statement = connection.createStatement();
125+
ResultSet rs = statement.executeQuery(TOPOLOGY_TABLE_EXIST_QUERY)) {
126+
return rs.next();
127+
}
128+
} catch (SQLException ex) {
129+
return false;
130+
}
131+
}
132+
108133
}
109134

wrapper/src/main/java/software/amazon/jdbc/dialect/AuroraPgDialect.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@
2424
import software.amazon.jdbc.hostlistprovider.AuroraHostListProvider;
2525
import software.amazon.jdbc.hostlistprovider.monitoring.MonitoringRdsHostListProvider;
2626
import software.amazon.jdbc.plugin.failover2.FailoverConnectionPlugin;
27+
import software.amazon.jdbc.util.DriverInfo;
2728

2829
/**
2930
* Suitable for the following AWS PG configurations.
3031
* - Regional Cluster
3132
*/
32-
public class AuroraPgDialect extends PgDialect implements AuroraLimitlessDialect {
33+
public class AuroraPgDialect extends PgDialect implements AuroraLimitlessDialect, SupportBlueGreen {
3334
private static final Logger LOGGER = Logger.getLogger(AuroraPgDialect.class.getName());
3435

3536
private static final String extensionsSql =
@@ -56,6 +57,12 @@ public class AuroraPgDialect extends PgDialect implements AuroraLimitlessDialect
5657
protected static final String LIMITLESS_ROUTER_ENDPOINT_QUERY =
5758
"select router_endpoint, load from aurora_limitless_router_endpoints()";
5859

60+
private static final String BG_STATUS_QUERY =
61+
"SELECT * FROM get_blue_green_fast_switchover_metadata('aws_jdbc_driver-" + DriverInfo.DRIVER_VERSION + "')";
62+
63+
private static final String TOPOLOGY_TABLE_EXIST_QUERY =
64+
"SELECT 'get_blue_green_fast_switchover_metadata'::regproc";
65+
5966
@Override
6067
public boolean isDialect(final Connection connection) {
6168
if (!super.isDialect(connection)) {
@@ -156,4 +163,21 @@ public HostListProviderSupplier getHostListProvider() {
156163
public String getLimitlessRouterEndpointQuery() {
157164
return LIMITLESS_ROUTER_ENDPOINT_QUERY;
158165
}
166+
167+
@Override
168+
public String getBlueGreenStatusQuery() {
169+
return BG_STATUS_QUERY;
170+
}
171+
172+
@Override
173+
public boolean isStatusAvailable(final Connection connection) {
174+
try {
175+
try (Statement statement = connection.createStatement();
176+
ResultSet rs = statement.executeQuery(TOPOLOGY_TABLE_EXIST_QUERY)) {
177+
return rs.next();
178+
}
179+
} catch (SQLException ex) {
180+
return false;
181+
}
182+
}
159183
}

wrapper/src/main/java/software/amazon/jdbc/dialect/RdsMultiAzDbClusterMysqlDialect.java

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import software.amazon.jdbc.plugin.failover.FailoverRestriction;
3131
import software.amazon.jdbc.plugin.failover2.FailoverConnectionPlugin;
3232
import software.amazon.jdbc.util.DriverInfo;
33+
import software.amazon.jdbc.util.RdsUtils;
34+
import software.amazon.jdbc.util.StringUtils;
3335

3436
public class RdsMultiAzDbClusterMysqlDialect extends MysqlDialect {
3537

@@ -50,41 +52,36 @@ public class RdsMultiAzDbClusterMysqlDialect extends MysqlDialect {
5052
private static final EnumSet<FailoverRestriction> RDS_MULTI_AZ_RESTRICTIONS =
5153
EnumSet.of(FailoverRestriction.DISABLE_TASK_A, FailoverRestriction.ENABLE_WRITER_IN_TASK_B);
5254

55+
protected final RdsUtils rdsUtils = new RdsUtils();
56+
5357
@Override
5458
public boolean isDialect(final Connection connection) {
55-
Statement stmt = null;
56-
ResultSet rs = null;
5759
try {
58-
stmt = connection.createStatement();
59-
rs = stmt.executeQuery(TOPOLOGY_TABLE_EXIST_QUERY);
60-
61-
if (rs.next()) {
62-
rs.close();
63-
stmt.close();
64-
65-
stmt = connection.createStatement();
66-
rs = stmt.executeQuery(TOPOLOGY_QUERY);
67-
68-
return rs.next();
60+
try (Statement stmt = connection.createStatement();
61+
ResultSet rs = stmt.executeQuery(TOPOLOGY_TABLE_EXIST_QUERY)) {
62+
if (!rs.next()) {
63+
return false;
64+
}
6965
}
70-
return false;
71-
} catch (final SQLException ex) {
72-
// ignore
73-
} finally {
74-
if (rs != null) {
75-
try {
76-
rs.close();
77-
} catch (SQLException ex) {
78-
// ignore
66+
67+
try (Statement stmt = connection.createStatement();
68+
ResultSet rs = stmt.executeQuery(TOPOLOGY_QUERY)) {
69+
if (!rs.next()) {
70+
return false;
7971
}
8072
}
81-
if (stmt != null) {
82-
try {
83-
stmt.close();
84-
} catch (SQLException ex) {
85-
// ignore
73+
74+
try (Statement stmt = connection.createStatement();
75+
ResultSet rs = stmt.executeQuery("SHOW VARIABLES LIKE 'report_host'")) {
76+
if (!rs.next()) {
77+
return false;
8678
}
79+
final String reportHost = rs.getString(2); // get variable value; expected value is IP address
80+
return !StringUtils.isNullOrEmpty(reportHost);
8781
}
82+
83+
} catch (final SQLException ex) {
84+
// ignore
8885
}
8986
return false;
9087
}

0 commit comments

Comments
 (0)