use of io.pravega.common.ObjectClosedException in project pravega by pravega.
the class DataFrameBuilder method append.
/**
* Appends a LogItem to the DataFrameBuilder. If any exceptions happened during serialization, whatever contents was
* written to the DataFrame will be discarded. Note that if a LogItem spans multiple DataFrames, in case of failure,
* the content serialized to already committed DataFrames will not be discarded. That case will have to be dealt with
* upon reading DataFrames from the DataFrameLog.
*
* Any exceptions that resulted from the Data Frame failing to commit will be routed through the dataFrameCommitFailureCallback
* callback, as well as being thrown from this exception.
*
* @param logItem The LogItem to append.
* @throws NullPointerException If logItem is null.
* @throws IllegalArgumentException If attempted to add LogItems out of order (based on Sequence Number).
* @throws IOException If the LogItem failed to serialize to the DataLog, or if one of the DataFrames containing
* the LogItem failed to commit to the DataFrameLog.
* @throws ObjectClosedException If the DataFrameBuilder is closed (or in in a failed state) and cannot be used anymore.
*/
void append(T logItem) throws IOException {
Exceptions.checkNotClosed(this.closed.get(), this);
long seqNo = logItem.getSequenceNumber();
Exceptions.checkArgument(this.lastSerializedSequenceNumber < seqNo, "logItem", "Invalid sequence number. Expected: greater than %d, given: %d.", this.lastSerializedSequenceNumber, seqNo);
// Remember the last Started SeqNo, in case of failure.
long previousLastStartedSequenceNumber = this.lastStartedSequenceNumber;
try {
// Indicate to the output stream that are about to write a new record.
this.outputStream.startNewRecord();
// Completely serialize the entry. Note that this may span more than one Data Frame.
this.lastStartedSequenceNumber = seqNo;
this.serializer.serialize(this.outputStream, logItem);
// Indicate to the output stream that have finished writing the record.
this.outputStream.endRecord();
this.lastSerializedSequenceNumber = seqNo;
} catch (Exception ex) {
if (this.closed.get()) {
// to indicate that we are closed by throwing ObjectClosedException.
throw new ObjectClosedException(this, ex);
} else if (ex instanceof ObjectClosedException) {
// TargetLog has closed. We need to close too.
close();
} else {
// Discard any information that we have about this record (pretty much revert back to where startNewEntry()
// would have begun writing).
this.outputStream.discardRecord();
this.lastStartedSequenceNumber = previousLastStartedSequenceNumber;
}
throw ex;
}
}
use of io.pravega.common.ObjectClosedException in project pravega by pravega.
the class OperationProcessorTests method testConcurrentStopAndCommit.
/**
* Tests a scenario where the OperationProcessor is shut down while a DataFrame is being processed and will eventually
* complete successfully - however its operation should be cancelled.
*/
@Test
public void testConcurrentStopAndCommit() throws Exception {
@Cleanup TestContext context = new TestContext();
// Generate some test data.
val segmentId = createStreamSegmentsInMetadata(1, context.metadata).stream().findFirst().orElse(-1L);
List<Operation> operations = Collections.singletonList(new StreamSegmentAppendOperation(segmentId, new byte[1], null));
CompletableFuture<LogAddress> appendCallback = new CompletableFuture<>();
// Setup an OperationProcessor with a custom DurableDataLog and start it.
@Cleanup DurableDataLog dataLog = new ManualAppendOnlyDurableDataLog(() -> appendCallback);
dataLog.initialize(TIMEOUT);
@Cleanup OperationProcessor operationProcessor = new OperationProcessor(context.metadata, context.stateUpdater, dataLog, getNoOpCheckpointPolicy(), executorService());
operationProcessor.startAsync().awaitRunning();
// Process all generated operations.
OperationWithCompletion completionFuture = processOperations(operations, operationProcessor).stream().findFirst().orElse(null);
operationProcessor.stopAsync();
appendCallback.complete(new TestLogAddress(1));
// Stop the processor.
operationProcessor.awaitTerminated();
// Wait for the operation to complete. The operation should have been cancelled (due to the OperationProcessor
// shutting down) - no other exception (or successful completion is accepted).
AssertExtensions.assertThrows("Operation did not fail with the right exception.", () -> completionFuture.completion, ex -> ex instanceof CancellationException || ex instanceof ObjectClosedException);
}
use of io.pravega.common.ObjectClosedException in project pravega by pravega.
the class StreamSegmentReadResultTests method testClose.
/**
* Tests the ability to close the result and cancel any items that were returned.
*/
@Test
public void testClose() {
AtomicReference<TestReadResultEntry> nextEntry = new AtomicReference<>();
StreamSegmentReadResult.NextEntrySupplier nes = (offset, length) -> nextEntry.get();
// We issue a read with length = MAX_RESULT_LENGTH, but we only get to read one item from it.
StreamSegmentReadResult r = new StreamSegmentReadResult(START_OFFSET, MAX_RESULT_LENGTH, nes, "");
nextEntry.set(TestReadResultEntry.cache(START_OFFSET, MAX_RESULT_LENGTH));
ReadResultEntry resultEntry = r.next();
// Close the result and verify we cannot read from it anymore and that the pending future is now canceled.
r.close();
Assert.assertTrue("Already returned result future is not canceled after closing the ReadResult.", resultEntry.getContent().isCancelled());
Assert.assertFalse("hasNext() did not return false after closing ", r.hasNext());
AssertExtensions.assertThrows("next() did not throw an appropriate exception when the ReadResult is closed.", r::next, ex -> ex instanceof ObjectClosedException);
}
use of io.pravega.common.ObjectClosedException in project pravega by pravega.
the class WriteQueueTests method testClose.
/**
* Tests the close() method.
*/
@Test
public void testClose() {
val q = new WriteQueue();
val expectedWrites = new ArrayList<Write>();
for (int i = 0; i < ITEM_COUNT; i++) {
val w = new Write(new ByteArraySegment(new byte[i]), new TestWriteLedger(i), CompletableFuture.completedFuture(null));
q.add(w);
expectedWrites.add(w);
}
val removedWrites = q.close();
AssertExtensions.assertListEquals("Unexpected writes removed.", expectedWrites, removedWrites, Object::equals);
val clearStats = q.getStatistics();
Assert.assertEquals("Unexpected getSize after clear.", 0, clearStats.getSize());
Assert.assertEquals("Unexpected getAverageFillRate after clear.", 0, clearStats.getAverageItemFillRatio(), 0);
Assert.assertEquals("Unexpected getExpectedProcessingTimeMillis after clear.", 0, clearStats.getExpectedProcessingTimeMillis());
AssertExtensions.assertThrows("add() worked after close().", () -> q.add(new Write(new ByteArraySegment(new byte[1]), new TestWriteLedger(0), CompletableFuture.completedFuture(null))), ex -> ex instanceof ObjectClosedException);
AssertExtensions.assertThrows("getWritesToExecute() worked after close().", () -> q.getWritesToExecute(1), ex -> ex instanceof ObjectClosedException);
AssertExtensions.assertThrows("removeFinishedWrites() worked after close().", q::removeFinishedWrites, ex -> ex instanceof ObjectClosedException);
}
use of io.pravega.common.ObjectClosedException in project pravega by pravega.
the class OrderedItemProcessorTests method testFailures.
@Test
public void testFailures() {
final int itemCount = 2 * CAPACITY;
val processedItems = Collections.synchronizedCollection(new HashSet<Integer>());
val processFutures = Collections.synchronizedList(new ArrayList<CompletableFuture<Integer>>());
Function<Integer, CompletableFuture<Integer>> itemProcessor = i -> {
if (!processedItems.add(i)) {
Assert.fail("Duplicate item detected: " + i);
}
CompletableFuture<Integer> result = new CompletableFuture<>();
processFutures.add(result);
return result;
};
val resultFutures = new ArrayList<CompletableFuture<Integer>>();
@Cleanup val p = new TestProcessor(CAPACITY, itemProcessor, executorService());
// Fill up to capacity, and beyond.
for (int i = 0; i < itemCount; i++) {
resultFutures.add(p.process(i));
}
// Fail an item.
val failedIndex = CAPACITY / 2;
processFutures.get(failedIndex).completeExceptionally(new IntentionalException());
AssertExtensions.assertThrows("Failed item did not have its result failed as well.", resultFutures.get(failedIndex)::join, ex -> ex instanceof IntentionalException);
// Verify all queued-up items have been failed, but none of the initial ones (that have already begun processing)
for (int i = CAPACITY; i < itemCount; i++) {
AssertExtensions.assertThrows("Queued-up item did not fail when a previous item failed.", resultFutures.get(i)::join, ex -> ex instanceof OrderedItemProcessor.ProcessingException && ex.getCause() instanceof IntentionalException);
}
for (int i = 0; i < CAPACITY; i++) {
if (i != failedIndex) {
Assert.assertFalse("Already-processing future was completed as well.", resultFutures.get(i).isDone());
}
}
// Verify we can't add anything else ...
AssertExtensions.assertThrows("failure did not cause OrderedItemProcessor to close.", () -> p.process(Integer.MAX_VALUE), ex -> ex instanceof ObjectClosedException);
}
Aggregations