Search in sources :

Example 11 with Watermark

use of io.pravega.shared.watermarks.Watermark in project pravega by pravega.

the class WatermarkingTest method watermarkingTests.

@Test
public void watermarkingTests() throws Exception {
    final ClientConfig clientConfig = Utils.buildClientConfig(controllerURI);
    @Cleanup ConnectionFactory connectionFactory = new SocketConnectionFactoryImpl(clientConfig);
    ControllerImpl controller = new ControllerImpl(ControllerImplConfig.builder().clientConfig(clientConfig).build(), connectionFactory.getInternalExecutor());
    // create 2 writers
    @Cleanup EventStreamClientFactory clientFactory = EventStreamClientFactory.withScope(SCOPE, clientConfig);
    JavaSerializer<Long> javaSerializer = new JavaSerializer<>();
    @Cleanup EventStreamWriter<Long> writer1 = clientFactory.createEventWriter(STREAM, javaSerializer, EventWriterConfig.builder().build());
    @Cleanup EventStreamWriter<Long> writer2 = clientFactory.createEventWriter(STREAM, javaSerializer, EventWriterConfig.builder().build());
    AtomicBoolean stopFlag = new AtomicBoolean(false);
    // write events
    writeEvents(writer1, stopFlag);
    writeEvents(writer2, stopFlag);
    // scale the stream several times so that we get complex positions
    Stream streamObj = Stream.of(SCOPE, STREAM);
    scale(controller, streamObj);
    @Cleanup ClientFactoryImpl syncClientFactory = new ClientFactoryImpl(SCOPE, new ControllerImpl(ControllerImplConfig.builder().clientConfig(clientConfig).build(), connectionFactory.getInternalExecutor()), connectionFactory);
    String markStream = NameUtils.getMarkStreamForStream(STREAM);
    RevisionedStreamClient<Watermark> watermarkReader = syncClientFactory.createRevisionedStreamClient(markStream, new WatermarkSerializer(), SynchronizerConfig.builder().build());
    LinkedBlockingQueue<Watermark> watermarks = new LinkedBlockingQueue<>();
    fetchWatermarks(watermarkReader, watermarks, stopFlag);
    AssertExtensions.assertEventuallyEquals(true, () -> watermarks.size() >= 2, 100000);
    // scale down one controller instance.
    Futures.getAndHandleExceptions(controllerInstance.scaleService(1), ExecutionException::new);
    // wait until at least 2 more watermarks are emitted
    AssertExtensions.assertEventuallyEquals(true, () -> watermarks.size() >= 4, 100000);
    stopFlag.set(true);
    Watermark watermark0 = watermarks.take();
    Watermark watermark1 = watermarks.take();
    Watermark watermark2 = watermarks.take();
    Watermark watermark3 = watermarks.take();
    assertTrue(watermark0.getLowerTimeBound() <= watermark0.getUpperTimeBound());
    assertTrue(watermark1.getLowerTimeBound() <= watermark1.getUpperTimeBound());
    assertTrue(watermark2.getLowerTimeBound() <= watermark2.getUpperTimeBound());
    assertTrue(watermark3.getLowerTimeBound() <= watermark3.getUpperTimeBound());
    // verify that watermarks are increasing in time.
    assertTrue(watermark0.getLowerTimeBound() < watermark1.getLowerTimeBound());
    assertTrue(watermark1.getLowerTimeBound() < watermark2.getLowerTimeBound());
    assertTrue(watermark2.getLowerTimeBound() < watermark3.getLowerTimeBound());
    // use watermark as lower and upper bounds.
    Map<Segment, Long> positionMap0 = watermark0.getStreamCut().entrySet().stream().collect(Collectors.toMap(x -> new Segment(SCOPE, STREAM, x.getKey().getSegmentId()), Map.Entry::getValue));
    StreamCut streamCutStart = new StreamCutImpl(streamObj, positionMap0);
    Map<Stream, StreamCut> start = Collections.singletonMap(streamObj, streamCutStart);
    Map<Segment, Long> positionMap2 = watermark2.getStreamCut().entrySet().stream().collect(Collectors.toMap(x -> new Segment(SCOPE, STREAM, x.getKey().getSegmentId()), Map.Entry::getValue));
    StreamCut streamCutEnd = new StreamCutImpl(streamObj, positionMap2);
    Map<Stream, StreamCut> end = Collections.singletonMap(streamObj, streamCutEnd);
    @Cleanup ReaderGroupManager readerGroupManager = new ReaderGroupManagerImpl(SCOPE, controller, syncClientFactory);
    String readerGroup = "rg";
    readerGroupManager.createReaderGroup(readerGroup, ReaderGroupConfig.builder().stream(streamObj).startingStreamCuts(start).endingStreamCuts(end).build());
    // create reader on the stream
    @Cleanup final EventStreamReader<Long> reader = clientFactory.createReader("myreader", readerGroup, javaSerializer, ReaderConfig.builder().build());
    // read events from the reader.
    // verify that events read belong to the bound
    EventRead<Long> event = reader.readNextEvent(10000L);
    AtomicReference<TimeWindow> currentTimeWindow = new AtomicReference<>();
    AssertExtensions.assertEventuallyEquals(true, () -> {
        currentTimeWindow.set(reader.getCurrentTimeWindow(streamObj));
        return currentTimeWindow.get() != null && currentTimeWindow.get().getLowerTimeBound() != null && currentTimeWindow.get().getUpperTimeBound() != null;
    }, 100000);
    log.info("current time window = {}", currentTimeWindow.get());
    while (event.getEvent() != null) {
        Long time = event.getEvent();
        log.info("event read = {}", time);
        event.getPosition();
        assertTrue(time >= currentTimeWindow.get().getLowerTimeBound());
        event = reader.readNextEvent(10000L);
        if (event.isCheckpoint()) {
            event = reader.readNextEvent(10000L);
        }
    }
}
Also used : StreamCut(io.pravega.client.stream.StreamCut) EventStreamWriter(io.pravega.client.stream.EventStreamWriter) MarathonException(mesosphere.marathon.client.MarathonException) AssertExtensions(io.pravega.test.common.AssertExtensions) ReaderGroupManagerImpl(io.pravega.client.admin.impl.ReaderGroupManagerImpl) Cleanup(lombok.Cleanup) JavaSerializer(io.pravega.client.stream.impl.JavaSerializer) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) EventRead(io.pravega.client.stream.EventRead) Service(io.pravega.test.system.framework.services.Service) ClientFactoryImpl(io.pravega.client.stream.impl.ClientFactoryImpl) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ReaderGroupManager(io.pravega.client.admin.ReaderGroupManager) Stream(io.pravega.client.stream.Stream) Duration(java.time.Duration) Map(java.util.Map) After(org.junit.After) TimeWindow(io.pravega.client.stream.TimeWindow) URI(java.net.URI) ReaderGroupConfig(io.pravega.client.stream.ReaderGroupConfig) Environment(io.pravega.test.system.framework.Environment) WatermarkSerializer(io.pravega.client.watermark.WatermarkSerializer) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Collectors(java.util.stream.Collectors) ControllerImplConfig(io.pravega.client.control.impl.ControllerImplConfig) List(java.util.List) Slf4j(lombok.extern.slf4j.Slf4j) Controller(io.pravega.client.control.impl.Controller) Futures(io.pravega.common.concurrent.Futures) Segment(io.pravega.client.segment.impl.Segment) ConnectionFactory(io.pravega.client.connection.impl.ConnectionFactory) StreamManager(io.pravega.client.admin.StreamManager) RunWith(org.junit.runner.RunWith) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) StreamCutImpl(io.pravega.client.stream.impl.StreamCutImpl) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Timeout(org.junit.rules.Timeout) EventStreamClientFactory(io.pravega.client.EventStreamClientFactory) RevisionedStreamClient(io.pravega.client.state.RevisionedStreamClient) SynchronizerConfig(io.pravega.client.state.SynchronizerConfig) Utils(io.pravega.test.system.framework.Utils) SocketConnectionFactoryImpl(io.pravega.client.connection.impl.SocketConnectionFactoryImpl) Before(org.junit.Before) EventWriterConfig(io.pravega.client.stream.EventWriterConfig) NameUtils(io.pravega.shared.NameUtils) Iterator(java.util.Iterator) Assert.assertTrue(org.junit.Assert.assertTrue) EventStreamReader(io.pravega.client.stream.EventStreamReader) Test(org.junit.Test) Watermark(io.pravega.shared.watermarks.Watermark) ExecutionException(java.util.concurrent.ExecutionException) AtomicLong(java.util.concurrent.atomic.AtomicLong) Rule(org.junit.Rule) ControllerImpl(io.pravega.client.control.impl.ControllerImpl) Revision(io.pravega.client.state.Revision) ReaderConfig(io.pravega.client.stream.ReaderConfig) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) RandomFactory(io.pravega.common.hash.RandomFactory) Collections(java.util.Collections) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) SystemTestRunner(io.pravega.test.system.framework.SystemTestRunner) ClientConfig(io.pravega.client.ClientConfig) StreamCutImpl(io.pravega.client.stream.impl.StreamCutImpl) EventStreamClientFactory(io.pravega.client.EventStreamClientFactory) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Cleanup(lombok.Cleanup) JavaSerializer(io.pravega.client.stream.impl.JavaSerializer) Segment(io.pravega.client.segment.impl.Segment) ConnectionFactory(io.pravega.client.connection.impl.ConnectionFactory) ClientFactoryImpl(io.pravega.client.stream.impl.ClientFactoryImpl) Stream(io.pravega.client.stream.Stream) ClientConfig(io.pravega.client.ClientConfig) ExecutionException(java.util.concurrent.ExecutionException) ReaderGroupManagerImpl(io.pravega.client.admin.impl.ReaderGroupManagerImpl) ReaderGroupManager(io.pravega.client.admin.ReaderGroupManager) StreamCut(io.pravega.client.stream.StreamCut) ControllerImpl(io.pravega.client.control.impl.ControllerImpl) WatermarkSerializer(io.pravega.client.watermark.WatermarkSerializer) AtomicReference(java.util.concurrent.atomic.AtomicReference) SocketConnectionFactoryImpl(io.pravega.client.connection.impl.SocketConnectionFactoryImpl) TimeWindow(io.pravega.client.stream.TimeWindow) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicLong(java.util.concurrent.atomic.AtomicLong) Watermark(io.pravega.shared.watermarks.Watermark) Map(java.util.Map) HashMap(java.util.HashMap) Test(org.junit.Test)

