Search in sources :

Example 6 with RaftMember

use of io.atomix.protocols.raft.cluster.RaftMember 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 7 with RaftMember

use of io.atomix.protocols.raft.cluster.RaftMember in project atomix by atomix.

the class RaftContext method anoint.

/**
 * Attempts to become the leader.
 */
public CompletableFuture<Void> anoint() {
    if (role.role() == RaftServer.Role.LEADER) {
        return CompletableFuture.completedFuture(null);
    }
    CompletableFuture<Void> future = new CompletableFuture<>();
    threadContext.execute(() -> {
        // Register a leader election listener to wait for the election of this node.
        Consumer<RaftMember> electionListener = new Consumer<RaftMember>() {

            @Override
            public void accept(RaftMember member) {
                if (member.nodeId().equals(cluster.getMember().nodeId())) {
                    future.complete(null);
                } else {
                    future.completeExceptionally(new RaftException.ProtocolException("Failed to transfer leadership"));
                }
                removeLeaderElectionListener(this);
            }
        };
        addLeaderElectionListener(electionListener);
        // If a leader already exists, request a leadership transfer from it. Otherwise, transition to the candidate
        // state and attempt to get elected.
        RaftMember member = getCluster().getMember();
        RaftMember leader = getLeader();
        if (leader != null) {
            protocol.transfer(leader.nodeId(), TransferRequest.builder().withMember(member.nodeId()).build()).whenCompleteAsync((response, error) -> {
                if (error != null) {
                    future.completeExceptionally(error);
                } else if (response.status() == RaftResponse.Status.ERROR) {
                    future.completeExceptionally(response.error().createException());
                } else {
                    transition(RaftServer.Role.CANDIDATE);
                }
            }, threadContext);
        } else {
            transition(RaftServer.Role.CANDIDATE);
        }
    });
    return future;
}
Also used : RaftMember(io.atomix.protocols.raft.cluster.RaftMember) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) CompletableFuture(java.util.concurrent.CompletableFuture) RaftException(io.atomix.protocols.raft.RaftException) Consumer(java.util.function.Consumer)

Example 8 with RaftMember

use of io.atomix.protocols.raft.cluster.RaftMember in project atomix by atomix.

the class RaftClusterContext method listen.

@Override
public synchronized CompletableFuture<Void> listen(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.PASSIVE);
        // 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();
}
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 9 with RaftMember

use of io.atomix.protocols.raft.cluster.RaftMember in project atomix by atomix.

the class RaftClusterContext method configure.

/**
 * Configures the cluster state.
 *
 * @param configuration The cluster configuration.
 * @return The cluster state.
 */
public RaftClusterContext configure(Configuration configuration) {
    checkNotNull(configuration, "configuration cannot be null");
    // Configurations can be persisted and applying old configurations can revert newer configurations.
    if (this.configuration != null && configuration.index() <= this.configuration.index()) {
        return this;
    }
    Instant time = Instant.ofEpochMilli(configuration.time());
    // Iterate through members in the new configuration, add any missing members, and update existing members.
    boolean transition = false;
    for (RaftMember member : configuration.members()) {
        if (member.equals(this.member)) {
            transition = this.member.getType().ordinal() < member.getType().ordinal();
            this.member.update(member.getType(), time);
            members.add(this.member);
        } else {
            // If the member state doesn't already exist, create it.
            RaftMemberContext state = membersMap.get(member.nodeId());
            if (state == null) {
                DefaultRaftMember defaultMember = new DefaultRaftMember(member.nodeId(), member.getType(), time);
                state = new RaftMemberContext(defaultMember, this);
                state.resetState(raft.getLog());
                this.members.add(state.getMember());
                this.remoteMembers.add(state);
                membersMap.put(member.nodeId(), state);
                listeners.forEach(l -> l.onEvent(new RaftClusterEvent(RaftClusterEvent.Type.JOIN, defaultMember, time.toEpochMilli())));
            }
            // If the member type has changed, update the member type and reset its state.
            if (state.getMember().getType() != member.getType()) {
                state.getMember().update(member.getType(), time);
                state.resetState(raft.getLog());
            }
            // Update the optimized member collections according to the member type.
            for (List<RaftMemberContext> memberType : memberTypes.values()) {
                memberType.remove(state);
            }
            List<RaftMemberContext> memberType = memberTypes.get(member.getType());
            if (memberType == null) {
                memberType = new CopyOnWriteArrayList<>();
                memberTypes.put(member.getType(), memberType);
            }
            memberType.add(state);
        }
    }
    // can commit the configuration change prior to shutting down.
    if (transition) {
        raft.transition(this.member.getType());
    }
    // Iterate through configured members and remove any that no longer exist in the configuration.
    int i = 0;
    while (i < this.remoteMembers.size()) {
        RaftMemberContext member = this.remoteMembers.get(i);
        if (!configuration.members().contains(member.getMember())) {
            this.members.remove(member.getMember());
            this.remoteMembers.remove(i);
            for (List<RaftMemberContext> memberType : memberTypes.values()) {
                memberType.remove(member);
            }
            membersMap.remove(member.getMember().nodeId());
            listeners.forEach(l -> l.onEvent(new RaftClusterEvent(RaftClusterEvent.Type.LEAVE, member.getMember(), time.toEpochMilli())));
        } else {
            i++;
        }
    }
    // If the local member was removed from the cluster, remove it from the members list.
    if (!configuration.members().contains(member)) {
        members.remove(member);
    }
    this.configuration = configuration;
    // Store the configuration if it's already committed.
    if (raft.getCommitIndex() >= configuration.index()) {
        raft.getMetaStore().storeConfiguration(configuration);
    }
    return this;
}
Also used : RaftMember(io.atomix.protocols.raft.cluster.RaftMember) RaftClusterEvent(io.atomix.protocols.raft.cluster.RaftClusterEvent) Instant(java.time.Instant)

