Search in sources :

Example 6 with ReadHandle

use of org.apache.bookkeeper.client.api.ReadHandle in project pravega by pravega.

the class Ledgers method fenceOut.

/**
 * Fences out a Log made up of the given ledgers.
 *
 * @param ledgers       An ordered list of LedgerMetadata objects representing all the Ledgers in the log.
 * @param bookKeeper    A reference to the BookKeeper client to use.
 * @param config        Configuration to use.
 * @param traceObjectId Used for logging.
 * @return A Map of LedgerId to LastAddConfirmed for those Ledgers that were fenced out and had a different
 * LastAddConfirmed than what their LedgerMetadata was indicating.
 * @throws DurableDataLogException If an exception occurred. The causing exception is wrapped inside it.
 */
static Map<Long, Long> fenceOut(List<LedgerMetadata> ledgers, BookKeeper bookKeeper, BookKeeperConfig config, String traceObjectId) throws DurableDataLogException {
    // Fence out the ledgers, in descending order. During the process, we need to determine whether the ledgers we
    // fenced out actually have any data in them, and update the LedgerMetadata accordingly.
    // We need to fence out at least MIN_FENCE_LEDGER_COUNT ledgers that are not empty to properly ensure we fenced
    // the log correctly and identify any empty ledgers (Since this algorithm is executed upon every recovery, any
    // empty ledgers should be towards the end of the Log).
    int nonEmptyCount = 0;
    val result = new HashMap<Long, Long>();
    val iterator = ledgers.listIterator(ledgers.size());
    while (iterator.hasPrevious() && (nonEmptyCount < MIN_FENCE_LEDGER_COUNT)) {
        LedgerMetadata ledgerMetadata = iterator.previous();
        ReadHandle handle;
        try {
            handle = openFence(ledgerMetadata.getLedgerId(), bookKeeper, config);
        } catch (DurableDataLogException ex) {
            val c = ex.getCause();
            if (ledgerMetadata.getStatus() == LedgerMetadata.Status.Empty && (c instanceof BKException.BKNoSuchLedgerExistsOnMetadataServerException || c instanceof BKException.BKNoSuchLedgerExistsException)) {
                log.warn("{}: Unable to open-fence EMPTY ledger {}. Skipping.", traceObjectId, ledgerMetadata, ex);
                continue;
            }
            throw ex;
        }
        if (handle.getLastAddConfirmed() != NO_ENTRY_ID) {
            // Non-empty.
            nonEmptyCount++;
        }
        if (ledgerMetadata.getStatus() == LedgerMetadata.Status.Unknown) {
            // We did not know the status of this Ledger before, but now we do.
            result.put(ledgerMetadata.getLedgerId(), handle.getLastAddConfirmed());
        }
        close(handle);
        log.info("{}: Fenced out Ledger {}.", traceObjectId, ledgerMetadata);
    }
    return result;
}
Also used : lombok.val(lombok.val) ReadHandle(org.apache.bookkeeper.client.api.ReadHandle) DurableDataLogException(io.pravega.segmentstore.storage.DurableDataLogException) HashMap(java.util.HashMap)

Example 7 with ReadHandle

use of org.apache.bookkeeper.client.api.ReadHandle in project pravega by pravega.

the class LogReader method openNextLedger.

