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);

Reply via email to