Example 12 with Watermark

use of io.pravega.shared.watermarks.Watermark in project pravega by pravega.

the class EventStreamReaderTest method testTimeWindow.

@Test
public void testTimeWindow() throws SegmentSealedException {
    String scope = "scope";
    String streamName = "stream";
    Stream stream = Stream.of(scope, streamName);
    String groupName = "readerGroup";
    String readerGroupStream = NameUtils.getStreamForReaderGroup(groupName);
    String markStream = NameUtils.getMarkStreamForStream(streamName);
    // Create factories
    MockSegmentStreamFactory segmentStreamFactory = new MockSegmentStreamFactory();
    @Cleanup MockClientFactory clientFactory = new MockClientFactory(scope, segmentStreamFactory);
    MockController controller = (MockController) clientFactory.getController();
    @Cleanup InlineExecutor executor = new InlineExecutor();
    // Create streams
    controller.createScope(scope).join();
    controller.createStream(scope, streamName, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(2)).build());
    controller.createStream(scope, readerGroupStream, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(1)).build());
    // Reader group state synchronizer
    ReaderGroupConfig config = ReaderGroupConfig.builder().disableAutomaticCheckpoints().stream(stream).build();
    StateSynchronizer<ReaderGroupState> sync = clientFactory.createStateSynchronizer(readerGroupStream, new ReaderGroupStateUpdatesSerializer(), new ReaderGroupStateInitSerializer(), SynchronizerConfig.builder().build());
    // Watermark reader/writer
    @Cleanup RevisionedStreamClient<Watermark> markWriter = clientFactory.createRevisionedStreamClient(markStream, new WatermarkSerializer(), SynchronizerConfig.builder().build());
    @Cleanup WatermarkReaderImpl markReader = new WatermarkReaderImpl(stream, markWriter, executor);
    // Initialize reader group state
    Map<SegmentWithRange, Long> segments = ReaderGroupImpl.getSegmentsForStreams(controller, config);
    sync.initialize(new ReaderGroupState.ReaderGroupStateInit(config, segments, getEndSegmentsForStreams(config), false));
    // Data segment writers
    Segment segment1 = new Segment(scope, streamName, 0);
    Segment segment2 = new Segment(scope, streamName, 1);
    @Cleanup SegmentOutputStream stream1 = segmentStreamFactory.createOutputStreamForSegment(segment1, segmentSealedCallback, writerConfig, DelegationTokenProviderFactory.createWithEmptyToken());
    @Cleanup SegmentOutputStream stream2 = segmentStreamFactory.createOutputStreamForSegment(segment2, segmentSealedCallback, writerConfig, DelegationTokenProviderFactory.createWithEmptyToken());
    // Write stream data
    writeInt(stream1, 1);
    writeInt(stream2, 2);
    writeInt(stream2, 2);
    writeInt(stream2, 2);
    // Write mark data
    val r1 = new SegmentWithRange(segment1, 0, 0.5).convert();
    val r2 = new SegmentWithRange(segment2, 0.5, 1).convert();
    markWriter.writeUnconditionally(new Watermark(0L, 99L, ImmutableMap.of(r1, 0L, r2, 0L)));
    markWriter.writeUnconditionally(new Watermark(100L, 199L, ImmutableMap.of(r1, 12L, r2, 0L)));
    markWriter.writeUnconditionally(new Watermark(200L, 299L, ImmutableMap.of(r1, 12L, r2, 12L)));
    markWriter.writeUnconditionally(new Watermark(300L, 399L, ImmutableMap.of(r1, 12L, r2, 24L)));
    markWriter.writeUnconditionally(new Watermark(400L, 499L, ImmutableMap.of(r1, 12L, r2, 36L)));
    // Create reader
    AtomicLong clock = new AtomicLong();
    ReaderGroupStateManager groupState = new ReaderGroupStateManager(scope, groupName, "reader1", sync, controller, clock::get);
    groupState.initializeReader(0);
    @Cleanup EventStreamReaderImpl<byte[]> reader = new EventStreamReaderImpl<>(segmentStreamFactory, segmentStreamFactory, new ByteArraySerializer(), groupState, new Orderer(), clock::get, ReaderConfig.builder().build(), ImmutableMap.of(stream, markReader), Mockito.mock(Controller.class));
    clock.addAndGet(ReaderGroupStateManager.UPDATE_WINDOW.toNanos());
    EventRead<byte[]> event = reader.readNextEvent(100);
    assertEquals(2, readInt(event));
    TimeWindow timeWindow = reader.getCurrentTimeWindow(Stream.of(scope, streamName));
    assertEquals(0, timeWindow.getLowerTimeBound().longValue());
    assertEquals(199, timeWindow.getUpperTimeBound().longValue());
    clock.addAndGet(ReaderGroupStateManager.UPDATE_WINDOW.toNanos());
    event = reader.readNextEvent(100);
    assertEquals(1, readInt(event));
    timeWindow = reader.getCurrentTimeWindow(Stream.of(scope, streamName));
    assertEquals(0, timeWindow.getLowerTimeBound().longValue());
    assertEquals(299, timeWindow.getUpperTimeBound().longValue());
    clock.addAndGet(ReaderGroupStateManager.UPDATE_WINDOW.toNanos());
    event = reader.readNextEvent(100);
    assertEquals(2, readInt(event));
    timeWindow = reader.getCurrentTimeWindow(Stream.of(scope, streamName));
    assertEquals(200, timeWindow.getLowerTimeBound().longValue());
    assertEquals(399, timeWindow.getUpperTimeBound().longValue());
    clock.addAndGet(ReaderGroupStateManager.UPDATE_WINDOW.toNanos());
    event = reader.readNextEvent(100);
    assertEquals(2, readInt(event));
    timeWindow = reader.getCurrentTimeWindow(Stream.of(scope, streamName));
    assertEquals(300, timeWindow.getLowerTimeBound().longValue());
    assertEquals(499, timeWindow.getUpperTimeBound().longValue());
    clock.addAndGet(ReaderGroupStateManager.UPDATE_WINDOW.toNanos());
    event = reader.readNextEvent(100);
    assertEquals(null, event.getEvent());
    timeWindow = reader.getCurrentTimeWindow(Stream.of(scope, streamName));
    assertEquals(400, timeWindow.getLowerTimeBound().longValue());
    assertEquals(null, timeWindow.getUpperTimeBound());
}
Also used : ReaderGroupStateInitSerializer(io.pravega.client.admin.impl.ReaderGroupManagerImpl.ReaderGroupStateInitSerializer) Cleanup(lombok.Cleanup) MockClientFactory(io.pravega.client.stream.mock.MockClientFactory) Segment(io.pravega.client.segment.impl.Segment) InlineExecutor(io.pravega.test.common.InlineExecutor) SegmentOutputStream(io.pravega.client.segment.impl.SegmentOutputStream) Stream(io.pravega.client.stream.Stream) SegmentOutputStream(io.pravega.client.segment.impl.SegmentOutputStream) ReaderGroupConfig(io.pravega.client.stream.ReaderGroupConfig) lombok.val(lombok.val) MockSegmentStreamFactory(io.pravega.client.stream.mock.MockSegmentStreamFactory) WatermarkSerializer(io.pravega.client.watermark.WatermarkSerializer) MockController(io.pravega.client.stream.mock.MockController) Controller(io.pravega.client.control.impl.Controller) TimeWindow(io.pravega.client.stream.TimeWindow) ReaderGroupStateUpdatesSerializer(io.pravega.client.admin.impl.ReaderGroupManagerImpl.ReaderGroupStateUpdatesSerializer) AtomicLong(java.util.concurrent.atomic.AtomicLong) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) AtomicLong(java.util.concurrent.atomic.AtomicLong) MockController(io.pravega.client.stream.mock.MockController) Watermark(io.pravega.shared.watermarks.Watermark) Test(org.junit.Test)

