Search in sources :

Example 11 with Revision

use of io.pravega.client.state.Revision in project pravega by pravega.

the class SynchronizerTest method testConcurrentFetchUpdatesAfterTruncation.

@Test(timeout = 20000)
@SuppressWarnings("unchecked")
public void testConcurrentFetchUpdatesAfterTruncation() {
    String streamName = "streamName";
    String scope = "scope";
    // Mock of the RevisionedStreamClient.
    RevisionedStreamClient<UpdateOrInit<RevisionedImpl>> revisionedStreamClient = mock(RevisionedStreamClient.class);
    final Segment segment = new Segment(scope, streamName, 0L);
    @Cleanup StateSynchronizerImpl<RevisionedImpl> syncA = new StateSynchronizerImpl<>(segment, revisionedStreamClient);
    Revision firstMark = new RevisionImpl(segment, 10L, 1);
    Revision secondMark = new RevisionImpl(segment, 20L, 2);
    final AbstractMap.SimpleImmutableEntry<Revision, UpdateOrInit<RevisionedImpl>> entry = new AbstractMap.SimpleImmutableEntry<>(secondMark, new UpdateOrInit<>(new RegularUpdate("x")));
    // Mock iterators to simulate concurrent revisionedStreamClient.readFrom(firstMark) call.
    Iterator<Entry<Revision, UpdateOrInit<RevisionedImpl>>> iterator1 = Collections.<Entry<Revision, UpdateOrInit<RevisionedImpl>>>singletonList(entry).iterator();
    Iterator<Entry<Revision, UpdateOrInit<RevisionedImpl>>> iterator2 = Collections.<Entry<Revision, UpdateOrInit<RevisionedImpl>>>singletonList(entry).iterator();
    // Latch to ensure both the thread encounter truncation exception.
    CountDownLatch truncationLatch = new CountDownLatch(2);
    // Latch to ensure both the threads invoke read attempt reading from same revision.
    // This will simulate the race condition where the in-memory state is newer than the state returned by RevisionedStreamClient.
    CountDownLatch raceLatch = new CountDownLatch(2);
    // Setup Mock
    when(revisionedStreamClient.getMark()).thenReturn(firstMark);
    when(revisionedStreamClient.readFrom(firstMark)).thenAnswer(invocation -> {
        truncationLatch.countDown();
        // wait until the other thread encounters the TruncationDataException.
        truncationLatch.await();
        throw new TruncatedDataException();
    }).thenAnswer(invocation -> {
        throw new TruncatedDataException();
    }).thenAnswer(invocation -> {
        truncationLatch.countDown();
        // wait until the other thread attempts to fetch updates from SSS post truncation and updates internal state.
        raceLatch.await();
        return iterator1;
    }).thenAnswer(invocation -> {
        raceLatch.countDown();
        return iterator2;
    });
    // Return an iterator whose hasNext is false.
    when(revisionedStreamClient.readFrom(secondMark)).thenAnswer(invocation -> {
        // release the waiting thread which is fetching updates from SSS when the internal state is already updated.
        raceLatch.countDown();
        return iterator2;
    });
    // Simulate concurrent invocations of fetchUpdates API.
    @Cleanup("shutdownNow") ScheduledExecutorService exec = ExecutorServiceHelpers.newScheduledThreadPool(2, "test-pool");
    CompletableFuture<Void> cf1 = CompletableFuture.supplyAsync(() -> {
        syncA.fetchUpdates();
        return null;
    }, exec);
    CompletableFuture<Void> cf2 = CompletableFuture.supplyAsync(() -> {
        syncA.fetchUpdates();
        return null;
    }, exec);
    // Wait until the completion of both the fetchUpdates() API.
    CompletableFuture.allOf(cf1, cf2).join();
    assertEquals("x", syncA.getState().getValue());
}
Also used : AssertExtensions(io.pravega.test.common.AssertExtensions) Cleanup(lombok.Cleanup) JavaSerializer(io.pravega.client.stream.impl.JavaSerializer) StreamConfiguration(io.pravega.client.stream.StreamConfiguration) StreamSegments(io.pravega.client.stream.impl.StreamSegments) ClientFactoryImpl(io.pravega.client.stream.impl.ClientFactoryImpl) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) URI(java.net.URI) InitialUpdate(io.pravega.client.state.InitialUpdate) MockSegmentStreamFactory(io.pravega.client.stream.mock.MockSegmentStreamFactory) Serializable(java.io.Serializable) CountDownLatch(java.util.concurrent.CountDownLatch) SetSynchronizer(io.pravega.client.state.examples.SetSynchronizer) Assert.assertFalse(org.junit.Assert.assertFalse) Entry(java.util.Map.Entry) SegmentAttribute(io.pravega.client.segment.impl.SegmentAttribute) Controller(io.pravega.client.control.impl.Controller) MockClientFactory(io.pravega.client.stream.mock.MockClientFactory) Mockito.mock(org.mockito.Mockito.mock) StateSynchronizer(io.pravega.client.state.StateSynchronizer) NotImplementedException(org.apache.commons.lang3.NotImplementedException) Segment(io.pravega.client.segment.impl.Segment) TruncatedDataException(io.pravega.client.stream.TruncatedDataException) CompletableFuture(java.util.concurrent.CompletableFuture) ConnectionPoolImpl(io.pravega.client.connection.impl.ConnectionPoolImpl) ByteArraySerializer(io.pravega.client.stream.impl.ByteArraySerializer) Update(io.pravega.client.state.Update) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) RevisionedStreamClient(io.pravega.client.state.RevisionedStreamClient) SynchronizerConfig(io.pravega.client.state.SynchronizerConfig) ReusableLatch(io.pravega.common.util.ReusableLatch) Iterator(java.util.Iterator) Assert.assertNotNull(org.junit.Assert.assertNotNull) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Mockito.when(org.mockito.Mockito.when) Revisioned(io.pravega.client.state.Revisioned) AtomicLong(java.util.concurrent.atomic.AtomicLong) AbstractMap(java.util.AbstractMap) Assert.assertNull(org.junit.Assert.assertNull) TreeMap(java.util.TreeMap) SynchronizerClientFactory(io.pravega.client.SynchronizerClientFactory) Data(lombok.Data) Revision(io.pravega.client.state.Revision) InvalidStreamException(io.pravega.client.stream.InvalidStreamException) ExecutorServiceHelpers(io.pravega.common.concurrent.ExecutorServiceHelpers) Collections(java.util.Collections) ScalingPolicy(io.pravega.client.stream.ScalingPolicy) Assert.assertEquals(org.junit.Assert.assertEquals) ClientConfig(io.pravega.client.ClientConfig) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) CountDownLatch(java.util.concurrent.CountDownLatch) Cleanup(lombok.Cleanup) Segment(io.pravega.client.segment.impl.Segment) AbstractMap(java.util.AbstractMap) Entry(java.util.Map.Entry) Revision(io.pravega.client.state.Revision) TruncatedDataException(io.pravega.client.stream.TruncatedDataException) Test(org.junit.Test)

