
io.atomix.copycat.client.RaftClient Maven / Gradle / Ivy
/*
* Copyright 2015 the original author or authors.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package io.atomix.copycat.client;
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.transport.Address;
import io.atomix.catalyst.transport.Transport;
import io.atomix.catalyst.util.Assert;
import io.atomix.catalyst.util.Managed;
import io.atomix.catalyst.util.concurrent.ThreadContext;
import io.atomix.copycat.client.session.Session;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
/**
* Provides an interface for submitting {@link Command commands} and {@link Query} queries to the Raft cluster.
*
* Raft clients are responsible for connecting to the cluster and submitting {@link Command commands} and {@link Query queries}
* that operate on the cluster's replicated state machine. Raft clients interact with one or more nodes in a Raft cluster
* through a session. When the client is {@link #open() opened}, the client will attempt to one of the known member
* {@link Address} provided to the builder. As long as the client can communicate with at least one correct member of the
* cluster, it can open a session. Once the client is able to register a {@link Session}, it will receive an updated list
* of members for the entire cluster and thereafter be allowed to communicate with all servers.
*
* Sessions are created by registering the client through the cluster leader. Clients always connect to a single node in the
* cluster, and in the event of a node failure or partition, the client will detect the failure and reconnect to a correct server.
*
* Clients periodically send keep-alive requests to the server to which they're connected. The keep-alive request
* interval is determined by the cluster's session timeout, and the session timeout is determined by the leader's configuration
* at the time that the session is registered. This ensures that clients cannot be misconfigured with a keep-alive interval
* greater than the cluster's session timeout.
*
* Clients communicate with the distributed state machine by submitting {@link Command commands} and {@link Query queries} to
* the cluster through the {@link #submit(Command)} and {@link #submit(Query)} methods respectively:
*
* {@code
* client.submit(new PutCommand("foo", "Hello world!")).thenAccept(result -> {
* System.out.println("Result is " + result);
* });
* }
*
* All client methods are fully asynchronous and return {@link CompletableFuture}. To block until a method is complete, use
* the {@link CompletableFuture#get()} or {@link CompletableFuture#join()} methods.
*
* Sessions work to provide linearizable semantics for client {@link Command commands}. When a command is submitted to the cluster,
* the command will be forwarded to the leader where it will be logged and replicated. Once the command is stored on a majority
* of servers, the leader will apply it to its state machine and respond according to the command's {@link Command#consistency()}.
* See the {@link Command.ConsistencyLevel} documentation for more info.
*
* Sessions also allow {@link Query queries} (read-only requests) submitted by the client to optionally be executed on follower
* nodes. When a query is submitted to the cluster, the query's {@link Query#consistency()} will be used to determine how the
* query is handled. For queries with stronger consistency levels, they will be forwarded to the cluster's leader. For weaker
* consistency queries, they may be executed on follower nodes according to the consistency level constraints. See the
* {@link Query.ConsistencyLevel} documentation for more info.
*
* @author System.out.println("acquired lock!"));
* }
*
* When a server-side state machine {@link Session#publish(String, Object) publishes} an event message to this session, the
* event message is guaranteed to be received in the order in which it was sent by the state machine. Note that the point
* in time at which events are received by the client is determined by the {@link Command#consistency()} of the command being
* executed when the state machine published the event. Events are not necessarily guaranteed to be received by the client
* during command execution. See the {@link Command.ConsistencyLevel} documentation for more info.
* * The returned {@link Session} instance will remain constant as long as the client maintains its session with the cluster. * Maintaining the client's session requires that the client be able to communicate with one server that can communicate * with the leader at any given time. During periods where the cluster is electing a new leader, the client's session will * not timeout but will resume once a new leader is elected. *
* Once the client connects to the cluster and opens its session, session listeners registered via {@link Session#onOpen(Consumer)} * will be called. In the event of a session expiration wherein the client fails to communicate with the cluster for at least * a session timeout, the session will be expired and listeners registered via {@link Session#onClose(Consumer)} will be called. * * @return The client session or {@code null} if no session is open. */ Session session(); /** * Submits an operation to the Raft cluster. *
* This method is provided for convenience. The submitted {@link Operation} must be an instance
* of {@link Command} or {@link Query}.
*
* @param operation The operation to submit.
* @param
* Commands are used to alter state machine state. All commands will be forwarded to the current Raft leader.
* Once a leader receives the command, it will write the command to its internal {@code Log} and replicate it to a majority
* of the cluster. Once the command has been replicated to a majority of the cluster, it will apply the command to its
* {@code StateMachine} and respond with the result.
*
* Once the command has been applied to a server state machine, the returned {@link java.util.concurrent.CompletableFuture}
* will be completed with the state machine output.
*
* Note that all client submissions are guaranteed to be completed in the same order in which they were sent (program order)
* and on the same thread. This does not, however, mean that they'll be applied to the server-side replicated state machine
* in that order. State machine order is dependent on the configured {@link Command.ConsistencyLevel}.
*
* @param command The command to submit.
* @param
* Queries are used to read state machine state. The behavior of query submissions is primarily dependent on the
* query's {@link Query.ConsistencyLevel}. For {@link Query.ConsistencyLevel#LINEARIZABLE}
* and {@link Query.ConsistencyLevel#BOUNDED_LINEARIZABLE} consistency levels, queries will be forwarded
* to the Raft leader. For lower consistency levels, queries are allowed to read from followers. All queries are executed
* by applying queries to an internal server state machine.
*
* Once the query has been applied to a server state machine, the returned {@link java.util.concurrent.CompletableFuture}
* will be completed with the state machine output.
*
* @param query The query to submit.
* @param
* When the client is opened, it will attempt to connect to and open a session with each unique configured server
* {@link Address}. Once the session is open, the returned {@link CompletableFuture} will be completed.
*
* @return A completable future to be completed once the client's {@link #session()} is open.
*/
@Override
CompletableFuture
* Whether the client is open depends on whether the client has an open session to the cluster.
*
* @return Indicates whether the client is open.
*/
@Override
boolean isOpen();
@Override
CompletableFuture
* Whether the client is closed depends on whether the client has not connected to the cluster or its session has been
* closed or expired.
*
* @return Indicates whether the client is closed.
*/
@Override
boolean isClosed();
}