Distributed group store using eventual consistent map abstraction

Change-Id: I618a0f6fa80e0e25285d7a2026032f09ba90aa70
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
index 2d8f81c..6601cbf 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
@@ -15,7 +15,13 @@
  */
 package org.onosproject.net.group.impl;
 
-import com.google.common.collect.Sets;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -48,12 +54,7 @@
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Set;
-
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.collect.Sets;
 
 /**
  * Provides implementation of the group service APIs.
@@ -103,6 +104,7 @@
      */
     @Override
     public void addGroup(GroupDescription groupDesc) {
+        log.trace("In addGroup API");
         store.storeGroupDescription(groupDesc);
     }
 
@@ -121,6 +123,7 @@
      */
     @Override
     public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
+        log.trace("In getGroup API");
         return store.getGroup(deviceId, appCookie);
     }
 
@@ -142,6 +145,7 @@
                            GroupBuckets buckets,
                            GroupKey newCookie,
                            ApplicationId appId) {
+        log.trace("In addBucketsToGroup API");
         store.updateGroupDescription(deviceId,
                                      oldCookie,
                                      UpdateType.ADD,
@@ -167,6 +171,7 @@
                                 GroupBuckets buckets,
                                 GroupKey newCookie,
                                 ApplicationId appId) {
+        log.trace("In removeBucketsFromGroup API");
         store.updateGroupDescription(deviceId,
                                      oldCookie,
                                      UpdateType.REMOVE,
@@ -188,6 +193,7 @@
     public void removeGroup(DeviceId deviceId,
                             GroupKey appCookie,
                             ApplicationId appId) {
+        log.trace("In removeGroup API");
         store.deleteGroupDescription(deviceId, appCookie);
     }
 
@@ -202,11 +208,13 @@
     @Override
     public Iterable<Group> getGroups(DeviceId deviceId,
                                      ApplicationId appId) {
+        log.trace("In getGroups API");
         return store.getGroups(deviceId);
     }
 
     @Override
     public Iterable<Group> getGroups(DeviceId deviceId) {
+        log.trace("In getGroups API");
         return store.getGroups(deviceId);
     }
 
@@ -217,6 +225,7 @@
      */
     @Override
     public void addListener(GroupListener listener) {
+        log.trace("In addListener API");
         listenerRegistry.addListener(listener);
     }
 
@@ -227,6 +236,7 @@
      */
     @Override
     public void removeListener(GroupListener listener) {
+        log.trace("In removeListener API");
         listenerRegistry.removeListener(listener);
     }
 
@@ -364,36 +374,52 @@
             Set<Group> extraneousStoredEntries =
                     Sets.newHashSet(store.getExtraneousGroups(deviceId));
 
-            log.trace("Displaying all southboundGroupEntries for device {}", deviceId);
+            log.trace("Displaying all ({}) southboundGroupEntries for device {}",
+                      southboundGroupEntries.size(),
+                      deviceId);
             for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
                 Group group = it.next();
                 log.trace("Group {} in device {}", group, deviceId);
             }
 
-            log.trace("Displaying all stored group entries for device {}", deviceId);
-            for (Iterator<Group> it = storedGroupEntries.iterator(); it.hasNext();) {
-                Group group = it.next();
+            log.trace("Displaying all ({}) stored group entries for device {}",
+                      storedGroupEntries.size(),
+                      deviceId);
+            for (Iterator<Group> it1 = storedGroupEntries.iterator(); it1.hasNext();) {
+                Group group = it1.next();
                 log.trace("Stored Group {} for device {}", group, deviceId);
             }
 
-            for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
-                Group group = it.next();
+            for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
+                Group group = it2.next();
                 if (storedGroupEntries.remove(group)) {
                     // we both have the group, let's update some info then.
                     log.trace("Group AUDIT: group {} exists "
                             + "in both planes for device {}",
                             group.id(), deviceId);
                     groupAdded(group);
-                    it.remove();
+                    it2.remove();
                 }
             }
             for (Group group : southboundGroupEntries) {
-                // there are groups in the switch that aren't in the store
-                log.trace("Group AUDIT: extraneous group {} exists "
-                        + "in data plane for device {}",
-                        group.id(), deviceId);
-                extraneousStoredEntries.remove(group);
-                extraneousGroup(group);
+                if (store.getGroup(group.deviceId(), group.id()) != null) {
+                    // There is a group existing with the same id
+                    // It is possible that group update is
+                    // in progress while we got a stale info from switch
+                    if (!storedGroupEntries.remove(store.getGroup(
+                                 group.deviceId(), group.id()))) {
+                        log.warn("Group AUDIT: Inconsistent state:"
+                                + "Group exists in ID based table while "
+                                + "not present in key based table");
+                    }
+                } else {
+                    // there are groups in the switch that aren't in the store
+                    log.trace("Group AUDIT: extraneous group {} exists "
+                            + "in data plane for device {}",
+                            group.id(), deviceId);
+                    extraneousStoredEntries.remove(group);
+                    extraneousGroup(group);
+                }
             }
             for (Group group : storedGroupEntries) {
                 // there are groups in the store that aren't in the switch