diff --git a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java index 0555936a51968ef1c3ce22ddd5ca0e4ca8ba4de4..1095a90f8755501b09290a9e8e3907d3f90e3bef 100644 --- a/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java +++ b/managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java @@ -19,6 +19,7 @@ package org.apache.bookkeeper.mledger.impl; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; import static java.lang.Math.min; import static org.apache.bookkeeper.mledger.impl.ManagedCursorImpl.FALSE; import static org.apache.bookkeeper.mledger.util.SafeRun.safeRun; @@ -2765,7 +2766,14 @@ public class ManagedLedgerImpl implements ManagedLedger, CreateCallback { PositionImpl getFirstPosition() { Long ledgerId = ledgers.firstKey(); - return ledgerId == null ? null : new PositionImpl(ledgerId, -1); + if (ledgerId == null) { + return null; + } + if (ledgerId > lastConfirmedEntry.getLedgerId()) { + checkState(ledgers.get(ledgerId).getEntries() == 0); + ledgerId = lastConfirmedEntry.getLedgerId(); + } + return new PositionImpl(ledgerId, -1); } PositionImpl getLastPosition() { diff --git a/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerTest.java b/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerTest.java index 40726c940a3e863e5424c01430afdc890a8ec0c7..d54f11275e0991581fe3c651f220932285bdb318 100644 --- a/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerTest.java +++ b/managed-ledger/src/test/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerTest.java @@ -1693,6 +1693,33 @@ public class ManagedLedgerTest extends MockedBookKeeperTestCase { ml.close(); } + /** + * Set retention time = 0 and create a empty ledger, + * first position can't higher than last after trim ledgers. + */ + @Test + public void testRetention0WithEmptyLedger() throws Exception { + ManagedLedgerFactory factory = new ManagedLedgerFactoryImpl(bkc, bkc.getZkHandle()); + ManagedLedgerConfig config = new ManagedLedgerConfig(); + config.setRetentionTime(0, TimeUnit.MINUTES); + config.setMaxEntriesPerLedger(1); + + ManagedLedgerImpl ml = (ManagedLedgerImpl) factory.open("deletion_after_retention_test_ledger", config); + ManagedCursor c1 = ml.openCursor("c1noretention"); + ml.addEntry("message1".getBytes()); + c1.skipEntries(1, IndividualDeletedEntries.Exclude); + ml.close(); + + // reopen ml + ml = (ManagedLedgerImpl) factory.open("deletion_after_retention_test_ledger", config); + c1 = ml.openCursor("c1noretention"); + ml.deleteCursor(c1.getName()); + ml.internalTrimConsumedLedgers(CompletableFuture.completedFuture(null)); + + assertTrue(ml.getFirstPosition().ledgerId <= ml.lastConfirmedEntry.ledgerId); + ml.close(); + } + @Test public void testInfiniteRetention() throws Exception { ManagedLedgerFactory factory = new ManagedLedgerFactoryImpl(bkc, bkc.getZkHandle());