From 2aac18f8966b6e7d7d1628e44192c5e1f530f37b Mon Sep 17 00:00:00 2001 From: Kodai Doki <52027276+KodaiD@users.noreply.github.com> Date: Wed, 18 Jun 2025 07:45:03 +0000 Subject: [PATCH 1/2] Empty commit [skip ci] From 97580497a5a06d029a51c2c8df81debbead06523 Mon Sep 17 00:00:00 2001 From: Kodai Doki <52027276+KodaiD@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:44:39 +0900 Subject: [PATCH 2/2] Resolve conflicts --- .../scalar/db/storage/dynamo/DynamoAdmin.java | 32 +++++++++---- .../storage/dynamo/DynamoAdminTestBase.java | 45 +++++++++++++++++++ 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java b/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java index f00f0df2a6..e17f426e94 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/DynamoAdmin.java @@ -97,6 +97,7 @@ public class DynamoAdmin implements DistributedStorageAdmin { public static final String DEFAULT_NO_BACKUP = "false"; public static final String DEFAULT_REQUEST_UNIT = "10"; private static final int DEFAULT_WAITING_DURATION_SECS = 3; + @VisibleForTesting static final int MAX_RETRY_COUNT = 10; @VisibleForTesting static final String PARTITION_KEY = "concatenatedPartitionKey"; @VisibleForTesting static final String CLUSTERING_KEY = "concatenatedClusteringKey"; @@ -430,15 +431,28 @@ private void putTableMetadata(Namespace namespace, String table, TableMetadata m METADATA_ATTR_SECONDARY_INDEX, AttributeValue.builder().ss(metadata.getSecondaryIndexNames()).build()); } - try { - client.putItem( - PutItemRequest.builder() - .tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE)) - .item(itemValues) - .build()); - } catch (Exception e) { - throw new ExecutionException( - "Adding the meta data for table " + getFullTableName(namespace, table) + " failed", e); + int retryCount = 0; + while (true) { + try { + client.putItem( + PutItemRequest.builder() + .tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE)) + .item(itemValues) + .build()); + return; + } catch (ResourceNotFoundException e) { + if (retryCount >= MAX_RETRY_COUNT) { + throw new ExecutionException( + "Adding the metadata for the " + getFullTableName(namespace, table) + " table failed", + e); + } + Uninterruptibles.sleepUninterruptibly(waitingDurationSecs, TimeUnit.SECONDS); + retryCount++; + } catch (Exception e) { + throw new ExecutionException( + "Adding the metadata for the " + getFullTableName(namespace, table) + " table failed", + e); + } } } diff --git a/core/src/test/java/com/scalar/db/storage/dynamo/DynamoAdminTestBase.java b/core/src/test/java/com/scalar/db/storage/dynamo/DynamoAdminTestBase.java index c49f4d34a5..b5715d8a35 100644 --- a/core/src/test/java/com/scalar/db/storage/dynamo/DynamoAdminTestBase.java +++ b/core/src/test/java/com/scalar/db/storage/dynamo/DynamoAdminTestBase.java @@ -656,6 +656,51 @@ public void createTable_WhenMetadataTableExists_ShouldCreateOnlyTable() .isInstanceOf(IllegalArgumentException.class); } + @Test + public void createTable_WhenActualMetadataTableCreationIsDelayed_ShouldFailAfterRetries() { + // Arrange + // prepare tableIsActiveResponse + TableDescription tableDescription = mock(TableDescription.class); + when(tableIsActiveResponse.table()).thenReturn(tableDescription); + when(tableDescription.tableStatus()).thenReturn(TableStatus.ACTIVE); + when(client.describeTable(any(DescribeTableRequest.class))).thenReturn(tableIsActiveResponse); + // prepare backupIsEnabledResponse + DescribeContinuousBackupsResponse backupIsEnabledResponse = + mock(DescribeContinuousBackupsResponse.class); + when(client.describeContinuousBackups(any(DescribeContinuousBackupsRequest.class))) + .thenReturn(backupIsEnabledResponse); + ContinuousBackupsDescription continuousBackupsDescription = + mock(ContinuousBackupsDescription.class); + when(backupIsEnabledResponse.continuousBackupsDescription()) + .thenReturn(continuousBackupsDescription); + when(continuousBackupsDescription.continuousBackupsStatus()) + .thenReturn(ContinuousBackupsStatus.ENABLED); + when(client.putItem(any(PutItemRequest.class))).thenThrow(ResourceNotFoundException.class); + TableMetadata metadata = + TableMetadata.newBuilder() + .addPartitionKey("c1") + .addClusteringKey("c2", Order.DESC) + .addClusteringKey("c3", Order.ASC) + .addColumn("c1", DataType.TEXT) + .addColumn("c2", DataType.BIGINT) + .addColumn("c3", DataType.BOOLEAN) + .addColumn("c4", DataType.INT) + .addColumn("c5", DataType.BLOB) + .addColumn("c6", DataType.DOUBLE) + .addColumn("c7", DataType.FLOAT) + .addColumn("c8", DataType.DATE) + .addColumn("c9", DataType.TIME) + .addColumn("c10", DataType.TIMESTAMP) + .addColumn("c11", DataType.TIMESTAMPTZ) + .addSecondaryIndex("c4") + .build(); + + // Act Assert + assertThatThrownBy(() -> admin.createTable(NAMESPACE, TABLE, metadata)) + .isInstanceOf(ExecutionException.class); + verify(client, times(DynamoAdmin.MAX_RETRY_COUNT + 1)).putItem(any(PutItemRequest.class)); + } + @Test public void dropTable_WithNoMetadataLeft_ShouldDropTableAndDeleteMetadata() throws ExecutionException {