This is an automated email from the ASF dual-hosted git repository.
terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new adc65c67d09 Continue closing storage data sources after a close
failure (#39988)
adc65c67d09 is described below
commit adc65c67d0948a045959fc3b15c59303ebf2c3c8
Author: ZIHAN DAI <[email protected]>
AuthorDate: Mon Oct 5 17:56:43 2026 +1100
Continue closing storage data sources after a close failure (#39988)
* Continue closing storage data sources after a close failure
* Keep data source test constructor calls on single lines
---
.../core/datasource/ShardingSphereDataSource.java | 14 ++++++-
.../datasource/ShardingSphereDataSourceTest.java | 47 ++++++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git
a/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSource.java
b/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSource.java
index 90b9c356f07..dbd1a71a38a 100644
---
a/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSource.java
+++
b/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSource.java
@@ -110,10 +110,22 @@ public final class ShardingSphereDataSource extends
AbstractDataSourceAdapter im
@Override
public void close() throws SQLException {
+ SQLException exception = null;
for (StorageUnit each :
contextManager.getStorageUnits(databaseName).values()) {
- close(each.getDataSource());
+ try {
+ close(each.getDataSource());
+ } catch (final SQLException ex) {
+ if (null == exception) {
+ exception = ex;
+ } else {
+ exception.addSuppressed(ex);
+ }
+ }
}
contextManager.close();
+ if (null != exception) {
+ throw exception;
+ }
}
private void close(final DataSource dataSource) throws SQLException {
diff --git
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSourceTest.java
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSourceTest.java
index e56194fff41..15aa73ac884 100644
---
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSourceTest.java
+++
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/datasource/ShardingSphereDataSourceTest.java
@@ -38,15 +38,20 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
class ShardingSphereDataSourceTest {
@@ -142,6 +147,48 @@ class ShardingSphereDataSourceTest {
}
}
+ @Test
+ void assertCloseRemainingDataSourcesWhenCloseFails() throws SQLException {
+ HikariDataSource failedDataSource = spy(createHikariDataSource());
+ HikariDataSource remainingDataSource = createHikariDataSource();
+ doThrow(new RuntimeException("close
failed")).doCallRealMethod().when(failedDataSource).close();
+ Map<String, DataSource> dataSources = new LinkedHashMap<>(2, 1F);
+ dataSources.put("ds_0", failedDataSource);
+ dataSources.put("ds_1", remainingDataSource);
+ ShardingSphereDataSource actual = new
ShardingSphereDataSource("foo_db", null, dataSources,
Collections.singleton(mock(RuleConfiguration.class)), new Properties());
+ try {
+ SQLException actualException = assertThrows(SQLException.class,
actual::close);
+ assertThat(actualException.getCause().getMessage(), is("close
failed"));
+ assertTrue(remainingDataSource.isClosed());
+ } finally {
+ reset(failedDataSource);
+ failedDataSource.close();
+ remainingDataSource.close();
+ }
+ }
+
+ @Test
+ void assertKeepLaterCloseFailuresAsSuppressed() throws SQLException {
+ HikariDataSource firstDataSource = spy(createHikariDataSource());
+ HikariDataSource secondDataSource = spy(createHikariDataSource());
+ doThrow(new RuntimeException("first close
failed")).doCallRealMethod().when(firstDataSource).close();
+ doThrow(new RuntimeException("second close
failed")).doCallRealMethod().when(secondDataSource).close();
+ Map<String, DataSource> dataSources = new LinkedHashMap<>(2, 1F);
+ dataSources.put("ds_0", firstDataSource);
+ dataSources.put("ds_1", secondDataSource);
+ ShardingSphereDataSource actual = new
ShardingSphereDataSource("foo_db", null, dataSources,
Collections.singleton(mock(RuleConfiguration.class)), new Properties());
+ try {
+ SQLException actualException = assertThrows(SQLException.class,
actual::close);
+ assertThat(actualException.getCause().getMessage(), is("first
close failed"));
+ assertThat(actualException.getSuppressed().length, is(1));
+
assertThat(actualException.getSuppressed()[0].getCause().getMessage(),
is("second close failed"));
+ } finally {
+ reset(firstDataSource, secondDataSource);
+ firstDataSource.close();
+ secondDataSource.close();
+ }
+ }
+
@SneakyThrows(ReflectiveOperationException.class)
private ContextManager getContextManager(final ShardingSphereDataSource
dataSource) {
return (ContextManager)
Plugins.getMemberAccessor().get(ShardingSphereDataSource.class.getDeclaredField("contextManager"),
dataSource);