Search in sources :

Example 1 with AsyncLogWriter

use of com.twitter.distributedlog.AsyncLogWriter in project distributedlog by twitter.

the class StreamImpl method doExecuteOp.

private void doExecuteOp(final StreamOp op, boolean success) {
    final AsyncLogWriter writer;
    final Throwable lastException;
    synchronized (this) {
        writer = this.writer;
        lastException = this.lastException;
    }
    if (null != writer && success) {
        op.execute(writer, sequencer, txnLock).addEventListener(new FutureEventListener<Void>() {

            @Override
            public void onSuccess(Void value) {
            // nop
            }

            @Override
            public void onFailure(Throwable cause) {
                boolean countAsException = true;
                if (cause instanceof DLException) {
                    final DLException dle = (DLException) cause;
                    switch(dle.getCode()) {
                        case FOUND:
                            assert (cause instanceof OwnershipAcquireFailedException);
                            countAsException = false;
                            handleOwnershipAcquireFailedException(op, (OwnershipAcquireFailedException) cause);
                            break;
                        case ALREADY_CLOSED:
                            assert (cause instanceof AlreadyClosedException);
                            op.fail(cause);
                            handleAlreadyClosedException((AlreadyClosedException) cause);
                            break;
                        // exceptions that mostly from client (e.g. too large record)
                        case NOT_IMPLEMENTED:
                        case METADATA_EXCEPTION:
                        case LOG_EMPTY:
                        case LOG_NOT_FOUND:
                        case TRUNCATED_TRANSACTION:
                        case END_OF_STREAM:
                        case TRANSACTION_OUT_OF_ORDER:
                        case INVALID_STREAM_NAME:
                        case TOO_LARGE_RECORD:
                        case STREAM_NOT_READY:
                        case OVER_CAPACITY:
                            op.fail(cause);
                            break;
                        // exceptions that *could* / *might* be recovered by creating a new writer
                        default:
                            handleRecoverableDLException(op, cause);
                            break;
                    }
                } else {
                    handleUnknownException(op, cause);
                }
                if (countAsException) {
                    countException(cause, streamExceptionStatLogger);
                }
            }
        });
    } else {
        op.fail(lastException);
    }
}
Also used : OwnershipAcquireFailedException(com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException) DLException(com.twitter.distributedlog.exceptions.DLException) AsyncLogWriter(com.twitter.distributedlog.AsyncLogWriter) AlreadyClosedException(com.twitter.distributedlog.exceptions.AlreadyClosedException)

Example 2 with AsyncLogWriter

use of com.twitter.distributedlog.AsyncLogWriter in project distributedlog by twitter.

the class StreamImpl method handleUnknownException.

/**
 * Handle unknown exception when executing <i>op</i>.
 *
 * @param op
 *          stream operation executing
 * @param cause
 *          exception received when executing <i>op</i>
 */
private void handleUnknownException(StreamOp op, final Throwable cause) {
    AsyncLogWriter oldWriter = null;
    boolean statusChanged = false;
    synchronized (this) {
        if (StreamStatus.INITIALIZED == status) {
            oldWriter = setStreamStatus(StreamStatus.FAILED, StreamStatus.INITIALIZED, null, null, cause);
            statusChanged = true;
        }
    }
    if (statusChanged) {
        Abortables.asyncAbort(oldWriter, false);
        logger.error("Failed to write data into stream {} : ", name, cause);
        scheduleTryAcquireOnce(0L);
    }
    op.fail(cause);
}
Also used : AsyncLogWriter(com.twitter.distributedlog.AsyncLogWriter)

Example 3 with AsyncLogWriter

use of com.twitter.distributedlog.AsyncLogWriter in project distributedlog by twitter.

the class StreamImpl method setStreamStatus.

/**
 * Update the stream status. The changes are only applied when there isn't status changed.
 *
 * @param newStatus
 *          new status
 * @param oldStatus
 *          old status
 * @param writer
 *          new log writer
 * @param owner
 *          new owner
 * @param t
 *          new exception
 * @return old writer if it exists
 */
