Skip to content

Commit 89a4147

Browse files
committed
Change to not create queue in createAcknowledgmentSet to prevent race condition
Signed-off-by: Taylor Gray <tylgry@amazon.com>
1 parent a29f545 commit 89a4147

2 files changed

Lines changed: 25 additions & 15 deletions

File tree

data-prepper-plugins/dynamodb-source/src/main/java/org/opensearch/dataprepper/plugins/source/dynamodb/stream/ShardAcknowledgementManager.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,12 @@ public AcknowledgementSet createAcknowledgmentSet(
190190
// Shard should already be in checkpoints map from call to startUpdatingOwnershipForShard, if it is not in the map
191191
// that means that ShardAcknowledgmentManager stopped tracking it due to some error, and another worker will pick it up
192192
// We throw an error in this case to have the ShardConsumer exit and stop reading data from the shard
193-
if (!isStillTrackingShard(streamPartition)) {
193+
ConcurrentLinkedQueue<ShardCheckpointStatus> queue = checkpoints.get(streamPartition);
194+
if (queue == null) {
194195
throw new ShardNotTrackedException("The shard {} is not being tracked anymore, stop reading from shard");
195196
}
196-
checkpoints.computeIfAbsent(streamPartition, segment -> new ConcurrentLinkedQueue<>()).add(shardCheckpointStatus);
197+
queue.add(shardCheckpointStatus);
198+
197199
ackStatuses.computeIfAbsent(streamPartition, segment -> new ConcurrentHashMap<>());
198200
ackStatuses.get(streamPartition).put(sequenceNumberNoNull, shardCheckpointStatus);
199201

@@ -217,6 +219,7 @@ public AcknowledgementSet createAcknowledgmentSet(
217219
}
218220

219221
void updateOwnershipForAllShardPartitions() {
222+
220223
if (Duration.between(lastCheckpointTime, Instant.now()).compareTo(CHECKPOINT_INTERVAL) > 0) {
221224
for (final StreamPartition streamPartition : checkpoints.keySet()) {
222225
if (!partitionsToRemove.contains(streamPartition)) {

data-prepper-plugins/dynamodb-source/src/test/java/org/opensearch/dataprepper/plugins/source/dynamodb/stream/ShardAcknowledgementManagerTest.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import static org.hamcrest.MatcherAssert.assertThat;
3232
import static org.hamcrest.Matchers.equalTo;
3333
import static org.junit.jupiter.api.Assertions.assertThrows;
34+
import static org.mockito.ArgumentMatchers.same;
35+
import static org.mockito.Mockito.doNothing;
3436
import static org.mockito.Mockito.doThrow;
3537
import static org.mockito.Mockito.lenient;
3638
import static org.mockito.Mockito.mock;
@@ -282,7 +284,7 @@ void create_acknowledgment_set_throws_ShardNotTrackedException_if_shard_is_not_b
282284
}
283285

284286
@Test
285-
void failure_to_update_state_for_one_partition_stops_tracking_that_partition_and_continues_on_others() {
287+
void failure_to_update_state_for_one_partition_stops_tracking_that_partition_and_continues_on_others() throws InterruptedException {
286288

287289
final ShardAcknowledgementManager shardAcknowledgementManager = createObjectUnderTest();
288290
final StreamPartition secondPartition = mock(StreamPartition.class);
@@ -311,14 +313,13 @@ void failure_to_update_state_for_one_partition_stops_tracking_that_partition_and
311313
callback1.accept(true); // Positive ack
312314
callback2.accept(true);
313315

314-
doThrow(PartitionUpdateException.class).when(sourceCoordinator).saveProgressStateForPartition(eq(streamPartition),
315-
any(Duration.class));
316+
// doThrow(PartitionUpdateException.class).when(sourceCoordinator).saveProgressStateForPartition(eq(streamPartition),
317+
// any(Duration.class));
318+
doThrow(new PartitionUpdateException("Failed update", mock(Throwable.class))).when(sourceCoordinator)
319+
.saveProgressStateForPartition(same(streamPartition), any(Duration.class));
316320

317-
318-
// Run the acknowledgment loop
319-
assertThat(shardAcknowledgementManager.isStillTrackingShard(streamPartition), equalTo(true));
320-
assertThat(shardAcknowledgementManager.isStillTrackingShard(secondPartition), equalTo(false));
321-
shardAcknowledgementManager.runMonitorAcknowledgmentLoop(stopWorkerConsumer);
321+
doNothing().when(sourceCoordinator)
322+
.saveProgressStateForPartition(same(secondPartition), any(Duration.class));
322323

323324
shardAcknowledgementManager.startUpdatingOwnershipForShard(secondPartition);
324325
// Create first acknowledgment set and capture its callback
@@ -331,15 +332,21 @@ void failure_to_update_state_for_one_partition_stops_tracking_that_partition_and
331332
callback1_2.accept(true);
332333
callback2_2.accept(true);
333334

335+
Thread.sleep(1000);
336+
337+
// Run the acknowledgment loop
338+
assertThat(shardAcknowledgementManager.isStillTrackingShard(streamPartition), equalTo(true));
339+
assertThat(shardAcknowledgementManager.isStillTrackingShard(secondPartition), equalTo(true));
340+
shardAcknowledgementManager.runMonitorAcknowledgmentLoop(stopWorkerConsumer);
341+
334342
assertThat(shardAcknowledgementManager.isStillTrackingShard(streamPartition), equalTo(false));
335343
assertThat(shardAcknowledgementManager.isStillTrackingShard(secondPartition), equalTo(true));
336344
shardAcknowledgementManager.runMonitorAcknowledgmentLoop(stopWorkerConsumer);
337345
assertThat(shardAcknowledgementManager.isStillTrackingShard(secondPartition), equalTo(true));
338346

339-
final InOrder inOrder = Mockito.inOrder(sourceCoordinator, secondStreamProgressState, streamProgressState);
340-
inOrder.verify(streamProgressState).setSequenceNumber("seq2");
341-
inOrder.verify(sourceCoordinator).giveUpPartition(streamPartition);
342-
inOrder.verify(secondStreamProgressState).setSequenceNumber("seq124");
343-
inOrder.verify(sourceCoordinator).saveProgressStateForPartition(secondPartition, dynamoDBSourceConfig.getShardAcknowledgmentTimeout());
347+
verify(streamProgressState).setSequenceNumber("seq2");
348+
verify(sourceCoordinator).giveUpPartition(streamPartition);
349+
verify(secondStreamProgressState).setSequenceNumber("seq124");
350+
verify(sourceCoordinator).saveProgressStateForPartition(secondPartition, dynamoDBSourceConfig.getShardAcknowledgmentTimeout());
344351
}
345352
}

0 commit comments

Comments
 (0)