use of com.alipay.sofa.jraft.closure.SynchronizedClosure in project sofa-jraft by sofastack.
the class NodeTest method testChangePeersAddMultiNodes.
@Test
public void testChangePeersAddMultiNodes() throws Exception {
final PeerId peer0 = new PeerId(TestUtils.getMyIp(), TestUtils.INIT_PORT);
final TestCluster cluster = new TestCluster("testChangePeers", this.dataPath, Collections.singletonList(peer0));
assertTrue(cluster.start(peer0.getEndpoint()));
cluster.waitLeader();
final Node leader = cluster.getLeader();
this.sendTestTaskAndWait(leader);
final Configuration conf = new Configuration();
for (int i = 0; i < 3; i++) {
final PeerId peer = new PeerId(TestUtils.getMyIp(), TestUtils.INIT_PORT + i);
conf.addPeer(peer);
}
PeerId peer = new PeerId(TestUtils.getMyIp(), peer0.getEndpoint().getPort() + 1);
// fail, because the peers are not started.
final SynchronizedClosure done = new SynchronizedClosure();
leader.changePeers(new Configuration(Collections.singletonList(peer)), done);
Assert.assertEquals(RaftError.ECATCHUP, done.await().getRaftError());
// start peer1
assertTrue(cluster.start(peer.getEndpoint()));
// still fail, because peer2 is not started
done.reset();
leader.changePeers(conf, done);
Assert.assertEquals(RaftError.ECATCHUP, done.await().getRaftError());
// start peer2
peer = new PeerId(TestUtils.getMyIp(), peer0.getEndpoint().getPort() + 2);
assertTrue(cluster.start(peer.getEndpoint()));
done.reset();
// works
leader.changePeers(conf, done);
assertTrue(done.await().isOk());
assertTrue(cluster.ensureSame());
assertEquals(3, cluster.getFsms().size());
for (final MockStateMachine fsm : cluster.getFsms()) {
assertEquals(10, fsm.getLogs().size());
}
cluster.stopAll();
}
use of com.alipay.sofa.jraft.closure.SynchronizedClosure in project sofa-jraft by sofastack.
the class SnapshotExecutorTest method testDoSnapshot.
@Test
public void testDoSnapshot() throws Exception {
Mockito.when(this.fSMCaller.getLastAppliedIndex()).thenReturn(1L);
final ArgumentCaptor<SaveSnapshotClosure> saveSnapshotClosureArg = ArgumentCaptor.forClass(SaveSnapshotClosure.class);
Mockito.when(this.fSMCaller.onSnapshotSave(saveSnapshotClosureArg.capture())).thenReturn(true);
final SynchronizedClosure done = new SynchronizedClosure();
this.executor.doSnapshot(done);
final SaveSnapshotClosure closure = saveSnapshotClosureArg.getValue();
assertNotNull(closure);
closure.start(RaftOutter.SnapshotMeta.newBuilder().setLastIncludedIndex(2).setLastIncludedTerm(1).build());
closure.run(Status.OK());
done.await();
this.executor.join();
assertTrue(done.getStatus().isOk());
assertEquals(1, this.executor.getLastSnapshotTerm());
assertEquals(2, this.executor.getLastSnapshotIndex());
}
use of com.alipay.sofa.jraft.closure.SynchronizedClosure in project sofa-jraft by sofastack.
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 = new NodeOptions();
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();
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;
}
Aggregations