use of org.apache.ignite.raft.jraft.closure.SynchronizedClosure in project ignite-3 by apache.
the class ItNodeTest method testChangePeers.
@Test
public void testChangePeers() throws Exception {
PeerId peer0 = new PeerId(TestUtils.getLocalAddress(), TestUtils.INIT_PORT);
cluster = new TestCluster("testChangePeers", dataPath, Collections.singletonList(peer0), testInfo);
assertTrue(cluster.start(peer0.getEndpoint()));
cluster.waitLeader();
Node leader = cluster.getLeader();
sendTestTaskAndWait(leader);
for (int i = 1; i < 10; i++) {
PeerId peer = new PeerId(TestUtils.getLocalAddress(), TestUtils.INIT_PORT + i);
assertTrue(cluster.start(peer.getEndpoint(), false, 300));
}
for (int i = 0; i < 9; i++) {
cluster.waitLeader();
leader = cluster.getLeader();
assertNotNull(leader);
PeerId peer = new PeerId(TestUtils.getLocalAddress(), peer0.getEndpoint().getPort() + i);
assertEquals(peer, leader.getNodeId().getPeerId());
peer = new PeerId(TestUtils.getLocalAddress(), peer0.getEndpoint().getPort() + i + 1);
SynchronizedClosure done = new SynchronizedClosure();
leader.changePeers(new Configuration(Collections.singletonList(peer)), done);
Status status = done.await();
assertTrue(status.isOk(), status.getRaftError().toString());
}
cluster.waitLeader();
for (MockStateMachine fsm : cluster.getFsms()) {
assertEquals(10, fsm.getLogs().size());
}
}
use of org.apache.ignite.raft.jraft.closure.SynchronizedClosure in project ignite-3 by apache.
the class ItNodeTest method testChangePeersStepsDownInJointConsensus.
@Test
public void testChangePeersStepsDownInJointConsensus() throws Exception {
List<PeerId> peers = new ArrayList<>();
PeerId peer0 = JRaftUtils.getPeerId(TestUtils.getLocalAddress() + ":5006");
PeerId peer1 = JRaftUtils.getPeerId(TestUtils.getLocalAddress() + ":5007");
PeerId peer2 = JRaftUtils.getPeerId(TestUtils.getLocalAddress() + ":5008");
PeerId peer3 = JRaftUtils.getPeerId(TestUtils.getLocalAddress() + ":5009");
// start single cluster
peers.add(peer0);
cluster = new TestCluster("testChangePeersStepsDownInJointConsensus", dataPath, peers, testInfo);
assertTrue(cluster.start(peer0.getEndpoint()));
cluster.waitLeader();
Node leader = cluster.getLeader();
assertNotNull(leader);
sendTestTaskAndWait(leader);
// start peer1-3
assertTrue(cluster.start(peer1.getEndpoint()));
assertTrue(cluster.start(peer2.getEndpoint()));
assertTrue(cluster.start(peer3.getEndpoint()));
// Make sure the topology is ready before adding peers.
assertTrue(waitForTopology(cluster, leader.getNodeId().getPeerId().getEndpoint(), 4, 3_000));
Configuration conf = new Configuration();
conf.addPeer(peer0);
conf.addPeer(peer1);
conf.addPeer(peer2);
conf.addPeer(peer3);
// change peers
SynchronizedClosure done = new SynchronizedClosure();
leader.changePeers(conf, done);
assertTrue(done.await().isOk());
// stop peer3
assertTrue(cluster.stop(peer3.getEndpoint()));
conf.removePeer(peer0);
conf.removePeer(peer1);
// Change peers to [peer2, peer3], which must fail since peer3 is stopped
done.reset();
leader.changePeers(conf, done);
assertEquals(RaftError.EPERM, done.await().getRaftError());
LOG.info(done.getStatus().toString());
assertFalse(((NodeImpl) leader).getConf().isStable());
leader = cluster.getLeader();
assertNull(leader);
assertTrue(cluster.start(peer3.getEndpoint()));
Thread.sleep(1000);
cluster.waitLeader();
leader = cluster.getLeader();
List<PeerId> thePeers = leader.listPeers();
assertTrue(!thePeers.isEmpty());
assertEquals(conf.getPeerSet(), new HashSet<>(thePeers));
}
use of org.apache.ignite.raft.jraft.closure.SynchronizedClosure in project ignite-3 by apache.
the class NodeImpl method bootstrap.
public boolean bootstrap(final BootstrapOptions opts) throws InterruptedException {
if (opts.getLastLogIndex() > 0 && (opts.getGroupConf().isEmpty() || opts.getFsm() == null)) {
LOG.error("Invalid arguments for bootstrap, groupConf={}, fsm={}, lastLogIndex={}.", opts.getGroupConf(), opts.getFsm(), opts.getLastLogIndex());
return false;
}
if (opts.getGroupConf().isEmpty()) {
LOG.error("Bootstrapping an empty node makes no sense.");
return false;
}
Requires.requireNonNull(opts.getServiceFactory(), "Null jraft service factory");
this.serviceFactory = opts.getServiceFactory();
// Term is not an option since changing it is very dangerous
final long bootstrapLogTerm = opts.getLastLogIndex() > 0 ? 1 : 0;
final LogId bootstrapId = new LogId(opts.getLastLogIndex(), bootstrapLogTerm);
this.options = opts.getNodeOptions() == null ? new NodeOptions() : opts.getNodeOptions();
this.raftOptions = this.options.getRaftOptions();
this.metrics = new NodeMetrics(opts.isEnableMetrics());
this.options.setFsm(opts.getFsm());
this.options.setLogUri(opts.getLogUri());
this.options.setRaftMetaUri(opts.getRaftMetaUri());
this.options.setSnapshotUri(opts.getSnapshotUri());
this.configManager = new ConfigurationManager();
// Create fsmCaller at first as logManager needs it to report error
this.fsmCaller = new FSMCallerImpl();
initPools(opts.getNodeOptions());
if (!initLogStorage()) {
LOG.error("Fail to init log storage.");
return false;
}
if (!initMetaStorage()) {
LOG.error("Fail to init meta storage.");
return false;
}
if (this.currTerm == 0) {
this.currTerm = 1;
if (!this.metaStorage.setTermAndVotedFor(1, new PeerId())) {
LOG.error("Fail to set term.");
return false;
}
}
if (opts.getFsm() != null && !initFSMCaller(bootstrapId)) {
LOG.error("Fail to init fsm caller.");
return false;
}
final LogEntry entry = new LogEntry(EnumOutter.EntryType.ENTRY_TYPE_CONFIGURATION);
entry.getId().setTerm(this.currTerm);
entry.setPeers(opts.getGroupConf().listPeers());
entry.setLearners(opts.getGroupConf().listLearners());
final List<LogEntry> entries = new ArrayList<>();
entries.add(entry);
final BootstrapStableClosure bootstrapDone = new BootstrapStableClosure();
this.logManager.appendEntries(entries, bootstrapDone);
if (!bootstrapDone.await().isOk()) {
LOG.error("Fail to append configuration.");
return false;
}
if (opts.getLastLogIndex() > 0) {
if (!initSnapshotStorage()) {
LOG.error("Fail to init snapshot storage.");
return false;
}
final SynchronizedClosure snapshotDone = new SynchronizedClosure();
this.snapshotExecutor.doSnapshot(snapshotDone);
if (!snapshotDone.await().isOk()) {
LOG.error("Fail to save snapshot, status={}.", snapshotDone.getStatus());
return false;
}
}
if (this.logManager.getFirstLogIndex() != opts.getLastLogIndex() + 1) {
throw new IllegalStateException("First and last log index mismatch");
}
if (opts.getLastLogIndex() > 0) {
if (this.logManager.getLastLogIndex() != opts.getLastLogIndex()) {
throw new IllegalStateException("Last log index mismatch");
}
} else {
if (this.logManager.getLastLogIndex() != opts.getLastLogIndex() + 1) {
throw new IllegalStateException("Last log index mismatch");
}
}
return true;
}
use of org.apache.ignite.raft.jraft.closure.SynchronizedClosure in project ignite-3 by apache.
the class ItNodeTest method testChangePeersChaosWithoutSnapshot.
@Test
public void testChangePeersChaosWithoutSnapshot() throws Exception {
// start cluster
List<PeerId> peers = new ArrayList<>();
peers.add(new PeerId(TestUtils.getLocalAddress(), TestUtils.INIT_PORT));
cluster = new TestCluster("unittest", dataPath, peers, ELECTION_TIMEOUT_MILLIS, testInfo);
assertTrue(cluster.start(peers.get(0).getEndpoint(), false, 100000));
// start other peers
for (int i = 1; i < 10; i++) {
PeerId peer = new PeerId(TestUtils.getLocalAddress(), TestUtils.INIT_PORT + i);
peers.add(peer);
assertTrue(cluster.start(peer.getEndpoint(), false, 10000));
}
ChangeArg arg = new ChangeArg(cluster, peers, false, true);
Future<?> future = startChangePeersThread(arg);
final int tasks = 5000;
for (int i = 0; i < tasks; ) {
cluster.waitLeader();
Node leader = cluster.getLeader();
if (leader == null)
continue;
SynchronizedClosure done = new SynchronizedClosure();
Task task = new Task(ByteBuffer.wrap(("hello" + i).getBytes(UTF_8)), done);
leader.apply(task);
Status status = done.await();
if (status.isOk()) {
if (++i % 100 == 0)
System.out.println("Progress:" + i);
} else
assertEquals(RaftError.EPERM, status.getRaftError());
}
arg.stop = true;
future.get();
cluster.waitLeader();
SynchronizedClosure done = new SynchronizedClosure();
Node leader = cluster.getLeader();
leader.changePeers(new Configuration(peers), done);
assertTrue(done.await().isOk());
cluster.ensureSame();
assertEquals(10, cluster.getFsms().size());
for (MockStateMachine fsm : cluster.getFsms()) {
assertTrue(fsm.getLogs().size() >= tasks);
assertTrue(fsm.getLogs().size() - tasks < 100);
}
}
use of org.apache.ignite.raft.jraft.closure.SynchronizedClosure in project ignite-3 by apache.
the class ItNodeTest method testTripleNodesWithLearners.
@Test
public void testTripleNodesWithLearners() throws Exception {
List<PeerId> peers = TestUtils.generatePeers(3);
cluster = new TestCluster("unittest", dataPath, peers, testInfo);
for (PeerId peer : peers) assertTrue(cluster.start(peer.getEndpoint()));
// elect leader
cluster.waitLeader();
// get leader
Node leader = cluster.getLeader();
assertNotNull(leader);
cluster.ensureLeader(leader);
assertEquals(3, leader.listPeers().size());
assertTrue(leader.listLearners().isEmpty());
assertTrue(leader.listAliveLearners().isEmpty());
{
// Adds a learner
SynchronizedClosure done = new SynchronizedClosure();
PeerId learnerPeer = new PeerId(TestUtils.getLocalAddress(), TestUtils.INIT_PORT + 3);
// Start learner
assertTrue(cluster.startLearner(learnerPeer));
leader.addLearners(Arrays.asList(learnerPeer), done);
assertTrue(done.await().isOk());
assertEquals(1, leader.listAliveLearners().size());
assertEquals(1, leader.listLearners().size());
}
// apply tasks to leader
sendTestTaskAndWait(leader);
{
ByteBuffer data = ByteBuffer.wrap("no closure".getBytes(UTF_8));
Task task = new Task(data, null);
leader.apply(task);
}
{
// task with TaskClosure
ByteBuffer data = ByteBuffer.wrap("task closure".getBytes(UTF_8));
List<String> cbs = synchronizedList(new ArrayList<>());
CountDownLatch latch = new CountDownLatch(1);
Task task = new Task(data, new TaskClosure() {
@Override
public void run(Status status) {
cbs.add("apply");
latch.countDown();
}
@Override
public void onCommitted() {
cbs.add("commit");
}
});
leader.apply(task);
latch.await();
assertEquals(2, cbs.size());
assertEquals("commit", cbs.get(0));
assertEquals("apply", cbs.get(1));
}
assertEquals(4, cluster.getFsms().size());
assertEquals(2, cluster.getFollowers().size());
assertEquals(1, cluster.getLearners().size());
cluster.ensureSame();
{
// Adds another learner
SynchronizedClosure done = new SynchronizedClosure();
PeerId learnerPeer = new PeerId(TestUtils.getLocalAddress(), TestUtils.INIT_PORT + 4);
// Start learner
assertTrue(cluster.startLearner(learnerPeer));
leader.addLearners(Arrays.asList(learnerPeer), done);
assertTrue(done.await().isOk());
assertEquals(2, leader.listAliveLearners().size());
assertEquals(2, leader.listLearners().size());
cluster.ensureSame();
}
{
// stop two followers
for (Node follower : cluster.getFollowers()) assertTrue(cluster.stop(follower.getNodeId().getPeerId().getEndpoint()));
// send a new task
ByteBuffer data = ByteBuffer.wrap("task closure".getBytes(UTF_8));
SynchronizedClosure done = new SynchronizedClosure();
leader.apply(new Task(data, done));
// should fail
assertFalse(done.await().isOk());
assertEquals(RaftError.EPERM, done.getStatus().getRaftError());
// One peer with two learners.
assertEquals(3, cluster.getFsms().size());
}
}
Aggregations