use of org.apache.distributedlog.exceptions.UnexpectedException in project bookkeeper by apache.
the class TestLogSegmentsZK method testCreateLogSegmentMissingMaxSequenceNumber.
/**
* Create Log Segment when no max sequence number recorded in /ledgers. e.g. old version.
*/
@Test(timeout = 60000)
public void testCreateLogSegmentMissingMaxSequenceNumber() throws Exception {
URI uri = createURI();
String streamName = testName.getMethodName();
DistributedLogConfiguration conf = new DistributedLogConfiguration().setLockTimeout(99999).setOutputBufferSize(0).setImmediateFlushEnabled(true).setEnableLedgerAllocatorPool(true).setLedgerAllocatorPoolName("test");
Namespace namespace = NamespaceBuilder.newBuilder().conf(conf).uri(uri).build();
namespace.createLog(streamName);
MaxLogSegmentSequenceNo max1 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf);
assertEquals(DistributedLogConstants.UNASSIGNED_LOGSEGMENT_SEQNO, max1.getSequenceNumber());
DistributedLogManager dlm = namespace.openLog(streamName);
final int numSegments = 3;
for (int i = 0; i < numSegments; i++) {
BKSyncLogWriter out = (BKSyncLogWriter) dlm.startLogSegmentNonPartitioned();
out.write(DLMTestUtil.getLogRecordInstance(i));
out.closeAndComplete();
}
MaxLogSegmentSequenceNo max2 = getMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf);
assertEquals(3, max2.getSequenceNumber());
// nuke the max ledger sequence number
updateMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf, new byte[0]);
DistributedLogManager dlm1 = namespace.openLog(streamName);
try {
dlm1.startLogSegmentNonPartitioned();
fail("Should fail with unexpected exceptions");
} catch (UnexpectedException ue) {
// expected
} finally {
dlm1.close();
}
// invalid max ledger sequence number
updateMaxLogSegmentSequenceNo(getZooKeeperClient(namespace), uri, streamName, conf, "invalid-max".getBytes(UTF_8));
DistributedLogManager dlm2 = namespace.openLog(streamName);
try {
dlm2.startLogSegmentNonPartitioned();
fail("Should fail with unexpected exceptions");
} catch (UnexpectedException ue) {
// expected
} finally {
dlm2.close();
}
dlm.close();
namespace.close();
}
use of org.apache.distributedlog.exceptions.UnexpectedException in project bookkeeper by apache.
the class ZKLogStreamMetadataStore method processLogMetadatas.
static LogMetadataForWriter processLogMetadatas(URI uri, String logName, String logIdentifier, List<Versioned<byte[]>> metadatas, boolean ownAllocator) throws UnexpectedException {
try {
// max id
Versioned<byte[]> maxTxnIdData = metadatas.get(MetadataIndex.MAX_TXID);
ensureMetadataExist(maxTxnIdData);
// version
Versioned<byte[]> versionData = metadatas.get(MetadataIndex.VERSION);
ensureMetadataExist(maxTxnIdData);
checkArgument(LAYOUT_VERSION == bytesToInt(versionData.getValue()));
// lock path
ensureMetadataExist(metadatas.get(MetadataIndex.LOCK));
// read lock path
ensureMetadataExist(metadatas.get(MetadataIndex.READ_LOCK));
// max lssn
Versioned<byte[]> maxLSSNData = metadatas.get(MetadataIndex.LOGSEGMENTS);
ensureMetadataExist(maxLSSNData);
try {
DLUtils.deserializeLogSegmentSequenceNumber(maxLSSNData.getValue());
} catch (NumberFormatException nfe) {
throw new UnexpectedException("Invalid max sequence number found in log " + logName, nfe);
}
// allocation path
Versioned<byte[]> allocationData;
if (ownAllocator) {
allocationData = metadatas.get(MetadataIndex.ALLOCATION);
ensureMetadataExist(allocationData);
} else {
allocationData = new Versioned<byte[]>(null, null);
}
return new LogMetadataForWriter(uri, logName, logIdentifier, maxLSSNData, maxTxnIdData, allocationData);
} catch (IllegalArgumentException iae) {
throw new UnexpectedException("Invalid log " + logName, iae);
} catch (NullPointerException npe) {
throw new UnexpectedException("Invalid log " + logName, npe);
}
}
use of org.apache.distributedlog.exceptions.UnexpectedException in project bookkeeper by apache.
the class BKDistributedLogManager method getAsyncLogReaderWithLock.
protected CompletableFuture<AsyncLogReader> getAsyncLogReaderWithLock(final Optional<DLSN> fromDLSN, final Optional<String> subscriberId) {
if (!fromDLSN.isPresent() && !subscriberId.isPresent()) {
return FutureUtils.exception(new UnexpectedException("Neither from dlsn nor subscriber id is provided."));
}
final BKAsyncLogReader reader = new BKAsyncLogReader(BKDistributedLogManager.this, scheduler, fromDLSN.isPresent() ? fromDLSN.get() : DLSN.InitialDLSN, subscriberId, false, statsLogger);
pendingReaders.add(reader);
final CompletableFuture<Void> lockFuture = reader.lockStream();
final CompletableFuture<AsyncLogReader> createPromise = FutureUtils.createFuture();
createPromise.whenComplete((value, cause) -> {
if (cause instanceof CancellationException) {
// cancel the lock when the creation future is cancelled
lockFuture.cancel(true);
}
});
// lock the stream - fetch the last commit position on success
lockFuture.thenCompose(new Function<Void, CompletableFuture<AsyncLogReader>>() {
@Override
public CompletableFuture<AsyncLogReader> apply(Void complete) {
if (fromDLSN.isPresent()) {
return FutureUtils.value(reader);
}
LOG.info("Reader {} @ {} reading last commit position from subscription store after acquired lock.", subscriberId.get(), name);
// we acquired lock
final SubscriptionsStore subscriptionsStore = driver.getSubscriptionsStore(getStreamName());
return subscriptionsStore.getLastCommitPosition(subscriberId.get()).thenCompose(lastCommitPosition -> {
LOG.info("Reader {} @ {} positioned to last commit position {}.", new Object[] { subscriberId.get(), name, lastCommitPosition });
try {
reader.setStartDLSN(lastCommitPosition);
} catch (UnexpectedException e) {
return FutureUtils.exception(e);
}
return FutureUtils.value(reader);
});
}
}).whenComplete(new FutureEventListener<AsyncLogReader>() {
@Override
public void onSuccess(AsyncLogReader r) {
pendingReaders.remove(reader);
FutureUtils.complete(createPromise, r);
}
@Override
public void onFailure(final Throwable cause) {
pendingReaders.remove(reader);
FutureUtils.ensure(reader.asyncClose(), () -> FutureUtils.completeExceptionally(createPromise, cause));
}
});
return createPromise;
}
use of org.apache.distributedlog.exceptions.UnexpectedException in project bookkeeper by apache.
the class PerStreamLogSegmentCache method getLogSegments.
/**
* Retrieve log segments from the cache.
*- first sort the log segments in ascending order
* - do validation and assign corresponding sequence id
* - apply comparator after validation
*
* @param comparator
* comparator to sort the returned log segments.
* @return list of sorted and filtered log segments.
* @throws UnexpectedException if unexpected condition detected (e.g. ledger sequence number gap)
*/
public List<LogSegmentMetadata> getLogSegments(Comparator<LogSegmentMetadata> comparator) throws UnexpectedException {
List<LogSegmentMetadata> segmentsToReturn;
synchronized (logSegments) {
segmentsToReturn = new ArrayList<LogSegmentMetadata>(logSegments.size());
segmentsToReturn.addAll(logSegments.values());
}
Collections.sort(segmentsToReturn, LogSegmentMetadata.COMPARATOR);
LogSegmentMetadata prevSegment = null;
if (validateLogSegmentSequenceNumber) {
// validation ledger sequence number to ensure the log segments are unique.
for (int i = 0; i < segmentsToReturn.size(); i++) {
LogSegmentMetadata segment = segmentsToReturn.get(i);
if (null != prevSegment && prevSegment.getVersion() >= LogSegmentMetadata.LogSegmentMetadataVersion.VERSION_V2_LEDGER_SEQNO.value && segment.getVersion() >= LogSegmentMetadata.LogSegmentMetadataVersion.VERSION_V2_LEDGER_SEQNO.value && prevSegment.getLogSegmentSequenceNumber() + 1 != segment.getLogSegmentSequenceNumber()) {
LOG.error("{} found ledger sequence number gap between log segment {} and {}", new Object[] { streamName, prevSegment, segment });
throw new UnexpectedException(streamName + " found ledger sequence number gap between log segment " + prevSegment.getLogSegmentSequenceNumber() + " and " + segment.getLogSegmentSequenceNumber());
}
prevSegment = segment;
}
}
prevSegment = null;
long startSequenceId = DistributedLogConstants.UNASSIGNED_SEQUENCE_ID;
for (int i = 0; i < segmentsToReturn.size(); i++) {
LogSegmentMetadata segment = segmentsToReturn.get(i);
// assign sequence id
if (!segment.isInProgress()) {
if (segment.supportsSequenceId()) {
startSequenceId = segment.getStartSequenceId() + segment.getRecordCount();
if (null != prevSegment && prevSegment.supportsSequenceId() && prevSegment.getStartSequenceId() > segment.getStartSequenceId()) {
LOG.warn("{} found decreasing start sequence id in log segment {}, previous is {}", new Object[] { streamName, segment, prevSegment });
}
} else {
startSequenceId = DistributedLogConstants.UNASSIGNED_SEQUENCE_ID;
}
} else {
if (segment.supportsSequenceId()) {
LogSegmentMetadata newSegment = segment.mutator().setStartSequenceId(startSequenceId == DistributedLogConstants.UNASSIGNED_SEQUENCE_ID ? 0L : startSequenceId).build();
segmentsToReturn.set(i, newSegment);
}
break;
}
prevSegment = segment;
}
if (comparator != LogSegmentMetadata.COMPARATOR) {
Collections.sort(segmentsToReturn, comparator);
}
return segmentsToReturn;
}
Aggregations