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 28808f9f720fb913603773a0f0e53640013de9a4..249fe0f0eec5964edc25913355c4173a9fb0d128 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; @@ -2763,7 +2764,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 baaa6f6316e7e89f9a2ed7703b2c53dac8eefd3a..c6ee9e9e46137aa1cbf2d7cb43a743d0a6fca156 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 @@ -1692,6 +1692,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());