Search in sources :

Example 1 with Configuration

use of io.atomix.protocols.raft.storage.system.Configuration in project atomix by atomix.

the class DefaultRaftMember method configure.

/**
 * Recursively reconfigures the cluster.
 */
private void configure(RaftMember.Type type, CompletableFuture<Void> future) {
    // Set a timer to retry the attempt to leave the cluster.
    configureTimeout = cluster.getContext().getThreadContext().schedule(cluster.getContext().getElectionTimeout(), () -> {
        configure(type, future);
    });
    // Attempt to leave the cluster by submitting a LeaveRequest directly to the server state.
    // Non-leader states should forward the request to the leader if there is one. Leader states
    // will log, replicate, and commit the reconfiguration.
    cluster.getContext().getRaftRole().onReconfigure(ReconfigureRequest.builder().withIndex(cluster.getConfiguration().index()).withTerm(cluster.getConfiguration().term()).withMember(new DefaultRaftMember(id, type, updated)).build()).whenComplete((response, error) -> {
        if (error == null) {
            if (response.status() == RaftResponse.Status.OK) {
                cancelConfigureTimer();
                cluster.configure(new Configuration(response.index(), response.term(), response.timestamp(), response.members()));
                future.complete(null);
            } else if (response.error() == null || response.error().type() == RaftError.Type.UNAVAILABLE || response.error().type() == RaftError.Type.PROTOCOL_ERROR || response.error().type() == RaftError.Type.NO_LEADER) {
                cancelConfigureTimer();
                configureTimeout = cluster.getContext().getThreadContext().schedule(cluster.getContext().getElectionTimeout().multipliedBy(2), () -> configure(type, future));
            } else {
                cancelConfigureTimer();
                future.completeExceptionally(response.error().createException());
            }
        } else {
            future.completeExceptionally(error);
        }
    });
}
Also used : Configuration(io.atomix.protocols.raft.storage.system.Configuration)

Example 2 with Configuration

use of io.atomix.protocols.raft.storage.system.Configuration in project atomix by atomix.

the class RaftClusterContext method leave.

/**
 * Attempts to leave the cluster.
 */
private void leave(CompletableFuture<Void> future) {
    // Set a timer to retry the attempt to leave the cluster.
    leaveTimeout = raft.getThreadContext().schedule(raft.getElectionTimeout(), () -> {
        leave(future);
    });
    // Attempt to leave the cluster by submitting a LeaveRequest directly to the server state.
    // Non-leader states should forward the request to the leader if there is one. Leader states
    // will log, replicate, and commit the reconfiguration.
    raft.getRaftRole().onLeave(LeaveRequest.builder().withMember(getMember()).build()).whenComplete((response, error) -> {
        // Cancel the leave timer.
        cancelLeaveTimer();
        if (error == null && response.status() == RaftResponse.Status.OK) {
            Configuration configuration = new Configuration(response.index(), response.term(), response.timestamp(), response.members());
            // Configure the cluster and commit the configuration as we know the successful response
            // indicates commitment.
            configure(configuration).commit();
            future.complete(null);
        } else {
            // Reset the leave timer.
            leaveTimeout = raft.getThreadContext().schedule(raft.getElectionTimeout(), () -> {
                leave(future);
            });
        }
    });
}
Also used : Configuration(io.atomix.protocols.raft.storage.system.Configuration)

Example 3 with Configuration

use of io.atomix.protocols.raft.storage.system.Configuration in project atomix by atomix.

the class RaftClusterContext method join.

