Search in sources :

Example 1 with GroupMember

use of io.atomix.primitive.partition.GroupMember 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();
    }
}
Also used : GroupMember(io.atomix.primitive.partition.GroupMember) MemberId(io.atomix.cluster.MemberId) PrimaryElectionEvent(io.atomix.primitive.partition.PrimaryElectionEvent) ArrayList(java.util.ArrayList) GroupMember(io.atomix.primitive.partition.GroupMember) Member(io.atomix.cluster.Member) PrimaryTerm(io.atomix.primitive.partition.PrimaryTerm)

Example 2 with GroupMember

use of io.atomix.primitive.partition.GroupMember in project atomix by atomix.

the class PrimaryElectorServiceTest method testEnterSeveralPartitions.

@Test
public void testEnterSeveralPartitions() {
    PrimaryElectorService elector = newService();
    PrimaryTerm term = null;
    int numParts = 10;
    int numMembers = 20;
    List<List<GroupMember>> allMembers = new ArrayList<>();
    List<PrimaryTerm> terms = new ArrayList<>();
    for (int p = 0; p < numParts; p++) {
        PartitionId partId = new PartitionId("test", p);
        allMembers.add(new ArrayList<>());
        // Add all members in same group.
        for (int i = 0; i < numMembers; i++) {
            GroupMember m = createGroupMember("node" + i, "group1");
            allMembers.get(p).add(m);
            Session<?> s = createSession(m);
            term = elector.enter(createEnterOp(partId, m, s));
        }
        if (term != null) {
            terms.add(term);
        }
    }
    // Check primary and candidates in each partition.
    for (int p = 0; p < numParts; p++) {
        assertEquals(1L, terms.get(p).term());
        assertEquals(allMembers.get(p).get(0), terms.get(p).primary());
        assertEquals(numMembers, terms.get(p).candidates().size());
        for (int i = 0; i < numMembers; i++) {
            assertEquals(allMembers.get(p).get(i), terms.get(p).candidates().get(i));
        }
    }
}
Also used : GroupMember(io.atomix.primitive.partition.GroupMember) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) PartitionId(io.atomix.primitive.partition.PartitionId) PrimaryTerm(io.atomix.primitive.partition.PrimaryTerm) Test(org.junit.Test)

Example 3 with GroupMember

use of io.atomix.primitive.partition.GroupMember in project atomix by atomix.

the class PrimaryElectorServiceTest method testEnterAndExpireSessions.

@Test
public void testEnterAndExpireSessions() {
    PrimaryElectorService elector = newService();
    PartitionId partId = new PartitionId("test", 1);
    PrimaryTerm term = null;
    int numMembers = 9;
    // Add 9 members in 3 different groups.
    List<Session<?>> sessions = new ArrayList<>();
    List<GroupMember> members = new ArrayList<>();
    for (int i = 0; i < numMembers; i++) {
        GroupMember m = createGroupMember("node" + i, "group" + (i / 3));
        members.add(m);
        Session<?> s = createSession(m);
        sessions.add(s);
        term = elector.enter(createEnterOp(partId, m, s));
    }
    // Check current primary.
    assertEquals(1L, term.term());
    assertEquals(members.get(0), term.primary());
    assertEquals(numMembers, term.candidates().size());
    List<GroupMember> backups1 = term.backups(2);
    assertEquals(members.get(3), backups1.get(0));
    assertEquals(members.get(6), backups1.get(1));
    // Expire session of primary and check new term.
    // New primary should be the first of the old backups.
    elector.onExpire(sessions.get(0));
    term = elector.getTerm(createGetTermOp(partId, members.get(3), sessions.get(3)));
    assertEquals(2L, term.term());
    assertEquals(members.get(3), term.primary());
    assertEquals(numMembers - 1, term.candidates().size());
    List<GroupMember> backups2 = term.backups(2);
    assertEquals(members.get(6), backups2.get(0));
    assertEquals(members.get(1), backups2.get(1));
    // Expire session of backup and check term updated.
    elector.onExpire(sessions.get(6));
    term = elector.getTerm(createGetTermOp(partId, members.get(5), sessions.get(5)));
    assertEquals(2L, term.term());
    assertEquals(members.get(3), term.primary());
    assertEquals(numMembers - 2, term.candidates().size());
    List<GroupMember> backups3 = term.backups(2);
    assertEquals(members.get(1), backups3.get(0));
    assertEquals(members.get(4), backups3.get(1));
}
Also used : GroupMember(io.atomix.primitive.partition.GroupMember) ArrayList(java.util.ArrayList) PartitionId(io.atomix.primitive.partition.PartitionId) PrimaryTerm(io.atomix.primitive.partition.PrimaryTerm) Session(io.atomix.primitive.session.Session) Test(org.junit.Test)

