Skip to content

Commit 3e622ab

Browse files
feeblefakieKodaiD
andauthored
Backport to branch(3.15) : Fix the DynamoDB metadata table upsert operation (#2788)
Co-authored-by: Kodai Doki <[email protected]>
1 parent 46ca3d5 commit 3e622ab

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
@@ -95,6 +95,7 @@ public class DynamoAdmin implements DistributedStorageAdmin {
9595
public static final String DEFAULT_NO_BACKUP = "false";
9696
public static final String DEFAULT_REQUEST_UNIT = "10";
9797
private static final int DEFAULT_WAITING_DURATION_SECS = 3;
98+
@VisibleForTesting static final int MAX_RETRY_COUNT = 10;
9899

99100
@VisibleForTesting static final String PARTITION_KEY = "concatenatedPartitionKey";
100101
@VisibleForTesting static final String CLUSTERING_KEY = "concatenatedClusteringKey";
@@ -422,15 +423,28 @@ private void putTableMetadata(Namespace namespace, String table, TableMetadata m
422423
METADATA_ATTR_SECONDARY_INDEX,
423424
AttributeValue.builder().ss(metadata.getSecondaryIndexNames()).build());
424425
}
425-
try {
426-
client.putItem(
427-
PutItemRequest.builder()
428-
.tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE))
429-
.item(itemValues)
430-
.build());
431-
} catch (Exception e) {
432-
throw new ExecutionException(
433-
"Adding the meta data for table " + getFullTableName(namespace, table) + " failed", e);
426+
int retryCount = 0;
427+
while (true) {
428+
try {
429+
client.putItem(
430+
PutItemRequest.builder()
431+
.tableName(ScalarDbUtils.getFullTableName(metadataNamespace, METADATA_TABLE))
432+
.item(itemValues)
433+
.build());
434+
return;
435+
} catch (ResourceNotFoundException e) {
436+
if (retryCount >= MAX_RETRY_COUNT) {
437+
throw new ExecutionException(
438+
"Adding the metadata for the " + getFullTableName(namespace, table) + " table failed",
439+
e);
440+
}
441+
Uninterruptibles.sleepUninterruptibly(waitingDurationSecs, TimeUnit.SECONDS);
442+
retryCount++;
443+
} catch (Exception e) {
444+
throw new ExecutionException(
445+
"Adding the metadata for the " + getFullTableName(namespace, table) + " table failed",
446+
e);
447+
}
434448
}
435449
}
436450

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)