io.pravega.client.state.impl.SynchronizerTest.java Source code

Java tutorial

Introduction

Here is the source code for io.pravega.client.state.impl.SynchronizerTest.java

Source

/**
 * Copyright (c) 2017 Dell Inc., or its subsidiaries. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 */
package io.pravega.client.state.impl;

import io.pravega.client.segment.impl.EndOfSegmentException;
import io.pravega.client.segment.impl.Segment;
import io.pravega.client.segment.impl.SegmentAttribute;
import io.pravega.client.state.InitialUpdate;
import io.pravega.client.state.Revision;
import io.pravega.client.state.Revisioned;
import io.pravega.client.state.RevisionedStreamClient;
import io.pravega.client.state.StateSynchronizer;
import io.pravega.client.state.SynchronizerConfig;
import io.pravega.client.state.Update;
import io.pravega.client.state.examples.SetSynchronizer;
import io.pravega.client.stream.impl.ByteArraySerializer;
import io.pravega.client.stream.impl.JavaSerializer;
import io.pravega.client.stream.mock.MockClientFactory;
import io.pravega.client.stream.mock.MockSegmentStreamFactory;
import io.pravega.common.util.ReusableLatch;
import io.pravega.test.common.Async;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import lombok.Cleanup;
import lombok.Data;
import org.apache.commons.lang.NotImplementedException;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class SynchronizerTest {

    @Data
    private static class RevisionedImpl implements Revisioned {
        private final String scopedStreamName;
        private final Revision revision;
    }

    @Data
    private static class RegularUpdate
            implements Update<RevisionedImpl>, InitialUpdate<RevisionedImpl>, Serializable {
        @Override
        public RevisionedImpl create(String scopedStreamName, Revision revision) {
            return new RevisionedImpl(scopedStreamName, revision);
        }

        @Override
        public RevisionedImpl applyTo(RevisionedImpl oldState, Revision newRevision) {
            return new RevisionedImpl(oldState.getScopedStreamName(), newRevision);
        }
    }

    @Data
    private static class BlockingUpdate implements Update<RevisionedImpl>, InitialUpdate<RevisionedImpl> {
        private final ReusableLatch latch = new ReusableLatch(false);
        private final int num;

        @Override
        public RevisionedImpl create(String scopedSteamName, Revision revision) {
            latch.awaitUninterruptibly();
            return new RevisionedImpl(scopedSteamName, new RevisionImpl(revision.asImpl().getSegment(), num, num));
        }

        @Override
        public RevisionedImpl applyTo(RevisionedImpl oldState, Revision newRevision) {
            latch.awaitUninterruptibly();
            return new RevisionedImpl(oldState.scopedStreamName,
                    new RevisionImpl(newRevision.asImpl().getSegment(), num, num));
        }
    }

    private static class MockRevisionedStreamClient
            implements RevisionedStreamClient<UpdateOrInit<RevisionedImpl>> {
        private Segment segment;
        private BlockingUpdate init;
        private BlockingUpdate[] updates;
        private int visableLength = 0;
        private final AtomicLong mark = new AtomicLong(SegmentAttribute.NULL_VALUE);

        @Override
        public Iterator<Entry<Revision, UpdateOrInit<RevisionedImpl>>> readFrom(Revision start) {
            return new Iterator<Entry<Revision, UpdateOrInit<RevisionedImpl>>>() {
                private int pos = start.asImpl().getEventAtOffset();

                @Override
                public Entry<Revision, UpdateOrInit<RevisionedImpl>> next() {
                    UpdateOrInit<RevisionedImpl> value;
                    RevisionImpl revision = new RevisionImpl(segment, pos, pos);
                    if (pos == 0) {
                        value = new UpdateOrInit<>(init);
                    } else {
                        value = new UpdateOrInit<>(Collections.singletonList(updates[pos - 1]));
                    }
                    pos++;
                    return new AbstractMap.SimpleImmutableEntry<>(revision, value);
                }

                @Override
                public boolean hasNext() {
                    return pos <= visableLength;
                }
            };
        }

        @Override
        public Revision writeConditionally(Revision latestRevision, UpdateOrInit<RevisionedImpl> value) {
            throw new NotImplementedException();
        }

        @Override
        public void writeUnconditionally(UpdateOrInit<RevisionedImpl> value) {
            throw new NotImplementedException();
        }

        @Override
        public Revision fetchLatestRevision() {
            return new RevisionImpl(segment, visableLength, visableLength);
        }

        @Override
        public Revision getMark() {
            long location = mark.get();
            return location == SegmentAttribute.NULL_VALUE ? null : new RevisionImpl(segment, location, 0);
        }

        @Override
        public boolean compareAndSetMark(Revision expected, Revision newLocation) {
            long exp = expected == null ? SegmentAttribute.NULL_VALUE : expected.asImpl().getOffsetInSegment();
            long value = newLocation == null ? SegmentAttribute.NULL_VALUE
                    : newLocation.asImpl().getOffsetInSegment();
            return mark.compareAndSet(exp, value);
        }

        @Override
        public Revision fetchOldestRevision() {
            return new RevisionImpl(segment, 0, 0);
        }

        @Override
        public void close() {
        }
    }

    @Test(timeout = 20000)
    public void testLocking() {
        String streamName = "streamName";
        String scope = "scope";
        Segment segment = new Segment(scope, streamName, 0);

        BlockingUpdate[] updates = new BlockingUpdate[] { new BlockingUpdate(1), new BlockingUpdate(2),
                new BlockingUpdate(3), new BlockingUpdate(4) };

        MockRevisionedStreamClient client = new MockRevisionedStreamClient();
        client.segment = segment;
        @Cleanup
        StateSynchronizerImpl<RevisionedImpl> sync = new StateSynchronizerImpl<RevisionedImpl>(segment, client);
        client.init = new BlockingUpdate(0);
        client.updates = updates;
        client.visableLength = 2;
        client.init.latch.release();
        updates[0].latch.release();
        updates[1].latch.release();
        sync.fetchUpdates();
        RevisionedImpl state1 = sync.getState();
        assertEquals(new RevisionImpl(segment, 2, 2), state1.getRevision());

        client.visableLength = 3;
        Async.testBlocking(() -> {
            sync.fetchUpdates();
        }, () -> updates[2].latch.release());
        RevisionedImpl state2 = sync.getState();
        assertEquals(new RevisionImpl(segment, 3, 3), state2.getRevision());

        client.visableLength = 4;
        Async.testBlocking(() -> {
            sync.fetchUpdates();
        }, () -> {
            client.visableLength = 3;
            sync.getState();
            updates[3].latch.release();
        });
        RevisionedImpl state3 = sync.getState();
        assertEquals(new RevisionImpl(segment, 4, 4), state3.getRevision());
    }

    @Test(timeout = 20000)
    public void testCompaction() throws EndOfSegmentException {
        String streamName = "streamName";
        String scope = "scope";

        MockSegmentStreamFactory ioFactory = new MockSegmentStreamFactory();
        @Cleanup
        MockClientFactory clientFactory = new MockClientFactory(scope, ioFactory);
        StateSynchronizer<RevisionedImpl> sync = clientFactory.createStateSynchronizer(streamName,
                new JavaSerializer<>(), new JavaSerializer<>(), SynchronizerConfig.builder().build());
        AtomicInteger callCount = new AtomicInteger(0);
        sync.initialize(new RegularUpdate());
        sync.updateState(state -> {
            callCount.incrementAndGet();
            return Collections.singletonList(new RegularUpdate());
        });
        assertEquals(1, callCount.get());
        sync.updateState(state -> {
            callCount.incrementAndGet();
            return Collections.singletonList(new RegularUpdate());
        });
        assertEquals(2, callCount.get());
        sync.compact(state -> {
            callCount.incrementAndGet();
            return new RegularUpdate();
        });
        assertEquals(3, callCount.get());
        sync.updateState(s -> {
            callCount.incrementAndGet();
            return Collections.singletonList(new RegularUpdate());
        });
        assertEquals(5, callCount.get());
        sync.compact(state -> {
            callCount.incrementAndGet();
            return new RegularUpdate();
        });
        assertEquals(6, callCount.get());
    }

    @Test(timeout = 20000)
    public void testCompactionShrinksSet() throws EndOfSegmentException {
        String streamName = "testCompactionShrinksSet";
        String scope = "scope";

        MockSegmentStreamFactory ioFactory = new MockSegmentStreamFactory();
        @Cleanup
        MockClientFactory clientFactory = new MockClientFactory(scope, ioFactory);
        SetSynchronizer<String> set = SetSynchronizer.createNewSet(streamName, clientFactory);
        RevisionedStreamClient<byte[]> rsc = clientFactory.createRevisionedStreamClient(streamName,
                new ByteArraySerializer(), SynchronizerConfig.builder().build());
        set.add("Foo");
        assertNull(rsc.getMark());
        set.add("Bar");
        assertNull(rsc.getMark());
        set.clear();
        assertNotNull(rsc.getMark());
        Iterator<?> iter = rsc.readFrom(rsc.getMark());
        assertTrue(iter.hasNext());
        iter.next();
        assertFalse(iter.hasNext());
        set.add("Foo2");
        assertNotNull(rsc.getMark());
        assertEquals(1, set.getCurrentSize());
    }

    @Test(timeout = 20000)
    public void testSetOperations() throws EndOfSegmentException {
        String streamName = "testCompactionShrinksSet";
        String scope = "scope";

        MockSegmentStreamFactory ioFactory = new MockSegmentStreamFactory();
        @Cleanup
        MockClientFactory clientFactory = new MockClientFactory(scope, ioFactory);
        SetSynchronizer<String> set = SetSynchronizer.createNewSet(streamName, clientFactory);
        SetSynchronizer<String> set2 = SetSynchronizer.createNewSet(streamName, clientFactory);
        assertEquals(0, set.getCurrentSize());
        set.add("Foo");
        set2.add("Bar");
        set.update();
        assertEquals(2, set.getCurrentSize());
        set.clear();
        assertEquals(0, set.getCurrentSize());
        set.add("Baz");
        assertEquals(2, set2.getCurrentSize());
        set2.remove("Bar");
        assertEquals(1, set2.getCurrentSize());
        set2.remove("Baz");
        assertEquals(0, set2.getCurrentSize());
        set.update();
        assertEquals(0, set.getCurrentSize());
        SetSynchronizer<String> set3 = SetSynchronizer.createNewSet(streamName, clientFactory);
        set3.update();
        assertEquals(0, set3.getCurrentSize());
    }

}