diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommand.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommand.java index 20b4232e314..0e034b08acd 100644 --- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommand.java +++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommand.java @@ -189,7 +189,13 @@ private boolean readledger(ServerConfiguration serverConf, ReadLedgerFlags flags executor, scheduler, NullStatsLogger.INSTANCE, bk.getBookieAddressResolver()); - LongStream.range(flags.firstEntryId, lastEntry).forEach(entryId -> { + // Determine the last ledger entry from ledger metadata if its is not provided + if (flags.lastEntryId == -1 && !flags.forceRecovery) { + LedgerHandle lh = bk.openLedgerNoRecovery(flags.ledgerId); + lastEntry = lh.getLastAddConfirmed(); + } + + LongStream.rangeClosed(flags.firstEntryId, lastEntry).forEach(entryId -> { CompletableFuture future = new CompletableFuture<>(); bookieClient.readEntry(bookie, flags.ledgerId, entryId, diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java index 3f80d31dba1..73adf204ace 100644 --- a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java +++ b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadLedgerCommandTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -35,6 +36,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; import lombok.SneakyThrows; +import org.apache.bookkeeper.client.BKException; import org.apache.bookkeeper.client.BookKeeperAdmin; import org.apache.bookkeeper.client.LedgerEntry; import org.apache.bookkeeper.client.LedgerHandle; @@ -42,6 +44,7 @@ import org.apache.bookkeeper.net.BookieId; import org.apache.bookkeeper.net.BookieSocketAddress; import org.apache.bookkeeper.proto.BookieClientImpl; +import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback; import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase; import org.junit.Assert; import org.junit.Test; @@ -89,6 +92,7 @@ public void accept(BookKeeperAdmin bookKeeperAdmin) { when(bookKeeperAdmin.getBookieAddressResolver()) .thenReturn(BookieSocketAddress.LEGACY_BOOKIEID_RESOLVER); when(bookKeeperAdmin.openLedger(anyLong())).thenReturn(ledgerHandle); + when(bookKeeperAdmin.openLedgerNoRecovery(anyLong())).thenReturn(ledgerHandle); when(bookKeeperAdmin.readEntries(anyLong(), anyLong(), anyLong())).thenReturn(entries); } }); @@ -110,7 +114,18 @@ public void accept(BookKeeperAdmin bookKeeperAdmin) { .newSingleThreadScheduledExecutor(any(DefaultThreadFactory.class))) .thenReturn(scheduledExecutorService); - mockConstruction(BookieClientImpl.class); + mockConstruction(BookieClientImpl.class, (mock, contest) -> { + doAnswer(invocation -> { + ReadEntryCallback callback = invocation.getArgument(3); + callback.readEntryComplete(BKException.Code.OK, + invocation.getArgument(1), // ledgerId + invocation.getArgument(2), // entryId + null, // buffer + invocation.getArgument(4)); // ctx + return null; + }).when(mock).readEntry(any(), anyLong(), anyLong(), any(), any(), anyInt()); + + }); }