Example 10 with RaftMember

use of io.atomix.protocols.raft.cluster.RaftMember in project atomix by atomix.

the class LeaderRole method onReconfigure.

@Override
public CompletableFuture<ReconfigureResponse> onReconfigure(final ReconfigureRequest request) {
    raft.checkThread();
    logRequest(request);
    // See https://groups.google.com/forum/#!topic/raft-dev/t4xj6dJTP6E
    if (configuring() || initializing()) {
        return CompletableFuture.completedFuture(logResponse(ReconfigureResponse.builder().withStatus(RaftResponse.Status.ERROR).build()));
    }
    // If the member is not a known member of the cluster, fail the promotion.
    DefaultRaftMember existingMember = raft.getCluster().getMember(request.member().nodeId());
    if (existingMember == null) {
        return CompletableFuture.completedFuture(logResponse(ReconfigureResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.UNKNOWN_SESSION).build()));
    }
    // the leader, fail the request to ensure servers can't reconfigure an old configuration.
    if (request.index() > 0 && request.index() < raft.getCluster().getConfiguration().index() || request.term() != raft.getCluster().getConfiguration().term()) {
        return CompletableFuture.completedFuture(logResponse(ReconfigureResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.CONFIGURATION_ERROR).build()));
    }
    // If the member type has not changed, complete the configuration change successfully.
    if (existingMember.getType() == request.member().getType()) {
        Configuration configuration = raft.getCluster().getConfiguration();
        return CompletableFuture.completedFuture(logResponse(ReconfigureResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(configuration.index()).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(configuration.members()).build()));
    }
    // Update the member type.
    existingMember.update(request.member().getType(), Instant.now());
    Collection<RaftMember> members = raft.getCluster().getMembers();
    CompletableFuture<ReconfigureResponse> future = new CompletableFuture<>();
    configure(members).whenComplete((index, error) -> {
        if (error == null) {
            future.complete(logResponse(ReconfigureResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(index).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(members).build()));
        } else {
            future.complete(logResponse(ReconfigureResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.PROTOCOL_ERROR).build()));
        }
    });
    return future;
}
Also used : RaftMember(io.atomix.protocols.raft.cluster.RaftMember) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) CompletableFuture(java.util.concurrent.CompletableFuture) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) Configuration(io.atomix.protocols.raft.storage.system.Configuration) ReconfigureResponse(io.atomix.protocols.raft.protocol.ReconfigureResponse)

Aggregations

RaftMember (io.atomix.protocols.raft.cluster.RaftMember)10 CompletableFuture (java.util.concurrent.CompletableFuture)8 DefaultRaftMember (io.atomix.protocols.raft.cluster.impl.DefaultRaftMember)6 RaftClusterEvent (io.atomix.protocols.raft.cluster.RaftClusterEvent)4 Configuration (io.atomix.protocols.raft.storage.system.Configuration)4 Instant (java.time.Instant)4 Consumer (java.util.function.Consumer)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 RaftClusterEventListener (io.atomix.protocols.raft.cluster.RaftClusterEventListener)3 RaftContext (io.atomix.protocols.raft.impl.RaftContext)3 JoinRequest (io.atomix.protocols.raft.protocol.JoinRequest)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