Skip to content

Commit 3daa2b6

Browse files
committed
Merge branch 'master' into permission-list
2 parents 2d7cad5 + 54ab4e6 commit 3daa2b6

File tree

11 files changed

+286
-22
lines changed

11 files changed

+286
-22
lines changed

.github/dependabot.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,49 +36,49 @@ updates:
3636
interval: "weekly"
3737

3838
- package-ecosystem: "github-actions"
39-
target-branch: "3.15"
39+
target-branch: "3.16"
4040
groups:
41-
actions on branch 3.15:
41+
actions on branch 3.16:
4242
patterns:
4343
- "*"
4444
directory: "/"
4545
schedule:
4646
interval: "weekly"
4747

4848
- package-ecosystem: "github-actions"
49-
target-branch: "3.14"
49+
target-branch: "3.15"
5050
groups:
51-
actions on branch 3.14:
51+
actions on branch 3.15:
5252
patterns:
5353
- "*"
5454
directory: "/"
5555
schedule:
5656
interval: "weekly"
5757

5858
- package-ecosystem: "github-actions"
59-
target-branch: "3.13"
59+
target-branch: "3.14"
6060
groups:
61-
actions on branch 3.13:
61+
actions on branch 3.14:
6262
patterns:
6363
- "*"
6464
directory: "/"
6565
schedule:
6666
interval: "weekly"
6767

6868
- package-ecosystem: "github-actions"
69-
target-branch: "3.12"
69+
target-branch: "3.13"
7070
groups:
71-
actions on branch 3.12:
71+
actions on branch 3.13:
7272
patterns:
7373
- "*"
7474
directory: "/"
7575
schedule:
7676
interval: "weekly"
7777

7878
- package-ecosystem: "github-actions"
79-
target-branch: "3.11"
79+
target-branch: "3.12"
8080
groups:
81-
actions on branch 3.11:
81+
actions on branch 3.12:
8282
patterns:
8383
- "*"
8484
directory: "/"

.github/workflows/scheduled-vuln-check.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,6 @@ jobs:
1616
CR_PAT: ${{ secrets.CR_PAT }}
1717
SLACK_SECURITY_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_WEBHOOK_URL }}
1818

19-
call-vuln-check-for-v3_11:
20-
uses: ./.github/workflows/vuln-check.yaml
21-
with:
22-
target-ref: v3.11
23-
find-latest-release: true
24-
secrets:
25-
CR_PAT: ${{ secrets.CR_PAT }}
26-
SLACK_SECURITY_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_WEBHOOK_URL }}
27-
2819
call-vuln-check-for-v3_12:
2920
uses: ./.github/workflows/vuln-check.yaml
3021
with:
@@ -60,3 +51,12 @@ jobs:
6051
secrets:
6152
CR_PAT: ${{ secrets.CR_PAT }}
6253
SLACK_SECURITY_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_WEBHOOK_URL }}
54+
55+
call-vuln-check-for-v3_16:
56+
uses: ./.github/workflows/vuln-check.yaml
57+
with:
58+
target-ref: v3.16
59+
find-latest-release: true
60+
secrets:
61+
CR_PAT: ${{ secrets.CR_PAT }}
62+
SLACK_SECURITY_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_WEBHOOK_URL }}

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ You can install it in your application using your build tool such as Gradle and
3737
To add a dependency on ScalarDB using Gradle, use the following:
3838
```gradle
3939
dependencies {
40-
implementation 'com.scalar-labs:scalardb:3.15.2'
40+
implementation 'com.scalar-labs:scalardb:3.16.0'
4141
}
4242
```
4343

@@ -46,7 +46,7 @@ To add a dependency using Maven:
4646
<dependency>
4747
<groupId>com.scalar-labs</groupId>
4848
<artifactId>scalardb</artifactId>
49-
<version>3.15.2</version>
49+
<version>3.16.0</version>
5050
</dependency>
5151
```
5252

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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,46 @@ columnName, getFullTableName(namespace, table)),
10321032
TableMetadata.newBuilder(tableMetadata).addSecondaryIndex(columnName).build());
10331033
}
10341034

1035+
private boolean rawIndexExists(String nonPrefixedNamespace, String table, String indexName) {
1036+
Namespace namespace = Namespace.of(namespacePrefix, nonPrefixedNamespace);
1037+
String globalIndexName =
1038+
String.join(
1039+
".",
1040+
getFullTableName(namespace, table),
1041+
DynamoAdmin.GLOBAL_INDEX_NAME_PREFIX,
1042+
indexName);
1043+
int retryCount = 0;
1044+
try {
1045+
while (true) {
1046+
DescribeTableResponse response =
1047+
client.describeTable(
1048+
DescribeTableRequest.builder()
1049+
.tableName(getFullTableName(namespace, table))
1050+
.build());
1051+
GlobalSecondaryIndexDescription description =
1052+
response.table().globalSecondaryIndexes().stream()
1053+
.filter(d -> d.indexName().equals(globalIndexName))
1054+
.findFirst()
1055+
.orElse(null);
1056+
if (description == null) {
1057+
return false;
1058+
}
1059+
if (description.indexStatus() == IndexStatus.ACTIVE) {
1060+
return true;
1061+
}
1062+
if (retryCount++ >= MAX_RETRY_COUNT) {
1063+
throw new IllegalStateException(
1064+
String.format(
1065+
"Waiting for the secondary index %s on the %s table to be active failed",
1066+
indexName, getFullTableName(namespace, table)));
1067+
}
1068+
Uninterruptibles.sleepUninterruptibly(waitingDurationSecs, TimeUnit.SECONDS);
1069+
}
1070+
} catch (ResourceNotFoundException e) {
1071+
return false;
1072+
}
1073+
}
1074+
10351075
private void waitForIndexCreation(Namespace namespace, String table, String columnName)
10361076
throws ExecutionException {
10371077
try {
@@ -1366,6 +1406,11 @@ public void repairTable(
13661406
throws ExecutionException {
13671407
try {
13681408
createTableInternal(nonPrefixedNamespace, table, metadata, true, options);
1409+
for (String indexColumnName : metadata.getSecondaryIndexNames()) {
1410+
if (!rawIndexExists(nonPrefixedNamespace, table, indexColumnName)) {
1411+
createIndex(nonPrefixedNamespace, table, indexColumnName, options);
1412+
}
1413+
}
13691414
} catch (RuntimeException e) {
13701415
throw new ExecutionException(
13711416
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

0 commit comments

Comments
 (0)