nahidupa commented on code in PR #17925:
URL: https://github.com/apache/iceberg/pull/17925#discussion_r3978568782


##########
kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/channel/CommitState.java:
##########
@@ -119,18 +131,18 @@ boolean isCommitReady(int expectedPartitionCount) {
       return false;
     }
 
-    if (receivedPartitionCount >= expectedPartitionCount) {
+    if (reportedPartitions.size() >= expectedPartitionCount) {

Review Comment:
   Implemented in 65320ff8f. `Coordinator` now captures an immutable 
`Set<TopicPartition>` from the member assignments, and 
`CommitState.isCommitReady` requires 
`reportedPartitions.containsAll(expectedPartitions)`. An unexpected partition 
can no longer substitute for a missing expected one.
   
   Added `unexpectedPartitionsDoNotSatisfyReadiness` and 
`unexpectedPartitionDoesNotCompleteCommit`; both fail when readiness is changed 
back to a cardinality comparison. This checks coverage against the assignment 
captured at coordinator construction, not its freshness after a rebalance or 
topic expansion.



##########
kafka-connect/kafka-connect/src/test/java/org/apache/iceberg/connect/channel/TestCommitState.java:
##########
@@ -60,16 +69,70 @@ public void testIsCommitReady() {
     assertThat(commitState.isCommitReady(4)).isFalse();
   }
 
+  @Test
+  public void testReplayedReadyDoesNotSatisfyQuorumTwice() {
+    CommitState commitState = new CommitState(mock(IcebergSinkConfig.class));
+    commitState.startNewCommit();
+
+    // one worker owning source partition 0 reports; a control-topic replay 
redelivers it
+    TopicPartitionOffset tp0 = partition(0);
+    DataComplete payload = mock(DataComplete.class);
+    when(payload.commitId()).thenReturn(commitState.currentCommitId());
+    when(payload.assignments()).thenReturn(ImmutableList.of(tp0));
+
+    commitState.addReady(wrapInEnvelope(payload));
+    commitState.addReady(wrapInEnvelope(payload));
+
+    assertThat(commitState.isCommitReady(2))
+        .as("a redelivered response must not stand in for a partition that 
never reported")
+        .isFalse();
+
+    // the partition that was actually missing reports
+    TopicPartitionOffset tp1 = partition(1);
+    DataComplete second = mock(DataComplete.class);
+    when(second.commitId()).thenReturn(commitState.currentCommitId());
+    when(second.assignments()).thenReturn(ImmutableList.of(tp1));
+    commitState.addReady(wrapInEnvelope(second));
+
+    assertThat(commitState.isCommitReady(2)).isTrue();
+  }
+
+  @Test
+  public void testOverlappingAssignmentsDoNotSatisfyQuorumTwice() {

Review Comment:
   Addressed in 65320ff8f. `testOverlappingAssignmentsDoNotSatisfyQuorumTwice` 
now expects `src-topic/0` and `other-topic/0`: two reports for `src-topic/0` 
remain insufficient, and a report for `other-topic/0` completes that expected 
set. It also checks that an additional expected `src-topic/1` is still missing.
   
   The test fails when topic identity is dropped from the recorded key. That 
gives it a distinct assertion beyond the duplicate-response case.



##########
kafka-connect/kafka-connect/src/test/java/org/apache/iceberg/connect/channel/TestCommitState.java:
##########
@@ -89,7 +152,7 @@ public void testIsCommitReadyResetsBetweenCommits() {
 
   @Test
   public void testIsCommitReadyIgnoresZombieCoordinatorPayloads() {
-    TopicPartitionOffset tp = mock(TopicPartitionOffset.class);
+    TopicPartitionOffset tp = partition(0);

Review Comment:
   Addressed in 65320ff8f. The stale-ID payload now carries partition 1 while 
the current-ID payload carries partition 0. Readiness for both partitions stays 
false until partition 1 is reported with the current commit ID.
   
   Removing the commit-ID guard makes 
`testIsCommitReadyIgnoresZombieCoordinatorPayloads` fail. The guard was 
restored after the negative-control run.



##########
kafka-connect/kafka-connect/src/test/java/org/apache/iceberg/connect/channel/TestCoordinator.java:
##########
@@ -480,6 +483,90 @@ private void assertCommitComplete(int idx, UUID commitId, 
OffsetDateTime ts) {
     assertThat(commitCompletePayload.validThroughTs()).isEqualTo(ts);
   }
 
+  @Test
+  public void testReplayedDataCompleteStillCommitsTheFileExactlyOnce() {

Review Comment:
   Addressed in 65320ff8f. Added 
`startCoordinator(Collection<MemberDescription> members)` and made the 
no-argument helper delegate with `ImmutableList.of()`. The assignment-aware 
tests now use the overload, sharing the config stubs, coordinator startup, and 
consumer initialization.



##########
kafka-connect/kafka-connect/src/test/java/org/apache/iceberg/connect/channel/TestCoordinator.java:
##########
@@ -480,6 +483,90 @@ private void assertCommitComplete(int idx, UUID commitId, 
OffsetDateTime ts) {
     assertThat(commitCompletePayload.validThroughTs()).isEqualTo(ts);
   }
 
+  @Test
+  public void testReplayedDataCompleteStillCommitsTheFileExactlyOnce() {
+    when(config.commitIntervalMs()).thenReturn(0);
+    when(config.commitTimeoutMs()).thenReturn(Integer.MAX_VALUE);
+
+    // two source partitions, so a commit is only ready once both have reported
+    MemberDescription member =
+        new MemberDescription(
+            "member",
+            Optional.empty(),
+            "client",
+            "host",
+            new MemberAssignment(
+                ImmutableSet.of(
+                    new TopicPartition(SRC_TOPIC_NAME, 0), new 
TopicPartition(SRC_TOPIC_NAME, 1))));
+    Coordinator coordinator =
+        new Coordinator(
+            catalog, config, ImmutableList.of(member), clientFactory, 
mock(SinkTaskContext.class));
+    coordinator.start();
+    initConsumer();
+
+    coordinator.process();
+    UUID commitId =
+        ((StartCommit) 
AvroUtil.decode(producer.history().get(0).value()).payload()).commitId();
+
+    DataFile dataFile = EventTestUtil.createDataFile();
+    Event written =
+        new Event(
+            config.connectGroupId(),
+            new DataWritten(
+                StructType.of(),
+                commitId,
+                TableReference.of("catalog", TABLE_IDENTIFIER, table.uuid()),
+                ImmutableList.of(dataFile),
+                ImmutableList.of()));
+    Event firstPartitionReady =
+        new Event(
+            config.connectGroupId(),
+            new DataComplete(
+                commitId, ImmutableList.of(new 
TopicPartitionOffset(SRC_TOPIC_NAME, 0, 1L, null))));

Review Comment:
   Addressed in 65320ff8f. Partition 0 now reports a timestamp one second later 
than partition 1. `repeatedDataCompleteWaitsForEveryExpectedPartition` asserts 
that no snapshot, completion event, or checkpoint advance occurs while 
partition 1 is missing, then checks that `VALID_THROUGH_TS_SNAPSHOT_PROP` and 
both completion-event timestamps equal partition 1's earlier timestamp.
   
   This runs for both a same-offset rewind and duplicate payloads at new 
offsets. Restoring duplicate-accepting counting makes both coordinator variants 
fail with premature snapshots carrying the later timestamp. All mutations were 
reverted; the forced connector check passed 149 tests, with no live-broker 
rebalance exercised.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to