Search in sources :

Example 11 with FutureEventListener

use of com.twitter.util.FutureEventListener in project distributedlog by twitter.

the class ZKDistributedLock method asyncTryLock.

void asyncTryLock(SessionLock lock, final Promise<ZKDistributedLock> acquirePromise, final long lockTimeout) {
    if (null != tryLockFuture) {
        tryLockFuture.cancel();
    }
    tryLockFuture = lock.asyncTryLock(lockTimeout, TimeUnit.MILLISECONDS);
    tryLockFuture.addEventListener(OrderedFutureEventListener.of(new FutureEventListener<LockWaiter>() {

        @Override
        public void onSuccess(LockWaiter waiter) {
            synchronized (ZKDistributedLock.this) {
                if (closed) {
                    LOG.info("Skipping acquiring lock {} since it is already closed", lockPath);
                    waiter.getAcquireFuture().raise(new LockingException(lockPath, "lock is already closed."));
                    FutureUtils.setException(acquirePromise, newLockClosedException());
                    return;
                }
            }
            tryLockFuture = null;
            lockWaiter = waiter;
            waitForAcquire(waiter, acquirePromise);
        }

        @Override
        public void onFailure(Throwable cause) {
            FutureUtils.setException(acquirePromise, cause);
        }
    }, lockStateExecutor, lockPath));
}
Also used : LockingException(com.twitter.distributedlog.exceptions.LockingException) FutureEventListener(com.twitter.util.FutureEventListener) OrderedFutureEventListener(com.twitter.distributedlog.util.FutureUtils.OrderedFutureEventListener)

Example 12 with FutureEventListener

use of com.twitter.util.FutureEventListener in project distributedlog by twitter.

the class BKLogWriteHandler method doCompleteAndCloseLogSegment.

protected void doCompleteAndCloseLogSegment(final String inprogressZnodeName, long logSegmentSeqNo, long ledgerId, long firstTxId, long lastTxId, int recordCount, long lastEntryId, long lastSlotId, final Promise<LogSegmentMetadata> promise) {
    try {
        lock.checkOwnershipAndReacquire();
    } catch (IOException ioe) {
        FutureUtils.setException(promise, ioe);
        return;
    }
    LOG.debug("Completing and Closing Log Segment {} {}", firstTxId, lastTxId);
    final String inprogressZnodePath = inprogressZNode(inprogressZnodeName);
    LogSegmentMetadata inprogressLogSegment = readLogSegmentFromCache(inprogressZnodeName);
    // validate log segment
    if (inprogressLogSegment.getLedgerId() != ledgerId) {
        FutureUtils.setException(promise, new IOException("Active ledger has different ID to inprogress. " + inprogressLogSegment.getLedgerId() + " found, " + ledgerId + " expected"));
        return;
    }
    // validate the transaction id
    if (inprogressLogSegment.getFirstTxId() != firstTxId) {
        FutureUtils.setException(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.setException(promise, new UnexpectedException("Didn't find matched inprogress log segments when completing inprogress " + inprogressLogSegment));
                return;
            }
            long leastInprogressLSSN = inprogressLSSNs.getFirst();
            // it should also be same as the least inprogress log segment sequence number tracked in {@link inprogressLSSNs}
            if ((inprogressLogSegment.getLogSegmentSequenceNumber() != logSegmentSeqNo) || (leastInprogressLSSN != logSegmentSeqNo)) {
                FutureUtils.setException(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, inprogressZnodePath });
    } else {
        LOG.warn("Unexpected max ledger sequence number {} found while completing log segment {} for {}", new Object[] { maxLogSegmentSequenceNo.getSequenceNumber(), logSegmentSeqNo, getFullyQualifiedName() });
        if (validateLogSegmentSequenceNumber) {
            FutureUtils.setException(promise, new DLIllegalStateException("Unexpected max log segment sequence number " + maxLogSegmentSequenceNo.getSequenceNumber() + " for " + getFullyQualifiedName() + ", expected " + (logSegmentSeqNo - 1)));
            return;
        }
    }
    // Prepare the completion
    final String nameForCompletedLedger = completedLedgerZNodeName(firstTxId, lastTxId, logSegmentSeqNo);
    final String pathForCompletedLedger = completedLedgerZNode(firstTxId, lastTxId, logSegmentSeqNo);
    long startSequenceId;
    try {
        startSequenceId = computeStartSequenceId(inprogressLogSegment);
    } catch (IOException ioe) {
        FutureUtils.setException(promise, ioe);
        return;
    }
    // write completed ledger znode
    final LogSegmentMetadata completedLogSegment = inprogressLogSegment.completeLogSegment(pathForCompletedLedger, lastTxId, recordCount, lastEntryId, lastSlotId, startSequenceId);
    setLastLedgerRollingTimeMillis(completedLogSegment.getCompletionTime());
    // prepare the transaction
    ZKTransaction txn = new ZKTransaction(zooKeeperClient);
    // create completed log segment
    writeLogSegment(txn, zooKeeperClient.getDefaultACL(), nameForCompletedLedger, completedLogSegment, pathForCompletedLedger);
    // delete inprogress log segment
    deleteLogSegment(txn, inprogressZnodeName, inprogressZnodePath);
    // 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().addEventListener(FutureEventListenerRunnable.of(new FutureEventListener<Void>() {

        @Override
        public void onSuccess(Void value) {
            LOG.info("Completed {} to {} for {} : {}", new Object[] { inprogressZnodeName, nameForCompletedLedger, getFullyQualifiedName(), completedLogSegment });
            FutureUtils.setValue(promise, completedLogSegment);
        }

        @Override
        public void onFailure(Throwable cause) {
            FutureUtils.setException(promise, cause);
        }
    }, scheduler));
}
Also used : UnexpectedException(com.twitter.distributedlog.exceptions.UnexpectedException) DLIllegalStateException(com.twitter.distributedlog.exceptions.DLIllegalStateException) FutureEventListener(com.twitter.util.FutureEventListener) IOException(java.io.IOException) ZKTransaction(com.twitter.distributedlog.zk.ZKTransaction)

