Search in sources :

Example 1 with RaftMember

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

the class LeaderRole method onKeepAlive.

@Override
public CompletableFuture<KeepAliveResponse> onKeepAlive(KeepAliveRequest request) {
    final long term = raft.getTerm();
    final long timestamp = System.currentTimeMillis();
    raft.checkThread();
    logRequest(request);
    CompletableFuture<KeepAliveResponse> future = new CompletableFuture<>();
    appendAndCompact(new KeepAliveEntry(term, timestamp, request.sessionIds(), request.commandSequenceNumbers(), request.eventIndexes())).whenCompleteAsync((entry, error) -> {
        if (error != null) {
            future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.ERROR).withLeader(raft.getCluster().getMember().nodeId()).withError(RaftError.Type.PROTOCOL_ERROR).build()));
            return;
        }
        appender.appendEntries(entry.index()).whenComplete((commitIndex, commitError) -> {
            raft.checkThread();
            if (isRunning()) {
                if (commitError == null) {
                    raft.getServiceManager().<long[]>apply(entry.index()).whenCompleteAsync((sessionResult, sessionError) -> {
                        if (sessionError == null) {
                            future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.OK).withLeader(raft.getCluster().getMember().nodeId()).withMembers(raft.getCluster().getMembers().stream().map(RaftMember::nodeId).filter(m -> m != null).collect(Collectors.toList())).withSessionIds(sessionResult).build()));
                        } else if (sessionError instanceof CompletionException && sessionError.getCause() instanceof RaftException) {
                            future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.ERROR).withLeader(raft.getCluster().getMember().nodeId()).withError(((RaftException) sessionError.getCause()).getType(), sessionError.getMessage()).build()));
                        } else if (sessionError instanceof RaftException) {
                            future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.ERROR).withLeader(raft.getCluster().getMember().nodeId()).withError(((RaftException) sessionError).getType(), sessionError.getMessage()).build()));
                        } else {
                            future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.ERROR).withLeader(raft.getCluster().getMember().nodeId()).withError(RaftError.Type.PROTOCOL_ERROR, sessionError.getMessage()).build()));
                        }
                    }, raft.getThreadContext());
                } else {
                    future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.ERROR).withLeader(raft.getCluster().getMember().nodeId()).withError(RaftError.Type.PROTOCOL_ERROR).build()));
                }
            } else {
                RaftMember leader = raft.getLeader();
                future.complete(logResponse(KeepAliveResponse.builder().withStatus(RaftResponse.Status.ERROR).withLeader(leader != null ? leader.nodeId() : null).withError(RaftError.Type.ILLEGAL_MEMBER_STATE).build()));
            }
        });
    }, raft.getThreadContext());
    return future;
}
Also used : KeepAliveResponse(io.atomix.protocols.raft.protocol.KeepAliveResponse) RaftMember(io.atomix.protocols.raft.cluster.RaftMember) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) CompletableFuture(java.util.concurrent.CompletableFuture) KeepAliveEntry(io.atomix.protocols.raft.storage.log.entry.KeepAliveEntry) RaftException(io.atomix.protocols.raft.RaftException) CompletionException(java.util.concurrent.CompletionException)

Example 2 with RaftMember

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

the class LeaderRole method onLeave.

@Override
public CompletableFuture<LeaveResponse> onLeave(final LeaveRequest request) {
    raft.checkThread();
    logRequest(request);
    // See https://groups.google.com/forum/#!topic/raft-dev/t4xj6dJTP6E
    if (configuring() || initializing()) {
        return CompletableFuture.completedFuture(logResponse(LeaveResponse.builder().withStatus(RaftResponse.Status.ERROR).build()));
    }
    // If the leaving member is not a known member of the cluster, complete the leave successfully.
    if (raft.getCluster().getMember(request.member().nodeId()) == null) {
        return CompletableFuture.completedFuture(logResponse(LeaveResponse.builder().withStatus(RaftResponse.Status.OK).withMembers(raft.getCluster().getMembers()).build()));
    }
    RaftMember member = request.member();
    Collection<RaftMember> members = raft.getCluster().getMembers();
    members.remove(member);
    CompletableFuture<LeaveResponse> future = new CompletableFuture<>();
    configure(members).whenComplete((index, error) -> {
        if (error == null) {
            future.complete(logResponse(LeaveResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(index).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(members).build()));
        } else {
            future.complete(logResponse(LeaveResponse.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) LeaveResponse(io.atomix.protocols.raft.protocol.LeaveResponse)

Example 3 with RaftMember

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

the class LeaderRole method onJoin.

@Override
public CompletableFuture<JoinResponse> onJoin(final JoinRequest request) {
    raft.checkThread();
    logRequest(request);
    // See https://groups.google.com/forum/#!topic/raft-dev/t4xj6dJTP6E
    if (configuring() || initializing()) {
        return CompletableFuture.completedFuture(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.ERROR).build()));
    }
    // If the member is already a known member of the cluster, complete the join successfully.
    if (raft.getCluster().getMember(request.member().nodeId()) != null) {
        return CompletableFuture.completedFuture(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(raft.getCluster().getConfiguration().index()).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(raft.getCluster().getMembers()).build()));
    }
    RaftMember member = request.member();
    // Add the joining member to the members list. If the joining member's type is ACTIVE, join the member in the
    // PROMOTABLE state to allow it to get caught up without impacting the quorum size.
    Collection<RaftMember> members = raft.getCluster().getMembers();
    members.add(new DefaultRaftMember(member.nodeId(), member.getType(), Instant.now()));
    CompletableFuture<JoinResponse> future = new CompletableFuture<>();
    configure(members).whenComplete((index, error) -> {
        if (error == null) {
            future.complete(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(index).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(members).build()));
        } else {
            future.complete(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.PROTOCOL_ERROR).build()));
        }
    });
    return future;
}
Also used : JoinResponse(io.atomix.protocols.raft.protocol.JoinResponse) 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)

Example 4 with RaftMember

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

the class RaftTest method testJoinEvent.

/**
 * Tests a member join event.
 */
private void testJoinEvent(RaftMember.Type type) throws Throwable {
    List<RaftServer> servers = createServers(3);
    RaftMember member = nextMember(type);
    RaftServer server = servers.get(0);
    server.cluster().addListener(event -> {
        if (event.type() == RaftClusterEvent.Type.JOIN) {
            threadAssertEquals(event.subject().nodeId(), member.nodeId());
            resume();
        }
    });
    RaftServer joiner = createServer(member.nodeId());
    if (type == RaftMember.Type.ACTIVE) {
        joiner.join(members.stream().map(RaftMember::nodeId).collect(Collectors.toList())).thenRun(this::resume);
    } else {
        joiner.listen(members.stream().map(RaftMember::nodeId).collect(Collectors.toList())).thenRun(this::resume);
    }
    await(10000, 2);
}
Also used : RaftMember(io.atomix.protocols.raft.cluster.RaftMember) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember)

Example 5 with RaftMember

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

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