use of org.apache.ratis.RaftTestUtil.SimpleMessage in project incubator-ratis by apache.
the class ServerRestartTests method runTestRestartCommitIndex.
void runTestRestartCommitIndex(MiniRaftCluster cluster) throws Exception {
final SimpleMessage[] messages = SimpleMessage.create(100);
final List<CompletableFuture<Void>> futures = new ArrayList<>(messages.length);
for (int i = 0; i < messages.length; i++) {
final CompletableFuture<Void> f = new CompletableFuture<>();
futures.add(f);
final SimpleMessage m = messages[i];
new Thread(() -> {
try (final RaftClient client = cluster.createClient()) {
Assert.assertTrue(client.io().send(m).isSuccess());
} catch (IOException e) {
throw new IllegalStateException("Failed to send " + m, e);
}
f.complete(null);
}).start();
}
JavaUtils.allOf(futures).get();
final List<RaftPeerId> ids = new ArrayList<>();
final RaftServer.Division leader = cluster.getLeader();
final RaftLog leaderLog = leader.getRaftLog();
final RaftPeerId leaderId = leader.getId();
ids.add(leaderId);
RaftTestUtil.getStateMachineLogEntries(leaderLog);
// check that the last metadata entry is written to the log
JavaUtils.attempt(() -> assertLastLogEntry(leader), 20, HUNDRED_MILLIS, "leader last metadata entry", LOG);
final long lastIndex = leaderLog.getLastEntryTermIndex().getIndex();
LOG.info("{}: leader lastIndex={}", leaderId, lastIndex);
final LogEntryProto lastEntry = leaderLog.get(lastIndex);
LOG.info("{}: leader lastEntry entry[{}] = {}", leaderId, lastIndex, LogProtoUtils.toLogEntryString(lastEntry));
final long loggedCommitIndex = lastEntry.getMetadataEntry().getCommitIndex();
final LogEntryProto lastCommittedEntry = leaderLog.get(loggedCommitIndex);
LOG.info("{}: leader lastCommittedEntry = entry[{}] = {}", leaderId, loggedCommitIndex, LogProtoUtils.toLogEntryString(lastCommittedEntry));
final SimpleStateMachine4Testing leaderStateMachine = SimpleStateMachine4Testing.get(leader);
final TermIndex lastAppliedTermIndex = leaderStateMachine.getLastAppliedTermIndex();
LOG.info("{}: leader lastAppliedTermIndex = {}", leaderId, lastAppliedTermIndex);
// check follower logs
for (RaftServer.Division s : cluster.iterateDivisions()) {
if (!s.getId().equals(leaderId)) {
ids.add(s.getId());
JavaUtils.attempt(() -> RaftTestUtil.assertSameLog(leaderLog, s.getRaftLog()), 10, HUNDRED_MILLIS, "assertRaftLog-" + s.getId(), LOG);
}
}
// take snapshot and truncate last (metadata) entry
leaderStateMachine.takeSnapshot();
leaderLog.truncate(lastIndex);
// kill all servers
ids.forEach(cluster::killServer);
// Restart and kill servers one by one so that they won't talk to each other.
for (RaftPeerId id : ids) {
cluster.restartServer(id, false);
final RaftServer.Division server = cluster.getDivision(id);
final RaftLog raftLog = server.getRaftLog();
JavaUtils.attemptRepeatedly(() -> {
Assert.assertTrue(raftLog.getLastCommittedIndex() >= loggedCommitIndex);
return null;
}, 10, HUNDRED_MILLIS, id + "(commitIndex >= loggedCommitIndex)", LOG);
JavaUtils.attemptRepeatedly(() -> {
Assert.assertTrue(server.getInfo().getLastAppliedIndex() >= loggedCommitIndex);
return null;
}, 10, HUNDRED_MILLIS, id + "(lastAppliedIndex >= loggedCommitIndex)", LOG);
LOG.info("{}: commitIndex={}, lastAppliedIndex={}", id, raftLog.getLastCommittedIndex(), server.getInfo().getLastAppliedIndex());
cluster.killServer(id);
}
}
use of org.apache.ratis.RaftTestUtil.SimpleMessage in project incubator-ratis by apache.
the class ServerRestartTests method runTestRestartWithCorruptedLogEntry.
private void runTestRestartWithCorruptedLogEntry(CLUSTER cluster) throws Exception {
// this is the only server
final RaftServer.Division leader = RaftTestUtil.waitForLeader(cluster);
final RaftPeerId id = leader.getId();
// send a few messages
final SimpleMessage[] messages = SimpleMessage.create(10);
final SimpleMessage lastMessage = messages[messages.length - 1];
try (final RaftClient client = cluster.createClient()) {
for (SimpleMessage m : messages) {
Assert.assertTrue(client.io().send(m).isSuccess());
}
// assert that the last message exists
Assert.assertTrue(client.io().sendReadOnly(lastMessage).isSuccess());
}
final RaftLog log = leader.getRaftLog();
final long size = TestSegmentedRaftLog.getOpenSegmentSize(log);
leader.getRaftServer().close();
// corrupt the log
final File openLogFile = JavaUtils.attemptRepeatedly(() -> getOpenLogFile(leader), 10, HUNDRED_MILLIS, id + "-getOpenLogFile", LOG);
try (final RandomAccessFile raf = new RandomAccessFile(openLogFile, "rw")) {
final long mid = size / 2;
raf.seek(mid);
for (long i = mid; i < size; i++) {
raf.write(0);
}
}
// after the log is corrupted and the server is restarted, the last entry should no longer exist.
cluster.restartServer(id, false);
testFailureCase("last-entry-not-found", () -> {
try (final RaftClient client = cluster.createClient()) {
client.io().sendReadOnly(lastMessage);
}
}, StateMachineException.class, IndexOutOfBoundsException.class);
}
use of org.apache.ratis.RaftTestUtil.SimpleMessage in project incubator-ratis by apache.
the class RaftAsyncTests method runTestStaleReadAsync.
void runTestStaleReadAsync(CLUSTER cluster) throws Exception {
final int numMesssages = 10;
try (RaftClient client = cluster.createClient()) {
RaftTestUtil.waitForLeader(cluster);
// submit some messages
final List<CompletableFuture<RaftClientReply>> futures = new ArrayList<>();
for (int i = 0; i < numMesssages; i++) {
final String s = "" + i;
LOG.info("sendAsync " + s);
futures.add(client.async().send(new SimpleMessage(s)));
}
Assert.assertEquals(numMesssages, futures.size());
final List<RaftClientReply> replies = new ArrayList<>();
for (CompletableFuture<RaftClientReply> f : futures) {
final RaftClientReply r = f.join();
Assert.assertTrue(r.isSuccess());
replies.add(r);
}
futures.clear();
// Use a follower with the max commit index
final RaftClientReply lastWriteReply = replies.get(replies.size() - 1);
final RaftPeerId leader = lastWriteReply.getServerId();
LOG.info("leader = " + leader);
final Collection<CommitInfoProto> commitInfos = lastWriteReply.getCommitInfos();
LOG.info("commitInfos = " + commitInfos);
final CommitInfoProto followerCommitInfo = commitInfos.stream().filter(info -> !RaftPeerId.valueOf(info.getServer().getId()).equals(leader)).max(Comparator.comparing(CommitInfoProto::getCommitIndex)).get();
final RaftPeerId follower = RaftPeerId.valueOf(followerCommitInfo.getServer().getId());
final long followerCommitIndex = followerCommitInfo.getCommitIndex();
LOG.info("max follower = {}, commitIndex = {}", follower, followerCommitIndex);
// test a failure case
testFailureCaseAsync("sendStaleReadAsync(..) with a larger commit index", () -> client.async().sendStaleRead(new SimpleMessage("" + Long.MAX_VALUE), followerCommitInfo.getCommitIndex(), follower), StateMachineException.class, IndexOutOfBoundsException.class);
// test sendStaleReadAsync
for (int i = 0; i < numMesssages; i++) {
final RaftClientReply reply = replies.get(i);
final String query = "" + i;
LOG.info("query=" + query + ", reply=" + reply);
final Message message = new SimpleMessage(query);
final CompletableFuture<RaftClientReply> readFuture = client.async().sendReadOnly(message);
futures.add(readFuture.thenCompose(r -> {
if (reply.getLogIndex() <= followerCommitIndex) {
LOG.info("sendStaleReadAsync, query=" + query);
return client.async().sendStaleRead(message, followerCommitIndex, follower);
} else {
return CompletableFuture.completedFuture(null);
}
}).thenApply(staleReadReply -> {
if (staleReadReply == null) {
return null;
}
final ByteString expected = readFuture.join().getMessage().getContent();
final ByteString computed = staleReadReply.getMessage().getContent();
try {
LOG.info("query " + query + " returns " + LogEntryProto.parseFrom(expected).getStateMachineLogEntry().getLogData().toStringUtf8());
} catch (InvalidProtocolBufferException e) {
throw new CompletionException(e);
}
Assert.assertEquals("log entry mismatch for query=" + query, expected, computed);
return null;
}));
}
JavaUtils.allOf(futures).join();
}
}
use of org.apache.ratis.RaftTestUtil.SimpleMessage in project incubator-ratis by apache.
the class RaftAsyncTests method runTestAsyncRequestSemaphore.
void runTestAsyncRequestSemaphore(CLUSTER cluster) throws Exception {
waitForLeader(cluster);
int numMessages = RaftClientConfigKeys.Async.outstandingRequestsMax(getProperties());
CompletableFuture[] futures = new CompletableFuture[numMessages + 1];
final SimpleMessage[] messages = SimpleMessage.create(numMessages);
try (final RaftClient client = cluster.createClient()) {
// Set blockTransaction flag so that transaction blocks
StreamSupport.stream(cluster.getServers().spliterator(), false).map(cluster::getDivision).map(SimpleStateMachine4Testing::get).forEach(SimpleStateMachine4Testing::blockStartTransaction);
// Send numMessages which are blocked and do not release the client semaphore permits
AtomicInteger blockedRequestsCount = new AtomicInteger();
for (int i = 0; i < numMessages; i++) {
blockedRequestsCount.getAndIncrement();
futures[i] = client.async().send(messages[i]);
blockedRequestsCount.decrementAndGet();
}
Assert.assertEquals(0, blockedRequestsCount.get());
futures[numMessages] = CompletableFuture.supplyAsync(() -> {
blockedRequestsCount.incrementAndGet();
client.async().send(new SimpleMessage("n1"));
blockedRequestsCount.decrementAndGet();
return null;
});
// Allow the last msg to be sent
while (blockedRequestsCount.get() != 1) {
Thread.sleep(1000);
}
Assert.assertEquals(1, blockedRequestsCount.get());
// Since all semaphore permits are acquired the last message sent is in queue
RaftClientTestUtil.assertAsyncRequestSemaphore(client, 0, 1);
// Unset the blockTransaction flag so that semaphore permits can be released
StreamSupport.stream(cluster.getServers().spliterator(), false).map(cluster::getDivision).map(SimpleStateMachine4Testing::get).forEach(SimpleStateMachine4Testing::unblockStartTransaction);
for (int i = 0; i <= numMessages; i++) {
futures[i].join();
}
Assert.assertEquals(0, blockedRequestsCount.get());
}
}
use of org.apache.ratis.RaftTestUtil.SimpleMessage in project incubator-ratis by apache.
the class RaftAsyncTests method runTestAppendEntriesTimeout.
void runTestAppendEntriesTimeout(CLUSTER cluster) throws Exception {
LOG.info("Running testAppendEntriesTimeout");
final TimeDuration oldExpiryTime = RaftServerConfigKeys.RetryCache.expiryTime(getProperties());
RaftServerConfigKeys.RetryCache.setExpiryTime(getProperties(), TimeDuration.valueOf(20, TimeUnit.SECONDS));
waitForLeader(cluster);
long time = System.currentTimeMillis();
long waitTime = 5000;
try (final RaftClient client = cluster.createClient()) {
// block append requests
cluster.getServerAliveStream().filter(impl -> !impl.getInfo().isLeader()).map(SimpleStateMachine4Testing::get).forEach(SimpleStateMachine4Testing::blockWriteStateMachineData);
CompletableFuture<RaftClientReply> replyFuture = client.async().send(new SimpleMessage("abc"));
Thread.sleep(waitTime);
// replyFuture should not be completed until append request is unblocked.
Assert.assertFalse(replyFuture.isDone());
// unblock append request.
cluster.getServerAliveStream().filter(impl -> !impl.getInfo().isLeader()).map(SimpleStateMachine4Testing::get).forEach(SimpleStateMachine4Testing::unblockWriteStateMachineData);
Assert.assertTrue(replyFuture.get().isSuccess());
Assert.assertTrue(System.currentTimeMillis() - time > waitTime);
}
// reset for the other tests
RaftServerConfigKeys.RetryCache.setExpiryTime(getProperties(), oldExpiryTime);
}
Aggregations