-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-7548: KafkaConsumer should not throw away already fetched data for paused partitions (v2) #6988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KAFKA-7548: KafkaConsumer should not throw away already fetched data for paused partitions (v2) #6988
Changes from 6 commits
8f832e0
fd57ff3
fbefb25
9095cda
ba68212
ded3f61
2f64a00
c9b4719
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -897,6 +897,145 @@ public void testFetchOnPausedPartition() { | |
| assertTrue(client.requests().isEmpty()); | ||
| } | ||
|
|
||
| @Test | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a test case which covers the case where the user seeks to a new offset while a partition is paused with data available to return? In this case, we expect the data to be discarded when the partition is resumed.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did a pass over |
||
| public void testFetchOnCompletedFetchesForPausedAndResumedPartitions() { | ||
| buildFetcher(); | ||
|
|
||
| assignFromUser(singleton(tp0)); | ||
| subscriptions.seek(tp0, 0); | ||
|
|
||
| assertEquals(1, fetcher.sendFetches()); | ||
|
|
||
| subscriptions.pause(tp0); | ||
|
|
||
| client.prepareResponse(fullFetchResponse(tp0, this.records, Errors.NONE, 100L, 0)); | ||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| Map<TopicPartition, List<ConsumerRecord<byte[], byte[]>>> fetchedRecords = fetchedRecords(); | ||
| assertEquals("Should not return any records when partition is paused", 0, fetchedRecords.size()); | ||
| assertTrue("Should still contain completed fetches", fetcher.hasCompletedFetches()); | ||
| assertNull(fetchedRecords.get(tp0)); | ||
| assertEquals(0, fetcher.sendFetches()); | ||
|
|
||
| subscriptions.resume(tp0); | ||
|
|
||
| consumerClient.poll(time.timer(0)); | ||
| fetchedRecords = fetchedRecords(); | ||
| assertEquals("Should return records when partition is resumed", 1, fetchedRecords.size()); | ||
| assertNotNull(fetchedRecords.get(tp0)); | ||
| assertEquals(3, fetchedRecords.get(tp0).size()); | ||
|
|
||
| consumerClient.poll(time.timer(0)); | ||
| fetchedRecords = fetchedRecords(); | ||
| assertEquals("Should not return records after previously paused partitions are fetched", 0, fetchedRecords.size()); | ||
| assertFalse("Should no longer contain completed fetches", fetcher.hasCompletedFetches()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFetchOnCompletedFetchesForSomePausedPartitions() { | ||
| buildFetcher(); | ||
|
|
||
| Map<TopicPartition, List<ConsumerRecord<byte[], byte[]>>> fetchedRecords; | ||
|
|
||
| assignFromUser(Utils.mkSet(tp0, tp1)); | ||
|
|
||
| // seek to tp0 and tp1 in two polls to generate 2 complete requests and responses | ||
|
|
||
| // #1 seek, request, poll, response | ||
| subscriptions.seek(tp0, 1); | ||
| assertEquals(1, fetcher.sendFetches()); | ||
| client.prepareResponse(fullFetchResponse(tp0, this.records, Errors.NONE, 100L, 0)); | ||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| // #2 seek, request, poll, response | ||
| subscriptions.seek(tp1, 1); | ||
| assertEquals(1, fetcher.sendFetches()); | ||
| client.prepareResponse(fullFetchResponse(tp1, this.nextRecords, Errors.NONE, 100L, 0)); | ||
|
|
||
| subscriptions.pause(tp0); | ||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| fetchedRecords = fetchedRecords(); | ||
| assertEquals("Should return completed fetch for unpaused partitions", 1, fetchedRecords.size()); | ||
| assertTrue("Should still contain completed fetches", fetcher.hasCompletedFetches()); | ||
| assertNotNull(fetchedRecords.get(tp1)); | ||
| assertNull(fetchedRecords.get(tp0)); | ||
|
|
||
| fetchedRecords = fetchedRecords(); | ||
| assertEquals("Should return no records for remaining paused partition", 0, fetchedRecords.size()); | ||
| assertTrue("Should still contain completed fetches", fetcher.hasCompletedFetches()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFetchOnCompletedFetchesForAllPausedPartitions() { | ||
| buildFetcher(); | ||
|
|
||
| Map<TopicPartition, List<ConsumerRecord<byte[], byte[]>>> fetchedRecords; | ||
|
|
||
| assignFromUser(Utils.mkSet(tp0, tp1)); | ||
|
|
||
| // seek to tp0 and tp1 in two polls to generate 2 complete requests and responses | ||
|
|
||
| // #1 seek, request, poll, response | ||
| subscriptions.seek(tp0, 1); | ||
| assertEquals(1, fetcher.sendFetches()); | ||
| client.prepareResponse(fullFetchResponse(tp0, this.records, Errors.NONE, 100L, 0)); | ||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| // #2 seek, request, poll, response | ||
| subscriptions.seek(tp1, 1); | ||
| assertEquals(1, fetcher.sendFetches()); | ||
| client.prepareResponse(fullFetchResponse(tp1, this.nextRecords, Errors.NONE, 100L, 0)); | ||
|
|
||
| subscriptions.pause(tp0); | ||
| subscriptions.pause(tp1); | ||
|
|
||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| fetchedRecords = fetchedRecords(); | ||
| assertEquals("Should return no records for all paused partitions", 0, fetchedRecords.size()); | ||
| assertTrue("Should still contain completed fetches", fetcher.hasCompletedFetches()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testPartialFetchWithPausedPartitions() { | ||
| // this test sends creates a completed fetch with 3 records and a max poll of 2 records to assert | ||
| // that a fetch that must be returned over at least 2 polls can be cached successfully when its partition is | ||
| // paused, then returned successfully after its been resumed again later | ||
| buildFetcher(2); | ||
|
|
||
| Map<TopicPartition, List<ConsumerRecord<byte[], byte[]>>> fetchedRecords; | ||
|
|
||
| assignFromUser(Utils.mkSet(tp0, tp1)); | ||
|
|
||
| subscriptions.seek(tp0, 1); | ||
| assertEquals(1, fetcher.sendFetches()); | ||
| client.prepareResponse(fullFetchResponse(tp0, this.records, Errors.NONE, 100L, 0)); | ||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| fetchedRecords = fetchedRecords(); | ||
|
|
||
| assertEquals("Should return 2 records from fetch with 3 records", 2, fetchedRecords.get(tp0).size()); | ||
| assertFalse("Should have no completed fetches", fetcher.hasCompletedFetches()); | ||
|
|
||
| subscriptions.pause(tp0); | ||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| fetchedRecords = fetchedRecords(); | ||
|
|
||
| assertEquals("Should return no records for paused partitions", 0, fetchedRecords.size()); | ||
| assertTrue("Should have 1 entry in completed fetches", fetcher.hasCompletedFetches()); | ||
|
|
||
| subscriptions.resume(tp0); | ||
|
|
||
| consumerClient.poll(time.timer(0)); | ||
|
|
||
| fetchedRecords = fetchedRecords(); | ||
|
|
||
| assertEquals("Should return last remaining record", 1, fetchedRecords.get(tp0).size()); | ||
| assertFalse("Should have no completed fetches", fetcher.hasCompletedFetches()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testFetchNotLeaderForPartition() { | ||
| buildFetcher(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.