/** * Reliably retrieves the LastAddConfirmed for the Ledger with given LedgerId, by opening the Ledger in fencing mode * and getting the value. NOTE: this open-fences the Ledger which will effectively stop any writing action on it. * * @param ledgerId The Id of the Ledger to query. * @param bookKeeper A references to the BookKeeper client to use. * @param config Configuration to use. * @return The LastAddConfirmed for the given LedgerId. * @throws DurableDataLogException If an exception occurred. The causing exception is wrapped inside it. */ static long readLastAddConfirmed(long ledgerId, BookKeeper bookKeeper, BookKeeperConfig config) throws DurableDataLogException { LedgerHandle h = null; try { // Here we open the Ledger WITH recovery, to force BookKeeper to reconcile any appends that may have been // interrupted and not properly acked. Otherwise there is no guarantee we can get an accurate value for // LastAddConfirmed. h = openFence(ledgerId, bookKeeper, config); return h.getLastAddConfirmed(); } finally { if (h != null) { close(h); } } }
/** * Opens a ledger for reading purposes (does not fence it). * * @param ledgerMetadata LedgerMetadata for the ledger to open. * @return A BookKeeper LedgerHandle representing the ledger. * @throws DurableDataLogException If an exception occurred. */ public LedgerHandle openLedgerNoFencing(LedgerMetadata ledgerMetadata) throws DurableDataLogException { return Ledgers.openRead(ledgerMetadata.getLedgerId(), this.bkClient, this.config); }
ledger = Ledgers.openRead(metadata.getLedgerId(), this.bookKeeper, this.config); } else { ledger = Ledgers.openFence(metadata.getLedgerId(), this.bookKeeper, this.config); if (lastEntryId < address.getEntryId()) { Ledgers.close(ledger); this.currentLedger = new ReadLedger(metadata, ledger, null); return; if (previousLedger != null) { Ledgers.close(previousLedger.handle); Ledgers.close(ledger); close(); throw new DurableDataLogException("Error while reading from BookKeeper.", ex);
val emptyLedgerIds = Ledgers.fenceOut(oldMetadata.getLedgers(), this.bookKeeper, this.config, this.traceObjectId); LedgerHandle newLedger = Ledgers.create(this.bookKeeper, this.config); log.info("{}: Created Ledger {}.", this.traceObjectId, newLedger.getId()); Ledgers.delete(id, this.bookKeeper); log.info("{}: Deleted orphan empty ledger {}.", this.traceObjectId, id); } catch (DurableDataLogException ex) {
if (shouldExist.test(i)) { Ledgers.openFence(e.getKey(), this.factory.get().getBookKeeperClient(), this.config.get()); } else { AssertExtensions.assertThrows( "Ledger not deleted from BookKeeper.", () -> Ledgers.openFence(e.getKey(), this.factory.get().getBookKeeperClient(), this.config.get()), ex -> true);
LedgerHandle newLedger = Ledgers.create(this.bookKeeper, this.config); log.debug("{}: Rollover: created new ledger {}.", this.traceObjectId, newLedger.getId()); Ledgers.close(oldLedger); log.info("{}: Rollover: swapped ledger and metadata pointers (Old = {}, New = {}) and closed old ledger.", this.traceObjectId, oldLedger.getId(), newLedger.getId());
@Override public void close() { if (!this.closed.getAndSet(true)) { if (this.currentLedger != null) { try { Ledgers.close(this.currentLedger.handle); } catch (DurableDataLogException bkEx) { log.error("Unable to close LedgerHandle for Ledger {}.", this.currentLedger.handle.getId(), bkEx); } this.currentLedger = null; } } }
val lm = ledgersToDelete.next(); try { Ledgers.delete(lm.getLedgerId(), this.bookKeeper); } catch (DurableDataLogException ex) {
/** * Reliably gets the LastAddConfirmed for the WriteLedger * * @param writeLedger The WriteLedger to query. * @param lastAddsConfirmed A Map of LedgerIds to LastAddConfirmed for each known ledger id. This is used as a cache * and will be updated if necessary. * @return The LastAddConfirmed for the WriteLedger. */ @SneakyThrows(DurableDataLogException.class) private long fetchLastAddConfirmed(WriteLedger writeLedger, Map<Long, Long> lastAddsConfirmed) { long ledgerId = writeLedger.ledger.getId(); long lac = lastAddsConfirmed.getOrDefault(ledgerId, -1L); long traceId = LoggerHelpers.traceEnterWithContext(log, this.traceObjectId, "fetchLastAddConfirmed", ledgerId, lac); if (lac < 0) { if (writeLedger.isRolledOver()) { // This close was not due to failure, rather a rollover - hence lastAddConfirmed can be relied upon. lac = writeLedger.ledger.getLastAddConfirmed(); } else { // Ledger got closed. This could be due to some external factor, and lastAddConfirmed can't be relied upon. // We need to re-open the ledger to get fresh data. lac = Ledgers.readLastAddConfirmed(ledgerId, this.bookKeeper, this.config); } lastAddsConfirmed.put(ledgerId, lac); log.info("{}: Fetched actual LastAddConfirmed ({}) for LedgerId {}.", this.traceObjectId, lac, ledgerId); } LoggerHelpers.traceLeave(log, this.traceObjectId, "fetchLastAddConfirmed", traceId, ledgerId, lac); return lac; }
@Override public void close() { if (!this.closed.getAndSet(true)) { this.metricReporter.cancel(true); this.metrics.close(); this.rolloverProcessor.close(); this.writeProcessor.close(); // Close active ledger. WriteLedger writeLedger; synchronized (this.lock) { writeLedger = this.writeLedger; this.writeLedger = null; this.logMetadata = null; } // Close the write queue and cancel the pending writes. this.writes.close().forEach(w -> w.fail(new CancellationException("BookKeeperLog has been closed."), true)); if (writeLedger != null) { try { Ledgers.close(writeLedger.ledger); } catch (DurableDataLogException bkEx) { log.error("{}: Unable to close LedgerHandle for Ledger {}.", this.traceObjectId, writeLedger.ledger.getId(), bkEx); } } log.info("{}: Closed.", this.traceObjectId); } }
} catch (DurableDataLogException ex) { try { Ledgers.delete(newLedger.getId(), this.bookKeeper); } catch (Exception deleteEx) { log.warn("{}: Unable to delete newly created ledger {}.", this.traceObjectId, newLedger.getId(), deleteEx);
while (iterator.hasPrevious() && (nonEmptyCount < MIN_FENCE_LEDGER_COUNT)) { LedgerMetadata ledgerMetadata = iterator.previous(); LedgerHandle handle = openFence(ledgerMetadata.getLedgerId(), bookKeeper, config); if (handle.getLastAddConfirmed() != NO_ENTRY_ID) { close(handle); log.info("{}: Fenced out Ledger {}.", traceObjectId, ledgerMetadata);
@Override public DurableDataLog.ReadItem getNext() throws DurableDataLogException { Exceptions.checkNotClosed(this.closed.get(), this); if (this.currentLedger == null) { // First time we call this. Locate the first ledger based on the metadata truncation address. We don't know // how many entries are in that first ledger, so open it anyway so we can figure out. openNextLedger(this.metadata.getNextAddress(this.metadata.getTruncationAddress(), Long.MAX_VALUE)); } while (this.currentLedger != null && (!this.currentLedger.canRead())) { // We have reached the end of the current ledger. Find next one, and skip over empty ledgers). val lastAddress = new LedgerAddress(this.currentLedger.metadata, this.currentLedger.handle.getLastAddConfirmed()); Ledgers.close(this.currentLedger.handle); openNextLedger(this.metadata.getNextAddress(lastAddress, this.currentLedger.handle.getLastAddConfirmed())); } // Try to read from the current reader. if (this.currentLedger == null || this.currentLedger.reader == null) { return null; } return new LogReader.ReadItem(this.currentLedger.reader.nextElement(), this.currentLedger.metadata); }