Eliminate the peformance penalty introduced in ReplicaInfoService.getReplicaInfoFor

Change-Id: Ie37d7e80c4dbf37a2ae6f452f6f66f4505d69a29
diff --git a/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfo.java b/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfo.java
index d33ac203..6011c16 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfo.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfo.java
@@ -22,6 +22,7 @@
 
 import org.onosproject.cluster.NodeId;
 
+import com.google.common.base.Objects;
 import com.google.common.base.Optional;
 
 /**
@@ -61,6 +62,21 @@
         return backups;
     }
 
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(master, backups);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof ReplicaInfo))  {
+            return false;
+        }
+        ReplicaInfo that = (ReplicaInfo) other;
+        return Objects.equal(this.master, that.master) &&
+                Objects.equal(this.backups, that.backups);
+    }
+
     // for Serializer
     private ReplicaInfo() {
         this.master = Optional.absent();
diff --git a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ReplicaInfoManager.java b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ReplicaInfoManager.java
index f94afe0..eaf3f8e 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ReplicaInfoManager.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ReplicaInfoManager.java
@@ -22,6 +22,7 @@
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -43,6 +44,10 @@
 import org.onosproject.store.flow.ReplicaInfoService;
 import org.slf4j.Logger;
 
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+
 /**
  * Manages replica placement information.
  */
@@ -63,6 +68,8 @@
     protected final AbstractListenerRegistry<ReplicaInfoEvent, ReplicaInfoEventListener>
         listenerRegistry = new AbstractListenerRegistry<>();
 
+    private final Map<DeviceId, ReplicaInfo> deviceReplicaInfoMap = Maps.newConcurrentMap();
+
     @Activate
     public void activate() {
         eventDispatcher.addSink(ReplicaInfoEvent.class, listenerRegistry);
@@ -79,7 +86,9 @@
 
     @Override
     public ReplicaInfo getReplicaInfoFor(DeviceId deviceId) {
-        return buildFromRoleInfo(mastershipService.getNodesFor(deviceId));
+        return deviceReplicaInfoMap.computeIfAbsent(
+                    deviceId,
+                    id -> buildFromRoleInfo(mastershipService.getNodesFor(deviceId)));
     }
 
     @Override
@@ -94,7 +103,7 @@
 
     private static ReplicaInfo buildFromRoleInfo(RoleInfo roles) {
         List<NodeId> backups = roles.backups() == null ?
-                Collections.emptyList() : roles.backups();
+                Collections.emptyList() : ImmutableList.copyOf(roles.backups());
         return new ReplicaInfo(roles.master(), backups);
     }
 
@@ -102,8 +111,12 @@
 
         @Override
         public void event(MastershipEvent event) {
+            final DeviceId deviceId = event.subject();
             final ReplicaInfo replicaInfo = buildFromRoleInfo(event.roleInfo());
-
+            ReplicaInfo oldReplicaInfo = deviceReplicaInfoMap.put(deviceId, replicaInfo);
+            if (Objects.equal(oldReplicaInfo, replicaInfo)) {
+                return;
+            }
             switch (event.type()) {
             case MASTER_CHANGED:
                 eventDispatcher.post(new ReplicaInfoEvent(MASTER_CHANGED,
diff --git a/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/ConsistentDeviceMastershipStore.java b/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/ConsistentDeviceMastershipStore.java
index bbd7b7a..9aa376a 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/ConsistentDeviceMastershipStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/ConsistentDeviceMastershipStore.java
@@ -17,6 +17,7 @@
 
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onlab.util.Tools.futureGetOrElse;
+import static org.onosproject.mastership.MastershipEvent.Type.BACKUPS_CHANGED;
 import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED;
 import static org.slf4j.LoggerFactory.getLogger;
 import static com.google.common.base.Preconditions.checkArgument;
@@ -409,6 +410,9 @@
                 case LEADER_BOOTED:
                     notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, getNodes(deviceId)));
                     break;
+                case CANDIDATES_CHANGED:
+                    notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, getNodes(deviceId)));
+                    break;
                 default:
                     return;
                 }