use of com.twitter.distributedlog.exceptions.WriteException in project distributedlog by twitter.
the class BKLogSegmentWriter method transmit.
/**
* Transmit the current buffer to bookkeeper.
* Synchronised at the class. #write() and #setReadyToFlush()
* are never called at the same time.
*
* NOTE: This method should only throw known exceptions so that we don't accidentally
* add new code that throws in an inappropriate place.
*
* @return a transmit future for caller to wait for transmit result if we transmit successfully,
* null if no data to transmit
* @throws BKTransmitException if the segment writer is already in error state
* @throws LockingException if the segment writer lost lock before transmit
* @throws WriteException if failed to create the envelope for the data to transmit
* @throws InvalidEnvelopedEntryException when built an invalid enveloped entry
*/
private Future<Integer> transmit() throws BKTransmitException, LockingException, WriteException, InvalidEnvelopedEntryException {
EntryBuffer recordSetToTransmit;
transmitLock.lock();
try {
synchronized (this) {
checkWriteLock();
// stream has encountered an error and cannot be written to.
if (!transmitResult.compareAndSet(BKException.Code.OK, BKException.Code.OK)) {
LOG.error("Log Segment {} Trying to write to an errored stream; Error is {}", fullyQualifiedLogSegment, BKException.getMessage(transmitResult.get()));
throw new BKTransmitException("Trying to write to an errored stream;" + " Error code : (" + transmitResult.get() + ") " + BKException.getMessage(transmitResult.get()), transmitResult.get());
}
if (recordSetWriter.getNumRecords() == 0) {
// Control flushes always have at least the control record to flush
transmitDataMisses.inc();
return null;
}
recordSetToTransmit = recordSetWriter;
recordSetWriter = newRecordSetWriter();
outstandingBytes = 0;
if (recordSetToTransmit.hasUserRecords()) {
numBytes += recordSetToTransmit.getNumBytes();
numFlushesSinceRestart++;
}
}
Buffer toSend;
try {
toSend = recordSetToTransmit.getBuffer();
FailpointUtils.checkFailPoint(FailpointUtils.FailPointName.FP_TransmitFailGetBuffer);
} catch (IOException e) {
if (e instanceof InvalidEnvelopedEntryException) {
alertStatsLogger.raise("Invalid enveloped entry for segment {} : ", fullyQualifiedLogSegment, e);
}
LOG.error("Exception while enveloping entries for segment: {}", new Object[] { fullyQualifiedLogSegment }, e);
// If a write fails here, we need to set the transmit result to an error so that
// no future writes go through and violate ordering guarantees.
transmitResult.set(BKException.Code.WriteException);
if (e instanceof InvalidEnvelopedEntryException) {
alertStatsLogger.raise("Invalid enveloped entry for segment {} : ", fullyQualifiedLogSegment, e);
throw (InvalidEnvelopedEntryException) e;
} else {
throw new WriteException(streamName, "Envelope Error");
}
}
synchronized (this) {
BKTransmitPacket packet = new BKTransmitPacket(recordSetToTransmit);
packetPrevious = packet;
entryWriter.asyncAddEntry(toSend.getData(), 0, toSend.size(), this, packet);
if (recordSetToTransmit.hasUserRecords()) {
transmitDataSuccesses.inc();
} else {
transmitControlSuccesses.inc();
}
lastTransmit.reset().start();
outstandingTransmits.incrementAndGet();
controlFlushNeeded = false;
return packet.getTransmitFuture();
}
} finally {
transmitLock.unlock();
}
}
use of com.twitter.distributedlog.exceptions.WriteException in project distributedlog by twitter.
the class BKLogSegmentWriter method addCompleteDeferredProcessing.
private void addCompleteDeferredProcessing(final BKTransmitPacket transmitPacket, final long entryId, final int rc) {
boolean cancelPendingPromises = false;
EntryBuffer recordSet = transmitPacket.getRecordSet();
synchronized (this) {
if (transmitResult.compareAndSet(BKException.Code.OK, rc)) {
// If this is the first time we are setting an error code in the transmitResult then
// we must cancel pending promises; once this error has been set, more records will not
// be enqueued; they will be failed with WriteException
cancelPendingPromises = (BKException.Code.OK != rc);
} else {
LOG.warn("Log segment {} entryId {}: Tried to set transmit result to ({}) but is already ({})", new Object[] { fullyQualifiedLogSegment, entryId, rc, transmitResult.get() });
}
if (transmitResult.get() != BKException.Code.OK) {
if (recordSet.hasUserRecords()) {
transmitDataPacketSize.registerFailedEvent(recordSet.getNumBytes());
}
} else {
// visible by advancing the lastAck
if (recordSet.hasUserRecords()) {
transmitDataPacketSize.registerSuccessfulEvent(recordSet.getNumBytes());
controlFlushNeeded = true;
if (immediateFlushEnabled) {
if (0 == minDelayBetweenImmediateFlushMs) {
backgroundFlush(true);
} else {
scheduleFlushWithDelayIfNeeded(new Callable<Void>() {
@Override
public Void call() throws Exception {
backgroundFlush(true);
return null;
}
}, immFlushSchedFutureRef);
}
}
}
}
// update last dlsn before satisifying future
if (BKException.Code.OK == transmitResult.get()) {
DLSN lastDLSNInPacket = recordSet.finalizeTransmit(logSegmentSequenceNumber, entryId);
if (recordSet.hasUserRecords()) {
if (null != lastDLSNInPacket && lastDLSN.compareTo(lastDLSNInPacket) < 0) {
lastDLSN = lastDLSNInPacket;
}
}
}
}
if (BKException.Code.OK == transmitResult.get()) {
recordSet.completeTransmit(logSegmentSequenceNumber, entryId);
} else {
recordSet.abortTransmit(FutureUtils.transmitException(transmitResult.get()));
}
if (cancelPendingPromises) {
// Since the writer is in a bad state no more packets will be tramsitted, and its safe to
// assign a new empty packet. This is to avoid a race with closeInternal which may also
// try to cancel the current packet;
final BKTransmitPacket packetCurrentSaved;
synchronized (this) {
packetCurrentSaved = new BKTransmitPacket(recordSetWriter);
recordSetWriter = newRecordSetWriter();
}
packetCurrentSaved.getRecordSet().abortTransmit(new WriteCancelledException(streamName, FutureUtils.transmitException(transmitResult.get())));
}
}
use of com.twitter.distributedlog.exceptions.WriteException in project distributedlog by twitter.
the class DistributedLogMultiStreamWriter method write.
public synchronized Future<DLSN> write(ByteBuffer buffer) {
int logRecordSize = buffer.remaining();
if (logRecordSize > MAX_LOGRECORD_SIZE) {
return Future.exception(new LogRecordTooLongException("Log record of size " + logRecordSize + " written when only " + MAX_LOGRECORD_SIZE + " is allowed"));
}
// if exceed max number of bytes
if ((recordSetWriter.getNumBytes() + logRecordSize) > MAX_LOGRECORDSET_SIZE) {
flush();
}
Promise<DLSN> writePromise = new Promise<DLSN>();
try {
recordSetWriter.writeRecord(buffer, writePromise);
} catch (LogRecordTooLongException e) {
return Future.exception(e);
} catch (WriteException e) {
recordSetWriter.abortTransmit(e);
recordSetWriter = newRecordSetWriter();
return Future.exception(e);
}
if (recordSetWriter.getNumBytes() >= bufferSize) {
flush();
}
return writePromise;
}
Aggregations