Search in sources :

Example 1 with ThreadContext

use of io.atomix.utils.concurrent.ThreadContext in project atomix by atomix.

the class RaftFuzzTest method runFuzzTest.

/**
 * Runs a single fuzz test.
 */
private void runFuzzTest() throws Exception {
    reset();
    createServers(randomNumber(5) + 3);
    final Object lock = new Object();
    final AtomicLong index = new AtomicLong();
    final Map<Integer, Long> indexes = new HashMap<>();
    ThreadContext context = new SingleThreadContext("fuzz-test");
    int clients = randomNumber(10) + 1;
    for (int i = 0; i < clients; i++) {
        ReadConsistency consistency = randomConsistency();
        RaftClient client = createClient();
        PrimitiveProxy proxy = createProxy(client, consistency);
        Scheduler scheduler = new SingleThreadContext("fuzz-test-" + i);
        final int clientId = i;
        scheduler.schedule(Duration.ofMillis((100 * clients) + (randomNumber(50) - 25)), Duration.ofMillis((100 * clients) + (randomNumber(50) - 25)), () -> {
            long lastLinearizableIndex = index.get();
            int type = randomNumber(4);
            switch(type) {
                case 0:
                    proxy.<Map.Entry<String, String>, Long>invoke(PUT, clientSerializer::encode, Maps.immutableEntry(randomKey(), randomString(1024 * 16)), clientSerializer::decode).thenAccept(result -> {
                        synchronized (lock) {
                            if (result < lastLinearizableIndex) {
                                System.out.println(result + " is less than last linearizable index " + lastLinearizableIndex);
                                System.exit(1);
                            } else if (result > index.get()) {
                                index.set(result);
                            }
                            Long lastSequentialIndex = indexes.get(clientId);
                            if (lastSequentialIndex == null) {
                                indexes.put(clientId, result);
                            } else if (result < lastSequentialIndex) {
                                System.out.println(result + " is less than last sequential index " + lastSequentialIndex);
                                System.exit(1);
                            } else {
                                indexes.put(clientId, lastSequentialIndex);
                            }
                        }
                    });
                    break;
                case 1:
                    proxy.invoke(GET, clientSerializer::encode, randomKey(), clientSerializer::decode);
                    break;
                case 2:
                    proxy.<String, Long>invoke(REMOVE, clientSerializer::encode, randomKey(), clientSerializer::decode).thenAccept(result -> {
                        synchronized (lock) {
                            if (result < lastLinearizableIndex) {
                                System.out.println(result + " is less than last linearizable index " + lastLinearizableIndex);
                                System.exit(1);
                            } else if (result > index.get()) {
                                index.set(result);
                            }
                            Long lastSequentialIndex = indexes.get(clientId);
                            if (lastSequentialIndex == null) {
                                indexes.put(clientId, result);
                            } else if (result < lastSequentialIndex) {
                                System.out.println(result + " is less than last sequential index " + lastSequentialIndex);
                                System.exit(1);
                            } else {
                                indexes.put(clientId, lastSequentialIndex);
                            }
                        }
                    });
                    break;
                case 3:
                    proxy.<Long>invoke(INDEX, clientSerializer::decode).thenAccept(result -> {
                        synchronized (lock) {
                            switch(consistency) {
                                case LINEARIZABLE:
                                case LINEARIZABLE_LEASE:
                                    if (result < lastLinearizableIndex) {
                                        System.out.println(result + " is less than last linearizable index " + lastLinearizableIndex);
                                        System.exit(1);
                                    } else if (result > index.get()) {
                                        index.set(result);
                                    }
                                case SEQUENTIAL:
                                    Long lastSequentialIndex = indexes.get(clientId);
                                    if (lastSequentialIndex == null) {
                                        indexes.put(clientId, result);
                                    } else if (result < lastSequentialIndex) {
                                        System.out.println(result + " is less than last sequential index " + lastSequentialIndex);
                                        System.exit(1);
                                    } else {
                                        indexes.put(clientId, lastSequentialIndex);
                                    }
                            }
                        }
                    });
            }
        });
    }
    scheduleRestarts(context);
    Thread.sleep(Duration.ofMinutes(15).toMillis());
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Scheduler(io.atomix.utils.concurrent.Scheduler) SingleThreadContext(io.atomix.utils.concurrent.SingleThreadContext) ThreadContext(io.atomix.utils.concurrent.ThreadContext) Endpoint(io.atomix.messaging.Endpoint) PrimitiveProxy(io.atomix.primitive.proxy.PrimitiveProxy) AtomicLong(java.util.concurrent.atomic.AtomicLong) AtomicLong(java.util.concurrent.atomic.AtomicLong) SingleThreadContext(io.atomix.utils.concurrent.SingleThreadContext) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap)

