junrao commented on code in PR #18459: URL: https://github.com/apache/kafka/pull/18459#discussion_r1915497293
########## core/src/test/java/kafka/server/share/SharePartitionTest.java: ########## @@ -1104,6 +1116,120 @@ public void testAcquireWithEmptyFetchRecords() { assertEquals(0, sharePartition.nextFetchOffset()); } + @Test + public void testAcquireWithBatchSizeAndSingleBatch() { + SharePartition sharePartition = SharePartitionBuilder.builder().withState(SharePartitionState.ACTIVE).build(); + // Single batch has more records than batch size. Hence, only a single batch exceeding the batch size + // should be acquired. + MemoryRecords records = memoryRecords(5); + List<AcquiredRecords> acquiredRecordsList = fetchAcquiredRecords(sharePartition.acquire( + MEMBER_ID, + 2 /* Batch size */, + 10, + new FetchPartitionData(Errors.NONE, 20, 0, records, + Optional.empty(), OptionalLong.empty(), Optional.empty(), OptionalInt.empty(), false)), + 5); + + assertArrayEquals(expectedAcquiredRecord(0, 4, 1).toArray(), acquiredRecordsList.toArray()); + assertEquals(5, sharePartition.nextFetchOffset()); + assertEquals(1, sharePartition.cachedState().size()); + assertEquals(0, sharePartition.cachedState().get(0L).firstOffset()); + assertEquals(4, sharePartition.cachedState().get(0L).lastOffset()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(0L).batchState()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(0L).batchMemberId()); + assertEquals(1, sharePartition.cachedState().get(0L).batchDeliveryCount()); + assertNull(sharePartition.cachedState().get(0L).offsetState()); + } + + @Test + public void testAcquireWithBatchSizeAndMultipleBatches() { + SharePartition sharePartition = SharePartitionBuilder.builder().withState(SharePartitionState.ACTIVE).build(); + // Create 3 batches of records. + ByteBuffer buffer = ByteBuffer.allocate(4096); + memoryRecordsBuilder(buffer, 5, 2).close(); + memoryRecordsBuilder(buffer, 5, 10).close(); + memoryRecordsBuilder(buffer, 7, 15).close(); + memoryRecordsBuilder(buffer, 6, 22).close(); + buffer.flip(); + MemoryRecords records = MemoryRecords.readableRecords(buffer); + + List<AcquiredRecords> acquiredRecordsList = fetchAcquiredRecords(sharePartition.acquire( + MEMBER_ID, + 5 /* Batch size */, + 100, + new FetchPartitionData(Errors.NONE, 20, 0, records, + Optional.empty(), OptionalLong.empty(), Optional.empty(), OptionalInt.empty(), false)), + 26 /* Gap of 3 records will also be added to first batch */); + + // Fetch expected records from 4 batches, but change the first expected record to include gap offsets. + List<AcquiredRecords> expectedAcquiredRecords = expectedAcquiredRecords(records, 1); + expectedAcquiredRecords.remove(0); + expectedAcquiredRecords.addAll(0, expectedAcquiredRecord(2, 9, 1)); + + assertArrayEquals(expectedAcquiredRecords.toArray(), acquiredRecordsList.toArray()); + assertEquals(28, sharePartition.nextFetchOffset()); + assertEquals(4, sharePartition.cachedState().size()); + assertTrue(sharePartition.cachedState().containsKey(2L)); + assertTrue(sharePartition.cachedState().containsKey(10L)); + assertTrue(sharePartition.cachedState().containsKey(15L)); + assertTrue(sharePartition.cachedState().containsKey(22L)); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(2L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(10L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(15L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(22L).batchState()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(2L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(10L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(15L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(22L).batchMemberId()); + assertEquals(1, sharePartition.cachedState().get(2L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(10L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(15L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(22L).batchDeliveryCount()); + assertNull(sharePartition.cachedState().get(2L).offsetState()); + assertNull(sharePartition.cachedState().get(10L).offsetState()); + assertNull(sharePartition.cachedState().get(15L).offsetState()); + assertNull(sharePartition.cachedState().get(22L).offsetState()); + } + + @Test + public void testAcquireWithBatchSizeAndMaxFetchRecords() { Review Comment: Thanks. This sounds good then. ########## core/src/test/java/kafka/server/share/SharePartitionTest.java: ########## @@ -1104,6 +1116,201 @@ public void testAcquireWithEmptyFetchRecords() { assertEquals(0, sharePartition.nextFetchOffset()); } + @Test + public void testAcquireWithBatchSizeAndSingleBatch() { + SharePartition sharePartition = SharePartitionBuilder.builder().withState(SharePartitionState.ACTIVE).build(); + // Single batch has more records than batch size. Hence, only a single batch exceeding the batch size + // should be acquired. + MemoryRecords records = memoryRecords(5); + List<AcquiredRecords> acquiredRecordsList = fetchAcquiredRecords(sharePartition.acquire( + MEMBER_ID, + 2 /* Batch size */, + 10, + new FetchPartitionData(Errors.NONE, 20, 0, records, + Optional.empty(), OptionalLong.empty(), Optional.empty(), OptionalInt.empty(), false)), + 5); + + assertArrayEquals(expectedAcquiredRecord(0, 4, 1).toArray(), acquiredRecordsList.toArray()); + assertEquals(5, sharePartition.nextFetchOffset()); + assertEquals(1, sharePartition.cachedState().size()); + assertEquals(0, sharePartition.cachedState().get(0L).firstOffset()); + assertEquals(4, sharePartition.cachedState().get(0L).lastOffset()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(0L).batchState()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(0L).batchMemberId()); + assertEquals(1, sharePartition.cachedState().get(0L).batchDeliveryCount()); + assertNull(sharePartition.cachedState().get(0L).offsetState()); + } + + @Test + public void testAcquireWithBatchSizeAndMultipleBatches() { + SharePartition sharePartition = SharePartitionBuilder.builder().withState(SharePartitionState.ACTIVE).build(); + // Create 4 batches of records. + ByteBuffer buffer = ByteBuffer.allocate(4096); + memoryRecordsBuilder(buffer, 5, 2).close(); + memoryRecordsBuilder(buffer, 5, 10).close(); + memoryRecordsBuilder(buffer, 7, 15).close(); + memoryRecordsBuilder(buffer, 6, 22).close(); + buffer.flip(); + MemoryRecords records = MemoryRecords.readableRecords(buffer); + + List<AcquiredRecords> acquiredRecordsList = fetchAcquiredRecords(sharePartition.acquire( + MEMBER_ID, + 5 /* Batch size */, + 100, + new FetchPartitionData(Errors.NONE, 20, 0, records, + Optional.empty(), OptionalLong.empty(), Optional.empty(), OptionalInt.empty(), false)), + 26 /* Gap of 3 records will also be added to first batch */); + + // Fetch expected records from 4 batches, but change the first expected record to include gap offsets. + List<AcquiredRecords> expectedAcquiredRecords = expectedAcquiredRecords(records, 1); + expectedAcquiredRecords.remove(0); + expectedAcquiredRecords.addAll(0, expectedAcquiredRecord(2, 9, 1)); + + assertArrayEquals(expectedAcquiredRecords.toArray(), acquiredRecordsList.toArray()); + assertEquals(28, sharePartition.nextFetchOffset()); + assertEquals(4, sharePartition.cachedState().size()); + assertTrue(sharePartition.cachedState().containsKey(2L)); + assertTrue(sharePartition.cachedState().containsKey(10L)); + assertTrue(sharePartition.cachedState().containsKey(15L)); + assertTrue(sharePartition.cachedState().containsKey(22L)); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(2L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(10L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(15L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(22L).batchState()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(2L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(10L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(15L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(22L).batchMemberId()); + assertEquals(1, sharePartition.cachedState().get(2L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(10L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(15L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(22L).batchDeliveryCount()); + assertNull(sharePartition.cachedState().get(2L).offsetState()); + assertNull(sharePartition.cachedState().get(10L).offsetState()); + assertNull(sharePartition.cachedState().get(15L).offsetState()); + assertNull(sharePartition.cachedState().get(22L).offsetState()); + } + + @Test + public void testAcquireWithBatchSizeAndMaxFetchRecords() { + SharePartition sharePartition = SharePartitionBuilder.builder().withState(SharePartitionState.ACTIVE).build(); + // Create 3 batches of records. + ByteBuffer buffer = ByteBuffer.allocate(4096); + memoryRecordsBuilder(buffer, 5, 0).close(); + memoryRecordsBuilder(buffer, 15, 5).close(); + memoryRecordsBuilder(buffer, 15, 20).close(); + buffer.flip(); + MemoryRecords records = MemoryRecords.readableRecords(buffer); + List<AcquiredRecords> acquiredRecordsList = fetchAcquiredRecords(sharePartition.acquire( + MEMBER_ID, + 2 /* Batch size */, + 10, + new FetchPartitionData(Errors.NONE, 20, 0, records, + Optional.empty(), OptionalLong.empty(), Optional.empty(), OptionalInt.empty(), false)), + 20); + + List<AcquiredRecords> expectedAcquiredRecords = expectedAcquiredRecords(records, 1); + // The last batch should be ignored as it exceeds the max fetch records. + expectedAcquiredRecords.remove(2); + + assertArrayEquals(expectedAcquiredRecords.toArray(), acquiredRecordsList.toArray()); + assertEquals(20, sharePartition.nextFetchOffset()); + assertEquals(2, sharePartition.cachedState().size()); + assertEquals(0, sharePartition.cachedState().get(0L).firstOffset()); + assertEquals(4, sharePartition.cachedState().get(0L).lastOffset()); + assertEquals(5, sharePartition.cachedState().get(5L).firstOffset()); + assertEquals(19, sharePartition.cachedState().get(5L).lastOffset()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(0L).batchState()); + assertEquals(RecordState.ACQUIRED, sharePartition.cachedState().get(5L).batchState()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(0L).batchMemberId()); + assertEquals(MEMBER_ID, sharePartition.cachedState().get(5L).batchMemberId()); + assertEquals(1, sharePartition.cachedState().get(0L).batchDeliveryCount()); + assertEquals(1, sharePartition.cachedState().get(5L).batchDeliveryCount()); + assertNull(sharePartition.cachedState().get(0L).offsetState()); + assertNull(sharePartition.cachedState().get(5L).offsetState()); + } + + @Test + public void testAcquireSingleBatchWithBatchSizeAndEndOffsetAheadBatchFirstOffset() { Review Comment: The endOffset is actually after the firstOffset of the first batch. Ditto in the two other tests below. -- 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: jira-unsubscr...@kafka.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org