ONOS-4590 - This has been noticed also in ONOS-3633 - Fixing an issue with intents.
Pending intents were not being removed from the Gossip intent store as the
intentData object did not match what was stored during the remove.
General cause: intent resubmission loops when installation time exceeds cleanup
polling interval

Change-Id: Id50baade9807c102b7cbff9a4667e048f57698bb
diff --git a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java b/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
index 98aa3cf..43b89f6 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
@@ -16,7 +16,6 @@
 package org.onosproject.store.intent.impl;
 
 import com.google.common.collect.ImmutableList;
-
 import org.apache.commons.lang.math.RandomUtils;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -31,19 +30,19 @@
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentData;
 import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentPartitionService;
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.IntentStore;
 import org.onosproject.net.intent.IntentStoreDelegate;
 import org.onosproject.net.intent.Key;
-import org.onosproject.net.intent.IntentPartitionService;
 import org.onosproject.store.AbstractStore;
-import org.onosproject.store.service.MultiValuedTimestamp;
-import org.onosproject.store.service.WallClockTimestamp;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.EventuallyConsistentMapEvent;
 import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.MultiValuedTimestamp;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
 import org.slf4j.Logger;
 
 import java.util.Collection;
@@ -91,7 +90,6 @@
     public void activate() {
         KryoNamespace.Builder intentSerializer = KryoNamespace.newBuilder()
                 .register(KryoNamespaces.API)
-                .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
                 .register(IntentData.class)
                 .register(MultiValuedTimestamp.class);
 
@@ -99,16 +97,17 @@
                 .withName("intent-current")
                 .withSerializer(intentSerializer)
                 .withTimestampProvider((key, intentData) ->
-                                            new MultiValuedTimestamp<>(intentData.version(),
-                                                                       sequenceNumber.getAndIncrement()))
+                                               new MultiValuedTimestamp<>(intentData.version(),
+                                                                          sequenceNumber.getAndIncrement()))
                 .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData))
                 .build();
 
         pendingMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
                 .withName("intent-pending")
                 .withSerializer(intentSerializer)
-                .withTimestampProvider((key, intentData) -> new MultiValuedTimestamp<>(intentData.version(),
-                                                                                       System.nanoTime()))
+                .withTimestampProvider((key, intentData) -> intentData == null ?
+                        new MultiValuedTimestamp<>(new WallClockTimestamp(), System.nanoTime()) :
+                        new MultiValuedTimestamp<>(intentData.version(), System.nanoTime()))
                 .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData))
                 .build();
 
@@ -183,8 +182,15 @@
                 currentMap.put(newData.key(), new IntentData(newData));
             }
 
-            // if current.put succeeded
-            pendingMap.remove(newData.key(), newData);
+            // Remove the intent data from the pending map if the newData is more
+            // recent or equal to the existing entry.
+            pendingMap.compute(newData.key(), (key, existingValue) -> {
+                if (existingValue == null || !existingValue.version().isNewerThan(newData.version())) {
+                    return null;
+                } else {
+                    return existingValue;
+                }
+            });
         }
     }
 
@@ -252,10 +258,10 @@
 
         if (data.version() == null) {
             pendingMap.put(data.key(), new IntentData(data.intent(), data.state(),
-                    new WallClockTimestamp(), clusterService.getLocalNode().id()));
+                                                      new WallClockTimestamp(), clusterService.getLocalNode().id()));
         } else {
             pendingMap.put(data.key(), new IntentData(data.intent(), data.state(),
-                    data.version(), clusterService.getLocalNode().id()));
+                                                      data.version(), clusterService.getLocalNode().id()));
         }
     }
 
@@ -282,7 +288,7 @@
         final WallClockTimestamp time = new WallClockTimestamp(now - olderThan);
         return pendingMap.values().stream()
                 .filter(data -> data.version().isOlderThan(time) &&
-                                (!localOnly || isMaster(data.key())))
+                        (!localOnly || isMaster(data.key())))
                 .collect(Collectors.toList());
     }