/** * Verify that registering a processing-time timer that is earlier than the existing timers * removes the one physical timer and creates one for the earlier timestamp {@link * ProcessingTimeService}. */ @Test public void testRegisterEarlierProcessingTimerMovesPhysicalProcessingTimer() throws Exception { @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable = mock(Triggerable.class); TestKeyContext keyContext = new TestKeyContext(); TestProcessingTimeService processingTimeService = new TestProcessingTimeService(); HeapInternalTimerService<Integer, String> timerService = createTimerService( mockTriggerable, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); int key = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); keyContext.setCurrentKey(key); timerService.registerProcessingTimeTimer("ciao", 20); assertEquals(1, timerService.numProcessingTimeTimers()); assertEquals(1, processingTimeService.getNumRegisteredTimers()); assertThat(processingTimeService.getRegisteredTimerTimestamps(), containsInAnyOrder(20L)); timerService.registerProcessingTimeTimer("ciao", 10); assertEquals(2, timerService.numProcessingTimeTimers()); assertEquals(1, processingTimeService.getNumRegisteredTimers()); assertThat(processingTimeService.getRegisteredTimerTimestamps(), containsInAnyOrder(10L)); }
@Test public void testRegisteringProcessingTimeTimerInOnProcessingTimeDoesNotLeakPhysicalTimers() throws Exception { @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable = mock(Triggerable.class); TestKeyContext keyContext = new TestKeyContext(); TestProcessingTimeService processingTimeService = new TestProcessingTimeService(); final HeapInternalTimerService<Integer, String> timerService = createTimerService( mockTriggerable, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); int key = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); keyContext.setCurrentKey(key); timerService.registerProcessingTimeTimer("ciao", 10); assertEquals(1, timerService.numProcessingTimeTimers()); assertEquals(1, processingTimeService.getNumRegisteredTimers()); assertThat(processingTimeService.getRegisteredTimerTimestamps(), containsInAnyOrder(10L)); doAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Exception { timerService.registerProcessingTimeTimer("ciao", 20); return null; } }) .when(mockTriggerable) .onProcessingTime(anyInternalTimer()); processingTimeService.setCurrentTime(10); assertEquals(1, processingTimeService.getNumRegisteredTimers()); assertThat(processingTimeService.getRegisteredTimerTimestamps(), containsInAnyOrder(20L)); doAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Exception { timerService.registerProcessingTimeTimer("ciao", 30); return null; } }) .when(mockTriggerable) .onProcessingTime(anyInternalTimer()); processingTimeService.setCurrentTime(20); assertEquals(1, timerService.numProcessingTimeTimers()); assertEquals(1, processingTimeService.getNumRegisteredTimers()); assertThat(processingTimeService.getRegisteredTimerTimestamps(), containsInAnyOrder(30L)); }
/** * This also verifies that we don't have leakage between keys/namespaces. * * <p>This also verifies that deleted timers don't fire. */ @Test public void testDeleteProcessingTimeTimers() throws Exception { @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable = mock(Triggerable.class); TestKeyContext keyContext = new TestKeyContext(); TestProcessingTimeService processingTimeService = new TestProcessingTimeService(); HeapInternalTimerService<Integer, String> timerService = createTimerService( mockTriggerable, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); // get two different keys int key1 = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); int key2 = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); while (key2 == key1) { key2 = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); } keyContext.setCurrentKey(key1); timerService.registerProcessingTimeTimer("ciao", 10); timerService.registerProcessingTimeTimer("hello", 10); keyContext.setCurrentKey(key2); timerService.registerProcessingTimeTimer("ciao", 10); timerService.registerProcessingTimeTimer("hello", 10); assertEquals(4, timerService.numProcessingTimeTimers()); assertEquals(2, timerService.numProcessingTimeTimers("hello")); assertEquals(2, timerService.numProcessingTimeTimers("ciao")); keyContext.setCurrentKey(key1); timerService.deleteProcessingTimeTimer("hello", 10); keyContext.setCurrentKey(key2); timerService.deleteProcessingTimeTimer("ciao", 10); assertEquals(2, timerService.numProcessingTimeTimers()); assertEquals(1, timerService.numProcessingTimeTimers("hello")); assertEquals(1, timerService.numProcessingTimeTimers("ciao")); processingTimeService.setCurrentTime(10); verify(mockTriggerable, times(2)).onProcessingTime(anyInternalTimer()); verify(mockTriggerable, times(1)).onProcessingTime(eq(new InternalTimer<>(10, key1, "ciao"))); verify(mockTriggerable, times(0)).onProcessingTime(eq(new InternalTimer<>(10, key1, "hello"))); verify(mockTriggerable, times(0)).onProcessingTime(eq(new InternalTimer<>(10, key2, "ciao"))); verify(mockTriggerable, times(1)).onProcessingTime(eq(new InternalTimer<>(10, key2, "hello"))); assertEquals(0, timerService.numEventTimeTimers()); }
@Test public void testCurrentProcessingTime() throws Exception { @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable = mock(Triggerable.class); TestKeyContext keyContext = new TestKeyContext(); TestProcessingTimeService processingTimeService = new TestProcessingTimeService(); HeapInternalTimerService<Integer, String> timerService = createTimerService( mockTriggerable, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); processingTimeService.setCurrentTime(17L); assertEquals(17, timerService.currentProcessingTime()); processingTimeService.setCurrentTime(42); assertEquals(42, timerService.currentProcessingTime()); }
/** * This test checks whether timers are assigned to correct key groups and whether snapshot/restore * respects key groups. */ @Test public void testSnapshotAndRebalancingRestore() throws Exception { @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable = mock(Triggerable.class); TestKeyContext keyContext = new TestKeyContext(); TestProcessingTimeService processingTimeService = new TestProcessingTimeService(); HeapInternalTimerService<Integer, String> timerService = createTimerService( mockTriggerable, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); int midpoint = testKeyGroupRange.getStartKeyGroup() + (testKeyGroupRange.getEndKeyGroup() - testKeyGroupRange.getStartKeyGroup()) / 2; // get two sub key-ranges so that we can restore two ranges separately KeyGroupRange subKeyGroupRange1 = new KeyGroupRange(testKeyGroupRange.getStartKeyGroup(), midpoint); KeyGroupRange subKeyGroupRange2 = new KeyGroupRange(midpoint + 1, testKeyGroupRange.getEndKeyGroup()); // get two different keys, one per sub range int key1 = getKeyInKeyGroupRange(subKeyGroupRange1, maxParallelism); int key2 = getKeyInKeyGroupRange(subKeyGroupRange2, maxParallelism); keyContext.setCurrentKey(key1); timerService.registerProcessingTimeTimer("ciao", 10); timerService.registerEventTimeTimer("hello", 10); keyContext.setCurrentKey(key2); timerService.registerEventTimeTimer("ciao", 10); timerService.registerProcessingTimeTimer("hello", 10); assertEquals(2, timerService.numProcessingTimeTimers()); assertEquals(1, timerService.numProcessingTimeTimers("hello")); assertEquals(1, timerService.numProcessingTimeTimers("ciao")); assertEquals(2, timerService.numEventTimeTimers()); assertEquals(1, timerService.numEventTimeTimers("hello")); assertEquals(1, timerService.numEventTimeTimers("ciao")); // one map per sub key-group range Map<Integer, byte[]> snapshot1 = new HashMap<>(); Map<Integer, byte[]> snapshot2 = new HashMap<>(); for (Integer keyGroupIndex : testKeyGroupRange) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); timerService.snapshotTimersForKeyGroup( new DataOutputViewStreamWrapper(outStream), keyGroupIndex); outStream.close(); if (subKeyGroupRange1.contains(keyGroupIndex)) { snapshot1.put(keyGroupIndex, outStream.toByteArray()); } else if (subKeyGroupRange2.contains(keyGroupIndex)) { snapshot2.put(keyGroupIndex, outStream.toByteArray()); } else { throw new IllegalStateException("Key-Group index doesn't belong to any sub range."); } } // from now on we need everything twice. once per sub key-group range @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable1 = mock(Triggerable.class); @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable2 = mock(Triggerable.class); TestKeyContext keyContext1 = new TestKeyContext(); TestKeyContext keyContext2 = new TestKeyContext(); TestProcessingTimeService processingTimeService1 = new TestProcessingTimeService(); TestProcessingTimeService processingTimeService2 = new TestProcessingTimeService(); HeapInternalTimerService<Integer, String> timerService1 = restoreTimerService( snapshot1, mockTriggerable1, keyContext1, processingTimeService1, subKeyGroupRange1, maxParallelism); HeapInternalTimerService<Integer, String> timerService2 = restoreTimerService( snapshot2, mockTriggerable2, keyContext2, processingTimeService2, subKeyGroupRange2, maxParallelism); processingTimeService1.setCurrentTime(10); timerService1.advanceWatermark(10); verify(mockTriggerable1, times(1)).onProcessingTime(anyInternalTimer()); verify(mockTriggerable1, times(1)).onProcessingTime(eq(new InternalTimer<>(10, key1, "ciao"))); verify(mockTriggerable1, never()).onProcessingTime(eq(new InternalTimer<>(10, key2, "hello"))); verify(mockTriggerable1, times(1)).onEventTime(anyInternalTimer()); verify(mockTriggerable1, times(1)).onEventTime(eq(new InternalTimer<>(10, key1, "hello"))); verify(mockTriggerable1, never()).onEventTime(eq(new InternalTimer<>(10, key2, "ciao"))); assertEquals(0, timerService1.numEventTimeTimers()); processingTimeService2.setCurrentTime(10); timerService2.advanceWatermark(10); verify(mockTriggerable2, times(1)).onProcessingTime(anyInternalTimer()); verify(mockTriggerable2, never()).onProcessingTime(eq(new InternalTimer<>(10, key1, "ciao"))); verify(mockTriggerable2, times(1)).onProcessingTime(eq(new InternalTimer<>(10, key2, "hello"))); verify(mockTriggerable2, times(1)).onEventTime(anyInternalTimer()); verify(mockTriggerable2, never()).onEventTime(eq(new InternalTimer<>(10, key1, "hello"))); verify(mockTriggerable2, times(1)).onEventTime(eq(new InternalTimer<>(10, key2, "ciao"))); assertEquals(0, timerService2.numEventTimeTimers()); }
@Test public void testSnapshotAndRestore() throws Exception { @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable = mock(Triggerable.class); TestKeyContext keyContext = new TestKeyContext(); TestProcessingTimeService processingTimeService = new TestProcessingTimeService(); HeapInternalTimerService<Integer, String> timerService = createTimerService( mockTriggerable, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); // get two different keys int key1 = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); int key2 = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); while (key2 == key1) { key2 = getKeyInKeyGroupRange(testKeyGroupRange, maxParallelism); } keyContext.setCurrentKey(key1); timerService.registerProcessingTimeTimer("ciao", 10); timerService.registerEventTimeTimer("hello", 10); keyContext.setCurrentKey(key2); timerService.registerEventTimeTimer("ciao", 10); timerService.registerProcessingTimeTimer("hello", 10); assertEquals(2, timerService.numProcessingTimeTimers()); assertEquals(1, timerService.numProcessingTimeTimers("hello")); assertEquals(1, timerService.numProcessingTimeTimers("ciao")); assertEquals(2, timerService.numEventTimeTimers()); assertEquals(1, timerService.numEventTimeTimers("hello")); assertEquals(1, timerService.numEventTimeTimers("ciao")); Map<Integer, byte[]> snapshot = new HashMap<>(); for (Integer keyGroupIndex : testKeyGroupRange) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); timerService.snapshotTimersForKeyGroup( new DataOutputViewStreamWrapper(outStream), keyGroupIndex); outStream.close(); snapshot.put(keyGroupIndex, outStream.toByteArray()); } @SuppressWarnings("unchecked") Triggerable<Integer, String> mockTriggerable2 = mock(Triggerable.class); keyContext = new TestKeyContext(); processingTimeService = new TestProcessingTimeService(); timerService = restoreTimerService( snapshot, mockTriggerable2, keyContext, processingTimeService, testKeyGroupRange, maxParallelism); processingTimeService.setCurrentTime(10); timerService.advanceWatermark(10); verify(mockTriggerable2, times(2)).onProcessingTime(anyInternalTimer()); verify(mockTriggerable2, times(1)).onProcessingTime(eq(new InternalTimer<>(10, key1, "ciao"))); verify(mockTriggerable2, times(1)).onProcessingTime(eq(new InternalTimer<>(10, key2, "hello"))); verify(mockTriggerable2, times(2)).onEventTime(anyInternalTimer()); verify(mockTriggerable2, times(1)).onEventTime(eq(new InternalTimer<>(10, key1, "hello"))); verify(mockTriggerable2, times(1)).onEventTime(eq(new InternalTimer<>(10, key2, "ciao"))); assertEquals(0, timerService.numEventTimeTimers()); }