Skip to content

Commit f8bf7e8

Browse files
feeblefakieKodaiD
andauthored
Backport to branch(3) : Fix the DynamoDB metadata table upsert operation (#2792)
Co-authored-by: Kodai Doki <[email protected]>
1 parent 0780c8f commit f8bf7e8

File tree

2 files changed

+68
-9
lines changed

2 files changed

+68
-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
@@ -97,6 +97,7 @@ public class DynamoAdmin implements DistributedStorageAdmin {
9797
public static final String DEFAULT_NO_BACKUP = "false";
9898
public static final String DEFAULT_REQUEST_UNIT = "10";
9999
private static final int DEFAULT_WAITING_DURATION_SECS = 3;
100+
@VisibleForTesting static final int MAX_RETRY_COUNT = 10;
100101

101102
@VisibleForTesting static final String PARTITION_KEY = "concatenatedPartitionKey";
102103
@VisibleForTesting static final String CLUSTERING_KEY = "concatenatedClusteringKey";
@@ -430,15 +431,28 @@ private void putTableMetadata(Namespace namespace, String table, TableMetadata m
430431
METADATA_ATTR_SECONDARY_INDEX,
431432
AttributeValue.builder().ss(metadata.getSecondaryIndexNames()).build());
432433
}
433-
try {
434-
client.putItem(
435-
PutItemRequest.builder()
436-
.tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE))
437-
.item(itemValues)
438-
.build());
439-
} catch (Exception e) {
440-
throw new ExecutionException(
441-
"Adding the meta data for table " + getFullTableName(namespace, table) + " failed", e);
434+
int retryCount = 0;
435+
while (true) {
436+
try {
437+
client.putItem(
438+
PutItemRequest.builder()
439+
.tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE))
440+
.item(itemValues)
441+
.build());
442+
return;
443+
} catch (ResourceNotFoundException e) {
444+
if (retryCount >= MAX_RETRY_COUNT) {
445+
throw new ExecutionException(
446+
"Adding the metadata for the " + getFullTableName(namespace, table) + " table failed",
447+
e);
448+
}
449+
Uninterruptibles.sleepUninterruptibly(waitingDurationSecs, TimeUnit.SECONDS);
450+
retryCount++;
451+
} catch (Exception e) {
452+
throw new ExecutionException(
453+
"Adding the metadata for the " + getFullTableName(namespace, table) + " table failed",
454+
e);
455+
}
442456
}
443457
}
444458

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,51 @@ public void createTable_WhenMetadataTableExists_ShouldCreateOnlyTable()
656656
.isInstanceOf(IllegalArgumentException.class);
657657
}
658658

659+
@Test
660+
public void createTable_WhenActualMetadataTableCreationIsDelayed_ShouldFailAfterRetries() {
661+
// Arrange
662+
// prepare tableIsActiveResponse
663+
TableDescription tableDescription = mock(TableDescription.class);
664+
when(tableIsActiveResponse.table()).thenReturn(tableDescription);
665+
when(tableDescription.tableStatus()).thenReturn(TableStatus.ACTIVE);
666+
when(client.describeTable(any(DescribeTableRequest.class))).thenReturn(tableIsActiveResponse);
667+
// prepare backupIsEnabledResponse
668+
DescribeContinuousBackupsResponse backupIsEnabledResponse =
669+
mock(DescribeContinuousBackupsResponse.class);
670+
when(client.describeContinuousBackups(any(DescribeContinuousBackupsRequest.class)))
671+
.thenReturn(backupIsEnabledResponse);
672+
ContinuousBackupsDescription continuousBackupsDescription =
673+
mock(ContinuousBackupsDescription.class);
674+
when(backupIsEnabledResponse.continuousBackupsDescription())
675+
.thenReturn(continuousBackupsDescription);
676+
when(continuousBackupsDescription.continuousBackupsStatus())
677+
.thenReturn(ContinuousBackupsStatus.ENABLED);
678+
when(client.putItem(any(PutItemRequest.class))).thenThrow(ResourceNotFoundException.class);
679+
TableMetadata metadata =
680+
TableMetadata.newBuilder()
681+
.addPartitionKey("c1")
682+
.addClusteringKey("c2", Order.DESC)
683+
.addClusteringKey("c3", Order.ASC)
684+
.addColumn("c1", DataType.TEXT)
685+
.addColumn("c2", DataType.BIGINT)
686+
.addColumn("c3", DataType.BOOLEAN)
687+
.addColumn("c4", DataType.INT)
688+
.addColumn("c5", DataType.BLOB)
689+
.addColumn("c6", DataType.DOUBLE)
690+
.addColumn("c7", DataType.FLOAT)
691+
.addColumn("c8", DataType.DATE)
692+
.addColumn("c9", DataType.TIME)
693+
.addColumn("c10", DataType.TIMESTAMP)
694+
.addColumn("c11", DataType.TIMESTAMPTZ)
695+
.addSecondaryIndex("c4")
696+
.build();
697+
698+
// Act Assert
699+
assertThatThrownBy(() -> admin.createTable(NAMESPACE, TABLE, metadata))
700+
.isInstanceOf(ExecutionException.class);
701+
verify(client, times(DynamoAdmin.MAX_RETRY_COUNT + 1)).putItem(any(PutItemRequest.class));
702+
}
703+
659704
@Test
660705
public void dropTable_WithNoMetadataLeft_ShouldDropTableAndDeleteMetadata()
661706
throws ExecutionException {

0 commit comments

Comments
 (0)