This is an automated email from the ASF dual-hosted git repository.
yx9o 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 c453536116f Warn when single tables exist in multiple storage units
(#39600)
c453536116f is described below
commit c453536116f57e5739eaa90fdbacb2747308a7cc
Author: Haoran Meng <[email protected]>
AuthorDate: Wed Aug 26 08:06:17 2026 +0800
Warn when single tables exist in multiple storage units (#39600)
---
.../single/datanode/SingleTableDataNodeLoader.java | 19 ++++++++-
.../datanode/SingleTableDataNodeLoaderTest.java | 48 ++++++++++++++++++++++
2 files changed, 65 insertions(+), 2 deletions(-)
diff --git
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoader.java
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoader.java
index f84d0fb1561..ae251323eb7 100644
---
a/kernel/single/core/src/main/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoader.java
+++
b/kernel/single/core/src/main/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoader.java
@@ -20,6 +20,7 @@ package org.apache.shardingsphere.single.datanode;
import com.cedarsoftware.util.CaseInsensitiveSet;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import
org.apache.shardingsphere.database.connector.core.metadata.data.loader.type.SchemaMetaDataLoader;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.database.DatabaseTypeEngine;
@@ -46,6 +47,7 @@ import java.util.stream.Collectors;
* Single table data node loader.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@Slf4j
public final class SingleTableDataNodeLoader {
/**
@@ -68,7 +70,9 @@ public final class SingleTableDataNodeLoader {
Collection<String> splitTables =
SingleTableLoadUtils.splitTableLines(configuredTables);
if (splitTables.contains(SingleTableConstants.ALL_TABLES) ||
splitTables.contains(SingleTableConstants.ALL_SCHEMA_TABLES)) {
Map<String, DatabaseType> storageTypes =
dataSourceMap.entrySet().stream().collect(Collectors.toMap(Entry::getKey, each
-> DatabaseTypeEngine.getStorageType(each.getValue())));
- return load(databaseName, dataSourceMap, Collections.emptySet(),
excludedTables, storageTypes);
+ Map<String, Collection<DataNode>> result = load(databaseName,
dataSourceMap, Collections.emptySet(), excludedTables, storageTypes);
+ warnIfSingleTableLoadedFromMultipleDataSources(databaseName,
result);
+ return result;
}
Collection<DataNode> configuredDataNodes =
getConfiguredDataNodes(splitTables);
Collection<String> configuredDataSources =
getConfiguredDataSources(configuredDataNodes);
@@ -78,7 +82,9 @@ public final class SingleTableDataNodeLoader {
Map<String, DatabaseType> validStorageTypes =
validDataSources.entrySet().stream().collect(Collectors.toMap(Entry::getKey,
each -> DatabaseTypeEngine.getStorageType(each.getValue())));
Map<String, Collection<DataNode>> actualDataNodes = load(databaseName,
validDataSources, includedTables, excludedTables, validStorageTypes);
Map<String, Map<String, Collection<String>>> configuredTableMap =
getConfiguredTableMap(databaseName, protocolType, splitTables,
validStorageTypes);
- return loadSpecifiedDataNodes(actualDataNodes,
featureRequiredSingleTables, configuredTableMap);
+ Map<String, Collection<DataNode>> result =
loadSpecifiedDataNodes(actualDataNodes, featureRequiredSingleTables,
configuredTableMap);
+ warnIfSingleTableLoadedFromMultipleDataSources(databaseName, result);
+ return result;
}
/**
@@ -121,6 +127,15 @@ public final class SingleTableDataNodeLoader {
return result;
}
+ private static void warnIfSingleTableLoadedFromMultipleDataSources(final
String databaseName, final Map<String, Collection<DataNode>> dataNodes) {
+ for (Entry<String, Collection<DataNode>> entry : dataNodes.entrySet())
{
+ Collection<String> dataSourceNames =
entry.getValue().stream().map(DataNode::getDataSourceName).collect(Collectors.toCollection(LinkedHashSet::new));
+ if (1 < dataSourceNames.size()) {
+ log.warn("Single table '{}' is loaded from multiple storage
units {} in database '{}'.", entry.getKey(), dataSourceNames, databaseName);
+ }
+ }
+ }
+
private static Collection<DataNode> getConfiguredDataNodes(final
Collection<String> splitTables) {
return
splitTables.stream().map(DataNode::new).collect(Collectors.toList());
}
diff --git
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoaderTest.java
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoaderTest.java
index 1b0966aea63..cad0aad5812 100644
---
a/kernel/single/core/src/test/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoaderTest.java
+++
b/kernel/single/core/src/test/java/org/apache/shardingsphere/single/datanode/SingleTableDataNodeLoaderTest.java
@@ -17,6 +17,8 @@
package org.apache.shardingsphere.single.datanode;
+import ch.qos.logback.classic.Level;
+import
org.apache.shardingsphere.database.connector.core.metadata.data.loader.type.SchemaMetaDataLoader;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.database.DatabaseTypeEngine;
import org.apache.shardingsphere.infra.datanode.DataNode;
@@ -25,12 +27,16 @@ import
org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
import
org.apache.shardingsphere.infra.rule.attribute.table.TableMapperRuleAttribute;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.single.exception.SingleTablesLoadingException;
+import
org.apache.shardingsphere.test.infra.framework.extension.log.LogCaptureAssertion;
+import
org.apache.shardingsphere.test.infra.framework.extension.log.LogCaptureExtension;
import org.apache.shardingsphere.test.infra.fixture.jdbc.MockedDataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import javax.sql.DataSource;
@@ -54,11 +60,13 @@ import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+@ExtendWith(LogCaptureExtension.class)
class SingleTableDataNodeLoaderTest {
private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
@@ -169,6 +177,46 @@ class SingleTableDataNodeLoaderTest {
assertTrue(SingleTableDataNodeLoader.load("foo_db", databaseType,
dataSourceMap, Collections.emptyList(), configuredTables).isEmpty());
}
+ @Test
+ void assertLoadWithSameTableInDifferentDataSources(final
LogCaptureAssertion logCaptureAssertion) throws SQLException {
+ Map<String, DataSource> localDataSourceMap = new LinkedHashMap<>(2,
1F);
+ localDataSourceMap.put("foo_ds", mockDataSource("foo_ds",
Collections.singletonList("same_tbl")));
+ localDataSourceMap.put("bar_ds", mockDataSource("bar_ds",
Collections.singletonList("same_tbl")));
+ Map<String, Collection<DataNode>> actual =
SingleTableDataNodeLoader.load(
+ "foo_db", databaseType, localDataSourceMap,
Collections.emptyList(), Arrays.asList("foo_ds.same_tbl", "bar_ds.same_tbl"));
+ assertThat(actual.get("same_tbl").size(), is(2));
+ logCaptureAssertion.assertLogCount(1);
+ logCaptureAssertion.assertLogContent(0, Level.WARN,
+ "Single table 'same_tbl' is loaded from multiple storage units
[foo_ds, bar_ds] in database 'foo_db'.", true);
+ }
+
+ @Test
+ void assertLoadWithSameTableInDifferentSchemasOfSameDataSource(final
LogCaptureAssertion logCaptureAssertion) throws SQLException {
+ Map<String, DataSource> localDataSourceMap =
Collections.singletonMap("foo_ds", dataSourceMap.get("foo_ds"));
+ Map<String, Collection<String>> schemaTableNames = new
LinkedHashMap<>(2, 1F);
+ schemaTableNames.put("foo_schema", Collections.singleton("same_tbl"));
+ schemaTableNames.put("bar_schema", Collections.singleton("same_tbl"));
+ try (
+ MockedConstruction<SchemaMetaDataLoader> ignored =
mockConstruction(SchemaMetaDataLoader.class,
+ (mock, context) ->
when(mock.loadSchemaTableNames("foo_db", localDataSourceMap.get("foo_ds"),
Collections.emptySet(), Collections.emptySet())).thenReturn(schemaTableNames)))
{
+ Map<String, Collection<DataNode>> actual =
SingleTableDataNodeLoader.load(
+ "foo_db", databaseType, localDataSourceMap,
Collections.emptyList(), Collections.singleton("*.*.*"));
+ assertThat(actual.get("same_tbl").size(), is(2));
+ logCaptureAssertion.assertLogCount(0);
+ }
+ }
+
+ @Test
+ void assertLoadWithDataSourceMapDoesNotWarn(final LogCaptureAssertion
logCaptureAssertion) throws SQLException {
+ Map<String, DataSource> localDataSourceMap = new LinkedHashMap<>(2,
1F);
+ localDataSourceMap.put("foo_ds", mockDataSource("foo_ds",
Collections.singletonList("same_tbl")));
+ localDataSourceMap.put("bar_ds", mockDataSource("bar_ds",
Collections.singletonList("same_tbl")));
+ Map<String, Collection<DataNode>> actual =
SingleTableDataNodeLoader.load(
+ "foo_db", localDataSourceMap, Collections.emptySet(),
Collections.emptySet(), createStorageTypes(localDataSourceMap));
+ assertThat(actual.get("same_tbl").size(), is(2));
+ logCaptureAssertion.assertLogCount(0);
+ }
+
@Test
void assertLoadWithEmptyConfiguredTablesAndFeatureRequiredSingleTables() {
assertTrue(SingleTableDataNodeLoader.load(