Skip to content

Commit 1d2ef42

Browse files
feeblefakieKodaiD
andauthored
Backport to branch(3.12) : Fix the DynamoDB metadata table upsert operation (#2791)
Co-authored-by: Kodai Doki <[email protected]>
1 parent 37e79a0 commit 1d2ef42

File tree

2 files changed

+65
-9
lines changed

2 files changed

+65
-9
lines changed

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public class DynamoAdmin implements DistributedStorageAdmin {
9494
public static final String DEFAULT_NO_BACKUP = "false";
9595
public static final String DEFAULT_REQUEST_UNIT = "10";
9696
private static final int DEFAULT_WAITING_DURATION_SECS = 3;
97+
@VisibleForTesting static final int MAX_RETRY_COUNT = 10;
9798

9899
@VisibleForTesting static final String PARTITION_KEY = "concatenatedPartitionKey";
99100
@VisibleForTesting static final String CLUSTERING_KEY = "concatenatedClusteringKey";
@@ -416,15 +417,28 @@ private void putTableMetadata(Namespace namespace, String table, TableMetadata m
416417
METADATA_ATTR_SECONDARY_INDEX,
417418
AttributeValue.builder().ss(metadata.getSecondaryIndexNames()).build());
418419
}
419-
try {
420-
client.putItem(
421-
PutItemRequest.builder()
422-
.tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE))
423-
.item(itemValues)
424-
.build());
425-
} catch (Exception e) {
426-
throw new ExecutionException(
427-
"Adding the meta data for table " + getFullTableName(namespace, table) + " failed", e);
420+
int retryCount = 0;
421+
while (true) {
422+
try {
423+
client.putItem(
424+
PutItemRequest.builder()
425+
.tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE))
426+
.item(itemValues)
427+
.build());
428+
return;
429+
} catch (ResourceNotFoundException e) {
430+
if (retryCount >= MAX_RETRY_COUNT) {
431+
throw new ExecutionException(
432+
"Adding the metadata for the " + getFullTableName(namespace, table) + " table failed",
433+
e);
434+
}
435+
Uninterruptibles.sleepUninterruptibly(waitingDurationSecs, TimeUnit.SECONDS);
436+
retryCount++;
437+
} catch (Exception e) {
438+
throw new ExecutionException(
439+
"Adding the metadata for the " + getFullTableName(namespace, table) + " table failed",
440+
e);
441+
}
428442
}
429443
}
430444

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,48 @@ public void createTable_WhenMetadataTableExists_ShouldCreateOnlyTable()
626626
.isInstanceOf(IllegalArgumentException.class);
627627
}
628628

629+
@Test
630+
public void createTable_WhenActualMetadataTableCreationIsDelayed_ShouldFailAfterRetries() {
631+
// Arrange
632+
// prepare tableIsActiveResponse
633+
DescribeTableResponse tableIsActiveResponse = mock(DescribeTableResponse.class);
634+
TableDescription tableDescription = mock(TableDescription.class);
635+
when(tableIsActiveResponse.table()).thenReturn(tableDescription);
636+
when(tableDescription.tableStatus()).thenReturn(TableStatus.ACTIVE);
637+
when(client.describeTable(any(DescribeTableRequest.class))).thenReturn(tableIsActiveResponse);
638+
// prepare backupIsEnabledResponse
639+
DescribeContinuousBackupsResponse backupIsEnabledResponse =
640+
mock(DescribeContinuousBackupsResponse.class);
641+
when(client.describeContinuousBackups(any(DescribeContinuousBackupsRequest.class)))
642+
.thenReturn(backupIsEnabledResponse);
643+
ContinuousBackupsDescription continuousBackupsDescription =
644+
mock(ContinuousBackupsDescription.class);
645+
when(backupIsEnabledResponse.continuousBackupsDescription())
646+
.thenReturn(continuousBackupsDescription);
647+
when(continuousBackupsDescription.continuousBackupsStatus())
648+
.thenReturn(ContinuousBackupsStatus.ENABLED);
649+
when(client.putItem(any(PutItemRequest.class))).thenThrow(ResourceNotFoundException.class);
650+
TableMetadata metadata =
651+
TableMetadata.newBuilder()
652+
.addPartitionKey("c1")
653+
.addClusteringKey("c2", Order.DESC)
654+
.addClusteringKey("c3", Order.ASC)
655+
.addColumn("c1", DataType.TEXT)
656+
.addColumn("c2", DataType.BIGINT)
657+
.addColumn("c3", DataType.BOOLEAN)
658+
.addColumn("c4", DataType.INT)
659+
.addColumn("c5", DataType.BLOB)
660+
.addColumn("c6", DataType.DOUBLE)
661+
.addColumn("c7", DataType.FLOAT)
662+
.addSecondaryIndex("c4")
663+
.build();
664+
665+
// Act Assert
666+
assertThatThrownBy(() -> admin.createTable(NAMESPACE, TABLE, metadata))
667+
.isInstanceOf(ExecutionException.class);
668+
verify(client, times(DynamoAdmin.MAX_RETRY_COUNT + 1)).putItem(any(PutItemRequest.class));
669+
}
670+
629671
@Test
630672
public void dropTable_WithNoMetadataLeft_ShouldDropTableAndDeleteMetadata()
631673
throws ExecutionException {

0 commit comments

Comments
 (0)