Also, updated Snapshot manager code, which may throw null pointer exception, if last log entry is null
Change-Id: I4363a3da38af99a4193b8ad2b1c0a5cbaf714a32
Signed-off-by: Harman Singh <harmasin@cisco.com>
import org.opendaylight.controller.cluster.notifications.RoleChanged;
import org.opendaylight.controller.cluster.raft.base.messages.ApplyJournalEntries;
import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
+import org.opendaylight.controller.cluster.raft.base.messages.InitiateCaptureSnapshot;
import org.opendaylight.controller.cluster.raft.base.messages.Replicate;
import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader;
import org.opendaylight.controller.cluster.raft.behaviors.DelegatingRaftActorBehavior;
);
} else if(message instanceof GetOnDemandRaftState) {
onGetOnDemandRaftStats();
+ } else if(message instanceof InitiateCaptureSnapshot) {
+ captureSnapshot();
} else if(!snapshotSupport.handleSnapshotMessage(message)) {
reusableBehaviorStateHolder.init(getCurrentBehavior());
return getRaftActorContext().hasFollowers();
}
+ private void captureSnapshot() {
+ SnapshotManager snapshotManager = context.getSnapshotManager();
+
+ if(!snapshotManager.isCapturing()) {
+ LOG.debug("Take a snapshot of current state. lastReplicatedLog is {} and replicatedToAllIndex is {}",
+ replicatedLog().last(), currentBehavior.getReplicatedToAllIndex());
+
+ snapshotManager.capture(replicatedLog().last(), currentBehavior.getReplicatedToAllIndex());
+ }
+ }
+
/**
* @deprecated Deprecated in favor of {@link org.opendaylight.controller.cluster.raft.base.messages.DeleteEntries}
* whose type for fromIndex is long instead of int. This class was kept for backwards
List<ReplicatedLogEntry> unAppliedEntries = context.getReplicatedLog().getFrom(lastAppliedIndex + 1);
- captureSnapshot = new CaptureSnapshot(lastLogEntry.getIndex(),
- lastLogEntry.getTerm(), lastAppliedIndex, lastAppliedTerm,
+ long lastLogEntryIndex = lastAppliedIndex;
+ long lastLogEntryTerm = lastAppliedTerm;
+ if(lastLogEntry != null) {
+ lastLogEntryIndex = lastLogEntry.getIndex();
+ lastLogEntryTerm = lastLogEntry.getTerm();
+ } else {
+ LOG.warn("Capturing Snapshot : lastLogEntry is null. Using lastAppliedIndex {} and lastAppliedTerm {} instead.",
+ lastAppliedIndex, lastAppliedTerm);
+ }
+
+ captureSnapshot = new CaptureSnapshot(lastLogEntryIndex,
+ lastLogEntryTerm, lastAppliedIndex, lastAppliedTerm,
newReplicatedToAllIndex, newReplicatedToAllTerm, unAppliedEntries, targetFollower != null);
if(captureSnapshot.isInstallSnapshotInitiated()) {
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.raft.base.messages;
+
+import java.io.Serializable;
+
+public class InitiateCaptureSnapshot implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
}
+ @Test
+ public void testCaptureWithNullLastLogEntry() throws Exception {
+ boolean capture = snapshotManager.capture(null, 1);
+
+ assertTrue(capture);
+
+ assertEquals(true, snapshotManager.isCapturing());
+
+ verify(mockProcedure).apply(null);
+
+ CaptureSnapshot captureSnapshot = snapshotManager.getCaptureSnapshot();
+
+ System.out.println(captureSnapshot);
+
+ // LastIndex and LastTerm are picked up from the lastLogEntry
+ assertEquals(-1L, captureSnapshot.getLastIndex());
+ assertEquals(-1L, captureSnapshot.getLastTerm());
+
+ // Since the actor does not have any followers (no peer addresses) lastApplied will be from lastLogEntry
+ assertEquals(-1L, captureSnapshot.getLastAppliedIndex());
+ assertEquals(-1L, captureSnapshot.getLastAppliedTerm());
+
+ //
+ assertEquals(-1L, captureSnapshot.getReplicatedToAllIndex());
+ assertEquals(-1L, captureSnapshot.getReplicatedToAllTerm());
+ actorRef.underlyingActor().clear();
+
+ }
+
@Test
public void testCaptureWithCreateProcedureError () throws Exception {
doThrow(new Exception("mock")).when(mockProcedure).apply(null);
package org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard;
+import akka.actor.ActorRef;
import akka.pattern.Patterns;
import akka.util.Timeout;
import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.controller.cluster.datastore.Shard;
+import org.opendaylight.controller.cluster.raft.base.messages.InitiateCaptureSnapshot;
import org.opendaylight.controller.cluster.raft.client.messages.FollowerInfo;
import org.opendaylight.controller.cluster.raft.client.messages.GetOnDemandRaftState;
import org.opendaylight.controller.cluster.raft.client.messages.OnDemandRaftState;
public int getPendingTxCommitQueueSize() {
return shard.getPendingTxCommitQueueSize();
}
+
+ @Override
+ public void captureSnapshot() {
+ if(shard != null) {
+ shard.getSelf().tell(new InitiateCaptureSnapshot(), ActorRef.noSender());
+ }
+ }
+
}
String getLastLeadershipChangeTime();
int getPendingTxCommitQueueSize();
+
+ void captureSnapshot();
+
}