use of io.atomix.cluster.MemberId in project atomix by atomix.
the class RaftClusterContext method listen.
@Override
public synchronized CompletableFuture<Void> listen(Collection<MemberId> 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.memberId())).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();
}
use of io.atomix.cluster.MemberId in project atomix by atomix.
the class RaftClusterContext method bootstrap.
@Override
public CompletableFuture<Void> bootstrap(Collection<MemberId> 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.memberId())).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();
}
use of io.atomix.cluster.MemberId in project atomix by atomix.
the class RaftClusterContext method join.
@Override
public synchronized CompletableFuture<Void> join(Collection<MemberId> 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.memberId())).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);
}
});
}
use of io.atomix.cluster.MemberId in project atomix by atomix.
the class HashBasedPrimaryElection method recomputeTerm.
/**
* Recomputes the current term.
*/
private synchronized void recomputeTerm(PartitionGroupMembership membership) {
if (membership == null) {
return;
}
// Create a list of candidates based on the availability of members in the group.
List<GroupMember> candidates = new ArrayList<>();
for (MemberId memberId : membership.members()) {
Member member = clusterMembershipService.getMember(memberId);
if (member != null && member.isReachable()) {
candidates.add(new GroupMember(memberId, MemberGroupId.from(memberId.id())));
}
}
// Sort the candidates by a hash of their member ID.
candidates.sort((a, b) -> {
int aoffset = Hashing.murmur3_32().hashString(a.memberId().id(), StandardCharsets.UTF_8).asInt() % partitionId.id();
int boffset = Hashing.murmur3_32().hashString(b.memberId().id(), StandardCharsets.UTF_8).asInt() % partitionId.id();
return aoffset - boffset;
});
// Store the current term in a local variable avoid repeated volatile reads.
PrimaryTerm currentTerm = this.currentTerm;
// Compute the primary from the sorted candidates list.
GroupMember primary = candidates.isEmpty() ? null : candidates.get(0);
// Remove the primary from the candidates list.
candidates = candidates.isEmpty() ? Collections.emptyList() : candidates.subList(1, candidates.size());
// If the primary has changed, increment the term. Otherwise, use the current term from the replicated counter.
long term = currentTerm != null && Objects.equals(currentTerm.primary(), primary) && Objects.equals(currentTerm.candidates(), candidates) ? currentTerm() : incrementTerm();
// Create the new primary term. If the term has changed update the term and trigger an event.
PrimaryTerm newTerm = new PrimaryTerm(term, primary, candidates);
if (!Objects.equals(currentTerm, newTerm)) {
this.currentTerm = newTerm;
LOGGER.debug("{} - Recomputed term for partition {}: {}", clusterMembershipService.getLocalMember().id(), partitionId, newTerm);
post(new PrimaryElectionEvent(PrimaryElectionEvent.Type.CHANGED, partitionId, newTerm));
broadcastCounters();
}
}
use of io.atomix.cluster.MemberId in project atomix by atomix.
the class PrimaryElectorServiceTest method newService.
PrimaryElectorService newService() {
PrimaryElectorService elector = new PrimaryElectorService();
elector.init(new ServiceContext() {
@Override
public PrimitiveId serviceId() {
return PrimitiveId.from(1L);
}
@Override
public String serviceName() {
return "test-primary-elector";
}
@SuppressWarnings("rawtypes")
@Override
public PrimitiveType serviceType() {
return PrimaryElectorType.instance();
}
@Override
public MemberId localMemberId() {
return null;
}
@Override
public <C extends ServiceConfig> C serviceConfig() {
return null;
}
@Override
public long currentIndex() {
return 0;
}
@Override
public Session<?> currentSession() {
return null;
}
@Override
public OperationType currentOperation() {
return null;
}
@Override
public LogicalClock logicalClock() {
return null;
}
@Override
public WallClock wallClock() {
return null;
}
});
elector.tick(WallClockTimestamp.from(System.currentTimeMillis()));
return elector;
}
Aggregations