Search in sources :

Example 6 with BKTransmitException

use of com.twitter.distributedlog.exceptions.BKTransmitException in project distributedlog by twitter.

the class TestBKLogSegmentWriter method testCloseShouldNotFlushIfInErrorState.

/**
     * Close a log segment writer that is already in error state, should not flush buffered data.
     *
     * @throws Exception
     */
void testCloseShouldNotFlushIfInErrorState(int rcToFailComplete) throws Exception {
    DistributedLogConfiguration confLocal = newLocalConf();
    confLocal.setImmediateFlushEnabled(false);
    confLocal.setOutputBufferSize(Integer.MAX_VALUE);
    confLocal.setPeriodicFlushFrequencyMilliSeconds(0);
    ZKDistributedLock lock = createLock("/test/lock-" + runtime.getMethodName(), zkc, true);
    BKLogSegmentWriter writer = createLogSegmentWriter(confLocal, 0L, -1L, lock);
    // Use another lock to wait for writer releasing lock
    ZKDistributedLock lock0 = createLock("/test/lock-" + runtime.getMethodName(), zkc0, false);
    Future<ZKDistributedLock> lockFuture0 = lock0.asyncAcquire();
    // add 10 records
    int numRecords = 10;
    List<Future<DLSN>> futureList = new ArrayList<Future<DLSN>>(numRecords);
    for (int i = 0; i < numRecords; i++) {
        futureList.add(writer.asyncWrite(DLMTestUtil.getLogRecordInstance(i)));
    }
    assertEquals("Last tx id should be " + (numRecords - 1), numRecords - 1, writer.getLastTxId());
    assertEquals("Last acked tx id should be -1", -1L, writer.getLastTxIdAcknowledged());
    assertEquals("Last DLSN should be " + DLSN.InvalidDLSN, DLSN.InvalidDLSN, writer.getLastDLSN());
    assertEquals("Position should be " + numRecords, 10, writer.getPositionWithinLogSegment());
    writer.setTransmitResult(rcToFailComplete);
    // close the writer should release lock but not flush data
    try {
        closeWriterAndLock(writer, lock);
        fail("Close a log segment writer in error state should throw exception");
    } catch (BKTransmitException bkte) {
        assertEquals("Inconsistent rc is thrown", rcToFailComplete, bkte.getBKResultCode());
    }
    Await.result(lockFuture0);
    lock0.checkOwnership();
    assertEquals("Last tx id should still be " + (numRecords - 1), numRecords - 1, writer.getLastTxId());
    assertEquals("Last acked tx id should still be " + (numRecords - 1), -1L, writer.getLastTxIdAcknowledged());
    assertEquals("Last DLSN should still be " + DLSN.InvalidDLSN, DLSN.InvalidDLSN, writer.getLastDLSN());
    assertEquals("Position should still be " + numRecords, 10, writer.getPositionWithinLogSegment());
    for (int i = 0; i < numRecords; i++) {
        try {
            Await.result(futureList.get(i));
            fail("Should be aborted record " + i + " with transmit exception");
        } catch (WriteCancelledException wce) {
            assertTrue("Record " + i + " should be aborted because of ledger fenced", wce.getCause() instanceof BKTransmitException);
            BKTransmitException bkte = (BKTransmitException) wce.getCause();
            assertEquals("Record " + i + " should be aborted", rcToFailComplete, bkte.getBKResultCode());
        }
    }
    // check no entries were written
    LedgerHandle lh = getLedgerHandle(writer);
    LedgerHandle readLh = openLedgerNoRecovery(lh);
    assertFalse("Ledger " + lh.getId() + " should not be closed", readLh.isClosed());
    assertEquals("There should be no entries in ledger " + lh.getId(), LedgerHandle.INVALID_ENTRY_ID, readLh.getLastAddConfirmed());
}
Also used : LedgerHandle(org.apache.bookkeeper.client.LedgerHandle) WriteCancelledException(com.twitter.distributedlog.exceptions.WriteCancelledException) BKTransmitException(com.twitter.distributedlog.exceptions.BKTransmitException) ArrayList(java.util.ArrayList) Future(com.twitter.util.Future) ZKDistributedLock(com.twitter.distributedlog.lock.ZKDistributedLock)

Example 7 with BKTransmitException

use of com.twitter.distributedlog.exceptions.BKTransmitException 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();
    }
}
Also used : Buffer(com.twitter.distributedlog.io.Buffer) WriteException(com.twitter.distributedlog.exceptions.WriteException) BKTransmitException(com.twitter.distributedlog.exceptions.BKTransmitException) IOException(java.io.IOException) InvalidEnvelopedEntryException(com.twitter.distributedlog.exceptions.InvalidEnvelopedEntryException)

Aggregations

BKTransmitException (com.twitter.distributedlog.exceptions.BKTransmitException)7 Test (org.junit.Test)5 ZKDistributedLock (com.twitter.distributedlog.lock.ZKDistributedLock)4 Future (com.twitter.util.Future)3 ArrayList (java.util.ArrayList)3 LedgerHandle (org.apache.bookkeeper.client.LedgerHandle)3 WriteCancelledException (com.twitter.distributedlog.exceptions.WriteCancelledException)2 WriteException (com.twitter.distributedlog.exceptions.WriteException)2 DynamicDistributedLogConfiguration (com.twitter.distributedlog.config.DynamicDistributedLogConfiguration)1 InvalidEnvelopedEntryException (com.twitter.distributedlog.exceptions.InvalidEnvelopedEntryException)1 Buffer (com.twitter.distributedlog.io.Buffer)1 IOException (java.io.IOException)1 BKException (org.apache.bookkeeper.client.BKException)1 BookieServer (org.apache.bookkeeper.proto.BookieServer)1