use of org.apache.bookkeeper.client.api.LedgerEntries 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