synchronized AsyncLogWriter setStreamStatus(StreamStatus newStatus, StreamStatus oldStatus, AsyncLogWriter writer, String owner, Throwable t) {
    if (oldStatus != this.status) {
        logger.info("Stream {} status already changed from {} -> {} when trying to change it to {}", new Object[] { name, oldStatus, this.status, newStatus });
        return null;
    }
    AsyncLogWriter oldWriter = this.writer;
    this.writer = writer;
    if (null != owner && owner.equals(clientId)) {
        unexpectedExceptions.inc();
        logger.error("I am waiting myself {} to release lock on stream {}, so have to shut myself down :", new Object[] { owner, name, t });
        // I lost the ownership but left a lock over zookeeper
        // I should not ask client to redirect to myself again as I can't handle it :(
        // shutdown myself
        fatalErrorHandler.notifyFatalError();
        this.owner = null;
    } else {
        this.owner = owner;
    }
    this.lastException = t;
    this.status = newStatus;
    if (StreamStatus.BACKOFF == newStatus && null != owner) {
        // start failure watch
        this.lastAcquireFailureWatch.reset().start();
    }
    if (StreamStatus.INITIALIZED == newStatus) {
        streamManager.notifyAcquired(this);
        logger.info("Inserted acquired stream {} -> writer {}", name, this);
    } else {
        streamManager.notifyReleased(this);
        logger.info("Removed acquired stream {} -> writer {}", name, this);
    }
    return oldWriter;
}
Also used : AsyncLogWriter(com.twitter.distributedlog.AsyncLogWriter)

Example 4 with AsyncLogWriter

use of com.twitter.distributedlog.AsyncLogWriter in project distributedlog by twitter.

the class StreamImpl method handleRecoverableDLException.

/**
 * Handle recoverable dl exception.
 *
 * @param op
 *          stream operation executing
 * @param cause
 *          exception received when executing <i>op</i>
 */
private void handleRecoverableDLException(StreamOp op, final Throwable cause) {
    AsyncLogWriter oldWriter = null;
    boolean statusChanged = false;
    synchronized (this) {
        if (StreamStatus.INITIALIZED == status) {
            oldWriter = setStreamStatus(StreamStatus.FAILED, StreamStatus.INITIALIZED, null, null, cause);
            statusChanged = true;
        }
    }
    if (statusChanged) {
        Abortables.asyncAbort(oldWriter, false);
        logger.error("Failed to write data into stream {} : ", name, cause);
        scheduleTryAcquireOnce(0L);
    }
    op.fail(cause);
}
Also used : AsyncLogWriter(com.twitter.distributedlog.AsyncLogWriter)

Example 5 with AsyncLogWriter

use of com.twitter.distributedlog.AsyncLogWriter in project distributedlog by twitter.

the class StreamImpl method acquireStream.