Example 13 with Watermark

use of io.pravega.shared.watermarks.Watermark in project pravega by pravega.

the class WatermarkWorkflowTest method testRevisionedClientThrowsNoSuchSegmentException.

@Test(timeout = 30000L)
public void testRevisionedClientThrowsNoSuchSegmentException() {
    String scope = "scope";
    String streamName = "stream";
    StreamImpl stream = new StreamImpl(scope, streamName);
    String markStreamName = NameUtils.getMarkStreamForStream(streamName);
    SynchronizerClientFactory clientFactory = spy(SynchronizerClientFactory.class);
    ConcurrentHashMap<String, MockRevisionedStreamClient> revisionedStreamClientMap = new ConcurrentHashMap<>();
    doAnswer(x -> {
        String name = x.getArgument(0);
        return revisionedStreamClientMap.compute(name, (s, rsc) -> new MockRevisionedStreamClient(() -> streamMetadataStore.getActiveSegments(scope, name, null, executor).join().get(0).segmentId()));
    }).when(clientFactory).createRevisionedStreamClient(anyString(), any(), any());
    @Cleanup PeriodicWatermarking periodicWatermarking = new PeriodicWatermarking(streamMetadataStore, bucketStore, sp -> clientFactory, executor, new RequestTracker(false));
    streamMetadataStore.createScope(scope, null, executor).join();
    streamMetadataStore.createStream(scope, streamName, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(2)).timestampAggregationTimeout(10000L).build(), System.currentTimeMillis(), null, executor).join();
    streamMetadataStore.createStream(scope, markStreamName, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(1)).build(), System.currentTimeMillis(), null, executor).join();
    streamMetadataStore.setState(scope, markStreamName, State.ACTIVE, null, executor).join();
    streamMetadataStore.setState(scope, streamName, State.ACTIVE, null, executor).join();
    // 1. note writer1 marks
    // writer 1 reports segments 0, 1.
    String writer1 = "writer1";
    Map<Long, Long> map1 = ImmutableMap.of(0L, 100L, 1L, 100L);
    streamMetadataStore.noteWriterMark(scope, streamName, writer1, 100L, map1, null, executor).join();
    // 2. run watermarking workflow.
    periodicWatermarking.watermark(stream).join();
    assertTrue(periodicWatermarking.checkExistsInCache(stream));
    // verify that a watermark has been emitted.
    MockRevisionedStreamClient revisionedClient = revisionedStreamClientMap.get(markStreamName);
    assertEquals(revisionedClient.watermarks.size(), 1);
    Watermark watermark = revisionedClient.watermarks.get(0).getValue();
    assertEquals(watermark.getLowerTimeBound(), 100L);
    // delete and recreate stream and its mark stream
    streamMetadataStore.deleteStream(scope, markStreamName, null, executor).join();
    streamMetadataStore.deleteStream(scope, streamName, null, executor).join();
    streamMetadataStore.createStream(scope, streamName, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(2)).timestampAggregationTimeout(10000L).build(), System.currentTimeMillis(), null, executor).join();
    streamMetadataStore.setState(scope, streamName, State.ACTIVE, null, executor).join();
    streamMetadataStore.createStream(scope, markStreamName, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(1)).build(), System.currentTimeMillis(), null, executor).join();
    streamMetadataStore.setState(scope, markStreamName, State.ACTIVE, null, executor).join();
    // 1. note writer1 marks
    // writer 1 reports segments 0, 1.
    map1 = ImmutableMap.of(2L, 10L, 3L, 10L);
    streamMetadataStore.noteWriterMark(scope, streamName, writer1, 10L, map1, null, executor).join();
    // 2. run watermarking workflow. this should fail and revisioned stream client should be invalidated in the cache.
    periodicWatermarking.watermark(stream).join();
    assertFalse(periodicWatermarking.checkExistsInCache(stream));
    // 3. run watermarking workflow again.
    periodicWatermarking.watermark(stream).join();
    assertTrue(periodicWatermarking.checkExistsInCache(stream));
    // verify that a watermark has been emitted.
    revisionedClient = revisionedStreamClientMap.get(markStreamName);
    assertEquals(revisionedClient.segment, 1L);
    assertEquals(revisionedClient.watermarks.size(), 1);
    watermark = revisionedClient.watermarks.get(0).getValue();
    assertEquals(watermark.getLowerTimeBound(), 10L);
}
Also used : SynchronizerClientFactory(io.pravega.client.SynchronizerClientFactory) StreamImpl(io.pravega.client.stream.impl.StreamImpl) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) RequestTracker(io.pravega.common.tracing.RequestTracker) Cleanup(lombok.Cleanup) Watermark(io.pravega.shared.watermarks.Watermark) Test(org.junit.Test)