Example 12 with Revision

use of io.pravega.client.state.Revision in project pravega by pravega.

the class StateSynchronizerImpl method fetchUpdates.

@Override
public void fetchUpdates() {
    Revision revision = getRevisionToReadFrom(true);
    log.trace("Fetching updates after {} ", revision);
    try {
        val iter = client.readFrom(revision);
        while (iter.hasNext()) {
            Entry<Revision, UpdateOrInit<StateT>> entry = iter.next();
            log.trace("Found entry {} ", entry.getValue());
            if (entry.getValue().isInit()) {
                InitialUpdate<StateT> init = entry.getValue().getInit();
                updateCurrentState(init.create(segment.getScopedStreamName(), entry.getKey()));
            } else {
                applyUpdates(entry.getKey().asImpl(), entry.getValue().getUpdates());
            }
        }
    } catch (TruncatedDataException e) {
        log.info("{} encountered truncation on segment {}, Details: {}", this, segment, e.getMessage());
        RETRY_INDEFINITELY.retryingOn(TruncatedDataException.class).throwingOn(RuntimeException.class).run(() -> handleTruncation());
    }
}
Also used : lombok.val(lombok.val) Revision(io.pravega.client.state.Revision) TruncatedDataException(io.pravega.client.stream.TruncatedDataException)

Example 13 with Revision

use of io.pravega.client.state.Revision in project pravega by pravega.

the class StateSynchronizerImpl method compact.

@Override
public void compact(Function<StateT, InitialUpdate<StateT>> compactor) {
    AtomicReference<Revision> compactedVersion = new AtomicReference<Revision>(null);
    conditionallyWrite(state -> {
        InitialUpdate<StateT> init = compactor.apply(state);
        if (init == null) {
            compactedVersion.set(null);
            return null;
        } else {
            compactedVersion.set(state.getRevision());
            return new UpdateOrInit<>(init);
        }
    });
    Revision newMark = compactedVersion.get();
    if (newMark != null) {
        Revision oldMark = client.getMark();
        if (oldMark == null || oldMark.compareTo(newMark) < 0) {
            client.compareAndSetMark(oldMark, newMark);
            log.info("Compacted state is written at {} the oldMark is {}", newMark, oldMark);
        }
        if (oldMark != null) {
            client.truncateToRevision(oldMark);
        }
    }
}
Also used : Revision(io.pravega.client.state.Revision) AtomicReference(java.util.concurrent.atomic.AtomicReference)

Example 14 with Revision

use of io.pravega.client.state.Revision in project pravega by pravega.

the class StateSynchronizerImpl method handleTruncation.