@Override
public synchronized CompletableFuture<Void> join(Collection<NodeId> cluster) {
    if (joinFuture != null)
        return joinFuture;
    // If no configuration was loaded from disk, create a new configuration.
    if (configuration == null) {
        member.setType(RaftMember.Type.PROMOTABLE);
        // Create a set of cluster members, excluding the local member which is joining a cluster.
        Set<RaftMember> activeMembers = cluster.stream().filter(m -> !m.equals(member.nodeId())).map(m -> new DefaultRaftMember(m, RaftMember.Type.ACTIVE, member.getLastUpdated())).collect(Collectors.toSet());
        // fail the join.
        if (activeMembers.isEmpty()) {
            return Futures.exceptionalFuture(new IllegalStateException("cannot join empty cluster"));
        }
        // Create a new configuration and configure the cluster. Once the cluster is configured, the configuration
        // will be stored on disk to ensure the cluster can fall back to the provided configuration if necessary.
        configure(new Configuration(0, 0, member.getLastUpdated().toEpochMilli(), activeMembers));
    }
    return join().thenCompose(v -> {
        if (member.getType() == RaftMember.Type.ACTIVE) {
            return CompletableFuture.completedFuture(null);
        } else {
            return member.promote(RaftMember.Type.ACTIVE);
        }
    });
}
Also used : RaftClusterEvent(io.atomix.protocols.raft.cluster.RaftClusterEvent) NodeId(io.atomix.cluster.NodeId) RaftMember(io.atomix.protocols.raft.cluster.RaftMember) RaftCluster(io.atomix.protocols.raft.cluster.RaftCluster) RaftClusterEventListener(io.atomix.protocols.raft.cluster.RaftClusterEventListener) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) JoinRequest(io.atomix.protocols.raft.protocol.JoinRequest) RaftServer(io.atomix.protocols.raft.RaftServer) ContextualLoggerFactory(io.atomix.utils.logging.ContextualLoggerFactory) LeaveRequest(io.atomix.protocols.raft.protocol.LeaveRequest) ArrayList(java.util.ArrayList) RaftResponse(io.atomix.protocols.raft.protocol.RaftResponse) Map(java.util.Map) RaftError(io.atomix.protocols.raft.RaftError) Scheduled(io.atomix.utils.concurrent.Scheduled) Futures(io.atomix.utils.concurrent.Futures) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) LoggerContext(io.atomix.utils.logging.LoggerContext) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) Set(java.util.Set) Instant(java.time.Instant) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) Collectors(java.util.stream.Collectors) Configuration(io.atomix.protocols.raft.storage.system.Configuration) Consumer(java.util.function.Consumer) List(java.util.List) RaftContext(io.atomix.protocols.raft.impl.RaftContext) Comparator(java.util.Comparator) Collections(java.util.Collections) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) RaftMember(io.atomix.protocols.raft.cluster.RaftMember) Configuration(io.atomix.protocols.raft.storage.system.Configuration)

Example 4 with Configuration

use of io.atomix.protocols.raft.storage.system.Configuration in project atomix by atomix.

the class RaftClusterContext method bootstrap.

@Override
public CompletableFuture<Void> bootstrap(Collection<NodeId> cluster) {
    if (joinFuture != null)
        return joinFuture;
    if (configuration == null) {
        member.setType(RaftMember.Type.ACTIVE);
        // Create a set of active members.
        Set<RaftMember> activeMembers = cluster.stream().filter(m -> !m.equals(member.nodeId())).map(m -> new DefaultRaftMember(m, RaftMember.Type.ACTIVE, member.getLastUpdated())).collect(Collectors.toSet());
        // Add the local member to the set of active members.
        activeMembers.add(member);
        // Create a new configuration and store it on disk to ensure the cluster can fall back to the configuration.
        configure(new Configuration(0, 0, member.getLastUpdated().toEpochMilli(), activeMembers));
    }
    return join();
}
Also used : RaftClusterEvent(io.atomix.protocols.raft.cluster.RaftClusterEvent) NodeId(io.atomix.cluster.NodeId) RaftMember(io.atomix.protocols.raft.cluster.RaftMember) RaftCluster(io.atomix.protocols.raft.cluster.RaftCluster) RaftClusterEventListener(io.atomix.protocols.raft.cluster.RaftClusterEventListener) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) JoinRequest(io.atomix.protocols.raft.protocol.JoinRequest) RaftServer(io.atomix.protocols.raft.RaftServer) ContextualLoggerFactory(io.atomix.utils.logging.ContextualLoggerFactory) LeaveRequest(io.atomix.protocols.raft.protocol.LeaveRequest) ArrayList(java.util.ArrayList) RaftResponse(io.atomix.protocols.raft.protocol.RaftResponse) Map(java.util.Map) RaftError(io.atomix.protocols.raft.RaftError) Scheduled(io.atomix.utils.concurrent.Scheduled) Futures(io.atomix.utils.concurrent.Futures) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) LoggerContext(io.atomix.utils.logging.LoggerContext) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) Set(java.util.Set) Instant(java.time.Instant) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) Collectors(java.util.stream.Collectors) Configuration(io.atomix.protocols.raft.storage.system.Configuration) Consumer(java.util.function.Consumer) List(java.util.List) RaftContext(io.atomix.protocols.raft.impl.RaftContext) Comparator(java.util.Comparator) Collections(java.util.Collections) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) RaftMember(io.atomix.protocols.raft.cluster.RaftMember) Configuration(io.atomix.protocols.raft.storage.system.Configuration)