Example 2 with ThreadContext

use of io.atomix.utils.concurrent.ThreadContext in project atomix by atomix.

the class RaftProxyInvokerTest method testExpireSessionOnCommandFailure.

/**
 * Tests that the client's session is expired when an UnknownSessionException is received from the cluster.
 */
@Test
public void testExpireSessionOnCommandFailure() throws Throwable {
    CompletableFuture<CommandResponse> future = new CompletableFuture<>();
    RaftProxyConnection connection = mock(RaftProxyConnection.class);
    Mockito.when(connection.command(any(CommandRequest.class))).thenReturn(future);
    RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000);
    RaftProxyManager manager = mock(RaftProxyManager.class);
    ThreadContext threadContext = new TestContext();
    RaftProxyInvoker submitter = new RaftProxyInvoker(connection, mock(RaftProxyConnection.class), state, new RaftProxySequencer(state), manager, threadContext);
    CompletableFuture<byte[]> result = submitter.invoke(new PrimitiveOperation(COMMAND, HeapBytes.EMPTY));
    assertEquals(state.getResponseIndex(), 1);
    assertFalse(result.isDone());
    future.completeExceptionally(new RaftException.UnknownSession("unknown session"));
    assertTrue(result.isCompletedExceptionally());
}
Also used : PrimitiveOperation(io.atomix.primitive.operation.PrimitiveOperation) RaftException(io.atomix.protocols.raft.RaftException) ThreadContext(io.atomix.utils.concurrent.ThreadContext) CommandResponse(io.atomix.protocols.raft.protocol.CommandResponse) CompletableFuture(java.util.concurrent.CompletableFuture) CommandRequest(io.atomix.protocols.raft.protocol.CommandRequest) Test(org.junit.Test)

Example 3 with ThreadContext

use of io.atomix.utils.concurrent.ThreadContext in project atomix by atomix.

the class RaftProxyInvokerTest method testSkippingOverFailedQuery.

/**
 * Tests skipping over a failed query attempt.
 */
@Test
public void testSkippingOverFailedQuery() throws Throwable {
    CompletableFuture<QueryResponse> future1 = new CompletableFuture<>();
    CompletableFuture<QueryResponse> future2 = new CompletableFuture<>();
    RaftProxyConnection connection = mock(RaftProxyConnection.class);
    Mockito.when(connection.query(any(QueryRequest.class))).thenReturn(future1).thenReturn(future2);
    RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000);
    RaftProxyManager manager = mock(RaftProxyManager.class);
    ThreadContext threadContext = new TestContext();
    RaftProxyInvoker submitter = new RaftProxyInvoker(mock(RaftProxyConnection.class), connection, state, new RaftProxySequencer(state), manager, threadContext);
    CompletableFuture<byte[]> result1 = submitter.invoke(new PrimitiveOperation(QUERY, HeapBytes.EMPTY));
    CompletableFuture<byte[]> result2 = submitter.invoke(new PrimitiveOperation(QUERY, HeapBytes.EMPTY));
    assertEquals(state.getResponseIndex(), 1);
    assertFalse(result1.isDone());
    assertFalse(result2.isDone());
    future1.completeExceptionally(new RaftException.QueryFailure("failure"));
    future2.complete(QueryResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(10).withResult("Hello world!".getBytes()).build());
    assertTrue(result1.isCompletedExceptionally());
    assertTrue(result2.isDone());
    assertTrue(Arrays.equals(result2.get(), "Hello world!".getBytes()));
    assertEquals(state.getResponseIndex(), 10);
}
Also used : PrimitiveOperation(io.atomix.primitive.operation.PrimitiveOperation) RaftException(io.atomix.protocols.raft.RaftException) ThreadContext(io.atomix.utils.concurrent.ThreadContext) CompletableFuture(java.util.concurrent.CompletableFuture) QueryResponse(io.atomix.protocols.raft.protocol.QueryResponse) Test(org.junit.Test)

Example 4 with ThreadContext

use of io.atomix.utils.concurrent.ThreadContext in project atomix by atomix.

the class RaftProxyInvokerTest method testSubmitQuery.

/**
 * Tests submitting a query to the cluster.
 */
