Search in sources :

Example 16 with ReusableLatch

use of io.pravega.common.util.ReusableLatch in project pravega by pravega.

the class AppendProcessorTest method testDelayedDataAppended.

/**
 * Test to ensure newer appends are processed only after successfully sending the DataAppended acknowledgement
 * back to client. This test tests the following:
 * - If sending first DataAppended is blocked, ensure future appends are not written to store.
 * - Once the first DataAppended is sent ensure the remaining appends are written to store and DataAppended ack'ed
 * back.
 */
@Test(timeout = 15 * 1000)
public void testDelayedDataAppended() throws Exception {
    ReusableLatch firstStoreAppendInvoked = new ReusableLatch();
    ReusableLatch completeFirstDataAppendedAck = new ReusableLatch();
    ReusableLatch secondStoreAppendInvoked = new ReusableLatch();
    @Cleanup("shutdownNow") ScheduledExecutorService nettyExecutor = ExecutorServiceHelpers.newScheduledThreadPool(1, "Netty-threadPool");
    String streamSegmentName = "testDelayedAppend";
    UUID clientId = UUID.randomUUID();
    byte[] data = new byte[] { 1, 2, 3, 4, 6, 7, 8, 9 };
    StreamSegmentStore store = mock(StreamSegmentStore.class);
    ServerConnection connection = mock(ServerConnection.class);
    // Ensure the first DataAppended is hung/delayed.
    doAnswer(invocation -> {
        firstStoreAppendInvoked.release();
        // wait, simulating a hung/delayed dataAppended acknowledgement.
        completeFirstDataAppendedAck.await();
        return null;
    }).doAnswer(invocation -> {
        secondStoreAppendInvoked.release();
        return null;
    }).when(connection).send(any(DataAppended.class));
    AppendProcessor processor = new AppendProcessor(store, connection, new FailingRequestProcessor(), null);
    CompletableFuture<SegmentProperties> propsFuture = CompletableFuture.completedFuture(StreamSegmentInformation.builder().name(streamSegmentName).build());
    when(store.getStreamSegmentInfo(streamSegmentName, true, AppendProcessor.TIMEOUT)).thenReturn(propsFuture);
    processor.setupAppend(new SetupAppend(1, clientId, streamSegmentName, ""));
    verify(store).getStreamSegmentInfo(streamSegmentName, true, AppendProcessor.TIMEOUT);
    CompletableFuture<Void> result = CompletableFuture.completedFuture(null);
    int eventCount = 100;
    when(store.append(streamSegmentName, data, updateEventNumber(clientId, 100, SegmentMetadata.NULL_ATTRIBUTE_VALUE, eventCount), AppendProcessor.TIMEOUT)).thenReturn(result);
    // Trigger the first append, here the sending of DataAppended ack will be delayed/hung.
    nettyExecutor.submit(() -> processor.append(new Append(streamSegmentName, clientId, 100, eventCount, Unpooled.wrappedBuffer(data), null)));
    firstStoreAppendInvoked.await();
    verify(store).append(streamSegmentName, data, updateEventNumber(clientId, 100, SegmentMetadata.NULL_ATTRIBUTE_VALUE, eventCount), AppendProcessor.TIMEOUT);
    /* Trigger the next append. This should be completed immediately and should not cause a store.append to be
        invoked as the previous DataAppended ack is still not sent. */
    processor.append(new Append(streamSegmentName, clientId, 200, eventCount, Unpooled.wrappedBuffer(data), null));
    // Since the first Ack was never sent the next append should not be written to the store.
    verifyNoMoreInteractions(store);
    // Setup mock for check behaviour after the delayed/hung dataAppended completes.
    when(store.append(streamSegmentName, data, updateEventNumber(clientId, 200, 100, eventCount), AppendProcessor.TIMEOUT)).thenReturn(result);
    // Now ensure the dataAppended sent
    completeFirstDataAppendedAck.release();
    // wait until the next store append is invoked.
    secondStoreAppendInvoked.await();
    // Verify that the next store append invoked.
    verify(store).append(streamSegmentName, data, updateEventNumber(clientId, 200, 100, eventCount), AppendProcessor.TIMEOUT);
    // Verify two DataAppended acks are sent out.
    verify(connection, times(2)).send(any(DataAppended.class));
    verify(connection).send(new DataAppended(clientId, 100, Long.MIN_VALUE));
    verify(connection).send(new DataAppended(clientId, 200, 100));
}
Also used : ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) Arrays(java.util.Arrays) StreamSegmentInformation(io.pravega.segmentstore.contracts.StreamSegmentInformation) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) ConditionalCheckFailed(io.pravega.shared.protocol.netty.WireCommands.ConditionalCheckFailed) Cleanup(lombok.Cleanup) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) Append(io.pravega.shared.protocol.netty.Append) Unpooled(io.netty.buffer.Unpooled) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) Mockito.verifyNoMoreInteractions(org.mockito.Mockito.verifyNoMoreInteractions) FailingRequestProcessor(io.pravega.shared.protocol.netty.FailingRequestProcessor) Map(java.util.Map) Mockito.doAnswer(org.mockito.Mockito.doAnswer) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Mockito.atLeast(org.mockito.Mockito.atLeast) Assert.fail(org.junit.Assert.fail) ReusableLatch(io.pravega.common.util.ReusableLatch) StreamSegmentStore(io.pravega.segmentstore.contracts.StreamSegmentStore) InOrder(org.mockito.InOrder) EVENT_COUNT(io.pravega.segmentstore.contracts.Attributes.EVENT_COUNT) AppendSetup(io.pravega.shared.protocol.netty.WireCommands.AppendSetup) Collection(java.util.Collection) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) UUID(java.util.UUID) Mockito.when(org.mockito.Mockito.when) Mockito.verify(org.mockito.Mockito.verify) Mockito(org.mockito.Mockito) Ignore(org.junit.Ignore) BadOffsetException(io.pravega.segmentstore.contracts.BadOffsetException) OperationUnsupported(io.pravega.shared.protocol.netty.WireCommands.OperationUnsupported) Mockito.atMost(org.mockito.Mockito.atMost) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) DataAppended(io.pravega.shared.protocol.netty.WireCommands.DataAppended) Collections(java.util.Collections) Futures(io.pravega.common.concurrent.Futures) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Mockito.mock(org.mockito.Mockito.mock) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) FailingRequestProcessor(io.pravega.shared.protocol.netty.FailingRequestProcessor) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Cleanup(lombok.Cleanup) StreamSegmentStore(io.pravega.segmentstore.contracts.StreamSegmentStore) ReusableLatch(io.pravega.common.util.ReusableLatch) Append(io.pravega.shared.protocol.netty.Append) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) DataAppended(io.pravega.shared.protocol.netty.WireCommands.DataAppended) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) UUID(java.util.UUID) Test(org.junit.Test)