private void openNextLedger(LedgerAddress address) throws DurableDataLogException {
    if (address == null) {
        // We have reached the end.
        close();
        return;
    }
    LedgerMetadata metadata = this.metadata.getLedger(address.getLedgerId());
    assert metadata != null : "no LedgerMetadata could be found with valid LedgerAddress " + address;
    val allMetadatas = this.metadata.getLedgers();
    // Open the ledger.
    ReadHandle ledger;
    if (allMetadatas.size() == 0 || metadata == allMetadatas.get(allMetadatas.size() - 1)) {
        // This is our last ledger (the active one); we need to make sure open it without recovery since otherwise we
        // we would fence ourselves out.
        ledger = Ledgers.openRead(metadata.getLedgerId(), this.bookKeeper, this.config);
    } else {
        // Older ledger. Open with recovery to make sure any uncommitted fragments will be recovered. Since we do our
        // Log fencing based on the last Ledger, open-fencing this Ledger will not have any adverse effects.
        ledger = Ledgers.openFence(metadata.getLedgerId(), this.bookKeeper, this.config);
    }
    checkLogIdProperty(ledger);
    long lastEntryId = ledger.getLastAddConfirmed();
    if (lastEntryId < address.getEntryId()) {
        // This ledger is empty.
        Ledgers.close(ledger);
        this.currentLedger = ReadLedger.empty(metadata, ledger);
        return;
    }
    ReadLedger previousLedger;
    try {
        previousLedger = this.currentLedger;
        this.currentLedger = new ReadLedger(metadata, ledger, address.getEntryId(), lastEntryId, this.config.getBkReadBatchSize());
        if (previousLedger != null) {
            // Close previous ledger handle.
            previousLedger.close();
        }
    } catch (Exception ex) {
        Ledgers.close(ledger);
        close();
        throw new DurableDataLogException("Error while reading from BookKeeper.", ex);
    }
}
Also used : lombok.val(lombok.val) ReadHandle(org.apache.bookkeeper.client.api.ReadHandle) DurableDataLogException(io.pravega.segmentstore.storage.DurableDataLogException) BKException(org.apache.bookkeeper.client.api.BKException) DataLogCorruptedException(io.pravega.segmentstore.storage.DataLogCorruptedException) DurableDataLogException(io.pravega.segmentstore.storage.DurableDataLogException)

Example 8 with ReadHandle

use of org.apache.bookkeeper.client.api.ReadHandle in project pravega by pravega.

the class BookKeeperListAllLedgersCommand method execute.

@Override
public void execute() throws Exception {
    ensureArgCount(0);
    @Cleanup val context = createContext();
    ClientConfiguration config = new ClientConfiguration().setMetadataServiceUri("zk://" + this.getServiceConfig().getZkURL() + context.bookKeeperConfig.getBkLedgerPath());
    @Cleanup BookKeeper bkClient = BookKeeper.forConfig(config).build();
    @Cleanup LedgerManager manager = bkClient.getLedgerManager();
    LedgerManager.LedgerRangeIterator ledgerRangeIterator = manager.getLedgerRanges(Long.MAX_VALUE);
    List<ReadHandle> candidateLedgers = new ArrayList<>();
    try {
        while (ledgerRangeIterator.hasNext()) {
            LedgerManager.LedgerRange lr = ledgerRangeIterator.next();
            for (long ledgerId : lr.getLedgers()) {
                candidateLedgers.add(Ledgers.openRead(ledgerId, bkClient, context.bookKeeperConfig));
            }
        }
        // Output all the ledgers found.
        output("List of ledgers in the system: ");
        for (ReadHandle rh : candidateLedgers) {
            output("%s, length: %d, lastEntryConfirmed: %d, ledgerMetadata: %s, bookieLogID: %d", rh.toString(), rh.getLength(), rh.readLastAddConfirmed(), rh.getLedgerMetadata().toSafeString(), Ledgers.getBookKeeperLogId(rh));
        }
    } finally {
        // Closing opened ledgers.
        closeBookkeeperReadHandles(candidateLedgers);
    }
}
Also used : lombok.val(lombok.val) ReadHandle(org.apache.bookkeeper.client.api.ReadHandle) LedgerManager(org.apache.bookkeeper.meta.LedgerManager) ArrayList(java.util.ArrayList) BookKeeper(org.apache.bookkeeper.client.BookKeeper) Cleanup(lombok.Cleanup) ClientConfiguration(org.apache.bookkeeper.conf.ClientConfiguration)

Example 9 with ReadHandle

use of org.apache.bookkeeper.client.api.ReadHandle in project herddb by diennea.

the class BookKeeperDataStorageManager method readPage.