@Test
public void testSubmitQuery() throws Throwable {
    RaftProxyConnection connection = mock(RaftProxyConnection.class);
    when(connection.query(any(QueryRequest.class))).thenReturn(CompletableFuture.completedFuture(QueryResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(10).withResult("Hello world!".getBytes()).build()));
    RaftProxyState state = new RaftProxyState("test", SessionId.from(1), UUID.randomUUID().toString(), new TestPrimitiveType(), 1000);
    RaftProxyManager manager = mock(RaftProxyManager.class);
    ThreadContext threadContext = new TestContext();
    RaftProxyInvoker submitter = new RaftProxyInvoker(mock(RaftProxyConnection.class), connection, state, new RaftProxySequencer(state), manager, threadContext);
    assertTrue(Arrays.equals(submitter.invoke(new PrimitiveOperation(QUERY, HeapBytes.EMPTY)).get(), "Hello world!".getBytes()));
    assertEquals(state.getResponseIndex(), 10);
}
Also used : PrimitiveOperation(io.atomix.primitive.operation.PrimitiveOperation) QueryRequest(io.atomix.protocols.raft.protocol.QueryRequest) ThreadContext(io.atomix.utils.concurrent.ThreadContext) Test(org.junit.Test)

Example 5 with ThreadContext

use of io.atomix.utils.concurrent.ThreadContext in project atomix by atomix.

the class RaftProxyManager method openSession.

/**
 * Opens a new session.
 *
 * @param serviceName           The session name.
 * @param primitiveType           The session type.
 * @param communicationStrategy The strategy with which to communicate with servers.
 * @param minTimeout            The minimum session timeout.
 * @param maxTimeout            The maximum session timeout.
 * @return A completable future to be completed once the session has been opened.
 */
public CompletableFuture<RaftProxyState> openSession(String serviceName, PrimitiveType primitiveType, ReadConsistency readConsistency, CommunicationStrategy communicationStrategy, Duration minTimeout, Duration maxTimeout) {
    checkNotNull(serviceName, "serviceName cannot be null");
    checkNotNull(primitiveType, "serviceType cannot be null");
    checkNotNull(communicationStrategy, "communicationStrategy cannot be null");
    checkNotNull(maxTimeout, "timeout cannot be null");
    log.debug("Opening session; name: {}, type: {}", serviceName, primitiveType);
    OpenSessionRequest request = OpenSessionRequest.builder().withNodeId(nodeId).withServiceName(serviceName).withServiceType(primitiveType).withReadConsistency(readConsistency).withMinTimeout(minTimeout.toMillis()).withMaxTimeout(maxTimeout.toMillis()).build();
    CompletableFuture<RaftProxyState> future = new CompletableFuture<>();
    ThreadContext proxyContext = threadContextFactory.createContext();
    connection.openSession(request).whenCompleteAsync((response, error) -> {
        if (error == null) {
            if (response.status() == RaftResponse.Status.OK) {
                // Create and store the proxy state.
                RaftProxyState state = new RaftProxyState(clientId, SessionId.from(response.session()), serviceName, primitiveType, response.timeout());
                sessions.put(state.getSessionId().id(), state);
                state.addStateChangeListener(s -> {
                    if (s == PrimitiveProxy.State.CLOSED) {
                        sessions.remove(state.getSessionId().id());
                    }
                });
                // Ensure the proxy session info is reset and the session is kept alive.
                keepAliveSessions(System.currentTimeMillis(), state.getSessionTimeout());
                future.complete(state);
            } else {
                future.completeExceptionally(new RaftException.Unavailable(response.error().message()));
            }
        } else {
            future.completeExceptionally(new RaftException.Unavailable(error.getMessage()));
        }
    }, proxyContext);
    return future;
}
Also used : OpenSessionRequest(io.atomix.protocols.raft.protocol.OpenSessionRequest) CompletableFuture(java.util.concurrent.CompletableFuture) RaftException(io.atomix.protocols.raft.RaftException) ThreadContext(io.atomix.utils.concurrent.ThreadContext)

Aggregations

ThreadContext (io.atomix.utils.concurrent.ThreadContext)9 PrimitiveOperation (io.atomix.primitive.operation.PrimitiveOperation)7 Test (org.junit.Test)7 CompletableFuture (java.util.concurrent.CompletableFuture)6 RaftException (io.atomix.protocols.raft.RaftException)4 QueryResponse (io.atomix.protocols.raft.protocol.QueryResponse)3 CommandRequest (io.atomix.protocols.raft.protocol.CommandRequest)2 CommandResponse (io.atomix.protocols.raft.protocol.CommandResponse)2 QueryRequest (io.atomix.protocols.raft.protocol.QueryRequest)2 Endpoint (io.atomix.messaging.Endpoint)1 PrimitiveProxy (io.atomix.primitive.proxy.PrimitiveProxy)1 OpenSessionRequest (io.atomix.protocols.raft.protocol.OpenSessionRequest)1 Scheduler (io.atomix.utils.concurrent.Scheduler)1 SingleThreadContext (io.atomix.utils.concurrent.SingleThreadContext)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1