static int count(RaftLog log, long startIndex) throws RaftLogIOException { final long nextIndex = log.getNextIndex(); int count = 0; for(long i = startIndex; i < nextIndex; i++) { if (log.get(i).hasStateMachineLogEntry()) { count++; } } return count; }
static void assertSameLog(RaftLog expected, RaftLog computed) throws Exception { Assert.assertEquals(expected.getLastEntryTermIndex(), computed.getLastEntryTermIndex()); final long lastIndex = expected.getNextIndex() - 1; Assert.assertEquals(expected.getLastEntryTermIndex().getIndex(), lastIndex); for(long i = 0; i < lastIndex; i++) { Assert.assertEquals(expected.get(i), computed.get(i)); } }
private boolean shouldAppendMetadata(long newCommitIndex) { if (newCommitIndex <= 0) { // do not log the first conf entry return false; } else if (Optional.ofNullable(lastMetadataEntry) .filter(e -> e.getIndex() == newCommitIndex || e.getMetadataEntry().getCommitIndex() >= newCommitIndex) .isPresent()) { //log neither lastMetadataEntry, nor entries with a smaller commit index. return false; } try { if (get(newCommitIndex).hasMetadataEntry()) { // do not log the metadata entry return false; } } catch(RaftLogIOException e) { LOG.error("Failed to get log entry for index " + newCommitIndex, e); } return true; } @Override
static Iterable<LogEntryProto> getLogEntryProtos(RaftLog log) { return CollectionUtils.as(log.getEntries(0, Long.MAX_VALUE), ti -> { try { return log.get(ti.getIndex()); } catch (IOException exception) { throw new AssertionError("Failed to get log at " + ti, exception); } }); }
static void printLog(RaftLog log, Consumer<String> println) { if (log == null) { println.accept("log == null"); return; } final TermIndex last; final long flushed, committed; try(AutoCloseableLock readlock = log.readLock()) { last = log.getLastEntryTermIndex(); flushed = log.getLatestFlushedIndex(); committed = log.getLastCommittedIndex(); } final StringBuilder b = new StringBuilder(); for(long i = 0; i <= last.getIndex(); i++) { b.setLength(0); b.append(i == flushed? 'f': ' '); b.append(i == committed? 'c': ' '); b.append(String.format("%3d: ", i)); try { b.append(ServerProtoUtils.toLogEntryString(log.get(i))); } catch (RaftLogIOException e) { b.append(e); } println.accept(b.toString()); } } }
private void checkLog(RaftLog raftLog, long expectedCommittedIndex, Supplier<byte[]> s) throws IOException { long committedIndex = raftLog.getLastCommittedIndex(); Assert.assertEquals(expectedCommittedIndex, committedIndex); // check the log content TermIndex[] entries = raftLog.getEntries(1, expectedCommittedIndex + 1); for (TermIndex entry : entries) { RaftProtos.LogEntryProto log = raftLog.get(entry.getIndex()); byte[] logData = log.getStateMachineLogEntry().getLogData().toByteArray(); byte[] expected = s.get(); LOG.info("log " + entry + " " + log.getLogEntryBodyCase() + " " + StringUtils.bytes2HexString(logData)); Assert.assertEquals(expected.length, logData.length); Assert.assertArrayEquals(expected, logData); } }
static void assertLeaderContent(MiniRaftCluster cluster) throws Exception { final RaftServerImpl leader = RaftTestUtil.waitForLeader(cluster); final RaftLog leaderLog = leader.getState().getLog(); final long lastIndex = leaderLog.getLastEntryTermIndex().getIndex(); final LogEntryProto e = leaderLog.get(lastIndex); Assert.assertTrue(e.hasMetadataEntry()); Assert.assertEquals(leaderLog.getLastCommittedIndex() - 1, e.getMetadataEntry().getCommitIndex()); final LogEntryProto[] entries = SimpleStateMachine4Testing.get(leader).getContent(); long message = 0; for (int i = 0; i < entries.length; i++) { LOG.info("{}) {} {}", i, message, entries[i]); if (entries[i].hasStateMachineLogEntry()) { final SimpleMessage m = new SimpleMessage("m" + message++); Assert.assertArrayEquals(m.getContent().toByteArray(), entries[i].getStateMachineLogEntry().getLogData().toByteArray()); } } }
void runTestNoChangeRequest(CLUSTER cluster) throws Exception { final RaftServerImpl leader = RaftTestUtil.waitForLeader(cluster); try(final RaftClient client = cluster.createClient(leader.getId())) { client.send(new SimpleMessage("m")); final RaftLog leaderLog = leader.getState().getLog(); final long committedIndex = leaderLog.getLastCommittedIndex(); final RaftConfiguration confBefore = cluster.getLeader().getRaftConf(); // no real configuration change in the request final RaftClientReply reply = client.setConfiguration(cluster.getPeers().toArray(RaftPeer.emptyArray())); Assert.assertTrue(reply.isSuccess()); final long newCommittedIndex = leaderLog.getLastCommittedIndex(); for(long i = committedIndex + 1; i <= newCommittedIndex; i++) { final LogEntryProto e = leaderLog.get(i); Assert.assertTrue(e.hasMetadataEntry()); } Assert.assertSame(confBefore, cluster.getLeader().getRaftConf()); client.close(); } }
private void checkEntries(RaftLog raftLog, List<LogEntryProto> expected, int offset, int size) throws IOException { if (size > 0) { for (int i = offset; i < size + offset; i++) { LogEntryProto entry = raftLog.get(expected.get(i).getIndex()); Assert.assertEquals(expected.get(i), entry); } TermIndex[] termIndices = raftLog.getEntries( expected.get(offset).getIndex(), expected.get(offset + size - 1).getIndex() + 1); LogEntryProto[] entriesFromLog = Arrays.stream(termIndices) .map(ti -> { try { return raftLog.get(ti.getIndex()); } catch (IOException e) { throw new RuntimeException(e); } }) .toArray(LogEntryProto[]::new); LogEntryProto[] expectedArray = expected.subList(offset, offset + size) .stream().toArray(LogEntryProto[]::new); Assert.assertArrayEquals(expectedArray, entriesFromLog); } }
static void printLog(RaftLog log, Consumer<String> println) { if (log == null) { println.accept("log == null"); return; } final TermIndex last; final long flushed, committed; try(AutoCloseableLock readlock = log.readLock()) { last = log.getLastEntryTermIndex(); flushed = log.getLatestFlushedIndex(); committed = log.getLastCommittedIndex(); } final StringBuilder b = new StringBuilder(); for(long i = 0; i <= last.getIndex(); i++) { b.setLength(0); b.append(i == flushed? 'f': ' '); b.append(i == committed? 'c': ' '); b.append(String.format("%3d: ", i)); try { final RaftProtos.LogEntryProto entry = log.get(i); b.append(entry != null? entry.getLogEntryBodyCase(): null); } catch (RaftLogIOException e) { b.append(e); } println.accept(b.toString()); } } }
private void checkLog(RaftLog raftLog, long expectedCommittedIndex, Supplier<byte[]> s) throws IOException { long committedIndex = raftLog.getLastCommittedIndex(); Assert.assertEquals(expectedCommittedIndex, committedIndex); // check the log content TermIndex[] entries = raftLog.getEntries(1, expectedCommittedIndex + 1); for (TermIndex entry : entries) { RaftProtos.LogEntryProto log = raftLog.get(entry.getIndex()); byte[] logData = log.getSmLogEntry().getData().toByteArray(); byte[] expected = s.get(); LOG.info("log " + entry + " " + log.getLogEntryBodyCase() + " " + StringUtils.bytes2HexString(logData)); Assert.assertEquals(expected.length, logData.length); Assert.assertArrayEquals(expected, logData); } }
static EnumMap<LogEntryBodyCase, AtomicLong> countEntries(RaftLog raftLog) throws Exception { final EnumMap<LogEntryBodyCase, AtomicLong> counts = new EnumMap<>(LogEntryBodyCase.class); for(long i = 0; i < raftLog.getNextIndex(); i++) { final LogEntryProto e = raftLog.get(i); counts.computeIfAbsent(e.getLogEntryBodyCase(), c -> new AtomicLong()).incrementAndGet(); } return counts; }
private void checkEntries(RaftLog raftLog, List<LogEntryProto> expected, int offset, int size) throws IOException { if (size > 0) { for (int i = offset; i < size + offset; i++) { LogEntryProto entry = raftLog.get(expected.get(i).getIndex()); Assert.assertEquals(expected.get(i), entry); } TermIndex[] termIndices = raftLog.getEntries( expected.get(offset).getIndex(), expected.get(offset + size - 1).getIndex() + 1); LogEntryProto[] entriesFromLog = Arrays.stream(termIndices) .map(ti -> { try { return raftLog.get(ti.getIndex()); } catch (IOException e) { throw new RuntimeException(e); } }) .toArray(LogEntryProto[]::new); LogEntryProto[] expectedArray = expected.subList(offset, offset + size) .stream().toArray(LogEntryProto[]::new); Assert.assertArrayEquals(expectedArray, entriesFromLog); } }
static LogEntryProto getLastEntry(LogEntryBodyCase targetCase, RaftLog raftLog) throws Exception { try(AutoCloseableLock readLock = raftLog.readLock()) { long i = raftLog.getNextIndex() - 1; for(; i >= 0; i--) { final LogEntryProto entry = raftLog.get(i); if (entry.getLogEntryBodyCase() == targetCase) { return entry; } } } return null; }
static void checkLogEntries(RaftLog log, SimpleMessage[] expectedMessages, Predicate<LogEntryProto> predicate) { TermIndex[] termIndices = log.getEntries(0, Long.MAX_VALUE); for (int i = 0; i < termIndices.length; i++) { for (int j = 0; j < expectedMessages.length; j++) { final LogEntryProto e; try { e = log.get(termIndices[i].getIndex()); if (Arrays.equals(expectedMessages[j].getContent().toByteArray(), e.getSmLogEntry().getData().toByteArray())) { Assert.assertTrue(predicate.test(e)); } } catch (IOException exception) { exception.printStackTrace(); } } } }
protected AppendEntriesRequestProto createRequest(long callId) throws RaftLogIOException { final TermIndex previous = getPrevious(); final long leaderNext = raftLog.getNextIndex(); long next = follower.getNextIndex() + buffer.getPendingEntryNum(); final boolean toSend; if (leaderNext == next && !buffer.isEmpty()) { // no new entries, then send out the entries in the buffer toSend = true; } else if (leaderNext > next) { boolean hasSpace = true; for(; hasSpace && leaderNext > next;) { hasSpace = buffer.addEntry(raftLog.get(next++)); } // buffer is full or batch sending is disabled, send out a request toSend = !hasSpace || !batchSending; } else { toSend = false; } if (toSend || shouldHeartbeat()) { return buffer.getAppendRequest(previous, callId); } return null; }
static boolean logEntriesContains(RaftLog log, long startIndex, long endIndex, SimpleMessage... expectedMessages) { int idxEntries = 0; int idxExpected = 0; TermIndex[] termIndices = log.getEntries(startIndex, endIndex); while (idxEntries < termIndices.length && idxExpected < expectedMessages.length) { try { if (Arrays.equals(expectedMessages[idxExpected].getContent().toByteArray(), log.get(termIndices[idxEntries].getIndex()).getStateMachineLogEntry().getLogData().toByteArray())) { ++idxExpected; } } catch (IOException e) { throw new RuntimeException(e); } ++idxEntries; } return idxExpected == expectedMessages.length; }
static boolean logEntriesContains(RaftLog log, SimpleMessage... expectedMessages) { int idxEntries = 0; int idxExpected = 0; TermIndex[] termIndices = log.getEntries(0, Long.MAX_VALUE); while (idxEntries < termIndices.length && idxExpected < expectedMessages.length) { try { if (Arrays.equals(expectedMessages[idxExpected].getContent().toByteArray(), log.get(termIndices[idxEntries].getIndex()).getSmLogEntry().getData().toByteArray())) { ++idxExpected; } } catch (IOException e) { throw new RuntimeException(e); } ++idxEntries; } return idxExpected == expectedMessages.length; }
static void checkLogEntries(RaftLog log, SimpleMessage[] expectedMessages, Predicate<LogEntryProto> predicate) { TermIndex[] termIndices = log.getEntries(0, Long.MAX_VALUE); for (int i = 0; i < termIndices.length; i++) { for (int j = 0; j < expectedMessages.length; j++) { final LogEntryProto e; try { e = log.get(termIndices[i].getIndex()); if (Arrays.equals(expectedMessages[j].getContent().toByteArray(), e.getStateMachineLogEntry().getLogData().toByteArray())) { Assert.assertTrue(predicate.test(e)); } } catch (IOException exception) { exception.printStackTrace(); } } } }
static void assertLogEntries(RaftLog log, long expectedTerm, SimpleMessage... expectedMessages) { final TermIndex[] termIndices = log.getEntries(1, Long.MAX_VALUE); final List<LogEntryProto> entries = new ArrayList<>(expectedMessages.length); for (TermIndex ti : termIndices) { final LogEntryProto e; try { e = log.get(ti.getIndex()); } catch (IOException exception) { throw new AssertionError("Failed to get log at " + ti, exception); } if (e.getLogEntryBodyCase() == LogEntryProto.LogEntryBodyCase.SMLOGENTRY) { LOG.info(ServerProtoUtils.toString(e) + ", " + e.getSmLogEntry().toString().trim().replace("\n", ", ")); entries.add(e); } else if (e.getLogEntryBodyCase() == LogEntryProto.LogEntryBodyCase.NOOP) { LOG.info("Found " + LogEntryProto.LogEntryBodyCase.NOOP + " at " + ti + ", ignoring it."); } else { throw new AssertionError("Unexpected LogEntryBodyCase " + e.getLogEntryBodyCase() + " at " + ti + ": " + ServerProtoUtils.toString(e)); } } try { assertLogEntries(entries, expectedTerm, expectedMessages); } catch(Throwable t) { throw new AssertionError("entries: " + entries, t); } }