Bug 2461 : Adding capture snapshot JMX operation. 32/26132/2
authorHarman Singh <harmasin@cisco.com>
Fri, 28 Aug 2015 01:28:23 +0000 (18:28 -0700)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 28 Aug 2015 04:10:45 +0000 (04:10 +0000)
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>
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/SnapshotManager.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/InitiateCaptureSnapshot.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/SnapshotManagerTest.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsMXBean.java

index ebc157bc1729aff08199b5d6fe4a17b04afdc552..7604e3575dfb30d135157e6734832e64e8552a57 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.controller.cluster.notifications.LeaderStateChanged;
 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;
@@ -234,6 +235,8 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             );
         } else if(message instanceof GetOnDemandRaftState) {
             onGetOnDemandRaftStats();
+        } else if(message instanceof InitiateCaptureSnapshot) {
+            captureSnapshot();
         } else if(!snapshotSupport.handleSnapshotMessage(message)) {
             reusableBehaviorStateHolder.init(getCurrentBehavior());
 
@@ -587,6 +590,17 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
         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
index 970fb8fc717c2b6d918c2e815fb9ef2b323a39fb..4c3fb109add982c9f2d5590d524d20dfbf7ea7b7 100644 (file)
@@ -211,8 +211,18 @@ public class SnapshotManager implements SnapshotState {
 
             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()) {
diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/InitiateCaptureSnapshot.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/InitiateCaptureSnapshot.java
new file mode 100644 (file)
index 0000000..d848a84
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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;
+}
index 0078c2bd848d6677efd7c0d241e1c083c07807e4..df83f8f55843b4f82ad9f4f8336c8b6913482c5b 100644 (file)
@@ -160,6 +160,35 @@ public class SnapshotManagerTest extends AbstractActorTest {
 
     }
 
+    @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);
index 1f51c6f3a14e48076549ee4ef4b9ea1d663a439c..1e6107c786bb0729f553ba876982fd50268c0452 100644 (file)
@@ -8,6 +8,7 @@
 
 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;
@@ -20,6 +21,7 @@ import java.util.Map;
 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;
@@ -344,4 +346,12 @@ public class ShardStats extends AbstractMXBean implements ShardStatsMXBean {
     public int getPendingTxCommitQueueSize() {
         return shard.getPendingTxCommitQueueSize();
     }
+
+    @Override
+    public void captureSnapshot() {
+        if(shard != null) {
+            shard.getSelf().tell(new InitiateCaptureSnapshot(), ActorRef.noSender());
+        }
+    }
+
 }