You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kafka.apache.org by ca...@apache.org on 2023/08/19 10:13:40 UTC
[kafka] branch trunk updated: MINOR: Decouple purging committed records from committing (#14227)
This is an automated email from the ASF dual-hosted git repository.
cadonna pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/trunk by this push:
new 4c7e0a9fa66 MINOR: Decouple purging committed records from committing (#14227)
4c7e0a9fa66 is described below
commit 4c7e0a9fa66fd1becc590d6060228b0305dd400b
Author: Bruno Cadonna <ca...@apache.org>
AuthorDate: Sat Aug 19 12:13:30 2023 +0200
MINOR: Decouple purging committed records from committing (#14227)
Currently, Kafka Streams only tries to purge records whose
offset are committed from a repartition topic when at
least one offset was committed in the current commit.
The coupling between committing some offsets and purging
records is not needed and might delay purging of records.
For example, if a in-flight call for purging records has not
completed yet when a commit happens, a new call
is not issued.
If then the earlier in-flight call for purging records
finally completes but the next commit does not commit any
offsets, Streams does not issue the call for purging records
whose offset were committed in the previous commit
because the purging call was still in-flight.
This change issues calls for purging records during any commit
if the purge interval passed, even if no offsets were committed
in the current commit.
Reviewers: Lucas Brutschy <lb...@confluent.io>, Walker Carlson <wc...@confluent.io>
---
.../streams/processor/internals/StreamThread.java | 2 +-
.../processor/internals/StreamThreadTest.java | 33 ++++++++++++++++++++++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/streams/src/main/java/org/apache/kafka/streams/processor/internals/StreamThread.java b/streams/src/main/java/org/apache/kafka/streams/processor/internals/StreamThread.java
index 1f2a91d27b7..883ec25ff10 100644
--- a/streams/src/main/java/org/apache/kafka/streams/processor/internals/StreamThread.java
+++ b/streams/src/main/java/org/apache/kafka/streams/processor/internals/StreamThread.java
@@ -1126,7 +1126,7 @@ public class StreamThread extends Thread {
.collect(Collectors.toSet())
);
- if (committed > 0 && (now - lastPurgeMs) > purgeTimeMs) {
+ if ((now - lastPurgeMs) > purgeTimeMs) {
// try to purge the committed records for repartition topics if possible
taskManager.maybePurgeCommittedRecords();
lastPurgeMs = now;
diff --git a/streams/src/test/java/org/apache/kafka/streams/processor/internals/StreamThreadTest.java b/streams/src/test/java/org/apache/kafka/streams/processor/internals/StreamThreadTest.java
index 6050de77be0..5830265753e 100644
--- a/streams/src/test/java/org/apache/kafka/streams/processor/internals/StreamThreadTest.java
+++ b/streams/src/test/java/org/apache/kafka/streams/processor/internals/StreamThreadTest.java
@@ -128,6 +128,7 @@ import static org.apache.kafka.common.utils.Utils.mkProperties;
import static org.apache.kafka.common.utils.Utils.mkSet;
import static org.apache.kafka.streams.processor.internals.ClientUtils.getSharedAdminClientId;
import static org.apache.kafka.streams.processor.internals.StateManagerUtil.CHECKPOINT_FILE_NAME;
+import static org.apache.kafka.test.StreamsTestUtils.TaskBuilder.statelessTask;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
@@ -509,6 +510,38 @@ public class StreamThreadTest {
verify(taskManager);
}
+ @Test
+ public void shouldAlsoPurgeWhenNothingGetsCommitted() {
+ final long purgeInterval = 1000L;
+ final Properties props = configProps(false);
+ props.setProperty(StreamsConfig.STATE_DIR_CONFIG, stateDir);
+ props.setProperty(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, Long.toString(purgeInterval));
+ props.setProperty(StreamsConfig.REPARTITION_PURGE_INTERVAL_MS_CONFIG, Long.toString(purgeInterval));
+
+ final StreamsConfig config = new StreamsConfig(props);
+ final Consumer<byte[], byte[]> consumer = EasyMock.createNiceMock(Consumer.class);
+ final ConsumerGroupMetadata consumerGroupMetadata = mock(ConsumerGroupMetadata.class);
+ expect(consumer.groupMetadata()).andStubReturn(consumerGroupMetadata);
+ expect(consumerGroupMetadata.groupInstanceId()).andReturn(Optional.empty());
+ final TaskId taskId = new TaskId(0, 0);
+ final Task runningTask = statelessTask(taskId)
+ .inState(Task.State.RUNNING).build();
+ final TaskManager taskManager = EasyMock.createNiceMock(TaskManager.class);
+ expect(taskManager.allOwnedTasks()).andStubReturn(Collections.singletonMap(taskId, runningTask));
+ expect(taskManager.commit(Collections.singleton(runningTask))).andStubReturn(0);
+ taskManager.maybePurgeCommittedRecords();
+ EasyMock.replay(consumer, consumerGroupMetadata, taskManager);
+
+ final TopologyMetadata topologyMetadata = new TopologyMetadata(internalTopologyBuilder, config);
+ topologyMetadata.buildAndRewriteTopology();
+ final StreamThread thread = buildStreamThread(consumer, taskManager, config, topologyMetadata);
+ thread.setNow(mockTime.milliseconds());
+ mockTime.sleep(purgeInterval + 10L);
+ thread.maybeCommit();
+
+ verify(taskManager);
+ }
+
@Test
public void shouldEnforceRebalanceWhenScheduledAndNotCurrentlyRebalancing() throws InterruptedException {
final StreamsConfig config = new StreamsConfig(configProps(false));