Search in sources :

Example 1 with AppendEntries

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();
}
Also used : ReplicatedLogEntry(org.opendaylight.controller.cluster.raft.ReplicatedLogEntry) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) IOException(java.io.IOException) ObjectOutputStream(java.io.ObjectOutputStream) SharedFileBackedOutputStream(org.opendaylight.controller.cluster.io.SharedFileBackedOutputStream)

Example 2 with AppendEntries

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());
    }
}
Also used : RequestVoteReply(org.opendaylight.controller.cluster.raft.messages.RequestVoteReply) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) RequestVote(org.opendaylight.controller.cluster.raft.messages.RequestVote) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot)

Example 3 with AppendEntries

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);
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ReplicatedLogEntry(org.opendaylight.controller.cluster.raft.ReplicatedLogEntry) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) FollowerInitialSyncUpStatus(org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus) Test(org.junit.Test)

Example 4 with AppendEntries

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());
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ReplicatedLogEntry(org.opendaylight.controller.cluster.raft.ReplicatedLogEntry) AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) FollowerInitialSyncUpStatus(org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus) Test(org.junit.Test)

Example 5 with AppendEntries

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());
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ReplicatedLogEntry(org.opendaylight.controller.cluster.raft.ReplicatedLogEntry) ByteString(com.google.protobuf.ByteString) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) FollowerInitialSyncUpStatus(org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) Test(org.junit.Test)

Aggregations

AppendEntries (org.opendaylight.controller.cluster.raft.messages.AppendEntries)62 Test (org.junit.Test)58 MockRaftActorContext (org.opendaylight.controller.cluster.raft.MockRaftActorContext)44 AppendEntriesReply (org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply)34 SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)34 ReplicatedLogEntry (org.opendaylight.controller.cluster.raft.ReplicatedLogEntry)30 FiniteDuration (scala.concurrent.duration.FiniteDuration)19 DefaultConfigParamsImpl (org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl)17 ByteString (com.google.protobuf.ByteString)15 ActorRef (akka.actor.ActorRef)9 FollowerInitialSyncUpStatus (org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus)9 InstallSnapshot (org.opendaylight.controller.cluster.raft.messages.InstallSnapshot)9 TestActorRef (akka.testkit.TestActorRef)8 ArrayList (java.util.ArrayList)8 HashMap (java.util.HashMap)5 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)5 FollowerLogInformation (org.opendaylight.controller.cluster.raft.FollowerLogInformation)4 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)4 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)4 Snapshot (org.opendaylight.controller.cluster.raft.persisted.Snapshot)4