use of org.apache.flink.core.testutils.OneShotLatch in project flink by apache.
the class AsyncWaitOperatorTest method testClosingWithBlockedEmitter.
/**
* Test case for FLINK-5638: Tests that the async wait operator can be closed even if the
* emitter is currently waiting on the checkpoint lock (e.g. in the case of two chained async
* wait operators where the latter operator's queue is currently full).
*
* Note that this test does not enforce the exact strict ordering because with the fix it is no
* longer possible. However, it provokes the described situation without the fix.
*/
@Test(timeout = 10000L)
public void testClosingWithBlockedEmitter() throws Exception {
final Object lock = new Object();
ArgumentCaptor<Throwable> failureReason = ArgumentCaptor.forClass(Throwable.class);
Environment environment = mock(Environment.class);
when(environment.getMetricGroup()).thenReturn(new UnregisteredTaskMetricsGroup());
when(environment.getTaskManagerInfo()).thenReturn(new TestingTaskManagerRuntimeInfo());
when(environment.getUserClassLoader()).thenReturn(getClass().getClassLoader());
when(environment.getTaskInfo()).thenReturn(new TaskInfo("testTask", 1, 0, 1, 0));
doNothing().when(environment).failExternally(failureReason.capture());
StreamTask<?, ?> containingTask = mock(StreamTask.class);
when(containingTask.getEnvironment()).thenReturn(environment);
when(containingTask.getCheckpointLock()).thenReturn(lock);
when(containingTask.getProcessingTimeService()).thenReturn(new TestProcessingTimeService());
StreamConfig streamConfig = mock(StreamConfig.class);
doReturn(IntSerializer.INSTANCE).when(streamConfig).getTypeSerializerIn1(any(ClassLoader.class));
final OneShotLatch closingLatch = new OneShotLatch();
final OneShotLatch outputLatch = new OneShotLatch();
Output<StreamRecord<Integer>> output = mock(Output.class);
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
assertTrue("Output should happen under the checkpoint lock.", Thread.currentThread().holdsLock(lock));
outputLatch.trigger();
// wait until we're in the closing method of the operator
while (!closingLatch.isTriggered()) {
lock.wait();
}
return null;
}
}).when(output).collect(any(StreamRecord.class));
AsyncWaitOperator<Integer, Integer> operator = new TestAsyncWaitOperator<>(new MyAsyncFunction(), 1000L, 1, AsyncDataStream.OutputMode.ORDERED, closingLatch);
operator.setup(containingTask, streamConfig, output);
operator.open();
synchronized (lock) {
operator.processElement(new StreamRecord<>(42));
}
outputLatch.await();
synchronized (lock) {
operator.close();
}
// check that no concurrent exception has occurred
try {
verify(environment, never()).failExternally(any(Throwable.class));
} catch (Error e) {
// add the exception occurring in the emitter thread (root cause) as a suppressed
// exception
e.addSuppressed(failureReason.getValue());
throw e;
}
}
use of org.apache.flink.core.testutils.OneShotLatch in project flink by apache.
the class StreamTaskTest method testEmptySubtaskStateLeadsToStatelessAcknowledgment.
/**
* FLINK-5985
*
* This test ensures that empty snapshots (no op/keyed stated whatsoever) will be reported as stateless tasks. This
* happens by translating an empty {@link SubtaskState} into reporting 'null' to #acknowledgeCheckpoint.
*/
@Test
public void testEmptySubtaskStateLeadsToStatelessAcknowledgment() throws Exception {
final long checkpointId = 42L;
final long timestamp = 1L;
TaskInfo mockTaskInfo = mock(TaskInfo.class);
when(mockTaskInfo.getTaskNameWithSubtasks()).thenReturn("foobar");
when(mockTaskInfo.getIndexOfThisSubtask()).thenReturn(0);
Environment mockEnvironment = mock(Environment.class);
// latch blocks until the async checkpoint thread acknowledges
final OneShotLatch checkpointCompletedLatch = new OneShotLatch();
final List<SubtaskState> checkpointResult = new ArrayList<>(1);
// we remember what is acknowledged (expected to be null as our task will snapshot empty states).
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
SubtaskState subtaskState = invocationOnMock.getArgumentAt(2, SubtaskState.class);
checkpointResult.add(subtaskState);
checkpointCompletedLatch.trigger();
return null;
}
}).when(mockEnvironment).acknowledgeCheckpoint(anyLong(), any(CheckpointMetrics.class), any(SubtaskState.class));
when(mockEnvironment.getTaskInfo()).thenReturn(mockTaskInfo);
StreamTask<?, AbstractStreamOperator<?>> streamTask = mock(StreamTask.class, Mockito.CALLS_REAL_METHODS);
CheckpointMetaData checkpointMetaData = new CheckpointMetaData(checkpointId, timestamp);
streamTask.setEnvironment(mockEnvironment);
// mock the operators
StreamOperator<?> statelessOperator = mock(StreamOperator.class, withSettings().extraInterfaces(StreamCheckpointedOperator.class));
// mock the returned empty snapshot result (all state handles are null)
OperatorSnapshotResult statelessOperatorSnapshotResult = new OperatorSnapshotResult();
when(statelessOperator.snapshotState(anyLong(), anyLong(), any(CheckpointOptions.class))).thenReturn(statelessOperatorSnapshotResult);
// set up the task
StreamOperator<?>[] streamOperators = { statelessOperator };
OperatorChain<Void, AbstractStreamOperator<Void>> operatorChain = mock(OperatorChain.class);
when(operatorChain.getAllOperators()).thenReturn(streamOperators);
Whitebox.setInternalState(streamTask, "isRunning", true);
Whitebox.setInternalState(streamTask, "lock", new Object());
Whitebox.setInternalState(streamTask, "operatorChain", operatorChain);
Whitebox.setInternalState(streamTask, "cancelables", new CloseableRegistry());
Whitebox.setInternalState(streamTask, "configuration", new StreamConfig(new Configuration()));
Whitebox.setInternalState(streamTask, "asyncOperationsThreadPool", Executors.newCachedThreadPool());
streamTask.triggerCheckpoint(checkpointMetaData, CheckpointOptions.forFullCheckpoint());
checkpointCompletedLatch.await(30, TimeUnit.SECONDS);
streamTask.cancel();
// ensure that 'null' was acknowledged as subtask state
Assert.assertNull(checkpointResult.get(0));
}
use of org.apache.flink.core.testutils.OneShotLatch in project flink by apache.
the class StreamTaskTest method testAsyncCheckpointingConcurrentCloseAfterAcknowledge.
/**
* FLINK-5667
*
* Tests that a concurrent cancel operation does not discard the state handles of an
* acknowledged checkpoint. The situation can only happen if the cancel call is executed
* after Environment.acknowledgeCheckpoint() and before the
* CloseableRegistry.unregisterClosable() call.
*/
@Test
public void testAsyncCheckpointingConcurrentCloseAfterAcknowledge() throws Exception {
final long checkpointId = 42L;
final long timestamp = 1L;
final OneShotLatch acknowledgeCheckpointLatch = new OneShotLatch();
final OneShotLatch completeAcknowledge = new OneShotLatch();
TaskInfo mockTaskInfo = mock(TaskInfo.class);
when(mockTaskInfo.getTaskNameWithSubtasks()).thenReturn("foobar");
when(mockTaskInfo.getIndexOfThisSubtask()).thenReturn(0);
Environment mockEnvironment = mock(Environment.class);
when(mockEnvironment.getTaskInfo()).thenReturn(mockTaskInfo);
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
acknowledgeCheckpointLatch.trigger();
// block here so that we can issue the concurrent cancel call
completeAcknowledge.await();
return null;
}
}).when(mockEnvironment).acknowledgeCheckpoint(anyLong(), any(CheckpointMetrics.class), any(SubtaskState.class));
StreamTask<?, AbstractStreamOperator<?>> streamTask = mock(StreamTask.class, Mockito.CALLS_REAL_METHODS);
CheckpointMetaData checkpointMetaData = new CheckpointMetaData(checkpointId, timestamp);
streamTask.setEnvironment(mockEnvironment);
StreamOperator<?> streamOperator = mock(StreamOperator.class, withSettings().extraInterfaces(StreamCheckpointedOperator.class));
KeyGroupsStateHandle managedKeyedStateHandle = mock(KeyGroupsStateHandle.class);
KeyGroupsStateHandle rawKeyedStateHandle = mock(KeyGroupsStateHandle.class);
OperatorStateHandle managedOperatorStateHandle = mock(OperatorStateHandle.class);
OperatorStateHandle rawOperatorStateHandle = mock(OperatorStateHandle.class);
OperatorSnapshotResult operatorSnapshotResult = new OperatorSnapshotResult(new DoneFuture<>(managedKeyedStateHandle), new DoneFuture<>(rawKeyedStateHandle), new DoneFuture<>(managedOperatorStateHandle), new DoneFuture<>(rawOperatorStateHandle));
when(streamOperator.snapshotState(anyLong(), anyLong(), any(CheckpointOptions.class))).thenReturn(operatorSnapshotResult);
StreamOperator<?>[] streamOperators = { streamOperator };
OperatorChain<Void, AbstractStreamOperator<Void>> operatorChain = mock(OperatorChain.class);
when(operatorChain.getAllOperators()).thenReturn(streamOperators);
StreamStateHandle streamStateHandle = mock(StreamStateHandle.class);
CheckpointStreamFactory.CheckpointStateOutputStream outStream = mock(CheckpointStreamFactory.CheckpointStateOutputStream.class);
when(outStream.closeAndGetHandle()).thenReturn(streamStateHandle);
CheckpointStreamFactory mockStreamFactory = mock(CheckpointStreamFactory.class);
when(mockStreamFactory.createCheckpointStateOutputStream(anyLong(), anyLong())).thenReturn(outStream);
AbstractStateBackend mockStateBackend = mock(AbstractStateBackend.class);
when(mockStateBackend.createStreamFactory(any(JobID.class), anyString())).thenReturn(mockStreamFactory);
Whitebox.setInternalState(streamTask, "isRunning", true);
Whitebox.setInternalState(streamTask, "lock", new Object());
Whitebox.setInternalState(streamTask, "operatorChain", operatorChain);
Whitebox.setInternalState(streamTask, "cancelables", new CloseableRegistry());
Whitebox.setInternalState(streamTask, "asyncOperationsThreadPool", Executors.newFixedThreadPool(1));
Whitebox.setInternalState(streamTask, "configuration", new StreamConfig(new Configuration()));
Whitebox.setInternalState(streamTask, "stateBackend", mockStateBackend);
streamTask.triggerCheckpoint(checkpointMetaData, CheckpointOptions.forFullCheckpoint());
acknowledgeCheckpointLatch.await();
ArgumentCaptor<SubtaskState> subtaskStateCaptor = ArgumentCaptor.forClass(SubtaskState.class);
// check that the checkpoint has been completed
verify(mockEnvironment).acknowledgeCheckpoint(eq(checkpointId), any(CheckpointMetrics.class), subtaskStateCaptor.capture());
SubtaskState subtaskState = subtaskStateCaptor.getValue();
// check that the subtask state contains the expected state handles
assertEquals(managedKeyedStateHandle, subtaskState.getManagedKeyedState());
assertEquals(rawKeyedStateHandle, subtaskState.getRawKeyedState());
assertEquals(new ChainedStateHandle<>(Collections.singletonList(managedOperatorStateHandle)), subtaskState.getManagedOperatorState());
assertEquals(new ChainedStateHandle<>(Collections.singletonList(rawOperatorStateHandle)), subtaskState.getRawOperatorState());
// check that the state handles have not been discarded
verify(managedKeyedStateHandle, never()).discardState();
verify(rawKeyedStateHandle, never()).discardState();
verify(managedOperatorStateHandle, never()).discardState();
verify(rawOperatorStateHandle, never()).discardState();
streamTask.cancel();
completeAcknowledge.trigger();
// canceling the stream task after it has acknowledged the checkpoint should not discard
// the state handles
verify(managedKeyedStateHandle, never()).discardState();
verify(rawKeyedStateHandle, never()).discardState();
verify(managedOperatorStateHandle, never()).discardState();
verify(rawOperatorStateHandle, never()).discardState();
}
use of org.apache.flink.core.testutils.OneShotLatch in project flink by apache.
the class SystemProcessingTimeServiceTest method testQuiescing.
@Test
public void testQuiescing() throws Exception {
final Object lock = new Object();
final AtomicReference<Throwable> errorRef = new AtomicReference<>();
final SystemProcessingTimeService timer = new SystemProcessingTimeService(new ReferenceSettingExceptionHandler(errorRef), lock);
try {
final OneShotLatch latch = new OneShotLatch();
final ReentrantLock scopeLock = new ReentrantLock();
timer.registerTimer(System.currentTimeMillis() + 20, new ProcessingTimeCallback() {
@Override
public void onProcessingTime(long timestamp) throws Exception {
scopeLock.lock();
try {
latch.trigger();
// delay a bit before leaving the method
Thread.sleep(5);
} finally {
scopeLock.unlock();
}
}
});
// after the task triggered, shut the timer down cleanly, waiting for the task to finish
latch.await();
timer.quiesceAndAwaitPending();
// should be able to immediately acquire the lock, since the task must have exited by now
assertTrue(scopeLock.tryLock());
// should be able to schedule more tasks (that never get executed)
ScheduledFuture<?> future = timer.registerTimer(System.currentTimeMillis() - 5, new ProcessingTimeCallback() {
@Override
public void onProcessingTime(long timestamp) throws Exception {
throw new Exception("test");
}
});
assertNotNull(future);
// nothing should be scheduled right now
assertEquals(0, timer.getNumTasksScheduled());
// triggerable did, in fact, not trigger
if (errorRef.get() != null) {
throw new Exception(errorRef.get());
}
} finally {
timer.shutdownService();
}
}
use of org.apache.flink.core.testutils.OneShotLatch in project flink by apache.
the class ContinuousFileProcessingRescalingTest method testReaderScalingUp.
@Test
public void testReaderScalingUp() throws Exception {
// simulates the scenario of scaling up from 1 to 2 instances
final OneShotLatch waitingLatch1 = new OneShotLatch();
final OneShotLatch triggerLatch1 = new OneShotLatch();
BlockingFileInputFormat format1 = new BlockingFileInputFormat(triggerLatch1, waitingLatch1, new Path("test"), 20, 5);
FileInputSplit[] splits = format1.createInputSplits(2);
OneInputStreamOperatorTestHarness<TimestampedFileInputSplit, String> testHarness1 = getTestHarness(format1, 1, 0);
testHarness1.open();
testHarness1.processElement(new StreamRecord<>(getTimestampedSplit(0, splits[0])));
testHarness1.processElement(new StreamRecord<>(getTimestampedSplit(1, splits[1])));
// wait until its arrives to element 5
if (!triggerLatch1.isTriggered()) {
triggerLatch1.await();
}
// this will be the state shared by the 2 new instances.
OperatorStateHandles snapshot = testHarness1.snapshot(0, 0);
// 1) clear the output of instance so that we can compare it with one created by the new instances, and
// 2) let the operator process the rest of its state
testHarness1.getOutput().clear();
waitingLatch1.trigger();
// create the second instance and let it process the second split till element 15
final OneShotLatch triggerLatch2 = new OneShotLatch();
final OneShotLatch waitingLatch2 = new OneShotLatch();
BlockingFileInputFormat format2 = new BlockingFileInputFormat(triggerLatch2, waitingLatch2, new Path("test"), 20, 15);
OneInputStreamOperatorTestHarness<TimestampedFileInputSplit, String> testHarness2 = getTestHarness(format2, 2, 0);
testHarness2.setup();
testHarness2.initializeState(snapshot);
testHarness2.open();
BlockingFileInputFormat format3 = new BlockingFileInputFormat(triggerLatch2, waitingLatch2, new Path("test"), 20, 15);
OneInputStreamOperatorTestHarness<TimestampedFileInputSplit, String> testHarness3 = getTestHarness(format3, 2, 1);
testHarness3.setup();
testHarness3.initializeState(snapshot);
testHarness3.open();
triggerLatch2.trigger();
waitingLatch2.trigger();
// and wait for the processing to finish
synchronized (testHarness1.getCheckpointLock()) {
testHarness1.close();
}
synchronized (testHarness2.getCheckpointLock()) {
testHarness2.close();
}
synchronized (testHarness3.getCheckpointLock()) {
testHarness3.close();
}
Queue<Object> expectedResult = new ArrayDeque<>();
putElementsInQ(expectedResult, testHarness1.getOutput());
Queue<Object> actualResult = new ArrayDeque<>();
putElementsInQ(actualResult, testHarness2.getOutput());
putElementsInQ(actualResult, testHarness3.getOutput());
Assert.assertEquals(35, actualResult.size());
Assert.assertArrayEquals(expectedResult.toArray(), actualResult.toArray());
}
Aggregations