Example 17 with ReusableLatch

use of io.pravega.common.util.ReusableLatch in project pravega by pravega.

the class ContainerReadIndexTests method testConcurrentEvictionTransactionStorageMerge.

/**
 * Tests a scenario where a call to {@link StreamSegmentReadIndex#completeMerge} executes concurrently with a
 * CacheManager eviction. The Cache Manager must not evict the data for recently transferred entries, even if they
 * would otherwise be eligible for eviction in the source segment.
 */
@Test
public void testConcurrentEvictionTransactionStorageMerge() throws Exception {
    val mergeOffset = 1;
    val appendLength = 1;
    CachePolicy cachePolicy = new CachePolicy(1, Duration.ZERO, Duration.ofMillis(1));
    @Cleanup TestContext context = new TestContext(DEFAULT_CONFIG, cachePolicy);
    // Create parent segment and one transaction
    long targetId = createSegment(0, context);
    long sourceId = createTransaction(1, context);
    val targetMetadata = context.metadata.getStreamSegmentMetadata(targetId);
    val sourceMetadata = context.metadata.getStreamSegmentMetadata(sourceId);
    createSegmentsInStorage(context);
    // Write something to the parent segment.
    appendSingleWrite(targetId, new ByteArraySegment(new byte[mergeOffset]), context);
    context.storage.openWrite(targetMetadata.getName()).thenCompose(handle -> context.storage.write(handle, 0, new ByteArrayInputStream(new byte[mergeOffset]), mergeOffset, TIMEOUT)).join();
    // Write something to the transaction, but do not write anything in Storage - we want to verify we don't even
    // try to reach in there.
    val sourceContents = getAppendData(context.metadata.getStreamSegmentMetadata(sourceId).getName(), sourceId, 0, 0);
    appendSingleWrite(sourceId, sourceContents, context);
    sourceMetadata.setStorageLength(sourceMetadata.getLength());
    // Seal & Begin-merge the transaction (do not seal in storage).
    sourceMetadata.markSealed();
    targetMetadata.setLength(sourceMetadata.getLength() + mergeOffset);
    context.readIndex.beginMerge(targetId, mergeOffset, sourceId);
    sourceMetadata.markMerged();
    sourceMetadata.markDeleted();
    // Trigger a Complete Merge. We want to intercept and pause it immediately before it is unregistered from the
    // Cache Manager.
    @Cleanup("release") val unregisterCalled = new ReusableLatch();
    @Cleanup("release") val unregisterBlocker = new ReusableLatch();
    context.cacheManager.setUnregisterInterceptor(c -> {
        unregisterCalled.release();
        Exceptions.handleInterrupted(unregisterBlocker::await);
    });
    val completeMerge = CompletableFuture.runAsync(() -> {
        try {
            context.readIndex.completeMerge(targetId, sourceId);
        } catch (Exception ex) {
            throw new CompletionException(ex);
        }
    }, executorService());
    // Clear the cache. The source Read index is still registered in the Cache Manager - we want to ensure that any
    // eviction happening at this point will not delete anything from the Cache that we don't want deleted.
    unregisterCalled.await();
    context.cacheManager.applyCachePolicy();
    // Wait for the operation to complete.
    unregisterBlocker.release();
    completeMerge.get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
    // Verify that we can append (appending will modify the last cache entry; if it had been modified this would not
    // work anymore).
    val appendOffset = (int) targetMetadata.getLength();
    val appendData = new byte[appendLength];
    appendData[0] = (byte) 23;
    targetMetadata.setLength(appendOffset + appendLength);
    context.readIndex.append(targetId, appendOffset, new ByteArraySegment(appendData));
    // Issue a read and verify we can read everything that we wrote. If it had been evicted or erroneously deleted
    // from the cache this would result in an error.
    byte[] expectedData = new byte[appendOffset + appendLength];
    sourceContents.copyTo(expectedData, mergeOffset, sourceContents.getLength());
    System.arraycopy(appendData, 0, expectedData, appendOffset, appendLength);
    ReadResult rr = context.readIndex.read(targetId, 0, expectedData.length, TIMEOUT);
    Assert.assertTrue("Parent Segment read indicates no data available.", rr.hasNext());
    byte[] actualData = new byte[expectedData.length];
    rr.readRemaining(actualData, TIMEOUT);
    Assert.assertArrayEquals("Unexpected data read back.", expectedData, actualData);
}
Also used : lombok.val(lombok.val) Arrays(java.util.Arrays) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) SneakyThrows(lombok.SneakyThrows) AssertExtensions(io.pravega.test.common.AssertExtensions) ReadOnlyStorage(io.pravega.segmentstore.storage.ReadOnlyStorage) RequiredArgsConstructor(lombok.RequiredArgsConstructor) TimeoutException(java.util.concurrent.TimeoutException) Cleanup(lombok.Cleanup) Random(java.util.Random) UpdateableSegmentMetadata(io.pravega.segmentstore.server.UpdateableSegmentMetadata) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) ByteArrayInputStream(java.io.ByteArrayInputStream) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) BufferView(io.pravega.common.util.BufferView) Duration(java.time.Duration) Map(java.util.Map) CachePolicy(io.pravega.segmentstore.server.CachePolicy) TestCacheManager(io.pravega.segmentstore.server.TestCacheManager) CancellationException(java.util.concurrent.CancellationException) Collection(java.util.Collection) InMemoryStorage(io.pravega.segmentstore.storage.mocks.InMemoryStorage) CompletionException(java.util.concurrent.CompletionException) ReadResultEntryType(io.pravega.segmentstore.contracts.ReadResultEntryType) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) StreamSegmentMetadata(io.pravega.segmentstore.server.containers.StreamSegmentMetadata) List(java.util.List) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ThreadPooledTestSuite(io.pravega.test.common.ThreadPooledTestSuite) DirectMemoryCache(io.pravega.segmentstore.storage.cache.DirectMemoryCache) TestUtils(io.pravega.test.common.TestUtils) Futures(io.pravega.common.concurrent.Futures) ReadResult(io.pravega.segmentstore.contracts.ReadResult) TestStorage(io.pravega.segmentstore.server.TestStorage) ObjectClosedException(io.pravega.common.ObjectClosedException) MetadataBuilder(io.pravega.segmentstore.server.MetadataBuilder) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Getter(lombok.Getter) Exceptions(io.pravega.common.Exceptions) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference) CacheStorage(io.pravega.segmentstore.storage.cache.CacheStorage) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) EvictableMetadata(io.pravega.segmentstore.server.EvictableMetadata) UpdateableContainerMetadata(io.pravega.segmentstore.server.UpdateableContainerMetadata) SegmentMetadata(io.pravega.segmentstore.server.SegmentMetadata) CacheState(io.pravega.segmentstore.storage.cache.CacheState) ReadResultEntry(io.pravega.segmentstore.contracts.ReadResultEntry) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) BiConsumer(java.util.function.BiConsumer) Timeout(org.junit.rules.Timeout) ReusableLatch(io.pravega.common.util.ReusableLatch) StreamSegmentTruncatedException(io.pravega.segmentstore.contracts.StreamSegmentTruncatedException) NameUtils(io.pravega.shared.NameUtils) IntentionalException(io.pravega.test.common.IntentionalException) lombok.val(lombok.val) IOException(java.io.IOException) Test(org.junit.Test) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) AtomicLong(java.util.concurrent.atomic.AtomicLong) Mockito(org.mockito.Mockito) Rule(org.junit.Rule) Assert(org.junit.Assert) Collections(java.util.Collections) ByteArraySegment(io.pravega.common.util.ByteArraySegment) ReadResult(io.pravega.segmentstore.contracts.ReadResult) Cleanup(lombok.Cleanup) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) TimeoutException(java.util.concurrent.TimeoutException) StreamSegmentSealedException(io.pravega.segmentstore.contracts.StreamSegmentSealedException) CancellationException(java.util.concurrent.CancellationException) CompletionException(java.util.concurrent.CompletionException) ObjectClosedException(io.pravega.common.ObjectClosedException) StreamSegmentTruncatedException(io.pravega.segmentstore.contracts.StreamSegmentTruncatedException) IntentionalException(io.pravega.test.common.IntentionalException) IOException(java.io.IOException) CachePolicy(io.pravega.segmentstore.server.CachePolicy) ReusableLatch(io.pravega.common.util.ReusableLatch) ByteArrayInputStream(java.io.ByteArrayInputStream) CompletionException(java.util.concurrent.CompletionException) Test(org.junit.Test)

