Shekharrajak commented on code in PR #23971:
URL: https://github.com/apache/kafka/pull/23971#discussion_r4385238642


##########
server-common/src/test/java/org/apache/kafka/server/share/persister/PersisterStateManagerTest.java:
##########
@@ -1835,6 +1836,224 @@ public void 
testWriteStateCombinedResponseNullClientResponseCompletesAllHandlers
         assertWriteStateResult(partition1, topicId, 1, 
Errors.UNKNOWN_SERVER_ERROR);
     }
 
+    private static ReadShareGroupStateResponseData.PartitionResult 
readStatePartitionResult(int partition, Errors error) {
+        return new ReadShareGroupStateResponseData.PartitionResult()
+            .setPartition(partition)
+            .setErrorCode(error.code())
+            .setErrorMessage(error.message())
+            .setStateEpoch(partition + 1)
+            .setStartOffset(100L + partition)
+            .setStateBatches(List.of(new 
ReadShareGroupStateResponseData.StateBatch()
+                .setFirstOffset(100L + partition)
+                .setLastOffset(110L + partition)
+                .setDeliveryState((byte) 0)
+                .setDeliveryCount((short) 2)));
+    }
+
+    private static ReadShareGroupStateResponseData.ReadStateResult 
readStateResult(
+        Uuid topicId,
+        ReadShareGroupStateResponseData.PartitionResult... partitions
+    ) {
+        return new ReadShareGroupStateResponseData.ReadStateResult()
+            .setTopicId(topicId)
+            .setPartitions(List.of(partitions));
+    }
+
+    private static ClientResponse 
readStateClientResponse(ReadShareGroupStateResponseData data) {
+        return new ClientResponse(
+            new RequestHeader(ApiKeys.READ_SHARE_GROUP_STATE, 
ApiKeys.READ_SHARE_GROUP_STATE.latestVersion(), "client-id", 0),
+            null,
+            HOST,
+            MOCK_TIME.milliseconds(),
+            MOCK_TIME.milliseconds(),
+            false,
+            null,
+            null,
+            new ReadShareGroupStateResponse(data)
+        );
+    }
+
+    private PersisterStateManager.ReadStateHandler batchedReadHandler(
+        PersisterStateManager stateManager,
+        Node coordinatorNode,
+        String groupId,
+        Uuid topicId,
+        int partition
+    ) {
+        PersisterStateManager.ReadStateHandler handler = stateManager.new 
ReadStateHandler(
+            groupId,
+            topicId,
+            partition,
+            0,
+            new CompletableFuture<>(),
+            REQUEST_BACKOFF_MS,
+            REQUEST_BACKOFF_MAX_MS,
+            MAX_RPC_RETRY_ATTEMPTS,
+            response -> { }
+        );
+        handler.addRequestToNodeMap(coordinatorNode, handler);
+        return handler;
+    }
+
+    private static void assertReadStateResult(
+        PersisterStateManager.ReadStateHandler handler,
+        Uuid expectedTopicId,
+        int expectedPartition,
+        Errors expectedError
+    ) {
+        ReadShareGroupStateResponse response = assertDoesNotThrow(() -> 
handler.result().get(5, TimeUnit.SECONDS));
+        assertEquals(1, response.data().results().size());
+        ReadShareGroupStateResponseData.ReadStateResult result = 
response.data().results().get(0);
+        assertEquals(expectedTopicId, result.topicId());
+        assertEquals(1, result.partitions().size());
+        assertEquals(expectedPartition, 
result.partitions().get(0).partition());
+        assertEquals(expectedError.code(), 
result.partitions().get(0).errorCode());
+        if (expectedError == Errors.NONE) {
+            assertEquals(readStatePartitionResult(expectedPartition, 
Errors.NONE), result.partitions().get(0));
+        }
+    }
+
+    @Test
+    public void testReadStateCombinedResponseDemultiplexedPerTopicPartition() {
+        String groupId = "group1";
+        Uuid topicId1 = Uuid.randomUuid();
+        Uuid topicId2 = Uuid.randomUuid();
+        Node coordinatorNode = new Node(1, HOST, PORT);
+
+        PersisterStateManager stateManager = 
PersisterStateManagerBuilder.builder()
+            .withKafkaClient(new MockClient(MOCK_TIME))
+            .withTimer(mockTimer)
+            .withCacheHelper(getCoordinatorCacheHelper(coordinatorNode))
+            .build();
+
+        PersisterStateManager.ReadStateHandler topic1Partition0 = 
batchedReadHandler(stateManager, coordinatorNode, groupId, topicId1, 0);
+        PersisterStateManager.ReadStateHandler topic1Partition1 = 
batchedReadHandler(stateManager, coordinatorNode, groupId, topicId1, 1);
+        PersisterStateManager.ReadStateHandler topic2Partition0 = 
batchedReadHandler(stateManager, coordinatorNode, groupId, topicId2, 0);
+        PersisterStateManager.ReadStateHandler topic2Partition1 = 
batchedReadHandler(stateManager, coordinatorNode, groupId, topicId2, 1);
+
+        Collection<RequestAndCompletionHandler> requests = 
stateManager.generateRequests();
+        assertEquals(1, requests.size());
+
+        requests.iterator().next().handler.onComplete(readStateClientResponse(
+            new ReadShareGroupStateResponseData().setResults(List.of(
+                readStateResult(topicId1,
+                    readStatePartitionResult(0, Errors.NONE),
+                    readStatePartitionResult(1, Errors.INVALID_REQUEST)),
+                readStateResult(topicId2,
+                    readStatePartitionResult(0, Errors.FENCED_LEADER_EPOCH),
+                    readStatePartitionResult(1, Errors.NONE))))));
+
+        assertReadStateResult(topic1Partition0, topicId1, 0, Errors.NONE);
+        assertReadStateResult(topic1Partition1, topicId1, 1, 
Errors.INVALID_REQUEST);
+        assertReadStateResult(topic2Partition0, topicId2, 0, 
Errors.FENCED_LEADER_EPOCH);
+        assertReadStateResult(topic2Partition1, topicId2, 1, Errors.NONE);
+    }
+
+    @ParameterizedTest
+    @ValueSource(ints = {1, 16, 256})
+    public void testReadStateCombinedResponseIndexedOncePerBatch(int 
partitionCount) {
+        String groupId = "group1";
+        Uuid topicId = Uuid.randomUuid();
+        Node coordinatorNode = new Node(1, HOST, PORT);
+
+        PersisterStateManager stateManager = 
PersisterStateManagerBuilder.builder()
+            .withKafkaClient(new MockClient(MOCK_TIME))
+            .withTimer(mockTimer)
+            .withCacheHelper(getCoordinatorCacheHelper(coordinatorNode))
+            .build();
+
+        List<PersisterStateManager.ReadStateHandler> handlers = new 
ArrayList<>();
+        for (int partition = 0; partition < partitionCount; partition++) {
+            PersisterStateManager.ReadStateHandler handler = 
spy(stateManager.new ReadStateHandler(
+                groupId,
+                topicId,
+                partition,
+                0,
+                new CompletableFuture<>(),
+                REQUEST_BACKOFF_MS,
+                REQUEST_BACKOFF_MAX_MS,
+                MAX_RPC_RETRY_ATTEMPTS,
+                response -> { }
+            ));
+            handler.addRequestToNodeMap(coordinatorNode, handler);
+            handlers.add(handler);
+        }
+
+        Collection<RequestAndCompletionHandler> requests = 
stateManager.generateRequests();
+        assertEquals(1, requests.size());
+
+        List<ReadShareGroupStateResponseData.PartitionResult> partitions = new 
ArrayList<>();
+        for (int partition = 0; partition < partitionCount; partition++) {
+            partitions.add(spy(readStatePartitionResult(partition, 
Errors.NONE)));
+        }
+        requests.iterator().next().handler.onComplete(readStateClientResponse(
+            new ReadShareGroupStateResponseData().setResults(List.of(
+                new 
ReadShareGroupStateResponseData.ReadStateResult().setTopicId(topicId).setPartitions(partitions)))));
+
+        for (var partition : partitions) {
+            verify(partition, times(1)).partition();
+        }
+
+        verify(handlers.get(0), times(1)).buildResultIndex(any());
+        for (int i = 1; i < handlers.size(); i++) {
+            verify(handlers.get(i), never()).buildResultIndex(any());

Review Comment:
   the other handlers reuse the shared index.



-- 
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]

Reply via email to