use of org.apache.bookkeeper.common.concurrent.FutureEventListener in project bookkeeper by apache.
the class FederatedZKLogMetadataStore method findSubNamespaceToCreateLog.
private void findSubNamespaceToCreateLog(final String logName, final Set<URI> uris, final CompletableFuture<URI> createPromise) {
final List<URI> uriList = Lists.newArrayListWithExpectedSize(uris.size());
List<CompletableFuture<Set<String>>> futureList = Lists.newArrayListWithExpectedSize(uris.size());
for (URI uri : uris) {
SubNamespace subNs = subNamespaces.get(uri);
if (null == subNs) {
createPromise.completeExceptionally(new UnexpectedException("No sub namespace " + uri + " found"));
return;
}
futureList.add(subNs.getLogs());
uriList.add(uri);
}
FutureUtils.collect(futureList).whenComplete(new FutureEventListener<List<Set<String>>>() {
@Override
public void onSuccess(List<Set<String>> resultList) {
for (int i = resultList.size() - 1; i >= 0; i--) {
Set<String> logs = resultList.get(i);
if (logs.size() < maxLogsPerSubnamespace) {
URI uri = uriList.get(i);
createLogInNamespace(uri, logName, createPromise);
return;
}
}
// All sub namespaces are full
createSubNamespace().whenComplete(new FutureEventListener<URI>() {
@Override
public void onSuccess(URI uri) {
// the new namespace will be propagated to the namespace cache by the namespace listener
// so we don't need to cache it here. we could go ahead to create the stream under this
// namespace, as we are using sequential znode. we are mostly the first guy who create
// the log under this namespace.
createLogInNamespace(uri, logName, createPromise);
}
@Override
public void onFailure(Throwable cause) {
createPromise.completeExceptionally(cause);
}
});
}
@Override
public void onFailure(Throwable cause) {
createPromise.completeExceptionally(cause);
}
});
}
use of org.apache.bookkeeper.common.concurrent.FutureEventListener in project bookkeeper by apache.
the class ZKSessionLock method asyncTryLock.
@Override
public CompletableFuture<LockWaiter> asyncTryLock(final long timeout, final TimeUnit unit) {
final CompletableFuture<String> result = new CompletableFuture<String>();
final boolean wait = DistributedLogConstants.LOCK_IMMEDIATE != timeout;
if (wait) {
asyncTryLock(wait, result);
} else {
// try to check locks first
zk.getChildren(lockPath, null, new AsyncCallback.Children2Callback() {
@Override
public void processResult(final int rc, String path, Object ctx, final List<String> children, Stat stat) {
lockStateExecutor.executeOrdered(lockPath, new SafeRunnable() {
@Override
public void safeRun() {
if (!lockState.inState(State.INIT)) {
result.completeExceptionally(new LockStateChangedException(lockPath, lockId, State.INIT, lockState.getState()));
return;
}
if (KeeperException.Code.OK.intValue() != rc) {
result.completeExceptionally(KeeperException.create(KeeperException.Code.get(rc)));
return;
}
FailpointUtils.checkFailPointNoThrow(FailpointUtils.FailPointName.FP_LockTryAcquire);
Collections.sort(children, MEMBER_COMPARATOR);
if (children.size() > 0) {
asyncParseClientID(zk, lockPath, children.get(0)).whenCompleteAsync(new FutureEventListener<Pair<String, Long>>() {
@Override
public void onSuccess(Pair<String, Long> owner) {
if (!checkOrClaimLockOwner(owner, result)) {
acquireFuture.complete(false);
}
}
@Override
public void onFailure(final Throwable cause) {
result.completeExceptionally(cause);
}
}, lockStateExecutor.chooseThread(lockPath));
} else {
asyncTryLock(wait, result);
}
}
});
}
}, null);
}
final CompletableFuture<Boolean> waiterAcquireFuture = FutureUtils.createFuture();
waiterAcquireFuture.whenComplete((value, cause) -> acquireFuture.completeExceptionally(cause));
return result.thenApply(new Function<String, LockWaiter>() {
@Override
public LockWaiter apply(final String currentOwner) {
final Exception acquireException = new OwnershipAcquireFailedException(lockPath, currentOwner);
FutureUtils.within(acquireFuture, timeout, unit, acquireException, lockStateExecutor, lockPath).whenComplete(new FutureEventListener<Boolean>() {
@Override
public void onSuccess(Boolean acquired) {
completeOrFail(acquireException);
}
@Override
public void onFailure(final Throwable acquireCause) {
completeOrFail(acquireException);
}
private void completeOrFail(final Throwable acquireCause) {
if (isLockHeld()) {
waiterAcquireFuture.complete(true);
} else {
asyncUnlock().whenComplete(new FutureEventListener<Void>() {
@Override
public void onSuccess(Void value) {
waiterAcquireFuture.completeExceptionally(acquireCause);
}
@Override
public void onFailure(Throwable cause) {
waiterAcquireFuture.completeExceptionally(acquireCause);
}
});
}
}
});
return new LockWaiter(lockId.getLeft(), currentOwner, waiterAcquireFuture);
}
});
}
use of org.apache.bookkeeper.common.concurrent.FutureEventListener in project bookkeeper by apache.
the class BKLogHandler method getLastLogRecordAsync.
public CompletableFuture<LogRecordWithDLSN> getLastLogRecordAsync(final boolean recover, final boolean includeEndOfStream) {
final CompletableFuture<LogRecordWithDLSN> promise = new CompletableFuture<LogRecordWithDLSN>();
streamMetadataStore.logExists(logMetadata.getUri(), logMetadata.getLogName()).whenComplete(new FutureEventListener<Void>() {
@Override
public void onSuccess(Void value) {
readLogSegmentsFromStore(LogSegmentMetadata.DESC_COMPARATOR, LogSegmentFilter.DEFAULT_FILTER, null).whenComplete(new FutureEventListener<Versioned<List<LogSegmentMetadata>>>() {
@Override
public void onSuccess(Versioned<List<LogSegmentMetadata>> ledgerList) {
if (ledgerList.getValue().isEmpty()) {
promise.completeExceptionally(new LogEmptyException("Log " + getFullyQualifiedName() + " has no records"));
return;
}
asyncGetLastLogRecord(ledgerList.getValue().iterator(), promise, recover, false, includeEndOfStream);
}
@Override
public void onFailure(Throwable cause) {
promise.completeExceptionally(cause);
}
});
}
@Override
public void onFailure(Throwable cause) {
promise.completeExceptionally(cause);
}
});
return promise;
}
use of org.apache.bookkeeper.common.concurrent.FutureEventListener in project bookkeeper by apache.
the class BKLogHandler method asyncGetFirstLogRecord.
public CompletableFuture<LogRecordWithDLSN> asyncGetFirstLogRecord() {
final CompletableFuture<LogRecordWithDLSN> promise = new CompletableFuture<LogRecordWithDLSN>();
streamMetadataStore.logExists(logMetadata.getUri(), logMetadata.getLogName()).whenComplete(new FutureEventListener<Void>() {
@Override
public void onSuccess(Void value) {
readLogSegmentsFromStore(LogSegmentMetadata.COMPARATOR, LogSegmentFilter.DEFAULT_FILTER, null).whenComplete(new FutureEventListener<Versioned<List<LogSegmentMetadata>>>() {
@Override
public void onSuccess(Versioned<List<LogSegmentMetadata>> ledgerList) {
if (ledgerList.getValue().isEmpty()) {
promise.completeExceptionally(new LogEmptyException("Log " + getFullyQualifiedName() + " has no records"));
return;
}
CompletableFuture<LogRecordWithDLSN> firstRecord = null;
for (LogSegmentMetadata ledger : ledgerList.getValue()) {
if (!ledger.isTruncated() && (ledger.getRecordCount() > 0 || ledger.isInProgress())) {
firstRecord = asyncReadFirstUserRecord(ledger, DLSN.InitialDLSN);
break;
}
}
if (null != firstRecord) {
FutureUtils.proxyTo(firstRecord, promise);
} else {
promise.completeExceptionally(new LogEmptyException("Log " + getFullyQualifiedName() + " has no records"));
}
}
@Override
public void onFailure(Throwable cause) {
promise.completeExceptionally(cause);
}
});
}
@Override
public void onFailure(Throwable cause) {
promise.completeExceptionally(cause);
}
});
return promise;
}
use of org.apache.bookkeeper.common.concurrent.FutureEventListener in project bookkeeper by apache.
the class ReadUtils method getLogRecordNotLessThanTxId.
//
// Search Functions
//
/**
* Get the log record whose transaction id is not less than provided <code>transactionId</code>.
*
* <p>
* It uses a binary-search like algorithm to find the log record whose transaction id is not less than
* provided <code>transactionId</code> within a log <code>segment</code>. You could think of a log segment
* in terms of a sequence of records whose transaction ids are non-decreasing.
*
* - The sequence of records within a log segment is divided into N pieces.
* - Find the piece of records that contains a record whose transaction id is not less than provided
* <code>transactionId</code>.
*
* N could be chosen based on trading off concurrency and latency.
* </p>
*
* @param logName
* name of the log
* @param segment
* metadata of the log segment
* @param transactionId
* transaction id
* @param executorService
* executor service used for processing entries
* @param entryStore
* log segment entry store
* @param nWays
* how many number of entries to search in parallel
* @return found log record. none if all transaction ids are less than provided <code>transactionId</code>.
*/
public static CompletableFuture<Optional<LogRecordWithDLSN>> getLogRecordNotLessThanTxId(final String logName, final LogSegmentMetadata segment, final long transactionId, final ExecutorService executorService, final LogSegmentEntryStore entryStore, final int nWays) {
if (!segment.isInProgress()) {
if (segment.getLastTxId() < transactionId) {
// all log records whose transaction id is less than provided transactionId
// then return none
Optional<LogRecordWithDLSN> noneRecord = Optional.absent();
return FutureUtils.value(noneRecord);
}
}
final CompletableFuture<Optional<LogRecordWithDLSN>> promise = new CompletableFuture<Optional<LogRecordWithDLSN>>();
final FutureEventListener<LogSegmentRandomAccessEntryReader> openReaderListener = new FutureEventListener<LogSegmentRandomAccessEntryReader>() {
@Override
public void onSuccess(final LogSegmentRandomAccessEntryReader reader) {
promise.whenComplete((value, cause) -> reader.asyncClose());
long lastEntryId = reader.getLastAddConfirmed();
if (lastEntryId < 0) {
// it means that the log segment is created but not written yet or an empty log segment.
// it is equivalent to 'all log records whose transaction id is less than provided transactionId'
Optional<LogRecordWithDLSN> nonRecord = Optional.absent();
promise.complete(nonRecord);
return;
}
// all log records whose transaction id is not less than provided transactionId
if (segment.getFirstTxId() >= transactionId) {
final FirstTxIdNotLessThanSelector selector = new FirstTxIdNotLessThanSelector(transactionId);
asyncReadRecordFromEntries(logName, reader, segment, executorService, new SingleEntryScanContext(0L), selector).whenComplete(new FutureEventListener<LogRecordWithDLSN>() {
@Override
public void onSuccess(LogRecordWithDLSN value) {
promise.complete(Optional.of(selector.result()));
}
@Override
public void onFailure(Throwable cause) {
promise.completeExceptionally(cause);
}
});
return;
}
getLogRecordNotLessThanTxIdFromEntries(logName, segment, transactionId, executorService, reader, Lists.newArrayList(0L, lastEntryId), nWays, Optional.<LogRecordWithDLSN>absent(), promise);
}
@Override
public void onFailure(final Throwable cause) {
promise.completeExceptionally(cause);
}
};
entryStore.openRandomAccessReader(segment, false).whenCompleteAsync(openReaderListener, executorService);
return promise;
}
Aggregations