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);
}
}
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);
}
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;
}
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);
}
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;
}
Aggregations