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;
}
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;
}
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;
}
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);
}
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);
}
});
}
Aggregations