Example 13 with FutureEventListener

use of com.twitter.util.FutureEventListener in project distributedlog by twitter.

the class ReadUtils method asyncReadRecord.

private static Future<LogRecordWithDLSN> asyncReadRecord(final String streamName, final LogSegmentMetadata l, final boolean fence, final boolean includeControl, final boolean includeEndOfStream, final int scanStartBatchSize, final int scanMaxBatchSize, final AtomicInteger numRecordsScanned, final ExecutorService executorService, final LedgerHandleCache handleCache, final LogRecordSelector selector, final boolean backward, final long startEntryId) {
    final Promise<LogRecordWithDLSN> promise = new Promise<LogRecordWithDLSN>();
    FutureEventListener<LedgerDescriptor> openLedgerListener = new FutureEventListener<LedgerDescriptor>() {

        @Override
        public void onSuccess(final LedgerDescriptor ledgerDescriptor) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} Opened logsegment {} for reading record", streamName, l);
            }
            promise.ensure(new AbstractFunction0<BoxedUnit>() {

                @Override
                public BoxedUnit apply() {
                    handleCache.asyncCloseLedger(ledgerDescriptor);
                    return BoxedUnit.UNIT;
                }
            });
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} {} scanning {}.", new Object[] { (backward ? "backward" : "forward"), streamName, l });
            }
            asyncReadRecordFromLogSegment(streamName, ledgerDescriptor, handleCache, l, executorService, scanStartBatchSize, scanMaxBatchSize, includeControl, includeEndOfStream, promise, numRecordsScanned, selector, backward, startEntryId);
        }

        @Override
        public void onFailure(final Throwable cause) {
            String errMsg = "Error opening log segment [" + l + "] for reading record of " + streamName;
            promise.setException(new IOException(errMsg, BKException.create(FutureUtils.bkResultCode(cause))));
        }
    };
    handleCache.asyncOpenLedger(l, fence).addEventListener(FutureEventListenerRunnable.of(openLedgerListener, executorService));
    return promise;
}
Also used : Promise(com.twitter.util.Promise) FutureEventListener(com.twitter.util.FutureEventListener) BoxedUnit(scala.runtime.BoxedUnit) IOException(java.io.IOException)

Example 14 with FutureEventListener

use of com.twitter.util.FutureEventListener in project distributedlog by twitter.

the class ReadUtils method getLogRecordNotLessThanTxIdFromEntries.

/**
 * Find the log record whose transaction id is not less than provided <code>transactionId</code> from
 * entries between <code>startEntryId</code> and <code>endEntryId</code>.
 *
 * @param logName
 *          name of the log
 * @param segment
 *          log segment
 * @param transactionId
 *          provided transaction id to search
 * @param executorService
 *          executor service
 * @param handleCache
 *          handle cache
 * @param entriesToSearch
 *          list of entries to search
 * @param nWays
 *          how many entries to search in parallel
 * @param prevFoundRecord
 *          the log record found in previous search
 * @param promise
 *          promise to satisfy the result
 */
