Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
b94b7f2
wip
aaron-congo Aug 15, 2025
29a58cb
Replace PluginService#forceConnect with ConnectionService#open in Clu…
aaron-congo Aug 15, 2025
f59930d
Add notes for how to fix the current issues
aaron-congo Aug 15, 2025
8fc6d1a
Integ test passing
aaron-congo Aug 18, 2025
b4e5b3a
Pass ConnectionService to ReaderFailoverHandler
aaron-congo Aug 19, 2025
a2342be
Adapted ReaderFailoverHandler, IT passing
aaron-congo Aug 19, 2025
cedbc1b
Merge branch 'main' into failover-handlers
aaron-congo Aug 20, 2025
8108551
Add hostAvailabilityMap to WriterFailoverResult
aaron-congo Aug 20, 2025
0a38ab3
Add hostAvailabilityMap to ReaderFailoverResult
aaron-congo Aug 20, 2025
1a7e2bc
Initialize HostListProvider in PartialPluginService constructor
aaron-congo Aug 20, 2025
a965c3f
Pass ConnectionService as constructor arg to failover handlers
aaron-congo Aug 21, 2025
a3d8a5e
PR suggestions
aaron-congo Aug 22, 2025
4df33da
Fix checkstyle
aaron-congo Aug 22, 2025
7a863c9
ReaderFailoverHandler tests passing
aaron-congo Aug 22, 2025
370d73f
WriterFailoverHandler tests passing
aaron-congo Aug 22, 2025
435f71a
FailoverConnectionPluginTests passing
aaron-congo Aug 22, 2025
7ba0f85
Merge branch 'main' into failover-handlers
aaron-congo Aug 22, 2025
6ebf706
Rename plugin to spyPlugin in FailoverConnectionPluginTest
aaron-congo Aug 22, 2025
7711a9e
Fix failing MonitorServiceImplTest tests
aaron-congo Aug 22, 2025
9928517
Fix failover1 integration test
aaron-congo Aug 26, 2025
6a338f2
testServerFailoverWithIdleConnections uses the correct failover plugin
aaron-congo Aug 26, 2025
367b6a5
Merge branch 'main' into failover-handlers
aaron-congo Aug 26, 2025
faa0915
Fix javadocs
aaron-congo Aug 26, 2025
23e177a
wip
aaron-congo Aug 26, 2025
e1af3eb
Add extra logging to debug IT failure
aaron-congo Aug 29, 2025
c077ee2
Fix bug where cached reader connection was incorrectly closed
aaron-congo Aug 29, 2025
a27cf9f
Merge branch 'main' into failover-handlers
aaron-congo Aug 29, 2025
73cf143
wip
aaron-congo Aug 29, 2025
99de6eb
Fix javadoc
aaron-congo Aug 29, 2025
f1eb529
Merge branch 'failover-handlers' into service-container-utility
aaron-congo Aug 29, 2025
9311447
wip
aaron-congo Aug 29, 2025
f987164
Add ConnectionProvider arg to FullServicesContainer constructor
aaron-congo Sep 2, 2025
47d2e20
Utils.getWriter, PluginService.getDefaultConnectionProvider, isolate …
aaron-congo Sep 2, 2025
fec3639
Merge branch 'main' into failover-handlers
aaron-congo Sep 2, 2025
f7b8db9
Fix failing integration tests
aaron-congo Sep 3, 2025
104d303
Fix dead markdown link
aaron-congo Sep 3, 2025
9fbc65f
Merge branch 'failover-handlers' into service-container-utility
aaron-congo Sep 3, 2025
04ac3c8
wip
aaron-congo Sep 3, 2025
bef4ea8
wip
aaron-congo Sep 3, 2025
cc9421a
Build successful
aaron-congo Sep 3, 2025
3f7fb28
Failover test passing
aaron-congo Sep 4, 2025
edeea73
PR suggestions
aaron-congo Sep 5, 2025
60dbc4e
Merge branch 'failover-handlers' into service-container-utility
aaron-congo Sep 5, 2025
cb6e6ec
Rename to ServiceUtility
aaron-congo Sep 8, 2025
b5f5649
Rename ServicesContainer to ServiceContainer
aaron-congo Sep 8, 2025
f3bb1fd
wip
aaron-congo Sep 8, 2025
b8461a5
wip move initialization out of ConnectionWrapper
aaron-congo Sep 11, 2025
77dccce
Fix unit tests
aaron-congo Sep 15, 2025
85252d0
Cleanup
aaron-congo Sep 15, 2025
85bb5c5
Merge branch 'main' into service-container-utility
aaron-congo Sep 15, 2025
c465a00
Cleanup
aaron-congo Sep 15, 2025
b2a107d
cleanup
aaron-congo Sep 15, 2025
e635745
Fix checkstyle
aaron-congo Sep 15, 2025
74d22c9
Revert "Rename ServicesContainer to ServiceContainer"
aaron-congo Sep 19, 2025
6311d63
Reuse service containers for reader failover ConnectionAttemptTasks
aaron-congo Sep 19, 2025
577ed48
Get build working
aaron-congo Sep 19, 2025
a0cc0c7
Remove pluginService reference in ConnectionPluginManager
aaron-congo Sep 19, 2025
27fc533
wip
aaron-congo Sep 23, 2025
4d984f5
Remove ConnectionWrapper dependency from ConnectionPluginManager wip
aaron-congo Sep 23, 2025
d50ae1e
Pass ConnectionWrapper to Wrapper objects wip
aaron-congo Sep 24, 2025
9364003
Pass ConnectionWrapper to Wrapper objects, building
aaron-congo Sep 24, 2025
7a11cdd
ConnectionPluginManager#init -> ConnectionPluginManager#initPlugins
aaron-congo Sep 24, 2025
8d3eef3
Build passing after uncommenting unit tests
aaron-congo Sep 25, 2025
dc36daa
Check for old connection in WrapperUtils#executeWithPlugins
aaron-congo Sep 25, 2025
7528368
Fix unit tests
aaron-congo Sep 25, 2025
dcc261a
Merge branch 'main' into init-cleanup
aaron-congo Sep 25, 2025
7365a37
gradlew check passing
aaron-congo Sep 25, 2025
20eb07e
Set initial host list provider
aaron-congo Sep 26, 2025
fc6f278
Add missing initHostProvider call
aaron-congo Sep 26, 2025
55c4e33
Integration test passing
aaron-congo Sep 26, 2025
5e01ead
PR suggestions
aaron-congo Oct 7, 2025
87c894b
Merge branch 'main' into service-container-utility
aaron-congo Oct 9, 2025
147a35a
Merge branch 'main' into init-cleanup
aaron-congo Oct 9, 2025
0c6bebc
Merge branch 'service-container-utility' into init-cleanup
aaron-congo Oct 9, 2025
257f856
Fix build, checkstyle
aaron-congo Oct 10, 2025
e0fe874
Close monitor in AbstractMonitor#run()
aaron-congo Oct 10, 2025
e9f5343
Merge branch 'main' into init-cleanup
aaron-congo Oct 10, 2025
16509c0
Overload MonitorServiceImpl#runIfAbsent
aaron-congo Oct 11, 2025
efafe8c
Merge branch 'main' into init-cleanup
aaron-congo Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
import software.amazon.jdbc.util.telemetry.TelemetryCounter;
import software.amazon.jdbc.util.telemetry.TelemetryFactory;
import software.amazon.jdbc.util.telemetry.TelemetryGauge;
import software.amazon.jdbc.wrapper.ConnectionWrapper;