Example 18 with ReusableLatch

use of io.pravega.common.util.ReusableLatch in project pravega by pravega.

the class SegmentOutputStreamTest method testFlushIsBlockedUntilCallBackInvoked.

/**
 * This test ensures that the flush() on a segment is released only after sealed segment callback is invoked.
 * The callback implemented in EventStreamWriter appends this segment to its sealedSegmentQueue.
 */
@Test(timeout = 10000)
public void testFlushIsBlockedUntilCallBackInvoked() throws Exception {
    // Segment sealed callback will finish execution only when the latch is released;
    ReusableLatch latch = new ReusableLatch(false);
    final Consumer<Segment> segmentSealedCallback = segment -> Exceptions.handleInterrupted(() -> latch.await());
    UUID cid = UUID.randomUUID();
    PravegaNodeUri uri = new PravegaNodeUri("endpoint", SERVICE_PORT);
    MockConnectionFactoryImpl cf = new MockConnectionFactoryImpl();
    cf.setExecutor(executorService());
    MockController controller = new MockController(uri.getEndpoint(), uri.getPort(), cf, true);
    ClientConnection connection = mock(ClientConnection.class);
    cf.provideConnection(uri, connection);
    InOrder order = Mockito.inOrder(connection);
    @SuppressWarnings("resource") SegmentOutputStreamImpl output = new SegmentOutputStreamImpl(SEGMENT, true, controller, cf, cid, segmentSealedCallback, RETRY_SCHEDULE, DelegationTokenProviderFactory.createWithEmptyToken());
    output.reconnect();
    order.verify(connection).send(new SetupAppend(output.getRequestId(), cid, SEGMENT, ""));
    cf.getProcessor(uri).appendSetup(new AppendSetup(output.getRequestId(), SEGMENT, cid, 0));
    ByteBuffer data = getBuffer("test");
    CompletableFuture<Void> ack = new CompletableFuture<>();
    output.write(PendingEvent.withoutHeader(null, data, ack));
    order.verify(connection).send(new Append(SEGMENT, cid, 1, 1, Unpooled.wrappedBuffer(data), null, output.getRequestId()));
    assertEquals(false, ack.isDone());
    @Cleanup("shutdownNow") ScheduledExecutorService executor = ExecutorServiceHelpers.newScheduledThreadPool(1, "netty-callback");
    // simulate a SegmentIsSealed WireCommand from SegmentStore.
    executor.submit(() -> cf.getProcessor(uri).segmentIsSealed(new WireCommands.SegmentIsSealed(output.getRequestId(), SEGMENT, "SomeException", 1)));
    AssertExtensions.assertBlocks(() -> {
        AssertExtensions.assertThrows(SegmentSealedException.class, () -> output.flush());
    }, () -> latch.release());
    AssertExtensions.assertThrows(SegmentSealedException.class, () -> output.flush());
}
Also used : ArgumentMatchers(org.mockito.ArgumentMatchers) Retry(io.pravega.common.util.Retry) AssertExtensions(io.pravega.test.common.AssertExtensions) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Cleanup(lombok.Cleanup) ByteBuffer(java.nio.ByteBuffer) Unpooled(io.netty.buffer.Unpooled) Mockito.doThrow(org.mockito.Mockito.doThrow) MockController(io.pravega.client.stream.mock.MockController) ClientConnection(io.pravega.client.connection.impl.ClientConnection) Mockito.verifyNoMoreInteractions(org.mockito.Mockito.verifyNoMoreInteractions) AccessOperation(io.pravega.shared.security.auth.AccessOperation) Mockito.doAnswer(org.mockito.Mockito.doAnswer) PravegaNodeUri(io.pravega.shared.protocol.netty.PravegaNodeUri) Assert.fail(org.junit.Assert.fail) LeakDetectorTestSuite(io.pravega.test.common.LeakDetectorTestSuite) AppendSetup(io.pravega.shared.protocol.netty.WireCommands.AppendSetup) AssertExtensions.assertThrows(io.pravega.test.common.AssertExtensions.assertThrows) DelegationTokenProviderFactory(io.pravega.client.security.auth.DelegationTokenProviderFactory) UUID(java.util.UUID) RetriesExhaustedException(io.pravega.common.util.RetriesExhaustedException) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Assert.assertFalse(org.junit.Assert.assertFalse) Mockito.inOrder(org.mockito.Mockito.inOrder) Futures(io.pravega.common.concurrent.Futures) ReplyProcessor(io.pravega.shared.protocol.netty.ReplyProcessor) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) ConnectionFailedException(io.pravega.shared.protocol.netty.ConnectionFailedException) Exceptions(io.pravega.common.Exceptions) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Callable(java.util.concurrent.Callable) CompletableFuture(java.util.concurrent.CompletableFuture) Mockito.spy(org.mockito.Mockito.spy) PendingEvent(io.pravega.client.stream.impl.PendingEvent) Append(io.pravega.shared.protocol.netty.Append) Answer(org.mockito.stubbing.Answer) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ImmutableList(com.google.common.collect.ImmutableList) CompletedCallback(io.pravega.client.connection.impl.ClientConnection.CompletedCallback) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ReusableLatch(io.pravega.common.util.ReusableLatch) RetryWithBackoff(io.pravega.common.util.Retry.RetryWithBackoff) InOrder(org.mockito.InOrder) ConnectionPool(io.pravega.client.connection.impl.ConnectionPool) MockConnectionFactoryImpl(io.pravega.client.stream.mock.MockConnectionFactoryImpl) lombok.val(lombok.val) Assert.assertTrue(org.junit.Assert.assertTrue) IOException(java.io.IOException) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) WireCommands(io.pravega.shared.protocol.netty.WireCommands) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) Mockito(org.mockito.Mockito) Mockito.never(org.mockito.Mockito.never) InlineExecutor(io.pravega.test.common.InlineExecutor) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) Collections(java.util.Collections) Mockito.reset(org.mockito.Mockito.reset) Assert.assertEquals(org.junit.Assert.assertEquals) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) InOrder(org.mockito.InOrder) ByteBuffer(java.nio.ByteBuffer) Cleanup(lombok.Cleanup) AppendSetup(io.pravega.shared.protocol.netty.WireCommands.AppendSetup) CompletableFuture(java.util.concurrent.CompletableFuture) ReusableLatch(io.pravega.common.util.ReusableLatch) Append(io.pravega.shared.protocol.netty.Append) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) PravegaNodeUri(io.pravega.shared.protocol.netty.PravegaNodeUri) MockConnectionFactoryImpl(io.pravega.client.stream.mock.MockConnectionFactoryImpl) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) MockController(io.pravega.client.stream.mock.MockController) ClientConnection(io.pravega.client.connection.impl.ClientConnection) UUID(java.util.UUID) Test(org.junit.Test)