Example 5 with Configuration

use of io.atomix.protocols.raft.storage.system.Configuration in project atomix by atomix.

the class RaftClusterContext method join.

/**
 * Recursively attempts to join the cluster.
 */
private void join(Iterator<RaftMemberContext> iterator) {
    if (iterator.hasNext()) {
        cancelJoinTimer();
        joinTimeout = raft.getThreadContext().schedule(raft.getElectionTimeout().multipliedBy(2), () -> {
            join(iterator);
        });
        RaftMemberContext member = iterator.next();
        log.debug("Attempting to join via {}", member.getMember().nodeId());
        JoinRequest request = JoinRequest.builder().withMember(new DefaultRaftMember(getMember().nodeId(), getMember().getType(), getMember().getLastUpdated())).build();
        raft.getProtocol().join(member.getMember().nodeId(), request).whenCompleteAsync((response, error) -> {
            // Cancel the join timer.
            cancelJoinTimer();
            if (error == null) {
                if (response.status() == RaftResponse.Status.OK) {
                    log.info("Successfully joined via {}", member.getMember().nodeId());
                    Configuration configuration = new Configuration(response.index(), response.term(), response.timestamp(), response.members());
                    // Configure the cluster with the join response.
                    // Commit the configuration as we know it was committed via the successful join response.
                    configure(configuration).commit();
                    // If the local member is not present in the configuration, fail the future.
                    if (!members.contains(this.member)) {
                        joinFuture.completeExceptionally(new IllegalStateException("not a member of the cluster"));
                    } else if (joinFuture != null) {
                        joinFuture.complete(null);
                    }
                } else if (response.error() == null || response.error().type() == RaftError.Type.CONFIGURATION_ERROR) {
                    // If the response error is null, that indicates that no error occurred but the leader was
                    // in a state that was incapable of handling the join request. Attempt to join the leader
                    // again after an election timeout.
                    log.debug("Failed to join {}", member.getMember().nodeId());
                    resetJoinTimer();
                } else {
                    // If the response error was non-null, attempt to join via the next server in the members list.
                    log.debug("Failed to join {}", member.getMember().nodeId());
                    join(iterator);
                }
            } else {
                log.debug("Failed to join {}", member.getMember().nodeId());
                join(iterator);
            }
        }, raft.getThreadContext());
    } else // If join attempts remain, schedule another attempt after two election timeouts. This allows enough time
    // for servers to potentially timeout and elect a leader.
    {
        log.debug("Failed to join cluster, retrying...");
        resetJoinTimer();
    }
}
Also used : Configuration(io.atomix.protocols.raft.storage.system.Configuration) JoinRequest(io.atomix.protocols.raft.protocol.JoinRequest)

Aggregations

Configuration (io.atomix.protocols.raft.storage.system.Configuration)9 RaftMember (io.atomix.protocols.raft.cluster.RaftMember)4 JoinRequest (io.atomix.protocols.raft.protocol.JoinRequest)4 CompletableFuture (java.util.concurrent.CompletableFuture)4 MoreObjects.toStringHelper (com.google.common.base.MoreObjects.toStringHelper)3 Preconditions.checkNotNull (com.google.common.base.Preconditions.checkNotNull)3 NodeId (io.atomix.cluster.NodeId)3 RaftError (io.atomix.protocols.raft.RaftError)3 RaftServer (io.atomix.protocols.raft.RaftServer)3 RaftCluster (io.atomix.protocols.raft.cluster.RaftCluster)3 RaftClusterEvent (io.atomix.protocols.raft.cluster.RaftClusterEvent)3 RaftClusterEventListener (io.atomix.protocols.raft.cluster.RaftClusterEventListener)3 RaftContext (io.atomix.protocols.raft.impl.RaftContext)3 LeaveRequest (io.atomix.protocols.raft.protocol.LeaveRequest)3 RaftResponse (io.atomix.protocols.raft.protocol.RaftResponse)3 Futures (io.atomix.utils.concurrent.Futures)3 Scheduled (io.atomix.utils.concurrent.Scheduled)3 ContextualLoggerFactory (io.atomix.utils.logging.ContextualLoggerFactory)3 LoggerContext (io.atomix.utils.logging.LoggerContext)3 Instant (java.time.Instant)3