Example 14 with Watermark

use of io.pravega.shared.watermarks.Watermark in project pravega by pravega.

the class WatermarkWorkflowTest method testWriterTimeout.

@Test(timeout = 30000L)
public void testWriterTimeout() {
    SynchronizerClientFactory clientFactory = spy(SynchronizerClientFactory.class);
    ConcurrentHashMap<String, MockRevisionedStreamClient> revisionedStreamClientMap = new ConcurrentHashMap<>();
    doAnswer(x -> {
        String streamName = x.getArgument(0);
        return revisionedStreamClientMap.compute(streamName, (s, rsc) -> {
            if (rsc != null) {
                return rsc;
            } else {
                return new MockRevisionedStreamClient();
            }
        });
    }).when(clientFactory).createRevisionedStreamClient(anyString(), any(), any());
    StreamMetadataStore streamMetadataStoreSpied = spy(this.streamMetadataStore);
    BucketStore bucketStoreSpied = spy(this.bucketStore);
    @Cleanup PeriodicWatermarking periodicWatermarking = new PeriodicWatermarking(streamMetadataStoreSpied, bucketStoreSpied, sp -> clientFactory, executor, new RequestTracker(false));
    String streamName = "stream";
    String scope = "scope";
    streamMetadataStoreSpied.createScope(scope, null, executor).join();
    streamMetadataStoreSpied.createStream(scope, streamName, StreamConfiguration.builder().scalingPolicy(ScalingPolicy.fixed(3)).timestampAggregationTimeout(3000L).build(), System.currentTimeMillis(), null, executor).join();
    streamMetadataStoreSpied.setState(scope, streamName, State.ACTIVE, null, executor).join();
    // 2. note writer1, writer2, writer3 marks
    // writer 1 reports segments 0, 1.
    // writer 2 reports segments 1, 2,
    // writer 3 reports segment 0, 2
    String writer1 = "writer1";
    streamMetadataStoreSpied.noteWriterMark(scope, streamName, writer1, 102L, ImmutableMap.of(0L, 100L, 1L, 0L, 2L, 0L), null, executor).join();
    String writer2 = "writer2";
    streamMetadataStoreSpied.noteWriterMark(scope, streamName, writer2, 101L, ImmutableMap.of(0L, 0L, 1L, 100L, 2L, 0L), null, executor).join();
    String writer3 = "writer3";
    streamMetadataStoreSpied.noteWriterMark(scope, streamName, writer3, 100L, ImmutableMap.of(0L, 0L, 1L, 0L, 2L, 100L), null, executor).join();
    // 3. run watermarking workflow.
    StreamImpl stream = new StreamImpl(scope, streamName);
    periodicWatermarking.watermark(stream).join();
    // verify that a watermark has been emitted.
    MockRevisionedStreamClient revisionedClient = revisionedStreamClientMap.get(NameUtils.getMarkStreamForStream(streamName));
    assertEquals(revisionedClient.watermarks.size(), 1);
    // Don't report time from writer3
    streamMetadataStoreSpied.noteWriterMark(scope, streamName, writer1, 200L, ImmutableMap.of(0L, 200L, 1L, 0L, 2L, 0L), null, executor).join();
    streamMetadataStoreSpied.noteWriterMark(scope, streamName, writer2, 200L, ImmutableMap.of(0L, 0L, 1L, 200L, 2L, 0L), null, executor).join();
    // no new watermark should be emitted, writers should be tracked for inactivity
    periodicWatermarking.watermark(stream).join();
    assertEquals(revisionedClient.watermarks.size(), 1);
    verify(streamMetadataStoreSpied, never()).removeWriter(anyString(), anyString(), anyString(), any(), any(), any());
    verify(bucketStoreSpied, never()).removeStreamFromBucketStore(any(), anyString(), anyString(), any());
    // call again. Still no new watermark should be emitted as writers have not timed out
    periodicWatermarking.watermark(stream).join();
    assertEquals(revisionedClient.watermarks.size(), 1);
    verify(streamMetadataStoreSpied, never()).removeWriter(anyString(), anyString(), anyString(), any(), any(), any());
    verify(bucketStoreSpied, never()).removeStreamFromBucketStore(any(), anyString(), anyString(), any());
    // call watermark after a delay of 5 more seconds. The writer3 should timeout because it has a timeout of 3 seconds.
    Futures.delayedFuture(() -> periodicWatermarking.watermark(stream), 5000L, executor).join();
    verify(streamMetadataStoreSpied, times(1)).removeWriter(anyString(), anyString(), anyString(), any(), any(), any());
    verify(bucketStoreSpied, never()).removeStreamFromBucketStore(any(), anyString(), anyString(), any());
    // watermark should be emitted. without considering writer3
    assertEquals(revisionedClient.watermarks.size(), 2);
    Watermark watermark = revisionedClient.watermarks.get(1).getValue();
    assertEquals(watermark.getLowerTimeBound(), 200L);
    assertEquals(watermark.getStreamCut().size(), 3);
    assertEquals(getSegmentOffset(watermark, 0L), 200L);
    assertEquals(getSegmentOffset(watermark, 1L), 200L);
    assertEquals(getSegmentOffset(watermark, 2L), 100L);
    // call watermark workflow again so that both writers are tracked for inactivity
    periodicWatermarking.watermark(stream).join();
    assertEquals(revisionedClient.watermarks.size(), 2);
    verify(streamMetadataStoreSpied, times(1)).removeWriter(anyString(), anyString(), anyString(), any(), any(), any());
    verify(bucketStoreSpied, never()).removeStreamFromBucketStore(any(), anyString(), anyString(), any());
    // now introduce more delays and see all writers are removed and stream is discontinued from watermarking computation.
    Futures.delayedFuture(() -> periodicWatermarking.watermark(stream), 5000L, executor).join();
    // verify that stream is discontinued from tracking for watermarking
    verify(streamMetadataStoreSpied, times(3)).removeWriter(anyString(), anyString(), anyString(), any(), any(), any());
    verify(bucketStoreSpied, times(1)).removeStreamFromBucketStore(any(), anyString(), anyString(), any());
    // call note time for writer3 and verify that watermark is emitted.
    streamMetadataStoreSpied.noteWriterMark(scope, streamName, writer3, 300L, ImmutableMap.of(0L, 300L, 1L, 0L, 2L, 0L), null, executor).join();
    periodicWatermarking.watermark(stream).join();
    assertEquals(revisionedClient.watermarks.size(), 3);
    watermark = revisionedClient.watermarks.get(2).getValue();
    assertEquals(watermark.getLowerTimeBound(), 300L);
    assertEquals(watermark.getStreamCut().size(), 3);
    assertEquals(getSegmentOffset(watermark, 0L), 300L);
    assertEquals(getSegmentOffset(watermark, 1L), 200L);
    assertEquals(getSegmentOffset(watermark, 2L), 100L);
}
Also used : SynchronizerClientFactory(io.pravega.client.SynchronizerClientFactory) StreamImpl(io.pravega.client.stream.impl.StreamImpl) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) StreamMetadataStore(io.pravega.controller.store.stream.StreamMetadataStore) BucketStore(io.pravega.controller.store.stream.BucketStore) RequestTracker(io.pravega.common.tracing.RequestTracker) Cleanup(lombok.Cleanup) Watermark(io.pravega.shared.watermarks.Watermark) Test(org.junit.Test)