Future<Boolean> acquireStream() {
    // Reset this flag so the acquire thread knows whether re-acquire is needed.
    writeSinceLastAcquire = false;
    final Stopwatch stopwatch = Stopwatch.createStarted();
    final Promise<Boolean> acquirePromise = new Promise<Boolean>();
    manager.openAsyncLogWriter().addEventListener(FutureUtils.OrderedFutureEventListener.of(new FutureEventListener<AsyncLogWriter>() {

        @Override
        public void onSuccess(AsyncLogWriter w) {
            synchronized (txnLock) {
                sequencer.setLastId(w.getLastTxId());
            }
            AsyncLogWriter oldWriter;
            Queue<StreamOp> oldPendingOps;
            boolean success;
            synchronized (StreamImpl.this) {
                oldWriter = setStreamStatus(StreamStatus.INITIALIZED, StreamStatus.INITIALIZING, w, null, null);
                oldPendingOps = pendingOps;
                pendingOps = new ArrayDeque<StreamOp>();
                success = true;
            }
            // check if the stream is allowed to be acquired
            if (!streamManager.allowAcquire(StreamImpl.this)) {
                if (null != oldWriter) {
                    Abortables.asyncAbort(oldWriter, true);
                }
                int maxAcquiredPartitions = dynConf.getMaxAcquiredPartitionsPerProxy();
                StreamUnavailableException sue = new StreamUnavailableException("Stream " + partition.getStream() + " is not allowed to acquire more than " + maxAcquiredPartitions + " partitions");
                countException(sue, exceptionStatLogger);
                logger.error("Failed to acquire stream {} because it is unavailable : {}", name, sue.getMessage());
                synchronized (this) {
                    oldWriter = setStreamStatus(StreamStatus.ERROR, StreamStatus.INITIALIZED, null, null, sue);
                    // we don't switch the pending ops since they are already switched
                    // when setting the status to initialized
                    success = false;
                }
            }
            processPendingRequestsAfterOpen(success, oldWriter, oldPendingOps);
        }

        @Override
        public void onFailure(Throwable cause) {
            AsyncLogWriter oldWriter;
            Queue<StreamOp> oldPendingOps;
            boolean success;
            if (cause instanceof AlreadyClosedException) {
                countException(cause, streamExceptionStatLogger);
                handleAlreadyClosedException((AlreadyClosedException) cause);
                return;
            } else if (cause instanceof OwnershipAcquireFailedException) {
                OwnershipAcquireFailedException oafe = (OwnershipAcquireFailedException) cause;
                logger.warn("Failed to acquire stream ownership for {}, current owner is {} : {}", new Object[] { name, oafe.getCurrentOwner(), oafe.getMessage() });
                synchronized (StreamImpl.this) {
                    oldWriter = setStreamStatus(StreamStatus.BACKOFF, StreamStatus.INITIALIZING, null, oafe.getCurrentOwner(), oafe);
                    oldPendingOps = pendingOps;
                    pendingOps = new ArrayDeque<StreamOp>();
                    success = false;
                }
            } else if (cause instanceof InvalidStreamNameException) {
                InvalidStreamNameException isne = (InvalidStreamNameException) cause;
                countException(isne, streamExceptionStatLogger);
                logger.error("Failed to acquire stream {} due to its name is invalid", name);
                synchronized (StreamImpl.this) {
                    oldWriter = setStreamStatus(StreamStatus.ERROR, StreamStatus.INITIALIZING, null, null, isne);
                    oldPendingOps = pendingOps;
                    pendingOps = new ArrayDeque<StreamOp>();
                    success = false;
                }
            } else {
                countException(cause, streamExceptionStatLogger);
                logger.error("Failed to initialize stream {} : ", name, cause);
                synchronized (StreamImpl.this) {
                    oldWriter = setStreamStatus(StreamStatus.FAILED, StreamStatus.INITIALIZING, null, null, cause);
                    oldPendingOps = pendingOps;
                    pendingOps = new ArrayDeque<StreamOp>();
                    success = false;
                }
            }
            processPendingRequestsAfterOpen(success, oldWriter, oldPendingOps);
        }

        void processPendingRequestsAfterOpen(boolean success, AsyncLogWriter oldWriter, Queue<StreamOp> oldPendingOps) {
            if (success) {
                streamAcquireStat.registerSuccessfulEvent(stopwatch.elapsed(TimeUnit.MICROSECONDS));
            } else {
                streamAcquireStat.registerFailedEvent(stopwatch.elapsed(TimeUnit.MICROSECONDS));
            }
            for (StreamOp op : oldPendingOps) {
                executeOp(op, success);
                pendingOpsCounter.dec();
            }
            Abortables.asyncAbort(oldWriter, true);
            FutureUtils.setValue(acquirePromise, success);
        }
    }, scheduler, getStreamName()));
    return acquirePromise;
}
Also used : StreamUnavailableException(com.twitter.distributedlog.exceptions.StreamUnavailableException) OwnershipAcquireFailedException(com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException) InvalidStreamNameException(com.twitter.distributedlog.exceptions.InvalidStreamNameException) Stopwatch(com.google.common.base.Stopwatch) AsyncLogWriter(com.twitter.distributedlog.AsyncLogWriter) AlreadyClosedException(com.twitter.distributedlog.exceptions.AlreadyClosedException) ArrayDeque(java.util.ArrayDeque) Promise(com.twitter.util.Promise) FutureEventListener(com.twitter.util.FutureEventListener) Queue(java.util.Queue)

Aggregations

AsyncLogWriter (com.twitter.distributedlog.AsyncLogWriter)9 AlreadyClosedException (com.twitter.distributedlog.exceptions.AlreadyClosedException)2 OwnershipAcquireFailedException (com.twitter.distributedlog.exceptions.OwnershipAcquireFailedException)2 Stopwatch (com.google.common.base.Stopwatch)1 DLSN (com.twitter.distributedlog.DLSN)1 DistributedLogManager (com.twitter.distributedlog.DistributedLogManager)1 DLException (com.twitter.distributedlog.exceptions.DLException)1 InternalServerException (com.twitter.distributedlog.exceptions.InternalServerException)1 InvalidStreamNameException (com.twitter.distributedlog.exceptions.InvalidStreamNameException)1 StreamUnavailableException (com.twitter.distributedlog.exceptions.StreamUnavailableException)1 WriteOp (com.twitter.distributedlog.service.stream.WriteOp)1 WriteResponse (com.twitter.distributedlog.thrift.service.WriteResponse)1 Sequencer (com.twitter.distributedlog.util.Sequencer)1 FutureEventListener (com.twitter.util.FutureEventListener)1 Promise (com.twitter.util.Promise)1 IOException (java.io.IOException)1 ArrayDeque (java.util.ArrayDeque)1 Queue (java.util.Queue)1 Test (org.junit.Test)1