Stopping map conflicts with persistent EC maps.
Change-Id: I30f132cbf1a330780fe09ef10e607e7ddab2fec0
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 c52b35e..c7dfb77 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
@@ -20,10 +20,13 @@
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.KryoNamespace;
+import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.ControllerNode;
import org.onosproject.cluster.NodeId;
@@ -32,29 +35,35 @@
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
-import org.onosproject.net.intent.WorkPartitionService;
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.WorkPartitionService;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.Timestamp;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.EventuallyConsistentMapBuilder;
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.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Collection;
+import java.util.Dictionary;
import java.util.List;
import java.util.Objects;
+import java.util.Properties;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
import static org.onosproject.net.intent.IntentState.PURGE_REQ;
import static org.slf4j.LoggerFactory.getLogger;
@@ -72,6 +81,8 @@
private final Logger log = getLogger(getClass());
+ private static final boolean PERSIST = false;
+
// Map of intent key => current intent state
private EventuallyConsistentMap<Key, IntentData> currentMap;
@@ -79,6 +90,9 @@
private EventuallyConsistentMap<Key, IntentData> pendingMap;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -95,8 +109,26 @@
private EventuallyConsistentMapListener<Key, IntentData>
mapPendingListener = new InternalPendingListener();
+ //Denotes the initial persistence value for this structure
+ private boolean initiallyPersistent = false;
+
+ //TODO this is currently an experimental feature used for performance
+ // evalutaion, enabling persistence with persist the intents but they will
+ // not be reinstalled and network state will not be consistent with the
+ // intents on cluster restart
+ @Property(name = "persistenceEnabled", boolValue = PERSIST,
+ label = "EXPERIMENTAL: Enable intent persistence")
+ private boolean persistenceEnabled;
+
+
@Activate
- public void activate() {
+ public void activate(ComponentContext context) {
+ configService.registerProperties(getClass());
+ modified(context);
+ //TODO persistent intents must be reevaluated and the appropriate
+ //processing done here, current implementation is not functional
+ //and is for performance evaluation only
+ initiallyPersistent = persistenceEnabled;
KryoNamespace.Builder intentSerializer = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(IntentData.class)
@@ -104,23 +136,31 @@
.register(NetworkId.class)
.register(MultiValuedTimestamp.class);
- currentMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
+ EventuallyConsistentMapBuilder currentECMapBuilder =
+ storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
.withName("intent-current")
.withSerializer(intentSerializer)
.withTimestampProvider((key, intentData) ->
- new MultiValuedTimestamp<>(intentData.version(),
+ new MultiValuedTimestamp<>(
+ intentData == null ? new WallClockTimestamp() :
+ intentData.version(),
sequenceNumber.getAndIncrement()))
- .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData))
- .build();
+ .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData));
- pendingMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
+ EventuallyConsistentMapBuilder pendingECMapBuilder =
+ storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
.withName("intent-pending")
.withSerializer(intentSerializer)
.withTimestampProvider((key, intentData) -> intentData == null ?
new MultiValuedTimestamp<>(new WallClockTimestamp(), System.nanoTime()) :
new MultiValuedTimestamp<>(intentData.version(), System.nanoTime()))
- .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData))
- .build();
+ .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData));
+ if (initiallyPersistent) {
+ currentECMapBuilder = currentECMapBuilder.withPersistence();
+ pendingECMapBuilder = pendingECMapBuilder.withPersistence();
+ }
+ currentMap = currentECMapBuilder.build();
+ pendingMap = pendingECMapBuilder.build();
currentMap.addListener(mapCurrentListener);
pendingMap.addListener(mapPendingListener);
@@ -130,6 +170,11 @@
@Deactivate
public void deactivate() {
+ if (initiallyPersistent && !persistenceEnabled) {
+ pendingMap.clear();
+ currentMap.clear();
+ log.debug("Persistent state has been purged");
+ }
currentMap.removeListener(mapCurrentListener);
pendingMap.removeListener(mapPendingListener);
currentMap.destroy();
@@ -138,6 +183,48 @@
log.info("Stopped");
}
+ @Modified
+ public void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context != null ? context.getProperties()
+ : new Properties();
+ try {
+ String s = get(properties, "persistenceEnabled");
+ persistenceEnabled = isNullOrEmpty(s) ? PERSIST :
+ Boolean.parseBoolean(s.trim());
+ } catch (Exception e) {
+ persistenceEnabled = initiallyPersistent;
+ log.error("Failed to retrieve the property value for persist," +
+ "defaulting to the initial setting of \"{}\"" +
+ "any persistent state will not be purged, if " +
+ "this occurred at startup changes made in this" +
+ "session will not be persisted to disk",
+ initiallyPersistent);
+ }
+ if (persistenceEnabled) {
+ //FIXME persistence is an experimental feature, warnings can be removed
+ //when the feature is completed
+ log.warn("Persistence is an experimental feature, it is not fully " +
+ "functional and is intended only for " +
+ "performance evaluation");
+ }
+ if (!initiallyPersistent && !persistenceEnabled) {
+ log.info("Persistence is set to \"false\", this was the initial" +
+ " setting so no state will be purged or " +
+ "persisted");
+ } else if (!initiallyPersistent && persistenceEnabled) {
+ log.info("Persistence is set to \"true\", entries will be begin " +
+ "to be persisted after restart");
+ } else if (initiallyPersistent && !persistenceEnabled) {
+ log.info("Persistence is set to \"false\", all persistent state " +
+ "will be purged on next shutdown");
+ } else {
+ log.info("Persistence is set to \"true\", entries from this and" +
+ " subsequent sessions will be persisted");
+ }
+
+
+ }
+
@Override
public long getIntentCount() {
return currentMap.size();
diff --git a/core/store/dist/src/test/java/org/onosproject/store/intent/impl/GossipIntentStoreTest.java b/core/store/dist/src/test/java/org/onosproject/store/intent/impl/GossipIntentStoreTest.java
index e1a4a4f..ba88e78 100644
--- a/core/store/dist/src/test/java/org/onosproject/store/intent/impl/GossipIntentStoreTest.java
+++ b/core/store/dist/src/test/java/org/onosproject/store/intent/impl/GossipIntentStoreTest.java
@@ -17,11 +17,14 @@
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.stream.IntStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cfg.ConfigProperty;
import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.core.IdGenerator;
import org.onosproject.net.intent.HostToHostIntent;
@@ -61,7 +64,8 @@
.one(hid("12:34:56:78:91:ab/1"))
.two(hid("12:34:56:78:91:ac/1"))
.appId(APP_ID);
- intentStore.activate();
+ intentStore.configService = new MockComponentConfigService();
+ intentStore.activate(null);
}
@After
@@ -231,4 +235,46 @@
data -> assertThat(data, is(installed))
);
}
+
+ private class MockComponentConfigService implements ComponentConfigService {
+
+ public MockComponentConfigService() {
+
+ }
+
+ @Override
+ public Set<String> getComponentNames() {
+ return null;
+ }
+
+ @Override
+ public void registerProperties(Class<?> componentClass) {
+
+ }
+
+ @Override
+ public void unregisterProperties(Class<?> componentClass, boolean clear) {
+
+ }
+
+ @Override
+ public Set<ConfigProperty> getProperties(String componentName) {
+ return null;
+ }
+
+ @Override
+ public void setProperty(String componentName, String name, String value) {
+
+ }
+
+ @Override
+ public void preSetProperty(String componentName, String name, String value) {
+
+ }
+
+ @Override
+ public void unsetProperty(String componentName, String name) {
+
+ }
+ }
}
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/EventuallyConsistentMapImpl.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/EventuallyConsistentMapImpl.java
index bba165f..7964187 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/EventuallyConsistentMapImpl.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/EventuallyConsistentMapImpl.java
@@ -125,9 +125,6 @@
private final boolean persistent;
- private static final String PERSISTENT_LOCAL_MAP_NAME = "itemsMap";
-
-
/**
* Creates a new eventually consistent map shared amongst multiple instances.
* <p>
@@ -178,7 +175,7 @@
persistent;
if (persistent) {
items = this.persistenceService.<K, MapValue<V>>persistentMapBuilder()
- .withName(PERSISTENT_LOCAL_MAP_NAME)
+ .withName(mapName)
.withSerializer(this.serializer)
.build();
} else {