Example 15 with Watermark

use of io.pravega.shared.watermarks.Watermark in project pravega by pravega.

the class PeriodicWatermarking method watermark.

/**
 * This method computes and emits a new watermark for the given stream.
 * It collects all the known writers for the given stream and includes only writers that are active (have reported
 * their marks recently). If all active writers have reported marks greater than the previously emitted watermark,
 * then new watermark is computed and emitted. If not, the window for considering writers as active is progressed.
 * @param stream stream for which watermark should be computed.
 * @return Returns a completableFuture which when completed will have completed another iteration of periodic watermark
 * computation.
 */
public CompletableFuture<Void> watermark(Stream stream) {
    String scope = stream.getScope();
    String streamName = stream.getStreamName();
    long requestId = requestIdGenerator.get();
    String requestDescriptor = RequestTracker.buildRequestDescriptor("watermark", stream.getScope(), stream.getStreamName());
    requestTracker.trackRequest(requestDescriptor, requestId);
    OperationContext context = streamMetadataStore.createStreamContext(scope, streamName, requestId);
    if (scope.equals(NameUtils.INTERNAL_SCOPE_NAME)) {
        return CompletableFuture.completedFuture(null);
    }
    log.debug(requestId, "Periodic background processing for watermarking called for stream {}/{}", scope, streamName);
    CompletableFuture<Map<String, WriterMark>> allWriterMarks = Futures.exceptionallyExpecting(streamMetadataStore.getAllWriterMarks(scope, streamName, context, executor), e -> Exceptions.unwrap(e) instanceof StoreException.DataNotFoundException, Collections.emptyMap());
    return allWriterMarks.thenCompose(writers -> {
        WatermarkClient watermarkClient = watermarkClientCache.getUnchecked(stream);
        try {
            watermarkClient.reinitialize();
        } catch (Exception e) {
            log.warn(requestId, "Watermarking client for stream {} threw exception {} during reinitialize.", stream, Exceptions.unwrap(e).getClass());
            if (Exceptions.unwrap(e) instanceof NoSuchSegmentException) {
                log.info(requestId, "Invalidating the watermark client in cache for stream {}.", stream);
                watermarkClientCache.invalidate(stream);
            }
            throw e;
        }
        return streamMetadataStore.getConfiguration(scope, streamName, context, executor).thenCompose(config -> filterWritersAndComputeWatermark(scope, streamName, context, watermarkClient, writers, config));
    }).exceptionally(e -> {
        log.warn(requestId, "Exception thrown while trying to perform periodic watermark computation. Logging and ignoring.", e);
        return null;
    });
}
Also used : OperationContext(io.pravega.controller.store.stream.OperationContext) LoadingCache(com.google.common.cache.LoadingCache) StreamSegmentRecord(io.pravega.controller.store.stream.records.StreamSegmentRecord) LoggerFactory(org.slf4j.LoggerFactory) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) ParametersAreNonnullByDefault(javax.annotation.ParametersAreNonnullByDefault) TagLogger(io.pravega.common.tracing.TagLogger) StoreException(io.pravega.controller.store.stream.StoreException) Stream(io.pravega.client.stream.Stream) Map(java.util.Map) SegmentWithRange(io.pravega.shared.watermarks.SegmentWithRange) Synchronized(lombok.Synchronized) WatermarkSerializer(io.pravega.client.watermark.WatermarkSerializer) ImmutableMap(com.google.common.collect.ImmutableMap) NoSuchSegmentException(io.pravega.client.segment.impl.NoSuchSegmentException) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) RequestTracker(io.pravega.common.tracing.RequestTracker) Collectors(java.util.stream.Collectors) CacheLoader(com.google.common.cache.CacheLoader) List(java.util.List) CompletionStage(java.util.concurrent.CompletionStage) Entry(java.util.Map.Entry) CacheBuilder(com.google.common.cache.CacheBuilder) StreamMetadataStore(io.pravega.controller.store.stream.StreamMetadataStore) Futures(io.pravega.common.concurrent.Futures) OperationContext(io.pravega.controller.store.stream.OperationContext) Exceptions(io.pravega.common.Exceptions) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) BucketStore(io.pravega.controller.store.stream.BucketStore) Lists(com.google.common.collect.Lists) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) RevisionedStreamClient(io.pravega.client.state.RevisionedStreamClient) SynchronizerConfig(io.pravega.client.state.SynchronizerConfig) LongSummaryStatistics(java.util.LongSummaryStatistics) NameUtils(io.pravega.shared.NameUtils) WriterMark(io.pravega.controller.store.stream.records.WriterMark) Watermark(io.pravega.shared.watermarks.Watermark) TimeUnit(java.util.concurrent.TimeUnit) EpochRecord(io.pravega.controller.store.stream.records.EpochRecord) SynchronizerClientFactory(io.pravega.client.SynchronizerClientFactory) Closeable(java.io.Closeable) Revision(io.pravega.client.state.Revision) RemovalListener(com.google.common.cache.RemovalListener) VisibleForTesting(com.google.common.annotations.VisibleForTesting) RandomFactory(io.pravega.common.hash.RandomFactory) Comparator(java.util.Comparator) Collections(java.util.Collections) ClientConfig(io.pravega.client.ClientConfig) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) StoreException(io.pravega.controller.store.stream.StoreException) NoSuchSegmentException(io.pravega.client.segment.impl.NoSuchSegmentException) StoreException(io.pravega.controller.store.stream.StoreException) NoSuchSegmentException(io.pravega.client.segment.impl.NoSuchSegmentException)

Aggregations

Watermark (io.pravega.shared.watermarks.Watermark)20 Test (org.junit.Test)16 Cleanup (lombok.Cleanup)15 Stream (io.pravega.client.stream.Stream)14 SynchronizerClientFactory (io.pravega.client.SynchronizerClientFactory)13 WatermarkSerializer (io.pravega.client.watermark.WatermarkSerializer)13 StreamConfiguration (io.pravega.client.stream.StreamConfiguration)12 ClientConfig (io.pravega.client.ClientConfig)10 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)10 Segment (io.pravega.client.segment.impl.Segment)9 Revision (io.pravega.client.state.Revision)9 RevisionedStreamClient (io.pravega.client.state.RevisionedStreamClient)9 SynchronizerConfig (io.pravega.client.state.SynchronizerConfig)9 NameUtils (io.pravega.shared.NameUtils)9 Collections (java.util.Collections)9 Futures (io.pravega.common.concurrent.Futures)8 Controller (io.pravega.client.control.impl.Controller)7 Map (java.util.Map)7 HashMap (java.util.HashMap)6 LinkedBlockingQueue (java.util.concurrent.LinkedBlockingQueue)6