Skip to content

Commit 8a83947

Browse files
committed
Improve sharding actual index naming to reduce name inflation
1 parent 24a65e6 commit 8a83947

10 files changed

Lines changed: 172 additions & 12 deletions

File tree

features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public Optional<IndexMetaData> revise(final String tableName, final IndexMetaDat
4040
return Optional.empty();
4141
}
4242
IndexMetaData result = new IndexMetaData(
43-
IndexMetaDataUtils.getLogicIndexName(originalMetaData.getName(), shardingTable.getActualDataNodes().iterator().next().getTableName()), originalMetaData.getColumns());
43+
IndexMetaDataUtils.getGeneratedLogicIndexName(originalMetaData.getName(), shardingTable.getActualDataNodes().iterator().next().getTableName()), originalMetaData.getColumns());
4444
result.setUnique(originalMetaData.isUnique());
4545
return Optional.of(result);
4646
}

features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/metadata/reviser/index/ShardingIndexReviserTest.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.apache.shardingsphere.database.connector.core.metadata.data.model.IndexMetaData;
2121
import org.apache.shardingsphere.infra.datanode.DataNode;
22+
import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
2223
import org.apache.shardingsphere.sharding.rule.ShardingRule;
2324
import org.apache.shardingsphere.sharding.rule.ShardingTable;
2425
import org.junit.jupiter.api.Test;
@@ -42,12 +43,21 @@ void assertReviseWithEmptyActualDataNode() {
4243

4344
@Test
4445
void assertReviseWithActualDataNodes() {
45-
Optional<IndexMetaData> actual = new ShardingIndexReviser(mockShardingTable()).revise("tbl_0", new IndexMetaData("foo_idx", Collections.singletonList("foo_col")), mock(ShardingRule.class));
46+
Optional<IndexMetaData> actual = new ShardingIndexReviser(mockShardingTable())
47+
.revise("tbl_0", new IndexMetaData(IndexMetaDataUtils.getActualIndexName("foo_idx", "tbl_0"), Collections.singletonList("foo_col")), mock(ShardingRule.class));
4648
assertTrue(actual.isPresent());
4749
assertThat(actual.get().getName(), is("foo_idx"));
4850
assertThat(actual.get().getColumns().size(), is(1));
4951
}
5052

53+
@Test
54+
void assertReviseWithLegacyActualIndexName() {
55+
Optional<IndexMetaData> actual = new ShardingIndexReviser(mockShardingTable())
56+
.revise("tbl_0", new IndexMetaData(IndexMetaDataUtils.getLegacyActualIndexName("foo_idx", "tbl_0"), Collections.singletonList("foo_col")), mock(ShardingRule.class));
57+
assertTrue(actual.isPresent());
58+
assertThat(actual.get().getName(), is("foo_idx"));
59+
}
60+
5161
private static ShardingTable mockShardingTable() {
5262
ShardingTable result = mock(ShardingTable.class);
5363
when(result.getActualDataNodes()).thenReturn(Arrays.asList(new DataNode("foo_schema", (String) null, "tbl_0"), new DataNode("foo_schema", (String) null, "tbl_1")));

features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/rewrite/token/pojo/IndexTokenTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
2323
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
2424
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
25+
import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
2526
import org.apache.shardingsphere.infra.route.context.RouteMapper;
2627
import org.apache.shardingsphere.infra.route.context.RouteUnit;
2728
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
@@ -58,15 +59,15 @@ void assertToStringWithShardingTable() {
5859
ShardingRule rule = mock(ShardingRule.class);
5960
when(rule.isShardingTable("foo_tbl")).thenReturn(true);
6061
IndexToken indexToken = new IndexToken(0, 0, new IdentifierValue("foo_idx"), selectStatementContext, rule, mockSchema());
61-
assertThat(indexToken.toString(mockRouteUnit()), is("foo_idx_foo_tbl_0"));
62+
assertThat(indexToken.toString(mockRouteUnit()), is(IndexMetaDataUtils.getActualIndexName("foo_idx", "foo_tbl_0")));
6263
}
6364

6465
@Test
6566
void assertToStringWithShardingTableAndGeneratedIndex() {
6667
CreateIndexStatement sqlStatement = CreateIndexStatement.builder().databaseType(databaseType).build();
6768
CommonSQLStatementContext sqlStatementContext = new CommonSQLStatementContext(sqlStatement);
6869
IndexToken indexToken = new IndexToken(0, 0, new IdentifierValue("bar_idx"), sqlStatementContext, mock(ShardingRule.class), mockSchema());
69-
assertThat(indexToken.toString(mockRouteUnit()), is(" bar_idx_foo_tbl_0 "));
70+
assertThat(indexToken.toString(mockRouteUnit()), is(" " + IndexMetaDataUtils.getActualIndexName("bar_idx", "foo_tbl_0") + " "));
7071
}
7172

7273
private ShardingSphereSchema mockSchema() {

features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResult.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,14 @@ private void replaceIndexes(final MemoryQueryResultRow memoryResultSetRow, final
8383
for (ShardingSphereIndex each : table.getAllIndexes()) {
8484
String actualIndexName = IndexMetaDataUtils.getActualIndexName(each.getName(), actualTableName);
8585
memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(actualIndexName, each.getName()));
86+
String legacyActualIndexName = IndexMetaDataUtils.getLegacyActualIndexName(each.getName(), actualTableName);
87+
memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(legacyActualIndexName, each.getName()));
8688
}
8789
}
8890

8991
private void replaceConstraints(final MemoryQueryResultRow memoryResultSetRow, final String actualTableName, final ShardingSphereTable table, final ShardingRule rule) {
9092
for (ShardingSphereConstraint each : table.getAllConstraints()) {
91-
String actualIndexName = IndexMetaDataUtils.getActualIndexName(each.getName(), actualTableName);
93+
String actualIndexName = IndexMetaDataUtils.getLegacyActualIndexName(each.getName(), actualTableName);
9294
memoryResultSetRow.setCell(2, memoryResultSetRow.getCell(2).toString().replace(actualIndexName, each.getName()));
9395
Optional<ShardingTable> shardingTable = rule.findShardingTable(each.getReferencedTableName());
9496
if (!shardingTable.isPresent()) {

features/sharding/dialect/mysql/src/main/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ protected List<MemoryQueryResultRow> init(final ShardingRule shardingRule, final
5252
String actualIndexName = memoryResultSetRow.getCell(3).toString();
5353
Optional<ShardingTable> shardingTable = shardingRule.findShardingTableByActualTable(actualTableName);
5454
shardingTable.ifPresent(optional -> memoryResultSetRow.setCell(1, optional.getLogicTable()));
55-
memoryResultSetRow.setCell(3, IndexMetaDataUtils.getLogicIndexName(actualIndexName, actualTableName));
55+
memoryResultSetRow.setCell(3, IndexMetaDataUtils.getGeneratedLogicIndexName(actualIndexName, actualTableName));
5656
result.add(memoryResultSetRow);
5757
}
5858
}

features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowCreateTableMergedResultTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
2424
import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
2525
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereConstraint;
26+
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereIndex;
2627
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
2728
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
29+
import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
2830
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
2931
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
3032
import org.apache.shardingsphere.sharding.rule.ShardingRule;
@@ -132,6 +134,28 @@ void assertGetValueWithoutTableRule() throws SQLException {
132134
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"));
133135
}
134136

137+
@Test
138+
void assertGetValueWithLegacyIndexName() throws SQLException {
139+
MySQLShardingShowCreateTableMergedResult actual = new MySQLShardingShowCreateTableMergedResult(
140+
rule, mock(SQLStatementContext.class), createSchemaWithIndex(), Collections.singletonList(mockQueryResultWithIndex(IndexMetaDataUtils.getLegacyActualIndexName("foo_idx", "foo_tbl_0"))));
141+
assertTrue(actual.next());
142+
assertThat(actual.getValue(2, String.class), is("CREATE TABLE `foo_tbl` (\n"
143+
+ " `id` int(11) NOT NULL,\n"
144+
+ " KEY `foo_idx` (`id`)\n"
145+
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"));
146+
}
147+
148+
@Test
149+
void assertGetValueWithShortenedIndexName() throws SQLException {
150+
MySQLShardingShowCreateTableMergedResult actual = new MySQLShardingShowCreateTableMergedResult(
151+
rule, mock(SQLStatementContext.class), createSchemaWithIndex(), Collections.singletonList(mockQueryResultWithIndex(IndexMetaDataUtils.getActualIndexName("foo_idx", "foo_tbl_0"))));
152+
assertTrue(actual.next());
153+
assertThat(actual.getValue(2, String.class), is("CREATE TABLE `foo_tbl` (\n"
154+
+ " `id` int(11) NOT NULL,\n"
155+
+ " KEY `foo_idx` (`id`)\n"
156+
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin"));
157+
}
158+
135159
private QueryResult mockQueryResultWithoutTableRule() throws SQLException {
136160
QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
137161
when(result.getMetaData().getColumnCount()).thenReturn(2);
@@ -148,4 +172,21 @@ private QueryResult mockQueryResultWithoutTableRule() throws SQLException {
148172
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin");
149173
return result;
150174
}
175+
176+
private ShardingSphereSchema createSchemaWithIndex() {
177+
ShardingSphereTable table = new ShardingSphereTable("foo_tbl", Collections.emptyList(), Collections.singleton(new ShardingSphereIndex("foo_idx", Collections.emptyList(), false)), Collections.emptyList());
178+
return new ShardingSphereSchema("foo_db", mock(DatabaseType.class), Collections.singleton(table), Collections.emptyList());
179+
}
180+
181+
private QueryResult mockQueryResultWithIndex(final String actualIndexName) throws SQLException {
182+
QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
183+
when(result.getMetaData().getColumnCount()).thenReturn(2);
184+
when(result.next()).thenReturn(true, false);
185+
when(result.getValue(1, Object.class)).thenReturn("foo_tbl_0");
186+
when(result.getValue(2, Object.class)).thenReturn("CREATE TABLE `foo_tbl_0` (\n"
187+
+ " `id` int(11) NOT NULL,\n"
188+
+ " KEY `" + actualIndexName + "` (`id`)\n"
189+
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin");
190+
return result;
191+
}
151192
}

features/sharding/dialect/mysql/src/test/java/org/apache/shardingsphere/sharding/merge/mysql/type/MySQLShardingShowIndexMergedResultTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
2121
import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
2222
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
23+
import org.apache.shardingsphere.infra.metadata.database.schema.util.IndexMetaDataUtils;
2324
import org.apache.shardingsphere.sharding.rule.ShardingRule;
2425
import org.junit.jupiter.api.Test;
2526
import org.junit.jupiter.api.extension.ExtendWith;
@@ -29,6 +30,8 @@
2930
import java.sql.SQLException;
3031
import java.util.Collections;
3132

33+
import static org.hamcrest.MatcherAssert.assertThat;
34+
import static org.hamcrest.Matchers.is;
3235
import static org.junit.jupiter.api.Assertions.assertFalse;
3336
import static org.junit.jupiter.api.Assertions.assertTrue;
3437
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -54,13 +57,25 @@ void assertNextForTableRuleIsPresent() throws SQLException {
5457
assertTrue(new MySQLShardingShowIndexMergedResult(rule, mock(SQLStatementContext.class), schema, Collections.singletonList(mockQueryResult())).next());
5558
}
5659

60+
@Test
61+
void assertGetValueWithShortenedIndexName() throws SQLException {
62+
MySQLShardingShowIndexMergedResult actual = new MySQLShardingShowIndexMergedResult(rule, mock(SQLStatementContext.class), schema,
63+
Collections.singletonList(mockQueryResult(IndexMetaDataUtils.getActualIndexName("t_order_index", "t_order_0"))));
64+
assertTrue(actual.next());
65+
assertThat(actual.getValue(3, String.class), is("t_order_index"));
66+
}
67+
5768
private QueryResult mockQueryResult() throws SQLException {
69+
return mockQueryResult("t_order_index_t_order_0");
70+
}
71+
72+
private QueryResult mockQueryResult(final String actualIndexName) throws SQLException {
5873
QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
5974
when(result.getMetaData().getColumnCount()).thenReturn(3);
6075
when(result.next()).thenReturn(true, false);
6176
when(result.getValue(1, Object.class)).thenReturn("t_order_0");
6277
when(result.getValue(2, Object.class)).thenReturn(1);
63-
when(result.getValue(3, Object.class)).thenReturn("t_order_index_t_order_0");
78+
when(result.getValue(3, Object.class)).thenReturn(actualIndexName);
6479
return result;
6580
}
6681
}

infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtils.java

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
2929
import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexSegment;
3030

31+
import java.nio.charset.StandardCharsets;
32+
import java.security.MessageDigest;
33+
import java.security.NoSuchAlgorithmException;
3134
import java.util.Collection;
3235
import java.util.LinkedList;
3336
import java.util.Optional;
@@ -40,6 +43,12 @@ public final class IndexMetaDataUtils {
4043

4144
private static final String UNDERLINE = "_";
4245

46+
private static final String SHORTENED_INDEX_SUFFIX_PREFIX = "_s";
47+
48+
private static final String HASH_ALGORITHM = "SHA-256";
49+
50+
private static final int SHORTENED_INDEX_SUFFIX_HASH_BYTES = 5;
51+
4352
/**
4453
* Get logic index name.
4554
*
@@ -48,8 +57,7 @@ public final class IndexMetaDataUtils {
4857
* @return logic index name
4958
*/
5059
public static String getLogicIndexName(final String actualIndexName, final String actualTableName) {
51-
String indexNameSuffix = UNDERLINE + actualTableName;
52-
return actualIndexName.endsWith(indexNameSuffix) ? actualIndexName.substring(0, actualIndexName.lastIndexOf(indexNameSuffix)) : actualIndexName;
60+
return stripActualIndexNameSuffix(actualIndexName, getLegacyActualIndexNameSuffix(actualTableName));
5361
}
5462

5563
/**
@@ -60,7 +68,30 @@ public static String getLogicIndexName(final String actualIndexName, final Strin
6068
* @return actual index name
6169
*/
6270
public static String getActualIndexName(final String logicIndexName, final String actualTableName) {
63-
return Strings.isNullOrEmpty(actualTableName) ? logicIndexName : logicIndexName + UNDERLINE + actualTableName;
71+
return Strings.isNullOrEmpty(actualTableName) ? logicIndexName : logicIndexName + getShortenedActualIndexNameSuffix(actualTableName);
72+
}
73+
74+
/**
75+
* Get legacy actual index name.
76+
*
77+
* @param logicIndexName logic index name
78+
* @param actualTableName actual table name
79+
* @return legacy actual index name
80+
*/
81+
public static String getLegacyActualIndexName(final String logicIndexName, final String actualTableName) {
82+
return Strings.isNullOrEmpty(actualTableName) ? logicIndexName : logicIndexName + getLegacyActualIndexNameSuffix(actualTableName);
83+
}
84+
85+
/**
86+
* Get logic index name from generated actual index name.
87+
*
88+
* @param actualIndexName actual index name
89+
* @param actualTableName actual table name
90+
* @return logic index name
91+
*/
92+
public static String getGeneratedLogicIndexName(final String actualIndexName, final String actualTableName) {
93+
String result = stripActualIndexNameSuffix(actualIndexName, getShortenedActualIndexNameSuffix(actualTableName));
94+
return result.equals(actualIndexName) ? getLogicIndexName(actualIndexName, actualTableName) : result;
6495
}
6596

6697
/**
@@ -85,4 +116,35 @@ public static Collection<QualifiedTable> getTableNames(final ShardingSphereDatab
85116
private static Optional<String> findLogicTableNameFromMetaData(final ShardingSphereSchema schema, final String logicIndexName) {
86117
return schema.getAllTables().stream().filter(table -> table.containsIndex(logicIndexName)).findFirst().map(ShardingSphereTable::getName);
87118
}
119+
120+
private static String getLegacyActualIndexNameSuffix(final String actualTableName) {
121+
return Strings.isNullOrEmpty(actualTableName) ? "" : UNDERLINE + actualTableName;
122+
}
123+
124+
private static String getShortenedActualIndexNameSuffix(final String actualTableName) {
125+
return Strings.isNullOrEmpty(actualTableName) ? "" : SHORTENED_INDEX_SUFFIX_PREFIX + shortenActualTableName(actualTableName);
126+
}
127+
128+
private static String stripActualIndexNameSuffix(final String actualIndexName, final String indexNameSuffix) {
129+
return Strings.isNullOrEmpty(indexNameSuffix) || !actualIndexName.endsWith(indexNameSuffix)
130+
? actualIndexName
131+
: actualIndexName.substring(0, actualIndexName.length() - indexNameSuffix.length());
132+
}
133+
134+
private static String shortenActualTableName(final String actualTableName) {
135+
byte[] digest = digest(actualTableName);
136+
long result = 0L;
137+
for (int i = 0; i < SHORTENED_INDEX_SUFFIX_HASH_BYTES; i++) {
138+
result = result << Byte.SIZE | digest[i] & 0xFF;
139+
}
140+
return Long.toString(result, Character.MAX_RADIX);
141+
}
142+
143+
private static byte[] digest(final String value) {
144+
try {
145+
return MessageDigest.getInstance(HASH_ALGORITHM).digest(value.getBytes(StandardCharsets.UTF_8));
146+
} catch (final NoSuchAlgorithmException ex) {
147+
throw new IllegalStateException(String.format("Could not find message digest algorithm `%s`.", HASH_ALGORITHM), ex);
148+
}
149+
}
88150
}

infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/util/IndexMetaDataUtilsTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@
3434
import java.util.Collection;
3535
import java.util.Collections;
3636

37+
import static org.hamcrest.Matchers.containsString;
3738
import static org.hamcrest.Matchers.is;
39+
import static org.hamcrest.Matchers.lessThan;
40+
import static org.hamcrest.Matchers.not;
41+
import static org.hamcrest.Matchers.startsWith;
3842
import static org.hamcrest.MatcherAssert.assertThat;
3943
import static org.mockito.Mockito.mock;
4044

@@ -57,14 +61,39 @@ void assertGetLogicIndexNameWithoutIndexNameSuffix() {
5761

5862
@Test
5963
void assertGetActualIndexNameWithActualTableName() {
60-
assertThat(IndexMetaDataUtils.getActualIndexName("order_index", "t_order"), is("order_index_t_order"));
64+
String actual = IndexMetaDataUtils.getActualIndexName("order_index", "t_order");
65+
assertThat(actual, startsWith("order_index_s"));
66+
assertThat(actual, not(containsString("t_order")));
67+
}
68+
69+
@Test
70+
void assertGetActualIndexNameReducesLengthForLongActualTableName() {
71+
String actualTableName = "order_detail_archive_20260316_0001";
72+
assertThat(IndexMetaDataUtils.getActualIndexName("order_index", actualTableName).length(),
73+
lessThan(IndexMetaDataUtils.getLegacyActualIndexName("order_index", actualTableName).length()));
74+
}
75+
76+
@Test
77+
void assertGetLegacyActualIndexNameWithActualTableName() {
78+
assertThat(IndexMetaDataUtils.getLegacyActualIndexName("order_index", "t_order"), is("order_index_t_order"));
6179
}
6280

6381
@Test
6482
void assertGetActualIndexNameWithoutActualTableName() {
6583
assertThat(IndexMetaDataUtils.getActualIndexName("order_index", null), is("order_index"));
6684
}
6785

86+
@Test
87+
void assertGetGeneratedLogicIndexNameWithShortenedIndexNameSuffix() {
88+
String actualIndexName = IndexMetaDataUtils.getActualIndexName("order_index", "t_order");
89+
assertThat(IndexMetaDataUtils.getGeneratedLogicIndexName(actualIndexName, "t_order"), is("order_index"));
90+
}
91+
92+
@Test
93+
void assertGetGeneratedLogicIndexNameWithLegacyIndexNameSuffix() {
94+
assertThat(IndexMetaDataUtils.getGeneratedLogicIndexName("order_index_t_order", "t_order"), is("order_index"));
95+
}
96+
6897
@Test
6998
void assertGetTableNames() {
7099
IndexSegment indexSegment = new IndexSegment(0, 0, new IndexNameSegment(0, 0, new IdentifierValue("foo_idx")));

0 commit comments

Comments
 (0)