Example 4 with GroupMember

use of io.atomix.primitive.partition.GroupMember in project atomix by atomix.

the class PrimaryElectorServiceTest method testEnterSinglePartitionWithGroups.

@Test
public void testEnterSinglePartitionWithGroups() {
    PrimaryElectorService elector = newService();
    PartitionId partId = new PartitionId("test", 1);
    PrimaryTerm term = null;
    int numMembers = 9;
    // Add 9 members in 3 different groups.
    List<GroupMember> members = new ArrayList<>();
    for (int i = 0; i < numMembers; i++) {
        GroupMember m = createGroupMember("node" + i, "group" + (i / 3));
        members.add(m);
        Session<?> s = createSession(m);
        term = elector.enter(createEnterOp(partId, m, s));
    }
    // Check primary and candidates.
    assertEquals(1L, term.term());
    assertEquals(members.get(0), term.primary());
    assertEquals(numMembers, term.candidates().size());
    // Check backups are selected in different groups.
    List<GroupMember> backups2 = term.backups(2);
    assertEquals(members.get(3), backups2.get(0));
    assertEquals(members.get(6), backups2.get(1));
    List<GroupMember> backups3 = term.backups(3);
    assertEquals(members.get(3), backups3.get(0));
    assertEquals(members.get(6), backups3.get(1));
    assertEquals(members.get(1), backups3.get(2));
}
Also used : GroupMember(io.atomix.primitive.partition.GroupMember) ArrayList(java.util.ArrayList) PartitionId(io.atomix.primitive.partition.PartitionId) PrimaryTerm(io.atomix.primitive.partition.PrimaryTerm) Test(org.junit.Test)

Example 5 with GroupMember

use of io.atomix.primitive.partition.GroupMember in project atomix by atomix.

the class DistributedLogServerContext method start.

