@Override public void asyncClearBacklog(final ClearBacklogCallback callback, Object ctx) { asyncMarkDelete(ledger.getLastPosition(), new MarkDeleteCallback() { @Override public void markDeleteComplete(Object ctx) { callback.clearBacklogComplete(ctx); } @Override public void markDeleteFailed(ManagedLedgerException exception, Object ctx) { if (exception.getCause() instanceof IllegalArgumentException) { // There could be a race condition between calling clear backlog and other mark delete operations. // If we get an exception it means the backlog was already cleared in the meantime. callback.clearBacklogComplete(ctx); } else { callback.clearBacklogFailed(exception, ctx); } } }, ctx); }
/** * Get the first position written in the managed ledger, alongside with the associated counter */ Pair<PositionImpl, Long> getFirstPositionAndCounter() { PositionImpl pos; long count; Pair<PositionImpl, Long> lastPositionAndCounter; do { pos = getFirstPosition(); lastPositionAndCounter = getLastPositionAndCounter(); count = lastPositionAndCounter.getRight() - getNumberOfEntries(Range.openClosed(pos, lastPositionAndCounter.getLeft())); } while (pos.compareTo(getFirstPosition()) != 0 || lastPositionAndCounter.getLeft().compareTo(getLastPosition()) != 0); return Pair.of(pos, count); }
boolean hasMoreEntries(PositionImpl position) { PositionImpl lastPositionInLedger = ledger.getLastPosition(); if (position.compareTo(lastPositionInLedger) <= 0) { return getNumberOfEntries(Range.closed(position, lastPositionInLedger)) > 0; } return false; }
@Override public long getNumberOfEntries() { if (readPosition.compareTo(ledger.getLastPosition().getNext()) > 0) { if (log.isDebugEnabled()) { log.debug("[{}] [{}] Read position {} is ahead of last position {}. There are no entries to read", ledger.getName(), name, readPosition, ledger.getLastPosition()); } return 0; } else { return getNumberOfEntries(Range.closedOpen(readPosition, ledger.getLastPosition().getNext())); } }
public ReadOnlyCursorImpl(BookKeeper bookkeeper, ManagedLedgerConfig config, ManagedLedgerImpl ledger, PositionImpl startPosition, String cursorName) { super(bookkeeper, config, ledger, cursorName); if (startPosition.equals(PositionImpl.earliest)) { readPosition = ledger.getFirstPosition().getNext(); } else { readPosition = startPosition; } if (ledger.getLastPosition().compareTo(readPosition) <= 0) { messagesConsumedCounter = 0; } else { messagesConsumedCounter = -getNumberOfEntries(Range.closed(readPosition, ledger.getLastPosition())); } this.state = State.NoLedger; }
@Override public long getNumberOfEntriesInBacklog() { if (log.isDebugEnabled()) { log.debug("[{}] Consumer {} cursor ml-entries: {} -- deleted-counter: {} other counters: mdPos {} rdPos {}", ledger.getName(), name, ManagedLedgerImpl.ENTRIES_ADDED_COUNTER_UPDATER.get(ledger), messagesConsumedCounter, markDeletePosition, readPosition); } long backlog = ManagedLedgerImpl.ENTRIES_ADDED_COUNTER_UPDATER.get(ledger) - messagesConsumedCounter; if (backlog < 0) { // In some case the counters get incorrect values, fall back to the precise backlog count backlog = getNumberOfEntries(Range.closed(markDeletePosition, ledger.getLastPosition())) - 1; } return backlog; }
public long getNumberOfEntriesInStorage() { return ledger.getNumberOfEntries(Range.openClosed(markDeletePosition, ledger.getLastPosition().getNext())); }
@Override public boolean hasMoreEntries() { // If writer and reader are on the same ledger, we just need to compare the entry id to know if we have more // entries. // If they are on different ledgers we have 2 cases : // * Writer pointing to valid entry --> should return true since we have available entries // * Writer pointing to "invalid" entry -1 (meaning no entries in that ledger) --> Need to check if the reader // is // at the last entry in the previous ledger PositionImpl writerPosition = ledger.getLastPosition(); if (writerPosition.getEntryId() != -1) { return readPosition.compareTo(writerPosition) <= 0; } else { // Fall back to checking the number of entries to ensure we are at the last entry in ledger and no ledgers // are in the middle return getNumberOfEntries() > 0; } }
private void recoveredCursor(PositionImpl position, Map<String, Long> properties, LedgerHandle recoveredFromCursorLedger) { // if the position was at a ledger that didn't exist (since it will be deleted if it was previously empty), // we need to move to the next existing ledger if (!ledger.ledgerExists(position.getLedgerId())) { Long nextExistingLedger = ledger.getNextValidLedger(position.getLedgerId()); if (nextExistingLedger == null) { log.info("[{}] [{}] Couldn't find next next valid ledger for recovery {}", ledger.getName(), name, position); } position = nextExistingLedger != null ? PositionImpl.get(nextExistingLedger, -1) : position; } if (position.compareTo(ledger.getLastPosition()) > 0) { log.warn("[{}] [{}] Current position {} is ahead of last position {}", ledger.getName(), name, position, ledger.getLastPosition()); position = PositionImpl.get(ledger.getLastPosition()); } log.info("[{}] Cursor {} recovered to position {}", ledger.getName(), name, position); messagesConsumedCounter = -getNumberOfEntries(Range.openClosed(position, ledger.getLastPosition())); markDeletePosition = position; readPosition = ledger.getNextValidPosition(position); lastMarkDeleteEntry = new MarkDeleteEntry(markDeletePosition, properties, null, null); // assign cursor-ledger so, it can be deleted when new ledger will be switched this.cursorLedger = recoveredFromCursorLedger; STATE_UPDATER.set(this, State.NoLedger); }
CompletableFuture<ManagedCursor> cursorFuture = new CompletableFuture<>(); uninitializedCursors.put(cursorName, cursorFuture); cursor.initialize(getLastPosition(), new VoidCallback() { @Override public void operationComplete() {
position = ledger.getFirstPosition(); } else if (position.equals(PositionImpl.latest)) { position = ledger.getLastPosition().getNext();
when(ml.getName()).thenReturn(mlName); when(ml.getStore()).thenReturn(mockMetaStore); when(ml.getLastPosition()).thenReturn(lastPosition); when(ml.getNextValidLedger(markDeleteLedgerId)).thenReturn(3L); when(ml.getNextValidPosition(lastPosition)).thenReturn(nextPosition);
@Override public void asyncGetNthEntry(int n, IndividualDeletedEntries deletedEntries, ReadEntryCallback callback, Object ctx) { checkArgument(n > 0); if (STATE_UPDATER.get(this) == State.Closed) { callback.readEntryFailed(new ManagedLedgerException("Cursor was already closed"), ctx); return; } PositionImpl startPosition = ledger.getNextValidPosition(markDeletePosition); PositionImpl endPosition = ledger.getLastPosition(); if (startPosition.compareTo(endPosition) <= 0) { long numOfEntries = getNumberOfEntries(Range.closed(startPosition, endPosition)); if (numOfEntries >= n) { long deletedMessages = 0; if (deletedEntries == IndividualDeletedEntries.Exclude) { deletedMessages = getNumIndividualDeletedEntriesToSkip(n); } PositionImpl positionAfterN = ledger.getPositionAfterN(markDeletePosition, n + deletedMessages, PositionBound.startExcluded); ledger.asyncReadEntry(positionAfterN, callback, ctx); } else { callback.readEntryComplete(null, ctx); } } else { callback.readEntryComplete(null, ctx); } }
@Test public void previousPosition() throws Exception { ManagedLedgerImpl ledger = (ManagedLedgerImpl) factory.open("my_test_ledger", new ManagedLedgerConfig().setMaxEntriesPerLedger(2)); ManagedCursor cursor = ledger.openCursor("my_cursor"); Position p0 = cursor.getMarkDeletedPosition(); // This is expected because p0 is already an "invalid" position (since no entry has been mark-deleted yet) assertEquals(ledger.getPreviousPosition((PositionImpl) p0), p0); // Force to close an empty ledger ledger.close(); ledger = (ManagedLedgerImpl) factory.open("my_test_ledger", new ManagedLedgerConfig().setMaxEntriesPerLedger(2)); // again ledger.close(); ledger = (ManagedLedgerImpl) factory.open("my_test_ledger", new ManagedLedgerConfig().setMaxEntriesPerLedger(2)); PositionImpl pBeforeWriting = ledger.getLastPosition(); PositionImpl p1 = (PositionImpl) ledger.addEntry("entry".getBytes()); ledger.close(); ledger = (ManagedLedgerImpl) factory.open("my_test_ledger", new ManagedLedgerConfig().setMaxEntriesPerLedger(2)); Position p2 = ledger.addEntry("entry".getBytes()); Position p3 = ledger.addEntry("entry".getBytes()); Position p4 = ledger.addEntry("entry".getBytes()); assertEquals(ledger.getPreviousPosition(p1), pBeforeWriting); assertEquals(ledger.getPreviousPosition((PositionImpl) p2), p1); assertEquals(ledger.getPreviousPosition((PositionImpl) p3), p2); assertEquals(ledger.getPreviousPosition((PositionImpl) p4), p3); }
boolean hasMoreEntries(PositionImpl position) { PositionImpl lastPositionInLedger = ledger.getLastPosition(); if (position.compareTo(lastPositionInLedger) <= 0) { return getNumberOfEntries(Range.closed(position, lastPositionInLedger)) > 0; } return false; }
boolean hasMoreEntries(PositionImpl position) { PositionImpl lastPositionInLedger = ledger.getLastPosition(); if (position.compareTo(lastPositionInLedger) <= 0) { return getNumberOfEntries(Range.closed(position, lastPositionInLedger)) > 0; } return false; }
@Override public long getNumberOfEntries() { if (readPosition.compareTo(ledger.getLastPosition().getNext()) > 0) { if (log.isDebugEnabled()) { log.debug("[{}] [{}] Read position {} is ahead of last position {}. There are no entries to read", ledger.getName(), name, readPosition, ledger.getLastPosition()); } return 0; } else { return getNumberOfEntries(Range.closedOpen(readPosition, ledger.getLastPosition().getNext())); } }
public long getNumberOfEntriesInStorage() { return ledger.getNumberOfEntries(Range.openClosed(markDeletePosition, ledger.getLastPosition().getNext())); }
@Override public long getNumberOfEntries() { return getNumberOfEntries(Range.closedOpen(readPosition, ledger.getLastPosition().getNext())); }
private void recoveredCursor(PositionImpl position) { // if the position was at a ledger that didn't exist (since it will be deleted if it was previously empty), // we need to move to the next existing ledger if (!ledger.ledgerExists(position.getLedgerId())) { long nextExistingLedger = ledger.getNextValidLedger(position.getLedgerId()); position = PositionImpl.get(nextExistingLedger, -1); } log.info("[{}] Cursor {} recovered to position {}", ledger.getName(), name, position); messagesConsumedCounter = -getNumberOfEntries(Range.openClosed(position, ledger.getLastPosition())); markDeletePosition = position; readPosition = ledger.getNextValidPosition(position); STATE_UPDATER.set(this, State.NoLedger); }