public WaitDetails waitUntilWaiting() throws TimeoutException { return waitUntilWaiting( details -> true ); }
private void assertBlock( Runnable runLock, Runnable runUnlock ) throws Exception { Future<Object> future = executor.execute( state -> { runLock.run(); return null; } ); executor.get().waitUntilWaiting( details -> details.isAt( GBPTreeLock.class, "doLock" ) ); runUnlock.run(); future.get(); }
private Future<Lock> tryToAcquireSameLockOnAnotherThread( Node resource, OtherThreadExecutor<Void> otherThread ) throws Exception { Future<Lock> future = otherThread.executeDontWait( acquireWriteLock( resource ) ); otherThread.waitUntilWaiting(); return future; }
private void assertThreadIsWaitingForLock( LockAcquisition lockAcquisition ) throws Exception { for ( int i = 0; i < 30 && !suite.isAwaitingLockAcquisition( lockAcquisition.executor.waitUntilWaiting() ); i++ ) { LockSupport.parkNanos( MILLISECONDS.toNanos( 100 ) ); } assertFalse( "locking thread completed", lockAcquisition.completed() ); }
@Test public void shouldMutexAccessBetweenInvalidateAndinstance() throws Exception { // GIVEN final CountDownLatch latch = new CountDownLatch( 1 ); final AtomicInteger initCalls = new AtomicInteger(); LazySingleReference<Integer> ref = new LazySingleReference<Integer>() { @Override protected Integer create() { awaitLatch( latch ); return initCalls.incrementAndGet(); } }; Future<Integer> t1Evaluate = t1.executeDontWait( evaluate( ref ) ); t1.waitUntilWaiting(); // WHEN Future<Void> t2Invalidate = t2.executeDontWait( invalidate( ref ) ); t2.waitUntilBlocked(); latch.countDown(); int e = t1Evaluate.get(); t2Invalidate.get(); // THEN assertEquals( "Evaluation", 1, e ); }
@Test public void shouldResumeWhenWritabilityChanged() throws Exception { TestThrottleLock lockOverride = new TestThrottleLock(); // given TransportThrottle throttle = newThrottleAndInstall( channel, lockOverride ); when( channel.isWritable() ).thenReturn( false ); Future<Void> completionFuture = otherThread.execute( state -> { throttle.acquire( channel ); return null; } ); otherThread.get().waitUntilWaiting(); // when when( channel.isWritable() ).thenReturn( true ); ArgumentCaptor<ChannelInboundHandler> captor = ArgumentCaptor.forClass( ChannelInboundHandler.class ); verify( channel.pipeline() ).addLast( captor.capture() ); captor.getValue().channelWritabilityChanged( context ); otherThread.get().awaitFuture( completionFuture ); assertThat( lockOverride.lockCallCount(), greaterThan( 0 ) ); assertThat( lockOverride.unlockCallCount(), is( 1 ) ); }
@Test public void shouldThrowThrottleExceptionWhenMaxDurationIsReached() throws Exception { // given TestThrottleLock lockOverride = new TestThrottleLock(); FakeClock clock = Clocks.fakeClock( 1, TimeUnit.SECONDS ); TransportThrottle throttle = newThrottleAndInstall( channel, lockOverride, clock, Duration.ofSeconds( 5 ) ); when( channel.isWritable() ).thenReturn( false ); // when Future<Void> future = otherThread.execute( state -> { throttle.acquire( channel ); return null; } ); otherThread.get().waitUntilWaiting(); clock.forward( 6, TimeUnit.SECONDS ); // expect try { future.get( 1, TimeUnit.MINUTES ); fail( "expecting ExecutionException" ); } catch ( ExecutionException ex ) { assertThat( ex.getCause(), instanceOf( TransportThrottleException.class ) ); assertThat( ex.getMessage(), containsString( "will be closed because the client did not consume outgoing buffers for" ) ); } }
@Test public void shouldOnlyAllowSingleThreadToInitialize() throws Exception { // GIVEN final CountDownLatch latch = new CountDownLatch( 1 ); final AtomicInteger initCalls = new AtomicInteger(); LazySingleReference<Integer> ref = new LazySingleReference<Integer>() { @Override protected Integer create() { awaitLatch( latch ); return initCalls.incrementAndGet(); } }; Future<Integer> t1Evaluate = t1.executeDontWait( evaluate( ref ) ); t1.waitUntilWaiting(); // WHEN Future<Integer> t2Evaluate = t2.executeDontWait( evaluate( ref ) ); t2.waitUntilBlocked(); latch.countDown(); int e1 = t1Evaluate.get(); int e2 = t2Evaluate.get(); // THEN assertEquals( "T1 evaluation", 1, e1 ); assertEquals( "T2 evaluation", 1, e2 ); }
return null; } ); while ( !closer.waitUntilWaiting().isAt( DynamicTaskExecutor.class, "close" ) )
@Test public void checkPointShouldBlockAnotherCheckPoint() throws Exception { // GIVEN try ( Resource lock = mutex.checkPoint() ) { // WHEN t2.execute( state -> mutex.checkPoint() ); // THEN t2.get().waitUntilWaiting( details -> details.isAt( StoreCopyCheckPointMutex.class, "checkPoint" ) ); } }
@Test( timeout = TEST_TIMEOUT ) public void unblockNewTransactionsFromWrongThreadThrows() throws Throwable { KernelTransactions kernelTransactions = newKernelTransactions(); kernelTransactions.blockNewTransactions(); Future<KernelTransaction> txOpener = t2.execute( state -> kernelTransactions.newInstance( explicit, AnonymousContext.write(), 0L ) ); t2.get().waitUntilWaiting( location -> location.isAt( KernelTransactions.class, "newInstance" ) ); assertNotDone( txOpener ); Future<?> wrongUnblocker = unblockTxsInSeparateThread( kernelTransactions ); try { wrongUnblocker.get(); } catch ( Exception e ) { assertThat( e, instanceOf( ExecutionException.class ) ); assertThat( e.getCause(), instanceOf( IllegalStateException.class ) ); } assertNotDone( txOpener ); kernelTransactions.unblockNewTransactions(); assertNotNull( txOpener.get() ); }
@Test public void checkPointShouldBlockStoreCopy() throws Exception { // GIVEN try ( Resource lock = mutex.checkPoint() ) { // WHEN t2.execute( state -> mutex.storeCopy( noop() ) ); // THEN t2.get().waitUntilWaiting( details -> details.isAt( StoreCopyCheckPointMutex.class, "storeCopy" ) ); } }
@Test( timeout = 10_000 ) public void shouldWaitForCompletionInHalt() throws Exception { // GIVEN PageCache pageCache = mock( PageCache.class ); Barrier.Control barrier = new Barrier.Control(); doAnswer( invocation -> { barrier.reached(); return null; } ).when( pageCache ).flushAndForce(); PageCacheFlusher flusher = new PageCacheFlusher( pageCache ); flusher.start(); // WHEN barrier.await(); Future<Object> halt = t2.execute( state -> { flusher.halt(); return null; } ); t2.get().waitUntilWaiting( details -> details.isAt( PageCacheFlusher.class, "halt" ) ); barrier.release(); // THEN halt call exits normally after (confirmed) ongoing flushAndForce call completed. halt.get(); }
@Test public void storeCopyShouldBlockCheckPoint() throws Exception { // GIVEN try ( Resource lock = mutex.storeCopy( noop() ) ) { // WHEN t2.execute( state -> mutex.checkPoint() ); // THEN t2.get().waitUntilWaiting( details -> details.isAt( StoreCopyCheckPointMutex.class, "checkPoint" ) ); } }
@Test public void shouldHaveOneThreadWaitForARemoval() throws Exception { // GIVEN IdOrderingQueue queue = new SynchronizedArrayIdOrderingQueue( 5 ); queue.offer( 3 ); queue.offer( 5 ); // WHEN another thread comes in and awaits 5 OtherThreadExecutor<Void> t2 = cleanup.add( new OtherThreadExecutor<Void>( "T2", null ) ); Future<Object> await5 = t2.executeDontWait( awaitHead( queue, 5 ) ); t2.waitUntilWaiting(); // ... and head (3) gets removed queue.removeChecked( 3 ); // THEN the other thread should be OK to continue await5.get(); }
@Test( timeout = TEST_TIMEOUT ) public void blockNewTransactions() throws Throwable { KernelTransactions kernelTransactions = newKernelTransactions(); kernelTransactions.blockNewTransactions(); Future<KernelTransaction> txOpener = t2.execute( state -> kernelTransactions.newInstance( explicit, AnonymousContext.write(), 0L ) ); t2.get().waitUntilWaiting( location -> location.isAt( KernelTransactions.class, "newInstance" ) ); assertNotDone( txOpener ); kernelTransactions.unblockNewTransactions(); assertNotNull( txOpener.get() ); }
@Test public void shouldApplyBackPressure() throws Exception { // given int backPressureThreshold = 10; BlockableMonitor monitor = new BlockableMonitor(); try ( OtherThreadExecutor<Void> t2 = new OtherThreadExecutor<>( "T2", null ); BadCollector badCollector = new BadCollector( NULL_OUTPUT_STREAM, UNLIMITED_TOLERANCE, COLLECT_ALL, backPressureThreshold, false, monitor ) ) { for ( int i = 0; i < backPressureThreshold; i++ ) { badCollector.collectDuplicateNode( i, i, "group" ); } // when Future<Object> enqueue = t2.executeDontWait( command( () -> badCollector.collectDuplicateNode( 999, 999, "group" ) ) ); t2.waitUntilWaiting( waitDetails -> waitDetails.isAt( BadCollector.class, "collect" ) ); monitor.unblock(); // then enqueue.get(); } }
return null; } ); t3.get().waitUntilWaiting( location -> location.isAt( DatabaseAvailability.class, "stop" ) ); barrier.release(); try
} ); secondTransactionExecutor.waitUntilWaiting( exclusiveLockWaitingPredicate() ); clockExecutor.execute( (OtherThreadExecutor.WorkerCommand<Void,Void>) state ->
} ); secondTransactionExecutor.waitUntilWaiting( sharedLockWaitingPredicate() ); clockExecutor.execute( (OtherThreadExecutor.WorkerCommand<Void,Void>) state ->