Example 19 with ReusableLatch

use of io.pravega.common.util.ReusableLatch in project pravega by pravega.

the class SegmentOutputStreamTest method testSegmentSealedFollowedbyConnectionDrop.

@Test(timeout = 10000)
public void testSegmentSealedFollowedbyConnectionDrop() throws Exception {
    @Cleanup("shutdownNow") ScheduledExecutorService executor = ExecutorServiceHelpers.newScheduledThreadPool(2, "netty-callback");
    // Segment sealed callback will finish execution only when the releaseCallbackLatch is released;
    ReusableLatch releaseCallbackLatch = new ReusableLatch(false);
    ReusableLatch callBackInvokedLatch = new ReusableLatch(false);
    final Consumer<Segment> segmentSealedCallback = segment -> Exceptions.handleInterrupted(() -> {
        callBackInvokedLatch.release();
        releaseCallbackLatch.await();
    });
    // Setup mocks.
    UUID cid = UUID.randomUUID();
    PravegaNodeUri uri = new PravegaNodeUri("endpoint", SERVICE_PORT);
    MockConnectionFactoryImpl cf = new MockConnectionFactoryImpl();
    cf.setExecutor(executorService());
    MockController controller = new MockController(uri.getEndpoint(), uri.getPort(), cf, true);
    // Mock client connection that is returned for every invocation of ConnectionFactory#establishConnection.
    ClientConnection connection = mock(ClientConnection.class);
    cf.provideConnection(uri, connection);
    InOrder order = Mockito.inOrder(connection);
    // Create a Segment writer.
    @SuppressWarnings("resource") SegmentOutputStreamImpl output = new SegmentOutputStreamImpl(SEGMENT, true, controller, cf, cid, segmentSealedCallback, RETRY_SCHEDULE, DelegationTokenProviderFactory.createWithEmptyToken());
    // trigger establishment of connection.
    output.reconnect();
    // Verify if SetupAppend is sent over the connection.
    order.verify(connection).send(new SetupAppend(output.getRequestId(), cid, SEGMENT, ""));
    cf.getProcessor(uri).appendSetup(new AppendSetup(output.getRequestId(), SEGMENT, cid, 0));
    // Write an event and ensure inflight has an event.
    ByteBuffer data = getBuffer("test");
    CompletableFuture<Void> ack = new CompletableFuture<>();
    output.write(PendingEvent.withoutHeader(null, data, ack));
    order.verify(connection).send(new Append(SEGMENT, cid, 1, 1, Unpooled.wrappedBuffer(data), null, output.getRequestId()));
    assertFalse(ack.isDone());
    // Simulate a SegmentIsSealed WireCommand from SegmentStore.
    executor.submit(() -> cf.getProcessor(uri).segmentIsSealed(new WireCommands.SegmentIsSealed(output.getRequestId(), SEGMENT, "SomeException", 1)));
    // Wait until callback invocation has been triggered, but has not completed.
    // If the callback is not invoked the test will fail due to a timeout.
    callBackInvokedLatch.await();
    // Now trigger a connection drop netty callback and wait until it is executed.
    executor.submit(() -> cf.getProcessor(uri).connectionDropped()).get();
    // close is invoked on the connection.
    order.verify(connection).close();
    // Verify no further reconnection attempts which involves sending of SetupAppend wire command.
    order.verifyNoMoreInteractions();
    // Release latch to ensure the callback is completed.
    releaseCallbackLatch.release();
    // Verify no further reconnection attempts which involves sending of SetupAppend wire command.
    order.verifyNoMoreInteractions();
    // Trigger a reconnect again and verify if any new connections are initiated.
    output.reconnect();
    // Reconnect operation will be executed on the executor service.
    ScheduledExecutorService service = executorService();
    service.shutdown();
    // Wait until all the tasks for reconnect have been completed.
    service.awaitTermination(10, TimeUnit.SECONDS);
    // Verify no further reconnection attempts which involves sending of SetupAppend wire command.
    order.verifyNoMoreInteractions();
}
Also used : ArgumentMatchers(org.mockito.ArgumentMatchers) Retry(io.pravega.common.util.Retry) AssertExtensions(io.pravega.test.common.AssertExtensions) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Cleanup(lombok.Cleanup) ByteBuffer(java.nio.ByteBuffer) Unpooled(io.netty.buffer.Unpooled) Mockito.doThrow(org.mockito.Mockito.doThrow) MockController(io.pravega.client.stream.mock.MockController) ClientConnection(io.pravega.client.connection.impl.ClientConnection) Mockito.verifyNoMoreInteractions(org.mockito.Mockito.verifyNoMoreInteractions) AccessOperation(io.pravega.shared.security.auth.AccessOperation) Mockito.doAnswer(org.mockito.Mockito.doAnswer) PravegaNodeUri(io.pravega.shared.protocol.netty.PravegaNodeUri) Assert.fail(org.junit.Assert.fail) LeakDetectorTestSuite(io.pravega.test.common.LeakDetectorTestSuite) AppendSetup(io.pravega.shared.protocol.netty.WireCommands.AppendSetup) AssertExtensions.assertThrows(io.pravega.test.common.AssertExtensions.assertThrows) DelegationTokenProviderFactory(io.pravega.client.security.auth.DelegationTokenProviderFactory) UUID(java.util.UUID) RetriesExhaustedException(io.pravega.common.util.RetriesExhaustedException) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Assert.assertFalse(org.junit.Assert.assertFalse) Mockito.inOrder(org.mockito.Mockito.inOrder) Futures(io.pravega.common.concurrent.Futures) ReplyProcessor(io.pravega.shared.protocol.netty.ReplyProcessor) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) ConnectionFailedException(io.pravega.shared.protocol.netty.ConnectionFailedException) Exceptions(io.pravega.common.Exceptions) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Callable(java.util.concurrent.Callable) CompletableFuture(java.util.concurrent.CompletableFuture) Mockito.spy(org.mockito.Mockito.spy) PendingEvent(io.pravega.client.stream.impl.PendingEvent) Append(io.pravega.shared.protocol.netty.Append) Answer(org.mockito.stubbing.Answer) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ImmutableList(com.google.common.collect.ImmutableList) CompletedCallback(io.pravega.client.connection.impl.ClientConnection.CompletedCallback) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ReusableLatch(io.pravega.common.util.ReusableLatch) RetryWithBackoff(io.pravega.common.util.Retry.RetryWithBackoff) InOrder(org.mockito.InOrder) ConnectionPool(io.pravega.client.connection.impl.ConnectionPool) MockConnectionFactoryImpl(io.pravega.client.stream.mock.MockConnectionFactoryImpl) lombok.val(lombok.val) Assert.assertTrue(org.junit.Assert.assertTrue) IOException(java.io.IOException) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) WireCommands(io.pravega.shared.protocol.netty.WireCommands) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) Mockito(org.mockito.Mockito) Mockito.never(org.mockito.Mockito.never) InlineExecutor(io.pravega.test.common.InlineExecutor) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) Collections(java.util.Collections) Mockito.reset(org.mockito.Mockito.reset) Assert.assertEquals(org.junit.Assert.assertEquals) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) InOrder(org.mockito.InOrder) Cleanup(lombok.Cleanup) ByteBuffer(java.nio.ByteBuffer) AppendSetup(io.pravega.shared.protocol.netty.WireCommands.AppendSetup) CompletableFuture(java.util.concurrent.CompletableFuture) ReusableLatch(io.pravega.common.util.ReusableLatch) Append(io.pravega.shared.protocol.netty.Append) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) PravegaNodeUri(io.pravega.shared.protocol.netty.PravegaNodeUri) MockConnectionFactoryImpl(io.pravega.client.stream.mock.MockConnectionFactoryImpl) SetupAppend(io.pravega.shared.protocol.netty.WireCommands.SetupAppend) MockController(io.pravega.client.stream.mock.MockController) ClientConnection(io.pravega.client.connection.impl.ClientConnection) UUID(java.util.UUID) Test(org.junit.Test)