private static void getLogRecordNotLessThanTxIdFromEntries(final String logName, final LedgerDescriptor ld, final LogSegmentMetadata segment, final long transactionId, final ExecutorService executorService, final LedgerHandleCache handleCache, final List<Long> entriesToSearch, final int nWays, final Optional<LogRecordWithDLSN> prevFoundRecord, final Promise<Optional<LogRecordWithDLSN>> promise) {
    final List<Future<LogRecordWithDLSN>> searchResults = Lists.newArrayListWithExpectedSize(entriesToSearch.size());
    for (Long entryId : entriesToSearch) {
        LogRecordSelector selector = new FirstTxIdNotLessThanSelector(transactionId);
        Future<LogRecordWithDLSN> searchResult = asyncReadRecordFromEntries(logName, ld, handleCache, segment, executorService, new SingleEntryScanContext(entryId), selector);
        searchResults.add(searchResult);
    }
    FutureEventListener<List<LogRecordWithDLSN>> processSearchResultsListener = new FutureEventListener<List<LogRecordWithDLSN>>() {

        @Override
        public void onSuccess(List<LogRecordWithDLSN> resultList) {
            processSearchResults(logName, ld, segment, transactionId, executorService, handleCache, resultList, nWays, prevFoundRecord, promise);
        }

        @Override
        public void onFailure(Throwable cause) {
            promise.setException(cause);
        }
    };
    Future.collect(searchResults).addEventListener(FutureEventListenerRunnable.of(processSearchResultsListener, executorService));
}
Also used : AtomicLong(java.util.concurrent.atomic.AtomicLong) Future(com.twitter.util.Future) LogRecordSelector(com.twitter.distributedlog.selector.LogRecordSelector) List(java.util.List) FutureEventListener(com.twitter.util.FutureEventListener) FirstTxIdNotLessThanSelector(com.twitter.distributedlog.selector.FirstTxIdNotLessThanSelector)

Example 15 with FutureEventListener

use of com.twitter.util.FutureEventListener in project distributedlog by twitter.

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 handleCache
 *          ledger handle cache
 * @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 Future<Optional<LogRecordWithDLSN>> getLogRecordNotLessThanTxId(final String logName, final LogSegmentMetadata segment, final long transactionId, final ExecutorService executorService, final LedgerHandleCache handleCache, 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 Future.value(noneRecord);
        }
    }
    final Promise<Optional<LogRecordWithDLSN>> promise = new Promise<Optional<LogRecordWithDLSN>>();
    final FutureEventListener<LedgerDescriptor> openLedgerListener = new FutureEventListener<LedgerDescriptor>() {

        @Override
        public void onSuccess(final LedgerDescriptor ld) {
            promise.ensure(new AbstractFunction0<BoxedUnit>() {

                @Override
                public BoxedUnit apply() {
                    handleCache.asyncCloseLedger(ld);
                    return BoxedUnit.UNIT;
                }
            });
            long lastEntryId;
            try {
                lastEntryId = handleCache.getLastAddConfirmed(ld);
            } catch (BKException e) {
                promise.setException(e);
                return;
            }
            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.setValue(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, ld, handleCache, segment, executorService, new SingleEntryScanContext(0L), selector).addEventListener(new FutureEventListener<LogRecordWithDLSN>() {

                    @Override
                    public void onSuccess(LogRecordWithDLSN value) {
                        promise.setValue(Optional.of(selector.result()));
                    }

                    @Override
                    public void onFailure(Throwable cause) {
                        promise.setException(cause);
                    }
                });
                return;
            }
            getLogRecordNotLessThanTxIdFromEntries(logName, ld, segment, transactionId, executorService, handleCache, Lists.newArrayList(0L, lastEntryId), nWays, Optional.<LogRecordWithDLSN>absent(), promise);
        }

        @Override
        public void onFailure(final Throwable cause) {
            String errMsg = "Error opening log segment [" + segment + "] for find record from " + logName;
            promise.setException(new IOException(errMsg, BKException.create(FutureUtils.bkResultCode(cause))));
        }
    };
    handleCache.asyncOpenLedger(segment, false).addEventListener(FutureEventListenerRunnable.of(openLedgerListener, executorService));
    return promise;
}
Also used : Optional(com.google.common.base.Optional) IOException(java.io.IOException) FirstTxIdNotLessThanSelector(com.twitter.distributedlog.selector.FirstTxIdNotLessThanSelector) Promise(com.twitter.util.Promise) FutureEventListener(com.twitter.util.FutureEventListener) BKException(org.apache.bookkeeper.client.BKException) BoxedUnit(scala.runtime.BoxedUnit)

Aggregations

FutureEventListener (com.twitter.util.FutureEventListener)23 Promise (com.twitter.util.Promise)9 IOException (java.io.IOException)6 List (java.util.List)6 Future (com.twitter.util.Future)5 Stopwatch (com.google.common.base.Stopwatch)4 UnexpectedException (com.twitter.distributedlog.exceptions.UnexpectedException)4 ArrayList (java.util.ArrayList)4 BoxedUnit (scala.runtime.BoxedUnit)4 DLInterruptedException (com.twitter.distributedlog.exceptions.DLInterruptedException)3 LogEmptyException (com.twitter.distributedlog.exceptions.LogEmptyException)3 Set (java.util.Set)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)3 LockingException (com.twitter.distributedlog.exceptions.LockingException)2 OwnershipAcquireFailedException (com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException)2 ZKException (com.twitter.distributedlog.exceptions.ZKException)2 FirstTxIdNotLessThanSelector (com.twitter.distributedlog.selector.FirstTxIdNotLessThanSelector)2 ZKTransaction (com.twitter.distributedlog.zk.ZKTransaction)2 HashSet (java.util.HashSet)2