@Override
public List<Record> readPage(String tableSpace, String tableName, Long pageId) throws DataStorageManagerException {
    long _start = System.currentTimeMillis();
    TableSpacePagesMapping tableSpacePagesMapping = getTableSpacePagesMapping(tableSpace);
    Long ledgerId = tableSpacePagesMapping.getTablePagesMapping(tableName).getLedgerIdForPage(pageId);
    if (ledgerId == null) {
        throw new DataPageDoesNotExistException("No such page: " + tableSpace + "_" + tableName + "." + pageId);
    }
    byte[] data;
    try (ReadHandle read = FutureUtils.result(bk.getBookKeeper().newOpenLedgerOp().withLedgerId(ledgerId).withPassword(EMPTY_ARRAY).execute(), BKException.HANDLER)) {
        try (LedgerEntries entries = read.readUnconfirmed(0, 0)) {
            data = entries.getEntry(0).getEntryBytes();
        }
        List<Record> result = rawReadDataPage(data);
        long _stop = System.currentTimeMillis();
        long delta = _stop - _start;
        LOGGER.log(Level.FINE, "readPage {0}.{1} {2} ms", new Object[] { tableSpace, tableName, delta + "" });
        dataPageReads.registerSuccessfulEvent(delta, TimeUnit.MILLISECONDS);
        return result;
    } catch (BKException.BKNoSuchLedgerExistsException err) {
        throw new DataStorageManagerException(err);
    } catch (BKException.BKNoSuchLedgerExistsOnMetadataServerException err) {
        throw new DataStorageManagerException(err);
    } catch (org.apache.bookkeeper.client.api.BKException err) {
        throw new DataStorageManagerException(err);
    } catch (IOException err) {
        throw new DataStorageManagerException(err);
    } catch (InterruptedException err) {
        Thread.currentThread().interrupt();
        throw new DataStorageManagerException(err);
    }
}
Also used : DataStorageManagerException(herddb.storage.DataStorageManagerException) IOException(java.io.IOException) DataPageDoesNotExistException(herddb.storage.DataPageDoesNotExistException) ReadHandle(org.apache.bookkeeper.client.api.ReadHandle) LedgerEntries(org.apache.bookkeeper.client.api.LedgerEntries) BKNoSuchLedgerExistsOnMetadataServerException(org.apache.bookkeeper.client.BKException.BKNoSuchLedgerExistsOnMetadataServerException) Record(herddb.model.Record) BKException(org.apache.bookkeeper.client.BKException)

Example 10 with ReadHandle

use of org.apache.bookkeeper.client.api.ReadHandle in project herddb by diennea.

the class BookkeeperCommitLog method recovery.