private Void handleTruncation() {
    Revision revision = getRevisionToReadFrom(false);
    log.info("{} encountered truncation, attempting to read from revision {}", this, revision);
    boolean foundInit = false;
    val iter = client.readFrom(revision);
    Revision currentRevision = null;
    while (!foundInit && iter.hasNext()) {
        Entry<Revision, UpdateOrInit<StateT>> entry = iter.next();
        currentRevision = entry.getKey();
        if (entry.getValue().isInit()) {
            log.trace("Found entry {} ", entry.getValue());
            InitialUpdate<StateT> init = entry.getValue().getInit();
            foundInit = true;
            updateCurrentState(init.create(segment.getScopedStreamName(), currentRevision));
        }
    }
    if (!foundInit) {
        throw new IllegalStateException(format("Data was truncated but there is no Init state after the truncation point. Last read revision is %s", currentRevision));
    }
    fetchUpdates();
    return null;
}
Also used : lombok.val(lombok.val) Revision(io.pravega.client.state.Revision)

Example 15 with Revision

use of io.pravega.client.state.Revision in project pravega by pravega.

the class SerializationTest method testUpdateDistanceToTail.

@Test
@SuppressWarnings("unchecked")
public void testUpdateDistanceToTail() throws Exception {
    UpdateDistanceToTailSerializer serializer = new UpdateDistanceToTail.UpdateDistanceToTailSerializer();
    UpdateDistanceToTail update = new UpdateDistanceToTail(createString(), r.nextLong(), createSegmentRangeMap());
    UpdateDistanceToTail deserialized = serializer.deserialize(serializer.serialize(update));
    assertEquals(deserialized, update);
    UpdateDistanceToTailSerializer oldSerializer = new UpdateDistanceToTailSerializer() {

        @Override
        protected void declareVersions() {
            version(0).revision(0, this::write00, this::read00);
        }
    };
    UpdateDistanceToTail oldStyleUpdate = serializer.deserialize(oldSerializer.serialize(update));
    assertEquals(update.getReaderId(), oldStyleUpdate.getReaderId());
    assertEquals(update.getDistanceToTail(), oldStyleUpdate.getDistanceToTail());
    assertEquals(null, oldStyleUpdate.getLastReadPositions());
    // Change the state to reflect the update
    val segmentToOffsets = ImmutableMap.of(new SegmentWithRange(new Segment("scope", "stream", 0), 0.0, 1.0), 0L);
    ReaderGroupState state = new ReaderGroupState("_RGTest", mock(Revision.class), mock(ReaderGroupConfig.class), segmentToOffsets, mock(Map.class), false);
    // ensure no exceptions are thrown.
    oldStyleUpdate.update(state);
}
Also used : UpdateDistanceToTailSerializer(io.pravega.client.stream.impl.ReaderGroupState.UpdateDistanceToTail.UpdateDistanceToTailSerializer) lombok.val(lombok.val) ReaderGroupConfig(io.pravega.client.stream.ReaderGroupConfig) Revision(io.pravega.client.state.Revision) UpdateDistanceToTail(io.pravega.client.stream.impl.ReaderGroupState.UpdateDistanceToTail) CompactReaderGroupState(io.pravega.client.stream.impl.ReaderGroupState.CompactReaderGroupState) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ByteArraySegment(io.pravega.common.util.ByteArraySegment) AcquireSegment(io.pravega.client.stream.impl.ReaderGroupState.AcquireSegment) ReleaseSegment(io.pravega.client.stream.impl.ReaderGroupState.ReleaseSegment) Segment(io.pravega.client.segment.impl.Segment) Test(org.junit.Test)

Aggregations

Revision (io.pravega.client.state.Revision)16 Test (org.junit.Test)10 Cleanup (lombok.Cleanup)9 ClientFactoryImpl (io.pravega.client.stream.impl.ClientFactoryImpl)7 Entry (java.util.Map.Entry)7 SynchronizerConfig (io.pravega.client.state.SynchronizerConfig)6 SynchronizerClientFactory (io.pravega.client.SynchronizerClientFactory)5 Segment (io.pravega.client.segment.impl.Segment)5 MockConnectionFactoryImpl (io.pravega.client.stream.mock.MockConnectionFactoryImpl)5 MockController (io.pravega.client.stream.mock.MockController)5 MockSegmentStreamFactory (io.pravega.client.stream.mock.MockSegmentStreamFactory)5 PravegaNodeUri (io.pravega.shared.protocol.netty.PravegaNodeUri)5 TruncatedDataException (io.pravega.client.stream.TruncatedDataException)3 lombok.val (lombok.val)3 ClientConfig (io.pravega.client.ClientConfig)2 Controller (io.pravega.client.control.impl.Controller)2 RevisionedStreamClient (io.pravega.client.state.RevisionedStreamClient)2 ScalingPolicy (io.pravega.client.stream.ScalingPolicy)2 StreamConfiguration (io.pravega.client.stream.StreamConfiguration)2 JavaSerializer (io.pravega.client.stream.impl.JavaSerializer)2