Example 20 with ReusableLatch

use of io.pravega.common.util.ReusableLatch in project pravega by pravega.

the class ThreadPoolScheduledExecutorServiceTest method testShutdownNow.

@Test(timeout = 10000)
public void testShutdownNow() throws Exception {
    ThreadPoolScheduledExecutorService pool = createPool(1);
    AtomicInteger count = new AtomicInteger(0);
    ReusableLatch latch = new ReusableLatch(false);
    AtomicReference<Exception> error = new AtomicReference<>();
    pool.submit(() -> {
        count.incrementAndGet();
        try {
            latch.await();
        } catch (Exception e) {
            error.set(e);
        }
    });
    pool.submit(() -> count.incrementAndGet());
    assertFalse(pool.isShutdown());
    assertFalse(pool.isTerminated());
    AssertExtensions.assertEventuallyEquals(1, count::get, 5000);
    List<Runnable> remaining = pool.shutdownNow();
    assertEquals(1, remaining.size());
    assertTrue(pool.isShutdown());
    AssertExtensions.assertThrows(RejectedExecutionException.class, () -> pool.submit(() -> count.incrementAndGet()));
    // No need to call latch.release() because thread should be interupted
    assertTrue(pool.awaitTermination(5, SECONDS));
    assertTrue(pool.isTerminated());
    assertNotNull(error.get());
    assertEquals(InterruptedException.class, error.get().getClass());
    assertEquals(1, count.get());
}
Also used : ReusableLatch(io.pravega.common.util.ReusableLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicReference(java.util.concurrent.atomic.AtomicReference) CancellationException(java.util.concurrent.CancellationException) RejectedExecutionException(java.util.concurrent.RejectedExecutionException) Test(org.junit.Test)

Aggregations

ReusableLatch (io.pravega.common.util.ReusableLatch)30 Test (org.junit.Test)30 Cleanup (lombok.Cleanup)25 CompletableFuture (java.util.concurrent.CompletableFuture)14 AtomicReference (java.util.concurrent.atomic.AtomicReference)14 lombok.val (lombok.val)14 AssertExtensions (io.pravega.test.common.AssertExtensions)13 IntentionalException (io.pravega.test.common.IntentionalException)13 IOException (java.io.IOException)13 TimeUnit (java.util.concurrent.TimeUnit)13 Exceptions (io.pravega.common.Exceptions)12 ArrayList (java.util.ArrayList)12 ByteArraySegment (io.pravega.common.util.ByteArraySegment)11 ThreadPooledTestSuite (io.pravega.test.common.ThreadPooledTestSuite)11 Duration (java.time.Duration)11 HashMap (java.util.HashMap)11 CancellationException (java.util.concurrent.CancellationException)11 CompletionException (java.util.concurrent.CompletionException)11 Assert (org.junit.Assert)11 Futures (io.pravega.common.concurrent.Futures)10