@Override
public void recovery(LogSequenceNumber snapshotSequenceNumber, BiConsumer<LogSequenceNumber, LogEntry> consumer, boolean fencing) throws LogNotAvailableException {
    String tableSpaceDescription = tableSpaceDescription();
    this.actualLedgersList = metadataManager.getActualLedgersList(tableSpaceUUID);
    LOGGER.log(Level.INFO, "Actual ledgers list:{0} tableSpace {1}", new Object[] { actualLedgersList, tableSpaceDescription });
    this.lastLedgerId = snapshotSequenceNumber.ledgerId;
    this.currentLedgerId = snapshotSequenceNumber.ledgerId;
    this.lastSequenceNumber.set(snapshotSequenceNumber.offset);
    LOGGER.log(Level.INFO, "recovery from latest snapshotSequenceNumber:{0} tableSpace {1}, node {2}, fencing {3}", new Object[] { snapshotSequenceNumber, tableSpaceDescription, localNodeId, fencing });
    if (!isRecoveryAvailable(snapshotSequenceNumber, actualLedgersList, tableSpaceDescription)) {
        throw new FullRecoveryNeededException("Cannot recover from BookKeeper, not enough data, plese check the logs");
    }
    for (long ledgerId : actualLedgersList.getActiveLedgers()) {
        try {
            Versioned<LedgerMetadata> result = FutureUtils.result(bookKeeper.getLedgerManager().readLedgerMetadata(ledgerId));
            LedgerMetadata metadata = result.getValue();
            String ledgerLeader = extractLeaderFromMetadata(metadata.getCustomMetadata());
            LOGGER.log(Level.INFO, "Ledger {0}: {1} {2} created by {3}, LastEntryId {4} Length {5}", new Object[] { String.valueOf(ledgerId), metadata.getState(), metadata.getAllEnsembles(), ledgerLeader, metadata.getLastEntryId(), metadata.getLength() });
        } catch (BKException.BKNoSuchLedgerExistsException | BKException.BKNoSuchLedgerExistsOnMetadataServerException e) {
            if (ledgerId < snapshotSequenceNumber.ledgerId) {
                LOGGER.log(Level.INFO, "Actual ledgers list includes a not existing ledgerid:" + ledgerId + " tablespace " + tableSpaceDescription + ", but this ledger is not useful for recovery (snapshotSequenceNumber.ledgerId is " + snapshotSequenceNumber.ledgerId);
            } else {
                throw new FullRecoveryNeededException(new Exception("Actual ledgers list includes a not existing ledgerid:" + ledgerId + " tablespace " + tableSpaceDescription));
            }
        } catch (LogNotAvailableException e) {
            throw e;
        } catch (Exception e) {
            throw new LogNotAvailableException(e);
        }
    }
    try {
        for (long ledgerId : actualLedgersList.getActiveLedgers()) {
            if (ledgerId < snapshotSequenceNumber.ledgerId) {
                LOGGER.log(Level.FINER, "Skipping ledger {0}", ledgerId);
                continue;
            }
            ReadHandle handle;
            try {
                if (fencing) {
                    handle = bookKeeper.openLedger(ledgerId, BookKeeper.DigestType.CRC32C, SHARED_SECRET.getBytes(StandardCharsets.UTF_8));
                } else {
                    handle = bookKeeper.openLedgerNoRecovery(ledgerId, BookKeeper.DigestType.CRC32C, SHARED_SECRET.getBytes(StandardCharsets.UTF_8));
                }
            } catch (org.apache.bookkeeper.client.api.BKException errorDuringOpen) {
                throw new LogNotAvailableException("Cannot open ledger " + ledgerId + " (fencing " + fencing + "): " + errorDuringOpen, errorDuringOpen);
            }
            try {
                long first;
                if (ledgerId == snapshotSequenceNumber.ledgerId) {
                    first = snapshotSequenceNumber.offset;
                    if (first == -1) {
                        // this can happen if checkpoint  happened while starting to follow a new ledger but actually no entry was ever read
                        LOGGER.log(Level.INFO, "Tablespace " + tableSpaceDescription + ", recovering from latest snapshot ledger " + ledgerId + ", first entry " + first + " is not valid. Adjusting to 0");
                        first = 0;
                    }
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.log(Level.FINE, "Tablespace " + tableSpaceDescription + ", recovering from latest snapshot ledger " + ledgerId + ", starting from entry " + first);
                    }
                } else {
                    first = 0;
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.log(Level.FINE, "Tablespace " + tableSpaceDescription + ", recovering from ledger " + ledgerId + ", starting from entry " + first);
                    }
                }
                long lastAddConfirmed = handle.getLastAddConfirmed();
                String ledgerLeader = extractLeaderFromMetadata(handle.getLedgerMetadata().getCustomMetadata());
                LOGGER.log(Level.INFO, "Tablespace " + tableSpaceDescription + ", Recovering from ledger " + ledgerId + ", first=" + first + " lastAddConfirmed=" + lastAddConfirmed + " written by " + ledgerLeader);
                if (lastAddConfirmed >= 0) {
                    for (long b = first; b <= lastAddConfirmed; ) {
                        long start = b;
                        long end = b + RECOVERY_BATCH_SIZE;
                        if (end > lastAddConfirmed) {
                            end = lastAddConfirmed;
                        }
                        b = end + 1;
                        double percent = ((start - first) * 100.0 / (lastAddConfirmed + 1));
                        int entriesToRead = (int) (1 + end - start);
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.log(Level.FINE, "{3} From entry {0}, to entry {1} ({2} %)", new Object[] { start, end, percent, tableSpaceDescription });
                        }
                        long _start = System.currentTimeMillis();
                        int localEntryCount = 0;
                        try (LedgerEntries entries = handle.read(start, end)) {
                            for (org.apache.bookkeeper.client.api.LedgerEntry entry : entries) {
                                long entryId = entry.getEntryId();
                                LogSequenceNumber number = new LogSequenceNumber(ledgerId, entryId);
                                LogEntry statusEdit = readLogEntry(entry);
                                lastLedgerId = ledgerId;
                                currentLedgerId = ledgerId;
                                lastSequenceNumber.set(entryId);
                                if (number.after(snapshotSequenceNumber)) {
                                    if (LOGGER.isLoggable(Level.FINEST)) {
                                        LOGGER.log(Level.FINEST, "rec " + tableSpaceName + " #" + localEntryCount + " {0}, {1}", new Object[] { number, statusEdit });
                                    }
                                    consumer.accept(number, statusEdit);
                                } else {
                                    if (LOGGER.isLoggable(Level.FINEST)) {
                                        LOGGER.log(Level.FINEST, "skip " + tableSpaceName + " #" + localEntryCount + " {0}<{1}, {2}", new Object[] { number, snapshotSequenceNumber, statusEdit });
                                    }
                                }
                                localEntryCount++;
                            }
                        }
                        LOGGER.log(Level.FINER, tableSpaceDescription() + " read " + localEntryCount + " entries from ledger " + ledgerId + ", expected " + entriesToRead);
                        if (localEntryCount != entriesToRead) {
                            throw new LogNotAvailableException(tableSpaceDescription() + " Read " + localEntryCount + " entries, expected " + entriesToRead);
                        }
                        lastLedgerId = ledgerId;
                        lastSequenceNumber.set(end);
                        long _stop = System.currentTimeMillis();
                        LOGGER.log(Level.INFO, "{4} From entry {0}, to entry {1} ({2} %) read time {3}", new Object[] { start, end, percent, (_stop - _start) + " ms", tableSpaceDescription });
                    }
                }
            } catch (RuntimeException err) {
                LOGGER.log(Level.SEVERE, "Internal error while recovering tablespace " + tableSpaceDescription() + ": " + err, err);
                throw err;
            } finally {
                handle.close();
            }
        }
        LOGGER.log(Level.INFO, "After recovery of {0} lastSequenceNumber {1}", new Object[] { tableSpaceDescription, getLastSequenceNumber() });
    } catch (IOException | InterruptedException | org.apache.bookkeeper.client.api.BKException err) {
        LOGGER.log(Level.SEVERE, "Fatal error during recovery of " + tableSpaceDescription(), err);
        signalLogFailed();
        throw new LogNotAvailableException(err);
    } catch (LogNotAvailableException err) {
        LOGGER.log(Level.SEVERE, "Fatal error during recovery of " + tableSpaceDescription(), err);
        signalLogFailed();
        throw err;
    }
}
Also used : ReadHandle(org.apache.bookkeeper.client.api.ReadHandle) FullRecoveryNeededException(herddb.log.FullRecoveryNeededException) LogEntry(herddb.log.LogEntry) LogSequenceNumber(herddb.log.LogSequenceNumber) IOException(java.io.IOException) BKNotEnoughBookiesException(org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException) LogNotAvailableException(herddb.log.LogNotAvailableException) IOException(java.io.IOException) CompletionException(java.util.concurrent.CompletionException) BKException(org.apache.bookkeeper.client.BKException) FullRecoveryNeededException(herddb.log.FullRecoveryNeededException) BKClientClosedException(org.apache.bookkeeper.client.BKException.BKClientClosedException) LedgerMetadata(org.apache.bookkeeper.client.api.LedgerMetadata) LedgerEntries(org.apache.bookkeeper.client.api.LedgerEntries) BKException(org.apache.bookkeeper.client.BKException) LogNotAvailableException(herddb.log.LogNotAvailableException)

