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;
}
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);
}
}
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);
}
}
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);
}
}
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;
}
}
Aggregations