use of com.hazelcast.config.cp.RaftAlgorithmConfig in project hazelcast by hazelcast.
the class MembershipChangeTest method when_newRaftNodeJoinsAfterAnotherNodeLeavesAndSnapshotIsTaken_then_itAppendsMissingEntries.
@Test
public void when_newRaftNodeJoinsAfterAnotherNodeLeavesAndSnapshotIsTaken_then_itAppendsMissingEntries() throws ExecutionException, InterruptedException {
int commitIndexAdvanceCountToSnapshot = 10;
RaftAlgorithmConfig config = new RaftAlgorithmConfig().setCommitIndexAdvanceCountToSnapshot(commitIndexAdvanceCountToSnapshot);
group = newGroup(3, config);
group.start();
RaftNodeImpl leader = group.waitUntilLeaderElected();
leader.replicate(new ApplyRaftRunnable("val")).get();
RaftNodeImpl[] followers = group.getNodesExcept(leader.getLocalMember());
RaftNodeImpl leavingFollower = followers[0];
RaftNodeImpl stayingFollower = followers[1];
leader.replicateMembershipChange(leavingFollower.getLocalMember(), REMOVE).get();
for (int i = 0; i < commitIndexAdvanceCountToSnapshot; i++) {
leader.replicate(new ApplyRaftRunnable("val" + i)).get();
}
assertTrueEventually(() -> assertTrue(getSnapshotEntry(leader).index() > 0));
RaftNodeImpl newRaftNode = group.createNewRaftNode();
leader.replicateMembershipChange(newRaftNode.getLocalMember(), MembershipChangeMode.ADD).get();
long commitIndex = getCommitIndex(leader);
assertTrueEventually(() -> assertEquals(commitIndex, getCommitIndex(newRaftNode)));
RaftGroupMembers lastGroupMembers = RaftUtil.getLastGroupMembers(leader);
assertTrueEventually(() -> {
for (RaftNodeImpl raftNode : asList(leader, stayingFollower, newRaftNode)) {
assertEquals(RaftNodeStatus.ACTIVE, getStatus(raftNode));
assertEquals(lastGroupMembers.members(), getLastGroupMembers(raftNode).members());
assertEquals(lastGroupMembers.index(), getLastGroupMembers(raftNode).index());
assertEquals(lastGroupMembers.members(), getCommittedGroupMembers(raftNode).members());
assertEquals(lastGroupMembers.index(), getCommittedGroupMembers(raftNode).index());
assertFalse(getLastGroupMembers(raftNode).isKnownMember(leavingFollower.getLocalMember()));
assertFalse(getCommittedGroupMembers(raftNode).isKnownMember(leavingFollower.getLocalMember()));
}
});
RaftDataService service = group.getService(newRaftNode);
assertEquals(commitIndexAdvanceCountToSnapshot + 1, service.size());
assertTrue(service.values().contains("val"));
for (int i = 0; i < commitIndexAdvanceCountToSnapshot; i++) {
assertTrue(service.values().contains("val" + i));
}
}
use of com.hazelcast.config.cp.RaftAlgorithmConfig in project hazelcast by hazelcast.
the class TestFullApplicationContext method testCPSubsystemConfig.
@Test
public void testCPSubsystemConfig() {
CPSubsystemConfig cpSubsystemConfig = config.getCPSubsystemConfig();
assertEquals(0, cpSubsystemConfig.getCPMemberCount());
assertEquals(0, cpSubsystemConfig.getGroupSize());
assertEquals(15, cpSubsystemConfig.getSessionTimeToLiveSeconds());
assertEquals(3, cpSubsystemConfig.getSessionHeartbeatIntervalSeconds());
assertEquals(120, cpSubsystemConfig.getMissingCPMemberAutoRemovalSeconds());
assertEquals(30, cpSubsystemConfig.getDataLoadTimeoutSeconds());
assertTrue(cpSubsystemConfig.isFailOnIndeterminateOperationState());
assertFalse(cpSubsystemConfig.isPersistenceEnabled());
assertEquals(new File("/custom-dir").getAbsolutePath(), cpSubsystemConfig.getBaseDir().getAbsolutePath());
RaftAlgorithmConfig raftAlgorithmConfig = cpSubsystemConfig.getRaftAlgorithmConfig();
assertEquals(500, raftAlgorithmConfig.getLeaderElectionTimeoutInMillis());
assertEquals(100, raftAlgorithmConfig.getLeaderHeartbeatPeriodInMillis());
assertEquals(3, raftAlgorithmConfig.getMaxMissedLeaderHeartbeatCount());
assertEquals(25, raftAlgorithmConfig.getAppendRequestMaxEntryCount());
assertEquals(250, raftAlgorithmConfig.getCommitIndexAdvanceCountToSnapshot());
assertEquals(75, raftAlgorithmConfig.getUncommittedEntryCountToRejectNewAppends());
assertEquals(50, raftAlgorithmConfig.getAppendRequestBackoffTimeoutInMillis());
SemaphoreConfig semaphoreConfig1 = cpSubsystemConfig.findSemaphoreConfig("sem1");
SemaphoreConfig semaphoreConfig2 = cpSubsystemConfig.findSemaphoreConfig("sem2");
assertNotNull(semaphoreConfig1);
assertNotNull(semaphoreConfig2);
assertTrue(semaphoreConfig1.isJDKCompatible());
assertFalse(semaphoreConfig2.isJDKCompatible());
assertEquals(1, semaphoreConfig1.getInitialPermits());
assertEquals(2, semaphoreConfig2.getInitialPermits());
FencedLockConfig lockConfig1 = cpSubsystemConfig.findLockConfig("lock1");
FencedLockConfig lockConfig2 = cpSubsystemConfig.findLockConfig("lock2");
assertNotNull(lockConfig1);
assertNotNull(lockConfig2);
assertEquals(1, lockConfig1.getLockAcquireLimit());
assertEquals(2, lockConfig2.getLockAcquireLimit());
}
use of com.hazelcast.config.cp.RaftAlgorithmConfig in project hazelcast by hazelcast.
the class ConfigXmlGenerator method cpSubsystemConfig.
private static void cpSubsystemConfig(XmlGenerator gen, Config config) {
CPSubsystemConfig cpSubsystemConfig = config.getCPSubsystemConfig();
gen.open("cp-subsystem").node("cp-member-count", cpSubsystemConfig.getCPMemberCount()).node("group-size", cpSubsystemConfig.getGroupSize()).node("session-time-to-live-seconds", cpSubsystemConfig.getSessionTimeToLiveSeconds()).node("session-heartbeat-interval-seconds", cpSubsystemConfig.getSessionHeartbeatIntervalSeconds()).node("missing-cp-member-auto-removal-seconds", cpSubsystemConfig.getMissingCPMemberAutoRemovalSeconds()).node("fail-on-indeterminate-operation-state", cpSubsystemConfig.isFailOnIndeterminateOperationState()).node("persistence-enabled", cpSubsystemConfig.isPersistenceEnabled()).node("base-dir", cpSubsystemConfig.getBaseDir().getAbsolutePath()).node("data-load-timeout-seconds", cpSubsystemConfig.getDataLoadTimeoutSeconds());
RaftAlgorithmConfig raftAlgorithmConfig = cpSubsystemConfig.getRaftAlgorithmConfig();
gen.open("raft-algorithm").node("leader-election-timeout-in-millis", raftAlgorithmConfig.getLeaderElectionTimeoutInMillis()).node("leader-heartbeat-period-in-millis", raftAlgorithmConfig.getLeaderHeartbeatPeriodInMillis()).node("max-missed-leader-heartbeat-count", raftAlgorithmConfig.getMaxMissedLeaderHeartbeatCount()).node("append-request-max-entry-count", raftAlgorithmConfig.getAppendRequestMaxEntryCount()).node("commit-index-advance-count-to-snapshot", raftAlgorithmConfig.getCommitIndexAdvanceCountToSnapshot()).node("uncommitted-entry-count-to-reject-new-appends", raftAlgorithmConfig.getUncommittedEntryCountToRejectNewAppends()).node("append-request-backoff-timeout-in-millis", raftAlgorithmConfig.getAppendRequestBackoffTimeoutInMillis()).close();
gen.open("semaphores");
for (SemaphoreConfig semaphoreConfig : cpSubsystemConfig.getSemaphoreConfigs().values()) {
gen.open("semaphore").node("name", semaphoreConfig.getName()).node("jdk-compatible", semaphoreConfig.isJDKCompatible()).node("initial-permits", semaphoreConfig.getInitialPermits()).close();
}
gen.close().open("locks");
for (FencedLockConfig lockConfig : cpSubsystemConfig.getLockConfigs().values()) {
gen.open("fenced-lock").node("name", lockConfig.getName()).node("lock-acquire-limit", lockConfig.getLockAcquireLimit()).close();
}
gen.close().close();
}
use of com.hazelcast.config.cp.RaftAlgorithmConfig in project hazelcast by hazelcast.
the class RaftService method createRaftNode.
void createRaftNode(CPGroupId groupId, Collection<RaftEndpoint> members, RaftEndpoint localCPMember) {
assert !(Thread.currentThread() instanceof PartitionOperationThread) : "Cannot create RaftNode of " + groupId + " in a partition thread!";
if (nodes.containsKey(groupId) || !isStartCompleted() || !hasSameSeed(groupId)) {
return;
}
if (getLocalCPMember() == null) {
logger.warning("Not creating Raft node for " + groupId + " because local CP member is not initialized yet.");
return;
}
nodeLock.readLock().lock();
try {
if (destroyedGroupIds.contains(groupId)) {
logger.warning("Not creating RaftNode[" + groupId + "] since the CP group is already destroyed.");
return;
} else if (terminatedRaftNodeGroupIds.contains(groupId)) {
if (!nodeEngine.isRunning()) {
logger.fine("Not creating RaftNode[" + groupId + "] since the local CP member is already terminated.");
return;
}
}
int partitionId = getCPGroupPartitionId(groupId);
RaftIntegration integration = new NodeEngineRaftIntegration(nodeEngine, groupId, localCPMember, partitionId);
RaftAlgorithmConfig raftAlgorithmConfig = config.getRaftAlgorithmConfig();
CPPersistenceService persistenceService = getCPPersistenceService();
RaftStateStore stateStore = persistenceService.createRaftStateStore((RaftGroupId) groupId, null);
RaftNodeImpl node = newRaftNode(groupId, localCPMember, members, raftAlgorithmConfig, integration, stateStore);
if (nodes.putIfAbsent(groupId, node) == null) {
if (destroyedGroupIds.contains(groupId)) {
nodes.remove(groupId, node);
removeNodeMetrics(groupId);
logger.warning("Not creating RaftNode[" + groupId + "] since the CP group is already destroyed.");
return;
}
node.start();
logger.info("RaftNode[" + groupId + "] is created with " + members);
}
} finally {
nodeLock.readLock().unlock();
}
}
use of com.hazelcast.config.cp.RaftAlgorithmConfig in project hazelcast by hazelcast.
the class RaftNodeImpl method takeSnapshotIfCommitIndexAdvanced.
/**
* Takes a snapshot if the advance in {@code commitIndex} is equal to
* {@link RaftAlgorithmConfig#getCommitIndexAdvanceCountToSnapshot()}.
* <p>
* Snapshot is not created if the Raft group is being destroyed.
*/
@SuppressWarnings("checkstyle:npathcomplexity")
private void takeSnapshotIfCommitIndexAdvanced() {
long commitIndex = state.commitIndex();
if ((commitIndex - state.log().snapshotIndex()) < commitIndexAdvanceCountToSnapshot) {
return;
}
if (isTerminatedOrSteppedDown()) {
// If the status is TERMINATED or STEPPED_DOWN, then there will not be any new appends.
return;
}
RaftLog log = state.log();
Object snapshot = raftIntegration.takeSnapshot(commitIndex);
if (snapshot instanceof Throwable) {
Throwable t = (Throwable) snapshot;
logger.severe("Could not take snapshot at commit index: " + commitIndex, t);
return;
}
int snapshotTerm = log.getLogEntry(commitIndex).term();
RaftGroupMembers members = state.committedGroupMembers();
SnapshotEntry snapshotEntry = new SnapshotEntry(snapshotTerm, commitIndex, snapshot, members.index(), members.members());
long highestLogIndexToTruncate = commitIndex - maxNumberOfLogsToKeepAfterSnapshot;
LeaderState leaderState = state.leaderState();
if (leaderState != null) {
long[] matchIndices = leaderState.matchIndices();
// Last slot is reserved for leader index and always zero.
// If there is at least one follower with unknown match index,
// its log can be close to the leader's log so we are keeping the old log entries.
boolean allMatchIndicesKnown = Arrays.stream(matchIndices, 0, matchIndices.length - 1).noneMatch(i -> i == 0);
if (allMatchIndicesKnown) {
// Otherwise, we will keep the log entries until the minimum match index
// that is bigger than (commitIndex - maxNumberOfLogsToKeepAfterSnapshot).
// If there is no such follower (all of the minority followers are far behind),
// then there is no need to keep the old log entries.
highestLogIndexToTruncate = Arrays.stream(matchIndices).filter(i -> i < commitIndex).filter(i -> i > commitIndex - maxNumberOfLogsToKeepAfterSnapshot).map(i -> i - 1).sorted().findFirst().orElse(commitIndex);
}
}
int truncatedEntryCount = log.setSnapshot(snapshotEntry, highestLogIndexToTruncate);
if (logger.isFineEnabled()) {
logger.fine(snapshotEntry + " is taken, " + truncatedEntryCount + " entries are truncated.");
}
}
Aggregations