Aggregations

ReadHandle (org.apache.bookkeeper.client.api.ReadHandle)10 lombok.val (lombok.val)5 LedgerEntries (org.apache.bookkeeper.client.api.LedgerEntries)5 IOException (java.io.IOException)4 BKException (org.apache.bookkeeper.client.BKException)4 DurableDataLogException (io.pravega.segmentstore.storage.DurableDataLogException)3 ArrayList (java.util.ArrayList)3 FullRecoveryNeededException (herddb.log.FullRecoveryNeededException)2 LogEntry (herddb.log.LogEntry)2 LogNotAvailableException (herddb.log.LogNotAvailableException)2 LogSequenceNumber (herddb.log.LogSequenceNumber)2 DataPageDoesNotExistException (herddb.storage.DataPageDoesNotExistException)2 DataStorageManagerException (herddb.storage.DataStorageManagerException)2 CompletionException (java.util.concurrent.CompletionException)2 Cleanup (lombok.Cleanup)2 ClientConfiguration (org.apache.bookkeeper.conf.ClientConfiguration)2 Preconditions (com.google.common.base.Preconditions)1 Record (herddb.model.Record)1 CloseableIterator (io.pravega.common.util.CloseableIterator)1 CompositeArrayView (io.pravega.common.util.CompositeArrayView)1