use of org.apache.distributedlog.exceptions.DLIllegalStateException in project bookkeeper by apache.
the class DistributedLogAdmin method fixInprogressSegmentWithLowerSequenceNumber.
/**
* Fix inprogress segment with lower ledger sequence number.
*
* @param namespace
* dl namespace
* @param metadataUpdater
* metadata updater.
* @param streamName
* stream name.
* @param verbose
* print verbose messages.
* @param interactive
* is confirmation needed before executing actual action.
* @throws IOException
*/
public static void fixInprogressSegmentWithLowerSequenceNumber(final Namespace namespace, final MetadataUpdater metadataUpdater, final String streamName, final boolean verbose, final boolean interactive) throws Exception {
DistributedLogManager dlm = namespace.openLog(streamName);
try {
List<LogSegmentMetadata> segments = dlm.getLogSegments();
if (verbose) {
System.out.println("LogSegments for " + streamName + " : ");
for (LogSegmentMetadata segment : segments) {
System.out.println(segment.getLogSegmentSequenceNumber() + "\t: " + segment);
}
}
LOG.info("Get log segments for {} : {}", streamName, segments);
// validate log segments
long maxCompletedLogSegmentSequenceNumber = -1L;
LogSegmentMetadata inprogressSegment = null;
for (LogSegmentMetadata segment : segments) {
if (!segment.isInProgress()) {
maxCompletedLogSegmentSequenceNumber = Math.max(maxCompletedLogSegmentSequenceNumber, segment.getLogSegmentSequenceNumber());
} else {
// we already found an inprogress segment
if (null != inprogressSegment) {
throw new DLIllegalStateException("Multiple inprogress segments found for stream " + streamName + " : " + segments);
}
inprogressSegment = segment;
}
}
if (null == inprogressSegment || inprogressSegment.getLogSegmentSequenceNumber() > maxCompletedLogSegmentSequenceNumber) {
// nothing to fix
return;
}
final long newLogSegmentSequenceNumber = maxCompletedLogSegmentSequenceNumber + 1;
if (interactive && !IOUtils.confirmPrompt("Confirm to fix (Y/N), Ctrl+C to break : ")) {
return;
}
final LogSegmentMetadata newSegment = FutureUtils.result(metadataUpdater.changeSequenceNumber(inprogressSegment, newLogSegmentSequenceNumber));
LOG.info("Fixed {} : {} -> {} ", new Object[] { streamName, inprogressSegment, newSegment });
if (verbose) {
System.out.println("Fixed " + streamName + " : " + inprogressSegment.getZNodeName() + " -> " + newSegment.getZNodeName());
System.out.println("\t old: " + inprogressSegment);
System.out.println("\t new: " + newSegment);
System.out.println();
}
} finally {
dlm.close();
}
}
use of org.apache.distributedlog.exceptions.DLIllegalStateException in project bookkeeper by apache.
the class BKLogWriteHandler method doCompleteAndCloseLogSegmentAfterLogSegmentListFetched.
private void doCompleteAndCloseLogSegmentAfterLogSegmentListFetched(final String inprogressZnodeName, long logSegmentSeqNo, long logSegmentId, long firstTxId, long lastTxId, int recordCount, long lastEntryId, long lastSlotId, final CompletableFuture<LogSegmentMetadata> promise) {
try {
lock.checkOwnershipAndReacquire();
} catch (IOException ioe) {
FutureUtils.completeExceptionally(promise, ioe);
return;
}
LOG.debug("Completing and Closing Log Segment {} {}", firstTxId, lastTxId);
LogSegmentMetadata inprogressLogSegment = readLogSegmentFromCache(inprogressZnodeName);
// validate log segment
if (inprogressLogSegment.getLogSegmentId() != logSegmentId) {
FutureUtils.completeExceptionally(promise, new IOException("Active ledger has different ID to inprogress. " + inprogressLogSegment.getLogSegmentId() + " found, " + logSegmentId + " expected"));
return;
}
// validate the transaction id
if (inprogressLogSegment.getFirstTxId() != firstTxId) {
FutureUtils.completeExceptionally(promise, new IOException("Transaction id not as expected, " + inprogressLogSegment.getFirstTxId() + " found, " + firstTxId + " expected"));
return;
}
// validate the log sequence number
if (validateLogSegmentSequenceNumber) {
synchronized (inprogressLSSNs) {
if (inprogressLSSNs.isEmpty()) {
FutureUtils.completeExceptionally(promise, new UnexpectedException("Didn't find matched inprogress log segments when completing inprogress " + inprogressLogSegment));
return;
}
long leastInprogressLSSN = inprogressLSSNs.getFirst();
// tracked in {@link inprogressLSSNs}
if ((inprogressLogSegment.getLogSegmentSequenceNumber() != logSegmentSeqNo) || (leastInprogressLSSN != logSegmentSeqNo)) {
FutureUtils.completeExceptionally(promise, new UnexpectedException("Didn't find matched inprogress log segments when completing inprogress " + inprogressLogSegment));
return;
}
}
}
// store max sequence number.
long maxSeqNo = Math.max(logSegmentSeqNo, maxLogSegmentSequenceNo.getSequenceNumber());
if (maxLogSegmentSequenceNo.getSequenceNumber() == logSegmentSeqNo || (maxLogSegmentSequenceNo.getSequenceNumber() == logSegmentSeqNo + 1)) {
// ignore the case that a new inprogress log segment is pre-allocated
// before completing current inprogress one
LOG.info("Try storing max sequence number {} in completing {}.", new Object[] { logSegmentSeqNo, inprogressLogSegment.getZkPath() });
} else {
LOG.warn("Unexpected max ledger sequence number {} found while completing log segment {} for {}", new Object[] { maxLogSegmentSequenceNo.getSequenceNumber(), logSegmentSeqNo, getFullyQualifiedName() });
if (validateLogSegmentSequenceNumber) {
FutureUtils.completeExceptionally(promise, new DLIllegalStateException("Unexpected max log segment sequence number " + maxLogSegmentSequenceNo.getSequenceNumber() + " for " + getFullyQualifiedName() + ", expected " + (logSegmentSeqNo - 1)));
return;
}
}
// Prepare the completion
final String pathForCompletedLedger = completedLedgerZNode(firstTxId, lastTxId, logSegmentSeqNo);
long startSequenceId;
try {
startSequenceId = computeStartSequenceId(inprogressLogSegment);
} catch (IOException ioe) {
FutureUtils.completeExceptionally(promise, ioe);
return;
}
// write completed ledger znode
final LogSegmentMetadata completedLogSegment = inprogressLogSegment.completeLogSegment(pathForCompletedLedger, lastTxId, recordCount, lastEntryId, lastSlotId, startSequenceId);
setLastLedgerRollingTimeMillis(completedLogSegment.getCompletionTime());
// prepare the transaction
Transaction<Object> txn = streamMetadataStore.newTransaction();
// create completed log segment
writeLogSegment(txn, completedLogSegment);
// delete inprogress log segment
deleteLogSegment(txn, inprogressLogSegment);
// store max sequence number
storeMaxSequenceNumber(txn, maxLogSegmentSequenceNo, maxSeqNo, false);
// update max txn id.
LOG.debug("Trying storing LastTxId in Finalize Path {} LastTxId {}", pathForCompletedLedger, lastTxId);
storeMaxTxId(txn, maxTxId, lastTxId);
txn.execute().whenCompleteAsync(new FutureEventListener<Void>() {
@Override
public void onSuccess(Void value) {
LOG.info("Completed {} to {} for {} : {}", new Object[] { inprogressZnodeName, completedLogSegment.getSegmentName(), getFullyQualifiedName(), completedLogSegment });
FutureUtils.complete(promise, completedLogSegment);
}
@Override
public void onFailure(Throwable cause) {
FutureUtils.completeExceptionally(promise, cause);
}
}, scheduler);
}
use of org.apache.distributedlog.exceptions.DLIllegalStateException in project bookkeeper by apache.
the class TestAsyncReaderWriter method testReadBrokenEntriesWithGapDetection.
@Test(timeout = 60000)
public void testReadBrokenEntriesWithGapDetection() throws Exception {
String name = runtime.getMethodName();
DistributedLogConfiguration confLocal = new DistributedLogConfiguration();
confLocal.loadConf(testConf);
confLocal.setOutputBufferSize(0);
confLocal.setPeriodicFlushFrequencyMilliSeconds(0);
confLocal.setImmediateFlushEnabled(true);
confLocal.setReadAheadWaitTime(10);
confLocal.setReadAheadBatchSize(1);
confLocal.setPositionGapDetectionEnabled(true);
confLocal.setReadAheadSkipBrokenEntries(true);
confLocal.setEIInjectReadAheadBrokenEntries(true);
DistributedLogManager dlm = createNewDLM(confLocal, name);
int numLogSegments = 1;
int numRecordsPerLogSegment = 100;
long txid = 1L;
txid = writeRecords(dlm, numLogSegments, numRecordsPerLogSegment, txid, false);
AsyncLogReader reader = dlm.getAsyncLogReader(DLSN.InvalidDLSN);
try {
// record in each ledger is discarded, for 30 - 3 = 27 records.
for (int i = 0; i < 30; i++) {
LogRecordWithDLSN record = Utils.ioResult(reader.readNext());
assertFalse(record.getDlsn().getEntryId() % 10 == 0);
}
fail("should have thrown");
} catch (DLIllegalStateException e) {
}
Utils.close(reader);
dlm.close();
}
use of org.apache.distributedlog.exceptions.DLIllegalStateException in project bookkeeper by apache.
the class TestZKTransaction method testAbortTransaction.
@Test(timeout = 60000)
public void testAbortTransaction() throws Exception {
ZooKeeperClient zkc = mock(ZooKeeperClient.class);
ZKTransaction transaction = new ZKTransaction(zkc);
int numOps = 3;
final CountDownLatch commitLatch = new CountDownLatch(numOps);
final CountDownLatch abortLatch = new CountDownLatch(numOps);
for (int i = 0; i < numOps; i++) {
transaction.addOp(new CountDownZKOp(commitLatch, abortLatch));
}
transaction.abort(new DLIllegalStateException("Illegal State"));
abortLatch.await();
assertEquals(0, abortLatch.getCount());
assertEquals(numOps, commitLatch.getCount());
}
use of org.apache.distributedlog.exceptions.DLIllegalStateException in project bookkeeper by apache.
the class BKLogWriteHandler method assignLogSegmentSequenceNumber.
protected long assignLogSegmentSequenceNumber() throws IOException {
// For any active stream we will always make sure that there is at least one
// active ledger (except when the stream first starts out). Therefore when we
// see no ledger metadata for a stream, we assume that this is the first ledger
// in the stream
long logSegmentSeqNo = DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO;
boolean logSegmentsFound = false;
if (LogSegmentMetadata.supportsLogSegmentSequenceNo(conf.getDLLedgerMetadataLayoutVersion())) {
List<LogSegmentMetadata> ledgerListDesc = getCachedLogSegments(LogSegmentMetadata.DESC_COMPARATOR);
Long nextLogSegmentSeqNo = DLUtils.nextLogSegmentSequenceNumber(ledgerListDesc);
if (null == nextLogSegmentSeqNo) {
logSegmentsFound = false;
// we don't find last assigned log segment sequence number
// then we start the log segment with configured FirstLogSegmentSequenceNumber.
logSegmentSeqNo = conf.getFirstLogSegmentSequenceNumber();
} else {
logSegmentsFound = true;
// latest log segment is assigned with a sequence number, start with next sequence number
logSegmentSeqNo = nextLogSegmentSeqNo;
}
}
// the maximum log segment sequence number is "UNASSIGNED".
if (!logSegmentsFound && (DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO == maxLogSegmentSequenceNo.getSequenceNumber())) {
// no ledger seqno stored in /ledgers before
LOG.info("No max ledger sequence number found while creating log segment {} for {}.", logSegmentSeqNo, getFullyQualifiedName());
} else if (maxLogSegmentSequenceNo.getSequenceNumber() + 1 != logSegmentSeqNo) {
LOG.warn("Unexpected max log segment sequence number {} for {} : list of cached segments = {}", new Object[] { maxLogSegmentSequenceNo.getSequenceNumber(), getFullyQualifiedName(), getCachedLogSegments(LogSegmentMetadata.DESC_COMPARATOR) });
// there is max log segment number recorded there and it isn't match. throw exception.
throw new DLIllegalStateException("Unexpected max log segment sequence number " + maxLogSegmentSequenceNo.getSequenceNumber() + " for " + getFullyQualifiedName() + ", expected " + (logSegmentSeqNo - 1));
}
return logSegmentSeqNo;
}
Aggregations