All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 The operation result type. * @return A completable future to be completed with the operation result. * @throws IllegalArgumentException If the {@link Operation} is not an instance of {@link Command} or {@link Query}. * @throws NullPointerException if {@code operation} is null */ default CompletableFuture submit(Operation operation) { Assert.notNull(operation, "operation"); if (operation instanceof Command) { return submit((Command) operation); } else if (operation instanceof Query) { return submit((Query) operation); } else { throw new IllegalArgumentException("unknown operation type"); } } /** * Submits a command to the Raft cluster. *

* 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 The command result type. * @return A completable future to be completed with the command result. The future is guaranteed to be completed after all * {@link Command} or {@link Query} submission futures that preceded it. The future will always be completed on the * {@link #context()} thread. * @throws NullPointerException if {@code command} is null * @throws IllegalStateException if the {@link #session()} is not open */ CompletableFuture submit(Command command); /** * Submits a query to the Raft cluster. *

* 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 The query result type. * @return A completable future to be completed with the query result. The future is guaranteed to be completed after all * {@link Command} or {@link Query} submission futures that preceded it. The future will always be completed on the * {@link #context()} thread. * @throws NullPointerException if {@code query} is null * @throws IllegalStateException if the {@link #session()} is not open */ CompletableFuture submit(Query query); /** * Connects the client to the Raft cluster. *

* 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 open(); /** * Returns a boolean value indicating whether the client is open. *

* 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 close(); /** * Returns a boolean value indicating whether the client is closed. *

* 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(); }



© 2015 - 2025 Weber Informatics LLC | Privacy Policy