Skip to content

Commit 948822d

Browse files
committed
Create index if not exists in repairTable of CosmosAdmin and DynamoAdmin
1 parent 644578b commit 948822d

File tree

7 files changed

+206
-1
lines changed

7 files changed

+206
-1
lines changed

core/src/main/java/com/scalar/db/storage/cosmos/CosmosAdmin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ public void repairTable(
588588
throws ExecutionException {
589589
try {
590590
createTableInternal(namespace, table, metadata, true);
591+
updateIndexingPolicy(namespace, table, metadata);
591592
} catch (IllegalArgumentException e) {
592593
throw e;
593594
} catch (Exception e) {

core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,9 @@ public void repairTable(
13411341
throws ExecutionException {
13421342
try {
13431343
createTableInternal(nonPrefixedNamespace, table, metadata, true, options);
1344+
for (String indexColumnName : metadata.getSecondaryIndexNames()) {
1345+
createIndex(nonPrefixedNamespace, table, indexColumnName, options);
1346+
}
13441347
} catch (RuntimeException e) {
13451348
throw new ExecutionException(
13461349
String.format(

core/src/main/java/com/scalar/db/storage/jdbc/JdbcAdmin.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,8 @@ columnName, getFullTableName(namespace, table)),
889889
}
890890
}
891891

892-
private void createIndex(
892+
@VisibleForTesting
893+
void createIndex(
893894
Connection connection, String schema, String table, String indexedColumn, boolean ifNotExists)
894895
throws SQLException {
895896
String indexName = getIndexName(schema, table, indexedColumn);

core/src/test/java/com/scalar/db/storage/cassandra/CassandraAdminTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import static org.mockito.ArgumentMatchers.any;
88
import static org.mockito.ArgumentMatchers.anyString;
99
import static org.mockito.Mockito.mock;
10+
import static org.mockito.Mockito.spy;
1011
import static org.mockito.Mockito.times;
1112
import static org.mockito.Mockito.verify;
1213
import static org.mockito.Mockito.when;
@@ -797,6 +798,43 @@ public void repairTable_ShouldCreateTableAndIndexesIfTheyDoNotExists() throws Ex
797798
}
798799
}
799800

801+
@Test
802+
public void repairTable_WhenTableAlreadyExistsWithoutIndex_ShouldCreateIndex()
803+
throws ExecutionException {
804+
// Arrange
805+
String namespace = "sample_ns";
806+
String table = "tbl";
807+
TableMetadata tableMetadata =
808+
TableMetadata.newBuilder()
809+
.addPartitionKey("c1")
810+
.addClusteringKey("c4")
811+
.addColumn("c1", DataType.INT)
812+
.addColumn("c2", DataType.TEXT)
813+
.addColumn("c3", DataType.BLOB)
814+
.addColumn("c4", DataType.INT)
815+
.addColumn("c5", DataType.BOOLEAN)
816+
.addSecondaryIndex("c2")
817+
.addSecondaryIndex("c4")
818+
.build();
819+
// The table already exists
820+
when(clusterManager.getMetadata(namespace, table))
821+
.thenReturn(mock(com.datastax.driver.core.TableMetadata.class));
822+
when(cassandraSession.getCluster()).thenReturn(cluster);
823+
when(cluster.getMetadata()).thenReturn(metadata);
824+
when(metadata.getKeyspace(any())).thenReturn(keyspaceMetadata);
825+
when(keyspaceMetadata.getTable(table))
826+
.thenReturn(mock(com.datastax.driver.core.TableMetadata.class));
827+
828+
CassandraAdmin adminSpy = spy(cassandraAdmin);
829+
830+
// Act
831+
adminSpy.repairTable(namespace, table, tableMetadata, Collections.emptyMap());
832+
833+
// Assert
834+
verify(adminSpy)
835+
.createSecondaryIndexes(namespace, table, tableMetadata.getSecondaryIndexNames(), true);
836+
}
837+
800838
@Test
801839
public void addNewColumnToTable_ShouldWorkProperly() throws ExecutionException {
802840
// Arrange

core/src/test/java/com/scalar/db/storage/cosmos/CosmosAdminTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,13 @@ public void repairTable_withStoredProcedure_ShouldNotAddStoredProcedure()
893893
when(scripts.getStoredProcedure(CosmosAdmin.STORED_PROCEDURE_FILE_NAME))
894894
.thenReturn(storedProcedure);
895895

896+
// Existing container properties
897+
CosmosContainerResponse response = mock(CosmosContainerResponse.class);
898+
when(database.createContainerIfNotExists(table, "/concatenatedPartitionKey"))
899+
.thenReturn(response);
900+
CosmosContainerProperties properties = mock(CosmosContainerProperties.class);
901+
when(response.getProperties()).thenReturn(properties);
902+
896903
// Act Assert
897904
admin.repairTable(namespace, table, tableMetadata, Collections.emptyMap());
898905

@@ -943,6 +950,13 @@ public void repairTable_withoutStoredProcedure_ShouldCreateStoredProcedure()
943950
when(cosmosException.getStatusCode()).thenReturn(404);
944951
when(storedProcedure.read()).thenThrow(cosmosException);
945952

953+
// Existing container properties
954+
CosmosContainerResponse response = mock(CosmosContainerResponse.class);
955+
when(database.createContainerIfNotExists(table, "/concatenatedPartitionKey"))
956+
.thenReturn(response);
957+
CosmosContainerProperties properties = mock(CosmosContainerProperties.class);
958+
when(response.getProperties()).thenReturn(properties);
959+
946960
// Act
947961
admin.repairTable(namespace, table, tableMetadata, Collections.emptyMap());
948962

@@ -996,6 +1010,13 @@ public void repairTable_ShouldCreateTableIfNotExistsAndUpsertMetadata()
9961010
when(cosmosException.getStatusCode()).thenReturn(404);
9971011
when(storedProcedure.read()).thenThrow(cosmosException);
9981012

1013+
// Existing container properties
1014+
CosmosContainerResponse response = mock(CosmosContainerResponse.class);
1015+
when(database.createContainerIfNotExists(table, "/concatenatedPartitionKey"))
1016+
.thenReturn(response);
1017+
CosmosContainerProperties properties = mock(CosmosContainerProperties.class);
1018+
when(response.getProperties()).thenReturn(properties);
1019+
9991020
// Act
10001021
admin.repairTable(namespace, table, tableMetadata, Collections.emptyMap());
10011022

@@ -1024,6 +1045,49 @@ public void repairTable_ShouldCreateTableIfNotExistsAndUpsertMetadata()
10241045
verify(scripts).createStoredProcedure(any());
10251046
}
10261047

1048+
@Test
1049+
public void repairTable_WhenTableAlreadyExistsWithoutIndex_ShouldCreateIndex()
1050+
throws ExecutionException {
1051+
// Arrange
1052+
String namespace = "ns";
1053+
String table = "tbl";
1054+
TableMetadata tableMetadata =
1055+
TableMetadata.newBuilder()
1056+
.addColumn("c1", DataType.INT)
1057+
.addColumn("c2", DataType.TEXT)
1058+
.addColumn("c3", DataType.BIGINT)
1059+
.addPartitionKey("c1")
1060+
.addSecondaryIndex("c3")
1061+
.build();
1062+
when(client.getDatabase(namespace)).thenReturn(database);
1063+
when(database.getContainer(table)).thenReturn(container);
1064+
// Metadata container
1065+
CosmosContainer metadataContainer = mock(CosmosContainer.class);
1066+
CosmosDatabase metadataDatabase = mock(CosmosDatabase.class);
1067+
when(client.getDatabase(METADATA_DATABASE)).thenReturn(metadataDatabase);
1068+
when(metadataDatabase.getContainer(CosmosAdmin.TABLE_METADATA_CONTAINER))
1069+
.thenReturn(metadataContainer);
1070+
// Stored procedure exists
1071+
CosmosScripts scripts = mock(CosmosScripts.class);
1072+
when(container.getScripts()).thenReturn(scripts);
1073+
CosmosStoredProcedure storedProcedure = mock(CosmosStoredProcedure.class);
1074+
when(scripts.getStoredProcedure(CosmosAdmin.STORED_PROCEDURE_FILE_NAME))
1075+
.thenReturn(storedProcedure);
1076+
// Existing container properties
1077+
CosmosContainerResponse response = mock(CosmosContainerResponse.class);
1078+
when(database.createContainerIfNotExists(table, "/concatenatedPartitionKey"))
1079+
.thenReturn(response);
1080+
CosmosContainerProperties properties = mock(CosmosContainerProperties.class);
1081+
when(response.getProperties()).thenReturn(properties);
1082+
1083+
// Act
1084+
admin.repairTable(namespace, table, tableMetadata, Collections.emptyMap());
1085+
1086+
// Assert
1087+
verify(container, times(1)).replace(properties);
1088+
verify(properties, times(1)).setIndexingPolicy(any(IndexingPolicy.class));
1089+
}
1090+
10271091
@Test
10281092
public void addNewColumnToTable_ShouldWorkProperly() throws ExecutionException {
10291093
// Arrange

core/src/test/java/com/scalar/db/storage/dynamo/DynamoAdminTestBase.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,74 @@ public void repairTable_WithNonExistingTableAndMetadataTables_shouldCreateBothTa
12701270
.build());
12711271
}
12721272

1273+
@Test
1274+
public void repairTable_WhenTableAlreadyExistsWithoutIndex_ShouldCreateIndex()
1275+
throws ExecutionException {
1276+
// Arrange
1277+
TableMetadata metadata =
1278+
TableMetadata.newBuilder()
1279+
.addPartitionKey("c1")
1280+
.addColumn("c1", DataType.TEXT)
1281+
.addColumn("c2", DataType.INT)
1282+
.addColumn("c3", DataType.INT)
1283+
.addSecondaryIndex("c3")
1284+
.build();
1285+
// The table to repair exists
1286+
when(client.describeTable(DescribeTableRequest.builder().tableName(getFullTableName()).build()))
1287+
.thenReturn(tableIsActiveResponse);
1288+
// The metadata table exists
1289+
when(client.describeTable(
1290+
DescribeTableRequest.builder().tableName(getFullMetadataTableName()).build()))
1291+
.thenReturn(tableIsActiveResponse);
1292+
// Continuous backup check
1293+
when(client.describeContinuousBackups(any(DescribeContinuousBackupsRequest.class)))
1294+
.thenReturn(backupIsEnabledResponse);
1295+
// Table metadata to return in createIndex
1296+
GetItemResponse getItemResponse = mock(GetItemResponse.class);
1297+
when(client.getItem(any(GetItemRequest.class))).thenReturn(getItemResponse);
1298+
when(getItemResponse.item())
1299+
.thenReturn(
1300+
ImmutableMap.<String, AttributeValue>builder()
1301+
.put(
1302+
DynamoAdmin.METADATA_ATTR_TABLE,
1303+
AttributeValue.builder().s(getFullTableName()).build())
1304+
.put(
1305+
DynamoAdmin.METADATA_ATTR_COLUMNS,
1306+
AttributeValue.builder()
1307+
.m(
1308+
ImmutableMap.<String, AttributeValue>builder()
1309+
.put("c1", AttributeValue.builder().s("text").build())
1310+
.put("c2", AttributeValue.builder().s("int").build())
1311+
.put("c3", AttributeValue.builder().s("int").build())
1312+
.build())
1313+
.build())
1314+
.put(
1315+
DynamoAdmin.METADATA_ATTR_PARTITION_KEY,
1316+
AttributeValue.builder().l(AttributeValue.builder().s("c1").build()).build())
1317+
.put(
1318+
DynamoAdmin.METADATA_ATTR_SECONDARY_INDEX,
1319+
AttributeValue.builder().ss("c3").build())
1320+
.build());
1321+
// For waitForTableCreation in createIndex
1322+
DescribeTableResponse describeTableResponse = mock(DescribeTableResponse.class);
1323+
when(client.describeTable(any(DescribeTableRequest.class))).thenReturn(describeTableResponse);
1324+
TableDescription tableDescription = mock(TableDescription.class);
1325+
when(describeTableResponse.table()).thenReturn(tableDescription);
1326+
GlobalSecondaryIndexDescription globalSecondaryIndexDescription =
1327+
mock(GlobalSecondaryIndexDescription.class);
1328+
when(tableDescription.globalSecondaryIndexes())
1329+
.thenReturn(Collections.singletonList(globalSecondaryIndexDescription));
1330+
String indexName = getFullTableName() + ".global_index.c3";
1331+
when(globalSecondaryIndexDescription.indexName()).thenReturn(indexName);
1332+
when(globalSecondaryIndexDescription.indexStatus()).thenReturn(IndexStatus.ACTIVE);
1333+
1334+
// Act
1335+
admin.repairTable(NAMESPACE, TABLE, metadata, ImmutableMap.of());
1336+
1337+
// Assert
1338+
verify(client, times(1)).updateTable(any(UpdateTableRequest.class));
1339+
}
1340+
12731341
@Test
12741342
public void addNewColumnToTable_ShouldWorkProperly() throws ExecutionException {
12751343
// Arrange

core/src/test/java/com/scalar/db/storage/jdbc/JdbcAdminTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,36 @@ public void repairTable_ShouldCallCreateTableAndAddTableMetadataCorrectly(RdbEng
14831483
verify(adminSpy).addTableMetadata(connection, namespace, table, metadata, true, true);
14841484
}
14851485

1486+
@ParameterizedTest
1487+
@EnumSource(RdbEngine.class)
1488+
public void repairTable_WhenTableAlreadyExistsWithoutIndex_ShouldCreateIndex(RdbEngine rdbEngine)
1489+
throws ExecutionException, SQLException {
1490+
// Arrange
1491+
String namespace = "my_ns";
1492+
String table = "foo_table";
1493+
TableMetadata metadata =
1494+
TableMetadata.newBuilder()
1495+
.addPartitionKey("c1")
1496+
.addClusteringKey("c2")
1497+
.addColumn("c1", DataType.INT)
1498+
.addColumn("c2", DataType.TEXT)
1499+
.addColumn("c3", DataType.BOOLEAN)
1500+
.addColumn("c4", DataType.BLOB)
1501+
.addSecondaryIndex("c3")
1502+
.addSecondaryIndex("c4")
1503+
.build();
1504+
when(connection.createStatement()).thenReturn(mock(Statement.class));
1505+
when(dataSource.getConnection()).thenReturn(connection);
1506+
JdbcAdmin adminSpy = spy(createJdbcAdminFor(rdbEngine));
1507+
1508+
// Act
1509+
adminSpy.repairTable(namespace, table, metadata, Collections.emptyMap());
1510+
1511+
// Assert
1512+
verify(adminSpy).createIndex(connection, namespace, table, "c3", true);
1513+
verify(adminSpy).createIndex(connection, namespace, table, "c4", true);
1514+
}
1515+
14861516
@Test
14871517
public void
14881518
createMetadataTableIfNotExists_WithInternalDbError_forMysql_shouldThrowInternalDbError()

0 commit comments

Comments
 (0)