use of io.pravega.common.util.ReusableLatch in project pravega by pravega.
the class ThreadPoolScheduledExecutorServiceTest method testShutdownWithRecurring.
@Test(timeout = 10000)
public void testShutdownWithRecurring() throws Exception {
ThreadPoolScheduledExecutorService pool = createPool(1);
ReusableLatch latch = new ReusableLatch(false);
AtomicInteger count = new AtomicInteger(0);
AtomicReference<Exception> error = new AtomicReference<>();
ScheduledFuture<?> future = pool.scheduleAtFixedRate(() -> {
count.incrementAndGet();
try {
latch.await();
} catch (Exception e) {
error.set(e);
}
}, 0, 20, SECONDS);
assertFalse(future.isCancelled());
assertFalse(future.isDone());
AssertExtensions.assertEventuallyEquals(1, count::get, 5000);
pool.shutdown();
latch.release();
AssertExtensions.assertThrows(CancellationException.class, () -> future.get());
assertTrue(future.isCancelled());
assertTrue(future.isDone());
assertEquals(1, count.get());
assertTrue(pool.awaitTermination(1, SECONDS));
}
use of io.pravega.common.util.ReusableLatch in project pravega by pravega.
the class ContainerEventProcessorTests method testReadWithFailingSegment.
/**
* Test the behavior of the EventProcessor when internal Segment reads fail.
*
* @throws Exception
*/
@Test(timeout = 10000)
public void testReadWithFailingSegment() throws Exception {
DirectSegmentAccess faultySegment = spy(new SegmentMock(this.executorService()));
Function<String, CompletableFuture<DirectSegmentAccess>> faultySegmentSupplier = s -> CompletableFuture.completedFuture(faultySegment);
@Cleanup ContainerEventProcessor eventProcessorService = new ContainerEventProcessorImpl(0, faultySegmentSupplier, ITERATION_DELAY, CONTAINER_OPERATION_TIMEOUT, this.executorService());
int maxItemsProcessed = 10;
int maxOutstandingBytes = 4 * 1024 * 1024;
int truncationDataSize = 500;
ContainerEventProcessor.EventProcessorConfig config = new ContainerEventProcessor.EventProcessorConfig(maxItemsProcessed, maxOutstandingBytes, truncationDataSize);
ReusableLatch latch = new ReusableLatch();
Function<List<BufferView>, CompletableFuture<Void>> doNothing = l -> {
latch.release();
return CompletableFuture.completedFuture(null);
};
// Make the internal Segment of the processor to fail upon a read.
when(faultySegment.read(anyLong(), anyInt(), any(Duration.class))).thenThrow(IntentionalException.class).thenCallRealMethod();
@Cleanup ContainerEventProcessor.EventProcessor processor = eventProcessorService.forConsumer("testSegmentMax", doNothing, config).get(TIMEOUT_FUTURE.toSeconds(), TimeUnit.SECONDS);
// Write an event to make sure that the processor is running and await for it to be processed.
BufferView event = new ByteArraySegment("Test".getBytes());
processor.add(event, TIMEOUT_FUTURE).join();
latch.await();
}
use of io.pravega.common.util.ReusableLatch in project pravega by pravega.
the class ContainerEventProcessorTests method testEventRejectionOnMaxOutstanding.
public static void testEventRejectionOnMaxOutstanding(ContainerEventProcessor eventProcessorService) throws Exception {
int maxItemsProcessed = 1000;
int maxOutstandingBytes = 1024 * 1024;
int truncationDataSize = 500;
ContainerEventProcessor.EventProcessorConfig config = new ContainerEventProcessor.EventProcessorConfig(maxItemsProcessed, maxOutstandingBytes, truncationDataSize);
AtomicLong processorResults = new AtomicLong(0);
ReusableLatch latch = new ReusableLatch();
Function<List<BufferView>, CompletableFuture<Void>> handler = l -> {
Exceptions.handleInterrupted(latch::await);
processorResults.addAndGet(l.size());
return CompletableFuture.completedFuture(null);
};
@Cleanup ContainerEventProcessor.EventProcessor processor = eventProcessorService.forConsumer("testSegmentMax", handler, config).get(TIMEOUT_FUTURE.toSeconds(), TimeUnit.SECONDS);
boolean foundMaxOutstandingLimit = false;
// Write a lot of data with the ContainerEventProcessor not started, so we ensure we get the max outstanding exception.
BufferView event = new ByteArraySegment("This needs to be a long string to reach the limit sooner!!!".getBytes());
while (!foundMaxOutstandingLimit) {
try {
processor.add(event, TIMEOUT_FUTURE).join();
processorResults.decrementAndGet();
} catch (Exception e) {
// We have reached the max outstanding bytes for this internal Segment.
Assert.assertTrue(e instanceof ContainerEventProcessor.TooManyOutstandingBytesException);
foundMaxOutstandingLimit = true;
}
}
latch.release();
// Wait until all the events are consumed.
AssertExtensions.assertEventuallyEquals(true, () -> processorResults.get() == 0, TIMEOUT_SUITE_MILLIS);
// Check that we cannot add empty events.
AssertExtensions.assertThrows(IllegalArgumentException.class, () -> processor.add(BufferView.empty(), TIMEOUT_FUTURE));
}
use of io.pravega.common.util.ReusableLatch in project pravega by pravega.
the class ContainerEventProcessorTests method testBasicContainerEventProcessor.
public static void testBasicContainerEventProcessor(ContainerEventProcessor containerEventProcessor) throws Exception {
int maxItemsPerBatch = 10;
int maxOutstandingBytes = 4 * 1024 * 1024;
int truncationDataSize = 500;
ReusableLatch latch = new ReusableLatch();
final AtomicReference<String> userEvent = new AtomicReference<>("event1");
Function<List<BufferView>, CompletableFuture<Void>> handler = l -> {
l.forEach(s -> Assert.assertEquals(userEvent.get().length(), s.getLength()));
return CompletableFuture.runAsync(latch::release);
};
ContainerEventProcessor.EventProcessorConfig eventProcessorConfig = new ContainerEventProcessor.EventProcessorConfig(maxItemsPerBatch, maxOutstandingBytes, truncationDataSize);
@Cleanup ContainerEventProcessor.EventProcessor processor = containerEventProcessor.forConsumer("testConsumer", handler, eventProcessorConfig).get(TIMEOUT_FUTURE.toSeconds(), TimeUnit.SECONDS);
// Test adding one Event to the EventProcessor and wait for the handle to get executed and unblock this thread.
BufferView event = new ByteArraySegment(userEvent.get().getBytes());
processor.add(event, TIMEOUT_FUTURE).join();
latch.await();
latch.reset();
// Test the same with a larger events.
userEvent.set("longerEvent2");
event = new ByteArraySegment(userEvent.get().getBytes());
processor.add(event, TIMEOUT_FUTURE).join();
processor.add(event, TIMEOUT_FUTURE).join();
processor.add(event, TIMEOUT_FUTURE).join();
latch.await();
// Check that if the same EventProcessor name is used, the same object is retrieved.
Assert.assertEquals(processor, containerEventProcessor.forConsumer("testConsumer", handler, eventProcessorConfig).get(TIMEOUT_FUTURE.toSeconds(), TimeUnit.SECONDS));
}
use of io.pravega.common.util.ReusableLatch in project pravega by pravega.
the class AsyncStorageWrapperTests method testConcurrencySameSegment.
/**
* Tests basic same-segment concurrency for simple operations. Since all operations use the same sequencing mechanism
* it suffices to test using two arbitrary operations instead of every possible pair.
*/
@Test
public void testConcurrencySameSegment() throws Exception {
final String segmentName = "Segment";
final String op1 = TestStorage.CREATE;
final String op2 = TestStorage.DELETE;
// Create a set of latches that can be used to detect when an operation was invoked and when to release it.
val invoked = new HashMap<String, ReusableLatch>();
val waitOn = new HashMap<String, ReusableLatch>();
invoked.put(op1, new ReusableLatch());
invoked.put(op2, new ReusableLatch());
waitOn.put(op1, new ReusableLatch());
waitOn.put(op2, new ReusableLatch());
val innerStorage = new TestStorage((operation, segment) -> {
invoked.get(operation).release();
Exceptions.handleInterrupted(() -> waitOn.get(operation).await());
return null;
});
@Cleanup val s = new AsyncStorageWrapper(innerStorage, executorService());
// Begin executing one operation (Create) and wait for it properly "acquire" the lock.
val futures = new ArrayList<CompletableFuture<?>>();
futures.add(s.create(segmentName, TIMEOUT));
invoked.get(op1).await(LOCK_TIMEOUT_MILLIS);
Assert.assertEquals("Unexpected number of active segments.", 1, s.getSegmentWithOngoingOperationsCount());
// Begin executing a second operation (Delete) and verify that it hasn't started within a reasonable amount of time.
futures.add(s.delete(InMemoryStorage.newHandle(segmentName, false), TIMEOUT));
AssertExtensions.assertThrows("Second operation was invoked while the first one was still running.", () -> invoked.get(op2).await(LOCK_TIMEOUT_MILLIS), ex -> ex instanceof TimeoutException);
// Complete the first operation and await the second operation to begin executing, then release it too.
waitOn.get(op1).release();
invoked.get(op2).await(LOCK_TIMEOUT_MILLIS);
Assert.assertEquals("Unexpected number of active segments.", 1, s.getSegmentWithOngoingOperationsCount());
waitOn.get(op2).release();
// Wait for both operations to complete. This will re-throw any exceptions that may have occurred.
allOf(futures).get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertEquals("Unexpected final number of active segments.", 0, s.getSegmentWithOngoingOperationsCount());
}
Aggregations