@Override
public CompletableFuture<Void> start() {
    registerListeners();
    compactTimer = threadContext.schedule(Duration.ofSeconds(30), this::compact);
    return memberGroupService.start().thenComposeAsync(v -> {
        MemberGroup group = memberGroupService.getMemberGroup(clusterMembershipService.getLocalMember());
        primaryElection.addListener(primaryElectionListener);
        if (group != null) {
            return primaryElection.enter(new GroupMember(clusterMembershipService.getLocalMember().id(), group.id())).thenApply(term -> {
                changeRole(term);
                return null;
            });
        }
        return CompletableFuture.completedFuture(null);
    }, threadContext).thenApply(v -> {
        started.set(true);
        return null;
    });
}
Also used : LogResponse(io.atomix.protocols.log.protocol.LogResponse) LogServerProtocol(io.atomix.protocols.log.protocol.LogServerProtocol) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) PrimaryElectionEventListener(io.atomix.primitive.partition.PrimaryElectionEventListener) ConsumeRequest(io.atomix.protocols.log.protocol.ConsumeRequest) JournalWriter(io.atomix.storage.journal.JournalWriter) Supplier(java.util.function.Supplier) BackupResponse(io.atomix.protocols.log.protocol.BackupResponse) Managed(io.atomix.utils.Managed) LogEntry(io.atomix.protocols.log.protocol.LogEntry) ClusterMembershipService(io.atomix.cluster.ClusterMembershipService) Duration(java.time.Duration) PrimaryTerm(io.atomix.primitive.partition.PrimaryTerm) MemberId(io.atomix.cluster.MemberId) AppendRequest(io.atomix.protocols.log.protocol.AppendRequest) Role(io.atomix.protocols.log.DistributedLogServer.Role) Scheduled(io.atomix.utils.concurrent.Scheduled) ConsumeResponse(io.atomix.protocols.log.protocol.ConsumeResponse) ResetRequest(io.atomix.protocols.log.protocol.ResetRequest) LogServerRole(io.atomix.protocols.log.roles.LogServerRole) Futures(io.atomix.utils.concurrent.Futures) BackupRequest(io.atomix.protocols.log.protocol.BackupRequest) GroupMember(io.atomix.primitive.partition.GroupMember) DistributedLogServer(io.atomix.protocols.log.DistributedLogServer) Logger(org.slf4j.Logger) LoggerContext(io.atomix.utils.logging.LoggerContext) Collection(java.util.Collection) FollowerRole(io.atomix.protocols.log.roles.FollowerRole) LeaderRole(io.atomix.protocols.log.roles.LeaderRole) Collectors(java.util.stream.Collectors) ManagedMemberGroupService(io.atomix.primitive.partition.ManagedMemberGroupService) SegmentedJournal(io.atomix.storage.journal.SegmentedJournal) ThreadContext(io.atomix.utils.concurrent.ThreadContext) Objects(java.util.Objects) NoneRole(io.atomix.protocols.log.roles.NoneRole) ThreadContextFactory(io.atomix.utils.concurrent.ThreadContextFactory) List(java.util.List) JournalSegment(io.atomix.storage.journal.JournalSegment) MemberGroup(io.atomix.primitive.partition.MemberGroup) AppendResponse(io.atomix.protocols.log.protocol.AppendResponse) ContextualLogger(io.atomix.utils.logging.ContextualLogger) PrimaryElection(io.atomix.primitive.partition.PrimaryElection) Replication(io.atomix.primitive.Replication) JournalReader(io.atomix.storage.journal.JournalReader) MemberGroup(io.atomix.primitive.partition.MemberGroup) GroupMember(io.atomix.primitive.partition.GroupMember)

Aggregations

GroupMember (io.atomix.primitive.partition.GroupMember)9 PrimaryTerm (io.atomix.primitive.partition.PrimaryTerm)6 PartitionId (io.atomix.primitive.partition.PartitionId)5 ArrayList (java.util.ArrayList)4 Test (org.junit.Test)4 MemberId (io.atomix.cluster.MemberId)2 Session (io.atomix.primitive.session.Session)2 FollowerRole (io.atomix.protocols.log.roles.FollowerRole)2 LeaderRole (io.atomix.protocols.log.roles.LeaderRole)2 NoneRole (io.atomix.protocols.log.roles.NoneRole)2 List (java.util.List)2 ClusterMembershipService (io.atomix.cluster.ClusterMembershipService)1 Member (io.atomix.cluster.Member)1 Replication (io.atomix.primitive.Replication)1 ManagedMemberGroupService (io.atomix.primitive.partition.ManagedMemberGroupService)1 MemberGroup (io.atomix.primitive.partition.MemberGroup)1 PrimaryElection (io.atomix.primitive.partition.PrimaryElection)1 PrimaryElectionEvent (io.atomix.primitive.partition.PrimaryElectionEvent)1 PrimaryElectionEventListener (io.atomix.primitive.partition.PrimaryElectionEventListener)1 BackupRole (io.atomix.protocols.backup.roles.BackupRole)1