use of org.opendaylight.controller.cluster.raft.messages.AppendEntries in project controller by opendaylight.
the class AbstractLeader method getEntriesToSend.
private List<ReplicatedLogEntry> getEntriesToSend(final FollowerLogInformation followerLogInfo, final ActorSelection followerActor) {
// Try to get all the entries in the journal but not exceeding the max data size for a single AppendEntries
// message.
int maxEntries = (int) context.getReplicatedLog().size();
final int maxDataSize = context.getConfigParams().getSnapshotChunkSize();
final long followerNextIndex = followerLogInfo.getNextIndex();
List<ReplicatedLogEntry> entries = context.getReplicatedLog().getFrom(followerNextIndex, maxEntries, maxDataSize);
// that is the case, then we need to slice it into smaller chunks.
if (!(entries.size() == 1 && entries.get(0).getData().size() > maxDataSize)) {
// Don't need to slice.
return entries;
}
log.debug("{}: Log entry size {} exceeds max payload size {}", logName(), entries.get(0).getData().size(), maxDataSize);
// If an AppendEntries has already been serialized for the log index then reuse the
// SharedFileBackedOutputStream.
final Long logIndex = entries.get(0).getIndex();
SharedFileBackedOutputStream fileBackedStream = sharedSerializedAppendEntriesStreams.get(logIndex);
if (fileBackedStream == null) {
fileBackedStream = context.getFileBackedOutputStreamFactory().newSharedInstance();
final AppendEntries appendEntries = new AppendEntries(currentTerm(), context.getId(), getLogEntryIndex(followerNextIndex - 1), getLogEntryTerm(followerNextIndex - 1), entries, context.getCommitIndex(), getReplicatedToAllIndex(), context.getPayloadVersion());
log.debug("{}: Serializing {} for slicing for follower {}", logName(), appendEntries, followerLogInfo.getId());
try (ObjectOutputStream out = new ObjectOutputStream(fileBackedStream)) {
out.writeObject(appendEntries);
} catch (IOException e) {
log.error("{}: Error serializing {}", logName(), appendEntries, e);
fileBackedStream.cleanup();
return Collections.emptyList();
}
sharedSerializedAppendEntriesStreams.put(logIndex, fileBackedStream);
fileBackedStream.setOnCleanupCallback(index -> {
log.debug("{}: On SharedFileBackedOutputStream cleanup for index {}", logName(), index);
sharedSerializedAppendEntriesStreams.remove(index);
}, logIndex);
} else {
log.debug("{}: Reusing SharedFileBackedOutputStream for follower {}", logName(), followerLogInfo.getId());
fileBackedStream.incrementUsageCount();
}
log.debug("{}: Slicing stream for index {}, follower {}", logName(), logIndex, followerLogInfo.getId());
// Record that slicing is in progress for the follower.
followerLogInfo.setSlicedLogEntryIndex(logIndex);
final FollowerIdentifier identifier = new FollowerIdentifier(followerLogInfo.getId());
appendEntriesMessageSlicer.slice(SliceOptions.builder().identifier(identifier).fileBackedOutputStream(fileBackedStream).sendTo(followerActor).replyTo(actor()).onFailureCallback(failure -> {
log.error("{}: Error slicing AppendEntries for follower {}", logName(), followerLogInfo.getId(), failure);
followerLogInfo.setSlicedLogEntryIndex(FollowerLogInformation.NO_INDEX);
}).build());
return Collections.emptyList();
}
use of org.opendaylight.controller.cluster.raft.messages.AppendEntries in project controller by opendaylight.
the class DummyShard method onReceive.
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof RequestVote) {
RequestVote req = (RequestVote) message;
sender().tell(new RequestVoteReply(req.getTerm(), true), self());
} else if (message instanceof AppendEntries) {
handleAppendEntries((AppendEntries) message);
} else if (message instanceof InstallSnapshot) {
handleInstallSnapshot((InstallSnapshot) message);
} else {
LOG.error("Unknown message : {}", message.getClass());
}
}
use of org.opendaylight.controller.cluster.raft.messages.AppendEntries in project controller by opendaylight.
the class FollowerTest method testHandleSyncUpAppendEntries.
@Test
public void testHandleSyncUpAppendEntries() {
logStart("testHandleSyncUpAppendEntries");
MockRaftActorContext context = createActorContext();
List<ReplicatedLogEntry> entries = Arrays.asList(newReplicatedLogEntry(2, 101, "foo"));
// The new commitIndex is 101
AppendEntries appendEntries = new AppendEntries(2, "leader-1", 100, 1, entries, 101, 100, (short) 0);
follower = createBehavior(context);
follower.handleMessage(leaderActor, appendEntries);
FollowerInitialSyncUpStatus syncStatus = MessageCollectorActor.expectFirstMatching(followerActor, FollowerInitialSyncUpStatus.class);
assertFalse(syncStatus.isInitialSyncDone());
// Clear all the messages
MessageCollectorActor.clearMessages(followerActor);
context.setLastApplied(101);
context.setCommitIndex(101);
setLastLogEntry(context, 1, 101, new MockRaftActorContext.MockPayload(""));
entries = Arrays.asList(newReplicatedLogEntry(2, 101, "foo"));
// The new commitIndex is 101
appendEntries = new AppendEntries(2, "leader-1", 101, 1, entries, 102, 101, (short) 0);
follower.handleMessage(leaderActor, appendEntries);
syncStatus = MessageCollectorActor.expectFirstMatching(followerActor, FollowerInitialSyncUpStatus.class);
assertTrue(syncStatus.isInitialSyncDone());
MessageCollectorActor.clearMessages(followerActor);
// Sending the same message again should not generate another message
follower.handleMessage(leaderActor, appendEntries);
syncStatus = MessageCollectorActor.getFirstMatching(followerActor, FollowerInitialSyncUpStatus.class);
assertNull(syncStatus);
}
use of org.opendaylight.controller.cluster.raft.messages.AppendEntries in project controller by opendaylight.
the class FollowerTest method testHandleFirstAppendEntriesWithPrevIndexMinusOneAndReplicatedToAllIndexPresentInLog.
@Test
public void testHandleFirstAppendEntriesWithPrevIndexMinusOneAndReplicatedToAllIndexPresentInLog() {
logStart("testHandleFirstAppendEntries");
MockRaftActorContext context = createActorContext();
context.getReplicatedLog().clear(0, 2);
context.getReplicatedLog().append(newReplicatedLogEntry(1, 100, "bar"));
context.getReplicatedLog().setSnapshotIndex(99);
List<ReplicatedLogEntry> entries = Arrays.asList(newReplicatedLogEntry(2, 101, "foo"));
// The new commitIndex is 101
AppendEntries appendEntries = new AppendEntries(2, "leader-1", -1, -1, entries, 101, 100, (short) 0);
follower = createBehavior(context);
follower.handleMessage(leaderActor, appendEntries);
FollowerInitialSyncUpStatus syncStatus = MessageCollectorActor.expectFirstMatching(followerActor, FollowerInitialSyncUpStatus.class);
AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(leaderActor, AppendEntriesReply.class);
assertFalse(syncStatus.isInitialSyncDone());
assertTrue("append entries reply should be true", reply.isSuccess());
}
use of org.opendaylight.controller.cluster.raft.messages.AppendEntries in project controller by opendaylight.
the class FollowerTest method testInitialSyncUpWithHandleInstallSnapshotFollowedByAppendEntries.
@Test
public void testInitialSyncUpWithHandleInstallSnapshotFollowedByAppendEntries() {
logStart("testInitialSyncUpWithHandleInstallSnapshot");
MockRaftActorContext context = createActorContext();
context.setCommitIndex(-1);
follower = createBehavior(context);
ByteString bsSnapshot = createSnapshot();
int offset = 0;
int snapshotLength = bsSnapshot.size();
int chunkSize = 50;
int totalChunks = snapshotLength / chunkSize + (snapshotLength % chunkSize > 0 ? 1 : 0);
int lastIncludedIndex = 1;
int chunkIndex = 1;
InstallSnapshot lastInstallSnapshot = null;
for (int i = 0; i < totalChunks; i++) {
byte[] chunkData = getNextChunk(bsSnapshot, offset, chunkSize);
lastInstallSnapshot = new InstallSnapshot(1, "leader", lastIncludedIndex, 1, chunkData, chunkIndex, totalChunks);
follower.handleMessage(leaderActor, lastInstallSnapshot);
offset = offset + 50;
lastIncludedIndex++;
chunkIndex++;
}
FollowerInitialSyncUpStatus syncStatus = MessageCollectorActor.expectFirstMatching(followerActor, FollowerInitialSyncUpStatus.class);
assertFalse(syncStatus.isInitialSyncDone());
// Clear all the messages
MessageCollectorActor.clearMessages(followerActor);
context.setLastApplied(101);
context.setCommitIndex(101);
setLastLogEntry(context, 1, 101, new MockRaftActorContext.MockPayload(""));
List<ReplicatedLogEntry> entries = Arrays.asList(newReplicatedLogEntry(2, 101, "foo"));
// The new commitIndex is 101
AppendEntries appendEntries = new AppendEntries(2, "leader", 101, 1, entries, 102, 101, (short) 0);
follower.handleMessage(leaderActor, appendEntries);
syncStatus = MessageCollectorActor.expectFirstMatching(followerActor, FollowerInitialSyncUpStatus.class);
assertTrue(syncStatus.isInitialSyncDone());
}
Aggregations