This is an automated email from the ASF dual-hosted git repository.
apoorvmittal10 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 1db1ae701c0 KAFKA-20678: Exception handling for read call in
ReplicaManagerLogReader.readAsync. (#22753)
1db1ae701c0 is described below
commit 1db1ae701c0cecbf5d868fae2f376246410511c9
Author: Sushant Mahajan <[email protected]>
AuthorDate: Wed Jul 8 01:52:02 2026 +0530
KAFKA-20678: Exception handling for read call in
ReplicaManagerLogReader.readAsync. (#22753)
The `read` call in `readAsync` was not protected by a try catch block
which could throw an exception in a non-async fashion to the caller.
This PR surrounds the call in try-catch and adds appropriate tests.
Reviewers: Apoorv Mittal <[email protected]>
---
.../kafka/server/share/ReplicaManagerLogReader.java | 11 +++++++++--
.../kafka/server/share/ReplicaManagerLogReaderTest.java | 17 +++++++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/kafka/server/share/ReplicaManagerLogReader.java
b/core/src/main/java/kafka/server/share/ReplicaManagerLogReader.java
index 70e798b6eb2..14a6ecdbd29 100644
--- a/core/src/main/java/kafka/server/share/ReplicaManagerLogReader.java
+++ b/core/src/main/java/kafka/server/share/ReplicaManagerLogReader.java
@@ -115,8 +115,15 @@ public class ReplicaManagerLogReader implements LogReader {
}
// Perform the local read for all partitions once; remote follow-ups
(if any) are issued per partition.
- LinkedHashMap<TopicIdPartition, LogReadResult> localReadResults =
- read(fetchParams, partitionsToFetch, topicPartitionFetchOffsets,
partitionMaxBytes);
+ // read() is expected to convert per-partition failures into a
LogReadResult carrying an error code
+ // rather than throwing, but guard against an unexpected throw here
anyway - readAsync must surface
+ // failures via the returned future, not by throwing synchronously out
of this method.
+ LinkedHashMap<TopicIdPartition, LogReadResult> localReadResults;
+ try {
+ localReadResults = read(fetchParams, partitionsToFetch,
topicPartitionFetchOffsets, partitionMaxBytes);
+ } catch (Exception e) {
+ return CompletableFuture.failedFuture(e);
+ }
// Only look at partitions with non-null read results.
LinkedHashMap<TopicIdPartition, CompletableFuture<LogReadResult>>
futures = new LinkedHashMap<>();
diff --git
a/core/src/test/java/kafka/server/share/ReplicaManagerLogReaderTest.java
b/core/src/test/java/kafka/server/share/ReplicaManagerLogReaderTest.java
index fb93cba205b..498298f621d 100644
--- a/core/src/test/java/kafka/server/share/ReplicaManagerLogReaderTest.java
+++ b/core/src/test/java/kafka/server/share/ReplicaManagerLogReaderTest.java
@@ -381,6 +381,23 @@ public class ReplicaManagerLogReaderTest {
verify(replicaManager, never()).remoteLogManager();
}
+ @Test
+ public void testReadAsyncCompletesExceptionallyWhenLocalReadThrows() {
+ ReplicaManager replicaManager = mockReplicaManager();
+ RuntimeException readError = new RuntimeException("read failed");
+ when(replicaManager.readFromLog(any(), any(), any(),
anyBoolean())).thenThrow(readError);
+
+ ReplicaManagerLogReader logReader = new
ReplicaManagerLogReader(replicaManager);
+ CompletableFuture<LinkedHashMap<TopicIdPartition, LogReadResult>>
future =
+ logReader.readAsync(fetchParams(), Set.of(TOPIC_ID_PARTITION),
+ offsets(TOPIC_ID_PARTITION), maxBytes(TOPIC_ID_PARTITION),
true);
+
+ // readAsync must surface the failure via the returned future rather
than throwing synchronously.
+ assertTrue(future.isCompletedExceptionally());
+ ExecutionException exception = assertThrows(ExecutionException.class,
() -> future.get(10, TimeUnit.SECONDS));
+ assertSame(readError, exception.getCause());
+ }
+
@Test
public void
testReadAsyncReturnsNoneErrorWhenRemoteReadFailsButLocalSucceeds() throws
Exception {
ReplicaManager replicaManager = mockReplicaManager();