You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kafka.apache.org by ce...@apache.org on 2023/10/20 16:23:23 UTC
[kafka] branch 3.6 updated: KAFKA-15607: Fix NPE in MirrorCheckpointTask::syncGroupOffset (#14587)
This is an automated email from the ASF dual-hosted git repository.
cegerton pushed a commit to branch 3.6
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/3.6 by this push:
new 9fca00871ab KAFKA-15607: Fix NPE in MirrorCheckpointTask::syncGroupOffset (#14587)
9fca00871ab is described below
commit 9fca00871ab2c218b797ef44213d80a3dc1f2098
Author: hudeqi <12...@qq.com>
AuthorDate: Sat Oct 21 00:17:51 2023 +0800
KAFKA-15607: Fix NPE in MirrorCheckpointTask::syncGroupOffset (#14587)
Reviewers: Chris Egerton <ch...@aiven.io>
---
.../kafka/connect/mirror/MirrorCheckpointTask.java | 19 +++++++++++----
.../connect/mirror/MirrorCheckpointTaskTest.java | 27 ++++++++++++++++++++++
2 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/connect/mirror/src/main/java/org/apache/kafka/connect/mirror/MirrorCheckpointTask.java b/connect/mirror/src/main/java/org/apache/kafka/connect/mirror/MirrorCheckpointTask.java
index a51846766a6..0bf2baa9d85 100644
--- a/connect/mirror/src/main/java/org/apache/kafka/connect/mirror/MirrorCheckpointTask.java
+++ b/connect/mirror/src/main/java/org/apache/kafka/connect/mirror/MirrorCheckpointTask.java
@@ -330,11 +330,20 @@ public class MirrorCheckpointTask extends SourceTask {
// if translated offset from upstream is smaller than the current consumer offset
// in the target, skip updating the offset for that partition
- long latestDownstreamOffset = targetConsumerOffset.get(topicPartition).offset();
- if (latestDownstreamOffset >= convertedOffset.offset()) {
- log.trace("latestDownstreamOffset {} is larger than or equal to convertedUpstreamOffset {} for "
- + "TopicPartition {}", latestDownstreamOffset, convertedOffset.offset(), topicPartition);
- continue;
+ OffsetAndMetadata targetOffsetAndMetadata = targetConsumerOffset.get(topicPartition);
+ if (targetOffsetAndMetadata != null) {
+ long latestDownstreamOffset = targetOffsetAndMetadata.offset();
+ if (latestDownstreamOffset >= convertedOffset.offset()) {
+ log.trace("latestDownstreamOffset {} is larger than or equal to convertedUpstreamOffset {} for "
+ + "TopicPartition {}", latestDownstreamOffset, convertedOffset.offset(), topicPartition);
+ continue;
+ }
+ } else {
+ // It is possible that when resetting offsets are performed in the java kafka client, the reset to -1 will be intercepted.
+ // However, there are some other types of clients such as sarama, which can magically reset the group offset to -1, which will cause
+ // `targetOffsetAndMetadata` here is null. For this case, just sync the offset to target.
+ log.warn("Group {} offset for partition {} may has been reset to a negative offset, just sync the offset to target.",
+ consumerGroupId, topicPartition);
}
offsetToSync.put(topicPartition, convertedOffset);
}
diff --git a/connect/mirror/src/test/java/org/apache/kafka/connect/mirror/MirrorCheckpointTaskTest.java b/connect/mirror/src/test/java/org/apache/kafka/connect/mirror/MirrorCheckpointTaskTest.java
index f9bc7bc76cb..8d8e8bd3a0d 100644
--- a/connect/mirror/src/test/java/org/apache/kafka/connect/mirror/MirrorCheckpointTaskTest.java
+++ b/connect/mirror/src/test/java/org/apache/kafka/connect/mirror/MirrorCheckpointTaskTest.java
@@ -169,6 +169,33 @@ public class MirrorCheckpointTaskTest {
"Consumer 2 " + topic2 + " failed");
}
+ @Test
+ public void testSyncOffsetForTargetGroupWithNullOffsetAndMetadata() {
+ Map<String, Map<TopicPartition, OffsetAndMetadata>> idleConsumerGroupsOffset = new HashMap<>();
+ Map<String, Map<TopicPartition, Checkpoint>> checkpointsPerConsumerGroup = new HashMap<>();
+
+ String consumer = "consumer";
+ String topic = "topic";
+ Map<TopicPartition, OffsetAndMetadata> ct = new HashMap<>();
+ TopicPartition tp = new TopicPartition(topic, 0);
+ // Simulate other clients such as Sarama, which may reset group offsets to -1. This can cause
+ // the obtained `OffsetAndMetadata` of the target cluster to be null.
+ ct.put(tp, null);
+ idleConsumerGroupsOffset.put(consumer, ct);
+
+ Checkpoint cp = new Checkpoint(consumer, new TopicPartition(topic, 0), 200, 101, "metadata");
+ Map<TopicPartition, Checkpoint> checkpointMap = new HashMap<>();
+ checkpointMap.put(cp.topicPartition(), cp);
+ checkpointsPerConsumerGroup.put(consumer, checkpointMap);
+
+ MirrorCheckpointTask mirrorCheckpointTask = new MirrorCheckpointTask("source", "target",
+ new DefaultReplicationPolicy(), null, idleConsumerGroupsOffset, checkpointsPerConsumerGroup);
+
+ Map<String, Map<TopicPartition, OffsetAndMetadata>> output = mirrorCheckpointTask.syncGroupOffset();
+
+ assertEquals(101, output.get(consumer).get(tp).offset(), "Consumer " + topic + " failed");
+ }
+
@Test
public void testNoCheckpointForTopicWithoutOffsetSyncs() {
OffsetSyncStoreTest.FakeOffsetSyncStore offsetSyncStore = new OffsetSyncStoreTest.FakeOffsetSyncStore();