@State(Scope.Benchmark)
@Fork(3)
Expand All @@ -94,7 +93,6 @@ public class ConnectionPluginManagerBenchmarks {
private ConnectionPluginManager pluginManagerWithNoPlugins;

@Mock ConnectionProvider mockConnectionProvider;
@Mock ConnectionWrapper mockConnectionWrapper;
@Mock FullServicesContainer mockServicesContainer;
@Mock PluginService mockPluginService;
@Mock PluginManagerService mockPluginManagerService;
Expand Down Expand Up @@ -162,15 +160,12 @@ public void setUpIteration() throws Exception {

TelemetryFactory telemetryFactory = new DefaultTelemetryFactory(propertiesWithPlugins);

pluginManager = new ConnectionPluginManager(mockConnectionProvider,
null,
mockConnectionWrapper,
telemetryFactory);
pluginManager.init(mockServicesContainer, propertiesWithPlugins, mockPluginManagerService, configurationProfile);
pluginManager = new ConnectionPluginManager(propertiesWithPlugins, telemetryFactory, mockConnectionProvider, null);
pluginManager.initPlugins(mockServicesContainer, configurationProfile);

pluginManagerWithNoPlugins = new ConnectionPluginManager(mockConnectionProvider, null,
mockConnectionWrapper, telemetryFactory);
pluginManagerWithNoPlugins.init(mockServicesContainer, propertiesWithoutPlugins, mockPluginManagerService, null);
pluginManagerWithNoPlugins =
new ConnectionPluginManager(propertiesWithoutPlugins, telemetryFactory, mockConnectionProvider, null);
pluginManagerWithNoPlugins.initPlugins(mockServicesContainer, null);
}

@TearDown(Level.Iteration)
Expand All @@ -180,17 +175,17 @@ public void tearDownIteration() throws Exception {

@Benchmark
public ConnectionPluginManager initConnectionPluginManagerWithNoPlugins() throws SQLException {
final ConnectionPluginManager manager = new ConnectionPluginManager(mockConnectionProvider, null,
mockConnectionWrapper, mockTelemetryFactory);
manager.init(mockServicesContainer, propertiesWithoutPlugins, mockPluginManagerService, configurationProfile);
final ConnectionPluginManager manager =
new ConnectionPluginManager(propertiesWithoutPlugins, mockTelemetryFactory, mockConnectionProvider, null);
manager.initPlugins(mockServicesContainer, configurationProfile);
return manager;
}

@Benchmark
public ConnectionPluginManager initConnectionPluginManagerWithPlugins() throws SQLException {
final ConnectionPluginManager manager = new ConnectionPluginManager(mockConnectionProvider, null,
mockConnectionWrapper, mockTelemetryFactory);
manager.init(mockServicesContainer, propertiesWithPlugins, mockPluginManagerService, configurationProfile);
final ConnectionPluginManager manager =
new ConnectionPluginManager(propertiesWithPlugins, mockTelemetryFactory, mockConnectionProvider, null);
manager.initPlugins(mockServicesContainer, configurationProfile);
return manager;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@
import software.amazon.jdbc.dialect.Dialect;
import software.amazon.jdbc.hostavailability.SimpleHostAvailabilityStrategy;
import software.amazon.jdbc.targetdriverdialect.TargetDriverDialect;
import software.amazon.jdbc.util.monitoring.MonitorService;
import software.amazon.jdbc.util.storage.StorageService;
import software.amazon.jdbc.util.telemetry.GaugeCallable;
import software.amazon.jdbc.util.telemetry.TelemetryContext;
import software.amazon.jdbc.util.telemetry.TelemetryCounter;
Expand All @@ -84,17 +82,15 @@ public class PluginBenchmarks {
private static final String FIELD_SERVER_ID = "SERVER_ID";
private static final String FIELD_SESSION_ID = "SESSION_ID";
private static final String CONNECTION_STRING = "jdbc:postgresql://my.domain.com";
private static final String PG_PROTOCOL = "jdbc:postgresql://";
private static final String PG_CONNECTION_STRING =
"jdbc:aws-wrapper:postgresql://instance-0.XYZ.us-east-2.rds.amazonaws.com";
private static final String TEST_HOST = "instance-0";
private static final int TEST_PORT = 5432;
private final HostSpec writerHostSpec = new HostSpecBuilder(new SimpleHostAvailabilityStrategy())
.host(TEST_HOST).port(TEST_PORT).build();

@Mock private StorageService mockStorageService;
@Mock private MonitorService mockMonitorService;
@Mock private PluginService mockPluginService;
@Mock private TargetDriverDialect mockTargetDriverDialect;
@Mock private Dialect mockDialect;
@Mock private ConnectionPluginManager mockConnectionPluginManager;
@Mock private TelemetryFactory mockTelemetryFactory;
Expand Down Expand Up @@ -173,15 +169,11 @@ private ConnectionWrapper getConnectionWrapper(Properties props, String connStri
return new TestConnectionWrapper(
props,
connString,
mockConnectionProvider,
mockTargetDriverDialect,
PG_PROTOCOL,
mockConnectionPluginManager,
mockTelemetryFactory,
mockPluginService,
mockHostListProviderService,
mockPluginManagerService,
mockStorageService,
mockMonitorService);
mockPluginManagerService);
}

@Benchmark
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,29 @@
import java.util.Properties;
import org.checkerframework.checker.nullness.qual.NonNull;
import software.amazon.jdbc.ConnectionPluginManager;
import software.amazon.jdbc.ConnectionProvider;
import software.amazon.jdbc.HostListProviderService;
import software.amazon.jdbc.PluginManagerService;
import software.amazon.jdbc.PluginService;
import software.amazon.jdbc.targetdriverdialect.TargetDriverDialect;
import software.amazon.jdbc.util.monitoring.MonitorService;
import software.amazon.jdbc.util.storage.StorageService;
import software.amazon.jdbc.util.telemetry.TelemetryFactory;
import software.amazon.jdbc.wrapper.ConnectionWrapper;

// Test class allowing for mocks to be used with ConnectionWrapper logic
public class TestConnectionWrapper extends ConnectionWrapper {

public TestConnectionWrapper(
@NonNull final Properties props,
@NonNull final String url,
@NonNull final ConnectionProvider defaultConnectionProvider,
@NonNull final TargetDriverDialect driverDialect,
@NonNull final String protocol,
@NonNull final ConnectionPluginManager connectionPluginManager,
@NonNull final TelemetryFactory telemetryFactory,
@NonNull final PluginService pluginService,
@NonNull final HostListProviderService hostListProviderService,
@NonNull final PluginManagerService pluginManagerService,
@NonNull final StorageService storageService,
@NonNull final MonitorService monitorService)
@NonNull final PluginManagerService pluginManagerService)
throws SQLException {
super(
props,
url,
defaultConnectionProvider,
driverDialect,
protocol,
connectionPluginManager,
telemetryFactory,
pluginService,
hostListProviderService,
pluginManagerService,
storageService,
monitorService);
pluginManagerService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ public List<ConnectionPlugin> getPlugins(
final FullServicesContainer servicesContainer,
final ConnectionProvider defaultConnProvider,
final ConnectionProvider effectiveConnProvider,
final PluginManagerService pluginManagerService,
final Properties props,
@Nullable ConfigurationProfile configurationProfile) throws SQLException {

Expand Down Expand Up @@ -234,7 +233,7 @@ public List<ConnectionPlugin> getPlugins(
servicesContainer.getPluginService(),
defaultConnProvider,
effectiveConnProvider,
pluginManagerService);
servicesContainer.getPluginManagerService());

plugins.add(defaultPlugin);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,9 @@
import software.amazon.jdbc.util.FullServicesContainer;
import software.amazon.jdbc.util.Messages;
import software.amazon.jdbc.util.Utils;
import software.amazon.jdbc.util.WrapperUtils;
import software.amazon.jdbc.util.telemetry.TelemetryContext;
import software.amazon.jdbc.util.telemetry.TelemetryFactory;
import software.amazon.jdbc.util.telemetry.TelemetryTraceLevel;
import software.amazon.jdbc.wrapper.ConnectionWrapper;

/**
* This class creates and handles a chain of {@link ConnectionPlugin} for each connection.
Expand Down Expand Up @@ -92,29 +90,25 @@ public class ConnectionPluginManager implements CanReleaseResources, Wrapper {
}
};

private final ReentrantLock lock = new ReentrantLock();

protected Properties props = new Properties();
protected List<ConnectionPlugin> plugins;
protected final @NonNull ConnectionProvider defaultConnProvider;
protected final @Nullable ConnectionProvider effectiveConnProvider;
protected final ConnectionWrapper connectionWrapper;
protected FullServicesContainer servicesContainer;
protected PluginService pluginService;
protected TelemetryFactory telemetryFactory;
protected boolean isTelemetryInUse;
@SuppressWarnings("rawtypes")
protected final PluginChainJdbcCallableInfo[] pluginChainFuncMap =
new PluginChainJdbcCallableInfo[JdbcMethod.ALL.id + 1]; // it should be the last element in JdbcMethod enum
protected final ReentrantLock lock = new ReentrantLock();
protected final Properties props;
protected final TelemetryFactory telemetryFactory;
protected final boolean isTelemetryInUse;
protected final ConnectionProvider defaultConnProvider;
protected final @Nullable ConnectionProvider effectiveConnProvider;
protected List<ConnectionPlugin> plugins;

public ConnectionPluginManager(
final @NonNull Properties props,
final @NonNull TelemetryFactory telemetryFactory,
final @NonNull ConnectionProvider defaultConnProvider,
final @Nullable ConnectionProvider effectiveConnProvider,
final @Nullable ConnectionWrapper connectionWrapper,
final @NonNull TelemetryFactory telemetryFactory) {
final @Nullable ConnectionProvider effectiveConnProvider) {
this.props = props;
this.defaultConnProvider = defaultConnProvider;
this.effectiveConnProvider = effectiveConnProvider;
this.connectionWrapper = connectionWrapper;
this.telemetryFactory = telemetryFactory;
this.isTelemetryInUse = telemetryFactory.inUse();
}
Expand All @@ -127,28 +121,11 @@ public ConnectionPluginManager(
final @Nullable ConnectionProvider effectiveConnProvider,
final Properties props,
final List<ConnectionPlugin> plugins,
final ConnectionWrapper connectionWrapper,
final PluginService pluginService,
final TelemetryFactory telemetryFactory) {
this(defaultConnProvider, effectiveConnProvider, props, plugins, connectionWrapper, telemetryFactory);
this.pluginService = pluginService;
}

/**
* This constructor is for testing purposes only.
*/
ConnectionPluginManager(
final @NonNull ConnectionProvider defaultConnProvider,
final @Nullable ConnectionProvider effectiveConnProvider,
final Properties props,
final List<ConnectionPlugin> plugins,
final ConnectionWrapper connectionWrapper,
final TelemetryFactory telemetryFactory) {
this.defaultConnProvider = defaultConnProvider;
this.effectiveConnProvider = effectiveConnProvider;
this.props = props;
this.plugins = plugins;
this.connectionWrapper = connectionWrapper;
this.telemetryFactory = telemetryFactory;
this.isTelemetryInUse = telemetryFactory.inUse();
}
Expand All @@ -170,30 +147,18 @@ public void unlock() {
* connection plugin in the chain.
*
* @param servicesContainer the service container for the services required by this class.
* @param props the configuration of the connection
* @param pluginManagerService a reference to a plugin manager service
* @param configurationProfile a profile configuration defined by the user
* @throws SQLException if errors occurred during the execution
*/
public void init(
public void initPlugins(
final FullServicesContainer servicesContainer,
final Properties props,
final PluginManagerService pluginManagerService,
@Nullable ConfigurationProfile configurationProfile) throws SQLException {

this.props = props;
this.servicesContainer = servicesContainer;
this.pluginService = servicesContainer.getPluginService();
this.telemetryFactory = servicesContainer.getTelemetryFactory();
this.isTelemetryInUse = telemetryFactory.inUse();

ConnectionPluginChainBuilder pluginChainBuilder = new ConnectionPluginChainBuilder();
this.plugins = pluginChainBuilder.getPlugins(
this.servicesContainer,
servicesContainer,
this.defaultConnProvider,
this.effectiveConnProvider,
pluginManagerService,
props,
this.props,
configurationProfile);
}

Expand Down Expand Up @@ -223,14 +188,8 @@ protected <T, E extends Exception> T executeWithSubscribedPlugins(
this.pluginChainFuncMap[jdbcMethod.id] = pluginChainJdbcCallableInfo;
}


if (pluginChainJdbcCallableInfo == null) {
throw new RuntimeException("Error processing this JDBC call.");
}

if (jdbcMethod.alwaysUsePipeline || pluginChainJdbcCallableInfo.isSubscribed) {
// noinspection unchecked
@SuppressWarnings("unchecked")
PluginChainJdbcCallable<T, E> pluginChainFunc = pluginChainJdbcCallableInfo.func;
return pluginChainFunc.call(pluginPipeline, jdbcMethodFunc, pluginToSkip);
} else {
Expand Down Expand Up @@ -320,10 +279,6 @@ protected <E extends Exception> void notifySubscribedPlugins(
}
}

public ConnectionWrapper getConnectionWrapper() {
return this.connectionWrapper;
}

public TelemetryFactory getTelemetryFactory() {
return this.telemetryFactory;
}
Expand All @@ -345,18 +300,6 @@ public <T, E extends Exception> T execute(
final JdbcCallable<T, E> jdbcMethodFunc,
final Object[] jdbcMethodArgs)
throws E {

// The target driver may block on Statement.getConnection().
if (jdbcMethod.shouldLockConnection && jdbcMethod.checkBoundedConnection) {
final Connection conn = WrapperUtils.getConnectionFromSqlObject(methodInvokeOn);
if (conn != null && conn != this.pluginService.getCurrentConnection()) {
throw WrapperUtils.wrapExceptionIfNeeded(
exceptionClass,
new SQLException(
Messages.get("ConnectionPluginManager.invokedAgainstOldConnection", new Object[]{methodInvokeOn})));
}
}

return executeWithSubscribedPlugins(
jdbcMethod,
(plugin, func) ->
Expand Down Expand Up @@ -635,9 +578,7 @@ public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface == ConnectionPluginManager.class) {
return iface.cast(this);
}
if (iface == PluginService.class) {
return iface.cast(this.pluginService);
}

if (this.plugins == null) {
return null;
}
Expand All @@ -647,6 +588,7 @@ public <T> T unwrap(Class<T> iface) throws SQLException {
return iface.cast(p);
}
}

return null;
}

Expand Down
19 changes: 11 additions & 8 deletions wrapper/src/main/java/software/amazon/jdbc/Driver.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@
import software.amazon.jdbc.util.CoreServicesContainer;
import software.amazon.jdbc.util.DriverInfo;
import software.amazon.jdbc.util.FullServicesContainer;
import software.amazon.jdbc.util.FullServicesContainerImpl;
import software.amazon.jdbc.util.Messages;
import software.amazon.jdbc.util.PropertyUtils;
import software.amazon.jdbc.util.RdsUtils;
import software.amazon.jdbc.util.ServiceUtility;
import software.amazon.jdbc.util.StringUtils;
import software.amazon.jdbc.util.WrapperUtils;
import software.amazon.jdbc.util.monitoring.MonitorService;
Expand Down Expand Up @@ -110,6 +110,7 @@ public class Driver implements java.sql.Driver {

private final StorageService storageService;
private final MonitorService monitorService;
private final ConnectionUrlParser urlParser = new ConnectionUrlParser();

public Driver() {
this(CoreServicesContainer.getInstance());
Expand Down Expand Up @@ -239,18 +240,20 @@ public Connection connect(final String url, final Properties info) throws SQLExc
effectiveConnectionProvider = configurationProfile.getConnectionProvider();
}

FullServicesContainer servicesContainer =
new FullServicesContainerImpl(storageService, monitorService, defaultConnectionProvider, telemetryFactory);

return new ConnectionWrapper(
servicesContainer,
props,
driverUrl,
String targetDriverProtocol = urlParser.getProtocol(driverUrl);
FullServicesContainer servicesContainer = ServiceUtility.getInstance().createStandardServiceContainer(
storageService,
monitorService,
defaultConnectionProvider,
effectiveConnectionProvider,
telemetryFactory,
driverUrl,
targetDriverProtocol,
targetDriverDialect,
props,
configurationProfile);

return new ConnectionWrapper(servicesContainer, props, url, targetDriverProtocol, configurationProfile);
} catch (Exception ex) {
if (context != null) {
context.setException(ex);
Expand Down
Loading
Loading