@Override @SneakyThrows(Exception.class) public void close() { ReusableLatch waitSignal = null; synchronized (this.stateLock) { if (this.closed) { return; } this.closed = true; if (this.activeCount != 0 || !this.pendingItems.isEmpty()) { // Setup a latch that will be released when the last item completes. this.emptyNotifier = new ReusableLatch(false); waitSignal = this.emptyNotifier; } } if (waitSignal != null) { // We have unfinished items. Wait for them. waitSignal.await(CLOSE_TIMEOUT_MILLIS); } }
@Test(timeout = 5000) public void testAlreadyRelease() throws InterruptedException { ReusableLatch latch = new ReusableLatch(false); latch.release(); latch.await(); latch = new ReusableLatch(true); latch.await(); }
@Test public void endOfStreamNotifierTest() throws Exception { AtomicBoolean listenerInvoked = new AtomicBoolean(); ReusableLatch latch = new ReusableLatch(); when(state.isEndOfData()).thenReturn(false).thenReturn(true); when(sync.getState()).thenReturn(state); Listener<EndOfDataNotification> listener1 = notification -> { log.info("listener 1 invoked"); listenerInvoked.set(true); latch.release(); }; Listener<EndOfDataNotification> listener2 = notification -> { }; EndOfDataNotifier notifier = new EndOfDataNotifier(system, sync, executor); notifier.registerListener(listener1); verify(executor, times(1)).scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); latch.await(); verify(state, times(2)).isEndOfData(); assertTrue(listenerInvoked.get()); notifier.registerListener(listener2); verify(executor, times(1)).scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); notifier.unregisterAllListeners(); verify(system, times(1)).removeListeners(EndOfDataNotification.class.getSimpleName()); }
@Test(timeout = 5000) public void testRelease() { ReusableLatch latch = new ReusableLatch(false); AssertExtensions.assertBlocks(() -> latch.awaitUninterruptibly(), () -> latch.release()); }
invoked.put(segment1, new ReusableLatch()); invoked.put(segment2, new ReusableLatch()); waitOn.put(segment1, new ReusableLatch()); waitOn.put(segment2, new ReusableLatch());
invoked.put(createSegment1Key, new ReusableLatch()); invoked.put(createSegment2Key, new ReusableLatch()); invoked.put(concatKey, new ReusableLatch()); invoked.put(writeSegment1Key, new ReusableLatch()); invoked.put(writeSegment2Key, new ReusableLatch()); waitOn.put(createSegment1Key, new ReusableLatch()); waitOn.put(createSegment2Key, new ReusableLatch()); waitOn.put(concatKey, new ReusableLatch()); waitOn.put(writeSegment1Key, new ReusableLatch()); waitOn.put(writeSegment2Key, new ReusableLatch());
invoked.put(op1, new ReusableLatch()); invoked.put(op2, new ReusableLatch()); waitOn.put(op1, new ReusableLatch()); waitOn.put(op2, new ReusableLatch());
ReusableLatch firstStoreAppendInvoked = new ReusableLatch(); ReusableLatch completeFirstDataAppendedAck = new ReusableLatch(); ReusableLatch secondStoreAppendInvoked = new ReusableLatch(); @Cleanup("shutdownNow") ScheduledExecutorService nettyExecutor = ExecutorServiceHelpers.newScheduledThreadPool(1, "Netty-threadPool");
container1.stopSignal = new ReusableLatch(); // Manually control when the Container actually shuts down. container1.fail(new IntentionalException()); val startContainer2 = registry.startContainer(containerId, TIMEOUT); container2.stopSignal = new ReusableLatch(); // Manually control when the Container actually shuts down. container2.stopAsync(); val startContainer3 = registry.startContainer(containerId, TIMEOUT);
ReusableLatch latch = new ReusableLatch(false); final Consumer<Segment> segmentSealedCallback = segment -> Exceptions.handleInterrupted(() -> latch.await());
/** * Tests the ability to detect a container failure and unregister the container in case the container fails on startup. */ @Test public void testContainerFailureOnStartup() throws Exception { final int containerId = 123; // We insert a ReusableLatch that will allow us to manually delay the TestContainer's shutdown/closing process // so that we have enough time to verify that calling getContainer() on a currently shutting down container will // throw the appropriate exception. ReusableLatch closeReleaseSignal = new ReusableLatch(); TestContainerFactory factory = new TestContainerFactory(new IntentionalException(), closeReleaseSignal); @Cleanup StreamSegmentContainerRegistry registry = new StreamSegmentContainerRegistry(factory, executorService()); AssertExtensions.assertThrows( "Unexpected exception thrown upon failed container startup.", registry.startContainer(containerId, TIMEOUT)::join, ex -> ex instanceof IntentionalException || (ex instanceof IllegalStateException && ex.getCause() instanceof IntentionalException)); AssertExtensions.assertThrows( "Container is registered even if it failed to start (and is currently shut down).", () -> registry.getContainer(containerId), ex -> ex instanceof ContainerNotFoundException); // Unblock container closing, which will, in turn, unblock its de-registration. closeReleaseSignal.release(); AssertExtensions.assertThrows( "Container is registered even if it failed to start (and has been unregistered).", () -> registry.getContainer(containerId), ex -> ex instanceof ContainerNotFoundException); }