Cleaned up IntentStores.
* Removed HazelcastIntentStore
* Moved SimpleIntentStore back to trivial bundle (and removed older version
that was already in the trivial bundle)
* Removed default methods from IntentStore interface
ONOS-1056
Change-Id: Id5e15f44e287f51cca3e0b12a85d49cb4a07a9d3
diff --git a/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java b/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java
index d8e63df..5cfae17 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java
@@ -17,7 +17,6 @@
import org.onosproject.store.Store;
-import java.util.Collections;
import java.util.List;
/**
@@ -45,27 +44,23 @@
* @param intentKey intent identification
* @return current intent state
*/
- default IntentState getIntentState(Key intentKey) {
- return null;
- }
+ IntentState getIntentState(Key intentKey);
/**
* Returns the list of the installable events associated with the specified
* original intent.
*
* @param intentKey original intent identifier
- * @return compiled installable intents
+ * @return compiled installable intents, or null if no installables exist
*/
- default List<Intent> getInstallableIntents(Key intentKey) {
- throw new UnsupportedOperationException("getInstallableIntents()");
- }
+ List<Intent> getInstallableIntents(Key intentKey);
/**
* Writes an IntentData object to the store.
*
* @param newData new intent data to write
*/
- default void write(IntentData newData) {}
+ void write(IntentData newData);
/**
* Writes a batch of IntentData objects to the store. A batch has no
@@ -73,7 +68,7 @@
*
* @param updates collection of intent data objects to write
*/
- default void batchWrite(Iterable<IntentData> updates) {}
+ void batchWrite(Iterable<IntentData> updates);
/**
* Returns the intent with the specified identifier.
@@ -81,10 +76,7 @@
* @param key key
* @return intent or null if not found
*/
- default Intent getIntent(Key key) {
- // FIXME remove this default implementation when all stores have implemented it
- return null;
- }
+ Intent getIntent(Key key);
/**
* Returns the intent data object associated with the specified key.
@@ -92,16 +84,14 @@
* @param key key to look up
* @return intent data object
*/
- default IntentData getIntentData(Key key) { //FIXME remove when impl.
- return null;
- }
+ IntentData getIntentData(Key key);
/**
* Adds a new operation, which should be persisted and delegated.
*
* @param intent operation
*/
- default void addPending(IntentData intent) {} //FIXME remove when impl.
+ void addPending(IntentData intent);
/**
* Checks to see whether the calling instance is the master for processing
@@ -111,17 +101,12 @@
* @return true if master; false, otherwise
*/
//TODO better name
- default boolean isMaster(Key intentKey) { //FIXME remove default when impl.
- return true;
- }
+ boolean isMaster(Key intentKey);
/**
* Returns the intent requests pending processing.
*
* @return pending intents
*/
- // FIXME remove default
- default Iterable<Intent> getPending() {
- return Collections.emptyList();
- }
+ Iterable<Intent> getPending();
}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index 4be32c4..566d39c 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -48,7 +48,7 @@
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
import org.onosproject.net.resource.LinkResourceAllocations;
-import org.onosproject.store.intent.impl.SimpleIntentStore;
+import org.onosproject.store.trivial.impl.SimpleIntentStore;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
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 9ae7b57..4bc0ed0 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
@@ -37,7 +37,7 @@
import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
import org.onosproject.store.impl.MultiValuedTimestamp;
-import org.onosproject.store.impl.SystemClockTimestamp;
+import org.onosproject.store.impl.WallClockTimestamp;
import org.onosproject.store.serializers.KryoNamespaces;
import org.slf4j.Logger;
@@ -80,7 +80,7 @@
.register(KryoNamespaces.API)
.register(IntentData.class)
.register(MultiValuedTimestamp.class)
- .register(SystemClockTimestamp.class);
+ .register(WallClockTimestamp.class);
currentMap = new EventuallyConsistentMapImpl<>("intent-current",
clusterService,
@@ -225,8 +225,6 @@
@Override
public void write(IntentData newData) {
- //log.debug("writing intent {}", newData);
-
IntentData currentData = currentMap.get(newData.key());
if (isUpdateAcceptable(currentData, newData)) {
@@ -239,12 +237,6 @@
} else {
log.debug("not writing update: current {}, new {}", currentData, newData);
}
- /*try {
- notifyDelegate(IntentEvent.getEvent(newData));
- } catch (IllegalArgumentException e) {
- //no-op
- log.trace("ignore this exception: {}", e);
- }*/
}
@Override
@@ -268,9 +260,8 @@
@Override
public void addPending(IntentData data) {
- log.debug("new pending {} {} {}", data.key(), data.state(), data.version());
if (data.version() == null) {
- data.setVersion(new SystemClockTimestamp());
+ data.setVersion(new WallClockTimestamp());
}
pendingMap.put(data.key(), copyData(data));
}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/HazelcastIntentStore.java b/core/store/dist/src/main/java/org/onosproject/store/intent/impl/HazelcastIntentStore.java
deleted file mode 100644
index 8514ded..0000000
--- a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/HazelcastIntentStore.java
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright 2014 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.store.intent.impl;
-
-import com.codahale.metrics.Timer;
-import com.codahale.metrics.Timer.Context;
-import com.google.common.base.Verify;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.hazelcast.config.Config;
-import com.hazelcast.config.MapConfig;
-import com.hazelcast.core.EntryAdapter;
-import com.hazelcast.core.EntryEvent;
-import com.hazelcast.core.EntryListener;
-import com.hazelcast.core.IMap;
-import com.hazelcast.core.Member;
-import org.apache.commons.lang3.tuple.Pair;
-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.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.Service;
-import org.onlab.metrics.MetricsService;
-import org.onlab.util.KryoNamespace;
-import org.onosproject.core.MetricsHelper;
-import org.onosproject.net.intent.BatchWrite;
-import org.onosproject.net.intent.BatchWrite.Operation;
-import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentEvent;
-import org.onosproject.net.intent.IntentId;
-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.store.hz.AbstractHazelcastStore;
-import org.onosproject.store.hz.SMap;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.serializers.KryoSerializer;
-import org.slf4j.Logger;
-
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.onlab.metrics.MetricsUtil.startTimer;
-import static org.onlab.metrics.MetricsUtil.stopTimer;
-import static org.onosproject.net.intent.IntentState.FAILED;
-import static org.onosproject.net.intent.IntentState.INSTALLED;
-import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
-import static org.onosproject.net.intent.IntentState.WITHDRAWN;
-import static org.slf4j.LoggerFactory.getLogger;
-
-//TODO Note: this store will be removed
-
-@Component(immediate = true, enabled = false)
-@Service
-public class HazelcastIntentStore
- extends AbstractHazelcastStore<IntentEvent, IntentStoreDelegate>
- implements IntentStore, MetricsHelper {
-
- /** Valid parking state, which can transition to INSTALLED. */
- private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(INSTALL_REQ, INSTALLED, FAILED);
-
- /** Valid parking state, which can transition to WITHDRAWN. */
- private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
-
- private static final Set<IntentState> PARKING = EnumSet.of(INSTALL_REQ, INSTALLED, WITHDRAWN, FAILED);
-
- private final Logger log = getLogger(getClass());
-
- // Assumption: IntentId will not have synonyms
- private static final String INTENTS_MAP_NAME = "intents";
- private SMap<IntentId, Intent> intents;
- private static final String INTENT_STATES_MAP_NAME = "intent-states";
- private SMap<IntentId, IntentState> states;
-
- // Map to store instance local intermediate state transition
- private transient Map<IntentId, IntentState> transientStates = new ConcurrentHashMap<>();
-
- private static final String INSTALLABLE_INTENTS_MAP_NAME = "installable-intents";
- private SMap<IntentId, List<Intent>> installable;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected MetricsService metricsService;
-
- private boolean onlyLogTransitionError = true;
-
- private Timer getInstallableIntentsTimer;
- private Timer getIntentCountTimer;
- private Timer getIntentsTimer;
- private Timer getIntentTimer;
- private Timer getIntentStateTimer;
-
- // manual near cache of Intent
- // (Note: IntentId -> Intent is expected to be immutable)
- // entry will be evicted, when state for that IntentId is removed.
- private Map<IntentId, Intent> localIntents;
-
- private String stateListenerId;
-
- private String intentsListenerId;
-
- private Timer createResponseTimer(String methodName) {
- return createTimer("IntentStore", methodName, "responseTime");
- }
-
- @Override
- @Activate
- public void activate() {
- localIntents = new ConcurrentHashMap<>();
-
- getInstallableIntentsTimer = createResponseTimer("getInstallableIntents");
- getIntentCountTimer = createResponseTimer("getIntentCount");
- getIntentsTimer = createResponseTimer("getIntents");
- getIntentTimer = createResponseTimer("getIntent");
- getIntentStateTimer = createResponseTimer("getIntentState");
-
- // We need a way to add serializer for intents which has been plugged-in.
- // As a short term workaround, relax Kryo config to
- // registrationRequired=false
- super.activate();
- super.serializer = new KryoSerializer() {
-
- @Override
- protected void setupKryoPool() {
- serializerPool = KryoNamespace.newBuilder()
- .setRegistrationRequired(false)
- .register(KryoNamespaces.API)
- .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
- .build();
- }
-
- };
-
- final Config config = theInstance.getConfig();
-
- MapConfig intentsCfg = config.getMapConfig(INTENTS_MAP_NAME);
- intentsCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - intentsCfg.getBackupCount());
-
- IMap<byte[], byte[]> rawIntents = super.theInstance.getMap(INTENTS_MAP_NAME);
- intents = new SMap<>(rawIntents , super.serializer);
- intentsListenerId = intents.addEntryListener(new RemoteIntentsListener(), true);
-
- MapConfig statesCfg = config.getMapConfig(INTENT_STATES_MAP_NAME);
- statesCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - statesCfg.getBackupCount());
-
- IMap<byte[], byte[]> rawStates = super.theInstance.getMap(INTENT_STATES_MAP_NAME);
- states = new SMap<>(rawStates , super.serializer);
- EntryListener<IntentId, IntentState> listener = new RemoteIntentStateListener();
- stateListenerId = states.addEntryListener(listener, true);
-
- transientStates.clear();
-
- MapConfig installableCfg = config.getMapConfig(INSTALLABLE_INTENTS_MAP_NAME);
- installableCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - installableCfg.getBackupCount());
-
- IMap<byte[], byte[]> rawInstallables = super.theInstance.getMap(INSTALLABLE_INTENTS_MAP_NAME);
- installable = new SMap<>(rawInstallables , super.serializer);
-
- log.info("Started");
- }
-
- @Deactivate
- public void deactivate() {
- intents.removeEntryListener(intentsListenerId);
- states.removeEntryListener(stateListenerId);
- log.info("Stopped");
- }
-
- @Override
- public MetricsService metricsService() {
- return metricsService;
- }
-
- @Override
- public long getIntentCount() {
- Context timer = startTimer(getIntentCountTimer);
- try {
- return intents.size();
- } finally {
- stopTimer(timer);
- }
- }
-
- @Override
- public Iterable<Intent> getIntents() {
- Context timer = startTimer(getIntentsTimer);
- try {
- return ImmutableSet.copyOf(intents.values());
- } finally {
- stopTimer(timer);
- }
- }
-
- @Override
- public Intent getIntent(Key intentKey) {
- return null;
- }
-
-
- public Intent getIntent(IntentId intentId) {
- Context timer = startTimer(getIntentTimer);
- try {
- Intent intent = localIntents.get(intentId);
- if (intent != null) {
- return intent;
- }
- intent = intents.get(intentId);
- if (intent != null) {
- localIntents.put(intentId, intent);
- }
- return intent;
- } finally {
- stopTimer(timer);
- }
- }
-
- @Override
- public IntentState getIntentState(Key key) {
- // TODO: either implement this or remove this class
- return IntentState.FAILED;
- /*
- Context timer = startTimer(getIntentStateTimer);
- try {
- final IntentState localState = transientStates.get(id);
- if (localState != null) {
- return localState;
- }
- return states.get(id);
- } finally {
- stopTimer(timer);
- }
- */
- }
-
- private void verify(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
- if (onlyLogTransitionError) {
- if (!expression) {
- log.error(errorMessageTemplate.replace("%s", "{}"), errorMessageArgs);
- }
- } else {
- Verify.verify(expression, errorMessageTemplate, errorMessageArgs);
- }
- }
-
- @Override
- public List<Intent> getInstallableIntents(Key intentKey) {
- // TODO: implement this or delete class
- return null;
-
- /*
- Context timer = startTimer(getInstallableIntentsTimer);
- try {
- return installable.get(intentId);
- } finally {
- stopTimer(timer);
- }
- */
- }
-
- /*@Override
- public List<Operation> batchWrite(BatchWrite batch) {
- if (batch.isEmpty()) {
- return Collections.emptyList();
- }
-
- // Hazelcast version will never fail for conditional failure now.
- List<Operation> failed = new ArrayList<>();
-
- List<Pair<Operation, List<Future<?>>>> futures = new ArrayList<>(batch.operations().size());
- List<IntentEvent> events = Lists.newArrayList();
-
- batchWriteAsync(batch, failed, futures);
-
- // verify result
- verifyAsyncWrites(futures, failed, events);
-
- notifyDelegate(events);
-
- return failed;
- }*/
-
- private void batchWriteAsync(BatchWrite batch, List<Operation> failed,
- List<Pair<Operation, List<Future<?>>>> futures) {
- for (Operation op : batch.operations()) {
- switch (op.type()) {
- case CREATE_INTENT:
- checkArgument(op.args().size() == 1,
- "CREATE_INTENT takes 1 argument. %s", op);
- Intent intent = op.arg(0);
- futures.add(Pair.of(op,
- ImmutableList.of(intents.putAsync(intent.id(), intent),
- states.putAsync(intent.id(), INSTALL_REQ))));
- break;
-
- case REMOVE_INTENT:
- checkArgument(op.args().size() == 1,
- "REMOVE_INTENT takes 1 argument. %s", op);
- IntentId intentId = (IntentId) op.arg(0);
- futures.add(Pair.of(op,
- ImmutableList.of(intents.removeAsync(intentId),
- states.removeAsync(intentId),
- installable.removeAsync(intentId))));
- break;
-
- case SET_STATE:
- checkArgument(op.args().size() == 2,
- "SET_STATE takes 2 arguments. %s", op);
- intent = op.arg(0);
- IntentState newState = op.arg(1);
- futures.add(Pair.of(op,
- ImmutableList.of(states.putAsync(intent.id(), newState))));
- break;
-
- case SET_INSTALLABLE:
- checkArgument(op.args().size() == 2,
- "SET_INSTALLABLE takes 2 arguments. %s", op);
- intentId = op.arg(0);
- List<Intent> installableIntents = op.arg(1);
- futures.add(Pair.of(op,
- ImmutableList.of(installable.putAsync(intentId, installableIntents))));
- break;
-
- case REMOVE_INSTALLED:
- checkArgument(op.args().size() == 1,
- "REMOVE_INSTALLED takes 1 argument. %s", op);
- intentId = op.arg(0);
- futures.add(Pair.of(op,
- ImmutableList.of(installable.removeAsync(intentId))));
- break;
-
- default:
- log.warn("Unknown Operation encountered: {}", op);
- failed.add(op);
- break;
- }
- }
- }
-
- /**
- * Checks the async write result Futures and prepare Events to post.
- *
- * @param futures async write Futures
- * @param failed list to output failed batch write operations
- * @param events list to output events to post as result of writes
- */
- private void verifyAsyncWrites(List<Pair<Operation, List<Future<?>>>> futures,
- List<Operation> failed,
- List<IntentEvent> events) {
- for (Pair<Operation, List<Future<?>>> future : futures) {
- final Operation op = future.getLeft();
- final List<Future<?>> subops = future.getRight();
-
- switch (op.type()) {
-
- case CREATE_INTENT:
- {
- Intent intent = op.arg(0);
- IntentState newIntentState = INSTALL_REQ;
-
- try {
- Intent prevIntent = (Intent) subops.get(0).get();
- IntentState prevIntentState = (IntentState) subops.get(1).get();
-
- if (prevIntent != null || prevIntentState != null) {
- log.warn("Overwriting existing Intent: {}@{} with {}@{}",
- prevIntent, prevIntentState,
- intent, newIntentState);
- }
- events.add(IntentEvent.getEvent(INSTALL_REQ, intent));
- } catch (InterruptedException e) {
- log.error("Batch write was interrupted while processing {}", op, e);
- failed.add(op);
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- log.error("Batch write failed processing {}", op, e);
- failed.add(op);
- }
- break;
- }
-
- case REMOVE_INTENT:
- {
- IntentId intentId = op.arg(0);
-
- try {
- Intent prevIntent = (Intent) subops.get(0).get();
- IntentState prevIntentState = (IntentState) subops.get(1).get();
- @SuppressWarnings("unchecked")
- List<Intent> prevInstallable = (List<Intent>) subops.get(2).get();
-
- if (prevIntent == null) {
- log.warn("Intent {} was already removed.", intentId);
- }
- if (prevIntentState == null) {
- log.warn("Intent {} state was already removed", intentId);
- }
- if (prevInstallable != null) {
- log.warn("Intent {} removed installable still found", intentId);
- }
- } catch (InterruptedException e) {
- log.error("Batch write was interrupted while processing {}", op, e);
- failed.add(op);
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- log.error("Batch write failed processing {}", op, e);
- failed.add(op);
- }
- break;
- }
-
- case SET_STATE:
- {
- Intent intent = op.arg(0);
- IntentId intentId = intent.id();
- IntentState newState = op.arg(1);
-
- try {
- IntentState prevIntentState = (IntentState) subops.get(0).get();
-
- if (PARKING.contains(newState)) {
- transientStates.remove(intentId);
- events.add(IntentEvent.getEvent(newState, intent));
- }
-
- log.trace("{} - {} -> {}", intentId, prevIntentState, newState);
- } catch (InterruptedException e) {
- log.error("Batch write was interrupted while processing {}", op, e);
- failed.add(op);
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- log.error("Batch write failed processing {}", op, e);
- failed.add(op);
- }
- break;
- }
-
- case SET_INSTALLABLE:
- {
- IntentId intentId = op.arg(0);
- List<Intent> installableIntents = op.arg(1);
-
- try {
- @SuppressWarnings("unchecked")
- List<Intent> prevInstallable = (List<Intent>) subops.get(0).get();
-
- if (prevInstallable != null) {
- log.warn("Overwriting Intent {} installable {} -> {}",
- intentId, prevInstallable, installableIntents);
- }
- } catch (InterruptedException e) {
- log.error("Batch write was interrupted while processing {}", op, e);
- failed.add(op);
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- log.error("Batch write failed processing {}", op, e);
- failed.add(op);
- }
- break;
- }
-
- case REMOVE_INSTALLED:
- {
- IntentId intentId = op.arg(0);
-
- try {
- @SuppressWarnings("unchecked")
- List<Intent> prevInstallable = (List<Intent>) subops.get(0).get();
-
- if (prevInstallable == null) {
- log.warn("Intent {} installable was already removed", intentId);
- }
- } catch (InterruptedException e) {
- log.error("Batch write was interrupted while processing {}", op, e);
- failed.add(op);
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- log.error("Batch write failed processing {}", op, e);
- failed.add(op);
- }
- break;
- }
-
- default:
- log.warn("Unknown Operation encountered: {}", op);
- if (!failed.contains(op)) {
- failed.add(op);
- }
- break;
- }
- }
- }
-
- public final class RemoteIntentsListener extends EntryAdapter<IntentId, Intent> {
-
- @Override
- public void entryAdded(EntryEvent<IntentId, Intent> event) {
- localIntents.put(event.getKey(), event.getValue());
- }
-
- @Override
- public void entryUpdated(EntryEvent<IntentId, Intent> event) {
- entryAdded(event);
- }
- }
-
- public final class RemoteIntentStateListener extends EntryAdapter<IntentId, IntentState> {
-
- @Override
- public void onEntryEvent(EntryEvent<IntentId, IntentState> event) {
- final IntentId intentId = event.getKey();
- final Member myself = theInstance.getCluster().getLocalMember();
- if (!myself.equals(event.getMember())) {
- // When Intent state was modified by remote node,
- // clear local transient state.
- IntentState oldState = transientStates.remove(intentId);
- if (oldState != null) {
- log.debug("{} state updated remotely, removing transient state {}",
- intentId, oldState);
- }
-
- if (event.getValue() != null) {
- // notify if this is not entry removed event
-
- final Intent intent = getIntent(intentId);
- if (intent == null) {
- log.warn("no Intent found for {} on Event {}", intentId, event);
- return;
- }
- notifyDelegate(IntentEvent.getEvent(event.getValue(), intent));
- // remove IntentCache
- localIntents.remove(intentId, intent);
- }
- }
-
- // populate manual near cache, to prepare for
- // transition event to WITHDRAWN
- getIntent(intentId);
- }
- }
-}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/SimpleIntentStore.java b/core/store/dist/src/main/java/org/onosproject/store/intent/impl/SimpleIntentStore.java
deleted file mode 100644
index 5f1cbd4..0000000
--- a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/SimpleIntentStore.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.store.intent.impl;
-
-import com.google.common.collect.Maps;
-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.Service;
-import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentData;
-import org.onosproject.net.intent.IntentEvent;
-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.store.AbstractStore;
-import org.onosproject.store.impl.SystemClockTimestamp;
-import org.slf4j.Logger;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.intent.IntentState.*;
-import static org.slf4j.LoggerFactory.getLogger;
-
-//TODO Note: this store will be removed once the GossipIntentStore is stable
-
-@Component(immediate = true, enabled = false)
-@Service
-//FIXME remove this
-public class SimpleIntentStore
- extends AbstractStore<IntentEvent, IntentStoreDelegate>
- implements IntentStore {
-
- private final Logger log = getLogger(getClass());
-
- private final Map<Key, IntentData> current = Maps.newConcurrentMap();
- private final Map<Key, IntentData> pending = Maps.newConcurrentMap();
-
- private IntentData copyData(IntentData original) {
- if (original == null) {
- return null;
- }
- IntentData result =
- new IntentData(original.intent(), original.state(), original.version());
-
- if (original.installables() != null) {
- result.setInstallables(original.installables());
- }
- return result;
- }
-
- @Activate
- public void activate() {
- log.info("Started");
- }
-
- @Deactivate
- public void deactivate() {
- log.info("Stopped");
- }
-
- @Override
- public long getIntentCount() {
- return current.size();
- }
-
- @Override
- public Iterable<Intent> getIntents() {
- return current.values().stream()
- .map(IntentData::intent)
- .collect(Collectors.toList());
- }
-
- @Override
- public IntentState getIntentState(Key intentKey) {
- IntentData data = current.get(intentKey);
- return (data != null) ? data.state() : null;
- }
-
- @Override
- public List<Intent> getInstallableIntents(Key intentKey) {
- // TODO: implement this or delete class
- return null;
- /*
- for (IntentData data : current.values()) {
- if (Objects.equals(data.intent().id(), intentId)) {
- return data.installables();
- }
- }
- return null;
- */
- }
-
-
- /**
- * Determines whether an intent data update is allowed. The update must
- * either have a higher version than the current data, or the state
- * transition between two updates of the same version must be sane.
- *
- * @param currentData existing intent data in the store
- * @param newData new intent data update proposal
- * @return true if we can apply the update, otherwise false
- */
- private boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
-
- if (currentData == null) {
- return true;
- } else if (currentData.version().compareTo(newData.version()) < 0) {
- return true;
- } else if (currentData.version().compareTo(newData.version()) > 0) {
- return false;
- }
-
- // current and new data versions are the same
- IntentState currentState = currentData.state();
- IntentState newState = newData.state();
-
- switch (newState) {
- case INSTALLING:
- if (currentState == INSTALLING) {
- return false;
- }
- // FALLTHROUGH
- case INSTALLED:
- if (currentState == INSTALLED) {
- return false;
- } else if (currentState == WITHDRAWING || currentState == WITHDRAWN) {
- log.warn("Invalid state transition from {} to {} for intent {}",
- currentState, newState, newData.key());
- return false;
- }
- return true;
-
- case WITHDRAWING:
- if (currentState == WITHDRAWING) {
- return false;
- }
- // FALLTHOUGH
- case WITHDRAWN:
- if (currentState == WITHDRAWN) {
- return false;
- } else if (currentState == INSTALLING || currentState == INSTALLED) {
- log.warn("Invalid state transition from {} to {} for intent {}",
- currentState, newState, newData.key());
- return false;
- }
- return true;
-
-
- case FAILED:
- if (currentState == FAILED) {
- return false;
- }
- return true;
-
-
- case COMPILING:
- case RECOMPILING:
- case INSTALL_REQ:
- case WITHDRAW_REQ:
- default:
- log.warn("Invalid state {} for intent {}", newState, newData.key());
- return false;
- }
- }
-
- @Override
- public void write(IntentData newData) {
- synchronized (this) {
- // TODO this could be refactored/cleaned up
- IntentData currentData = current.get(newData.key());
- IntentData pendingData = pending.get(newData.key());
-
- if (isUpdateAcceptable(currentData, newData)) {
- current.put(newData.key(), copyData(newData));
-
- if (pendingData != null
- // pendingData version is less than or equal to newData's
- // Note: a new update for this key could be pending (it's version will be greater)
- && pendingData.version().compareTo(newData.version()) <= 0) {
- pending.remove(newData.key());
- }
-
- notifyDelegateIfNotNull(IntentEvent.getEvent(newData));
- }
- }
- }
-
- private void notifyDelegateIfNotNull(IntentEvent event) {
- if (event != null) {
- notifyDelegate(event);
- }
- }
-
- @Override
- public void batchWrite(Iterable<IntentData> updates) {
- for (IntentData data : updates) {
- write(data);
- }
- }
-
- @Override
- public Intent getIntent(Key key) {
- IntentData data = current.get(key);
- return (data != null) ? data.intent() : null;
- }
-
- @Override
- public IntentData getIntentData(Key key) {
- return copyData(current.get(key));
- }
-
- @Override
- public void addPending(IntentData data) {
- if (data.version() == null) { // recompiled intents will already have a version
- data.setVersion(new SystemClockTimestamp());
- }
- synchronized (this) {
- IntentData existingData = pending.get(data.key());
- if (existingData == null ||
- // existing version is strictly less than data's version
- // Note: if they are equal, we already have the update
- // TODO maybe we should still make this <= to be safe?
- existingData.version().compareTo(data.version()) < 0) {
- pending.put(data.key(), data);
- checkNotNull(delegate, "Store delegate is not set")
- .process(data);
- notifyDelegateIfNotNull(IntentEvent.getEvent(data));
- } else {
- log.debug("IntentData {} is older than existing: {}",
- data, existingData);
- }
- //TODO consider also checking the current map at this point
- }
- }
-
- @Override
- public boolean isMaster(Key intentKey) {
- return true;
- }
-}
diff --git a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleIntentStore.java b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleIntentStore.java
index 0eef07a..0a4fcb5 100644
--- a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleIntentStore.java
+++ b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleIntentStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Open Networking Laboratory
+ * Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,10 +35,9 @@
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.intent.IntentState.*;
import static org.slf4j.LoggerFactory.getLogger;
-//TODO Note: this store will be removed
-
@Component(immediate = true)
@Service
public class SimpleIntentStore
@@ -47,9 +46,21 @@
private final Logger log = getLogger(getClass());
- // current state maps FIXME.. make this a IntentData map
private final Map<Key, IntentData> current = Maps.newConcurrentMap();
- private final Map<Key, IntentData> pending = Maps.newConcurrentMap(); //String is "key"
+ private final Map<Key, IntentData> pending = Maps.newConcurrentMap();
+
+ private IntentData copyData(IntentData original) {
+ if (original == null) {
+ return null;
+ }
+ IntentData result =
+ new IntentData(original.intent(), original.state(), original.version());
+
+ if (original.installables() != null) {
+ result.setInstallables(original.installables());
+ }
+ return result;
+ }
@Activate
public void activate() {
@@ -82,22 +93,110 @@
@Override
public List<Intent> getInstallableIntents(Key intentKey) {
IntentData data = current.get(intentKey);
- return (data != null) ? data.installables() : null;
+ if (data != null) {
+ return data.installables();
+ }
+ return null;
+ }
+
+
+ /**
+ * Determines whether an intent data update is allowed. The update must
+ * either have a higher version than the current data, or the state
+ * transition between two updates of the same version must be sane.
+ *
+ * @param currentData existing intent data in the store
+ * @param newData new intent data update proposal
+ * @return true if we can apply the update, otherwise false
+ */
+ private boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
+
+ if (currentData == null) {
+ return true;
+ } else if (currentData.version().compareTo(newData.version()) < 0) {
+ return true;
+ } else if (currentData.version().compareTo(newData.version()) > 0) {
+ return false;
+ }
+
+ // current and new data versions are the same
+ IntentState currentState = currentData.state();
+ IntentState newState = newData.state();
+
+ switch (newState) {
+ case INSTALLING:
+ if (currentState == INSTALLING) {
+ return false;
+ }
+ // FALLTHROUGH
+ case INSTALLED:
+ if (currentState == INSTALLED) {
+ return false;
+ } else if (currentState == WITHDRAWING || currentState == WITHDRAWN) {
+ log.warn("Invalid state transition from {} to {} for intent {}",
+ currentState, newState, newData.key());
+ return false;
+ }
+ return true;
+
+ case WITHDRAWING:
+ if (currentState == WITHDRAWING) {
+ return false;
+ }
+ // FALLTHOUGH
+ case WITHDRAWN:
+ if (currentState == WITHDRAWN) {
+ return false;
+ } else if (currentState == INSTALLING || currentState == INSTALLED) {
+ log.warn("Invalid state transition from {} to {} for intent {}",
+ currentState, newState, newData.key());
+ return false;
+ }
+ return true;
+
+
+ case FAILED:
+ if (currentState == FAILED) {
+ return false;
+ }
+ return true;
+
+
+ case COMPILING:
+ case RECOMPILING:
+ case INSTALL_REQ:
+ case WITHDRAW_REQ:
+ default:
+ log.warn("Invalid state {} for intent {}", newState, newData.key());
+ return false;
+ }
}
@Override
public void write(IntentData newData) {
- //FIXME need to compare the versions
- current.put(newData.key(), newData);
- try {
- notifyDelegate(IntentEvent.getEvent(newData));
- } catch (IllegalArgumentException e) {
- //no-op
- log.trace("ignore this exception: {}", e);
+ synchronized (this) {
+ // TODO this could be refactored/cleaned up
+ IntentData currentData = current.get(newData.key());
+ IntentData pendingData = pending.get(newData.key());
+
+ if (isUpdateAcceptable(currentData, newData)) {
+ current.put(newData.key(), copyData(newData));
+
+ if (pendingData != null
+ // pendingData version is less than or equal to newData's
+ // Note: a new update for this key could be pending (it's version will be greater)
+ && pendingData.version().compareTo(newData.version()) <= 0) {
+ pending.remove(newData.key());
+ }
+
+ notifyDelegateIfNotNull(IntentEvent.getEvent(newData));
+ }
}
- IntentData old = pending.get(newData.key());
- if (old != null /* && FIXME version check */) {
- pending.remove(newData.key());
+ }
+
+ private void notifyDelegateIfNotNull(IntentEvent event) {
+ if (event != null) {
+ notifyDelegate(event);
}
}
@@ -114,14 +213,44 @@
return (data != null) ? data.intent() : null;
}
+ @Override
+ public IntentData getIntentData(Key key) {
+ return copyData(current.get(key));
+ }
@Override
public void addPending(IntentData data) {
- //FIXME need to compare versions
- pending.put(data.key(), data);
- checkNotNull(delegate, "Store delegate is not set")
- .process(data);
- notifyDelegate(IntentEvent.getEvent(data));
+ if (data.version() == null) { // recompiled intents will already have a version
+ data.setVersion(new SystemClockTimestamp());
+ }
+ synchronized (this) {
+ IntentData existingData = pending.get(data.key());
+ if (existingData == null ||
+ // existing version is strictly less than data's version
+ // Note: if they are equal, we already have the update
+ // TODO maybe we should still make this <= to be safe?
+ existingData.version().compareTo(data.version()) < 0) {
+ pending.put(data.key(), data);
+ checkNotNull(delegate, "Store delegate is not set")
+ .process(data);
+ notifyDelegateIfNotNull(IntentEvent.getEvent(data));
+ } else {
+ log.debug("IntentData {} is older than existing: {}",
+ data, existingData);
+ }
+ //TODO consider also checking the current map at this point
+ }
}
+ @Override
+ public boolean isMaster(Key intentKey) {
+ return true;
+ }
+
+ @Override
+ public Iterable<Intent> getPending() {
+ return pending.values().stream()
+ .map(IntentData::intent)
+ .collect(Collectors.toList());
+ }
}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/impl/SystemClockTimestamp.java b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SystemClockTimestamp.java
similarity index 97%
rename from core/store/dist/src/main/java/org/onosproject/store/impl/SystemClockTimestamp.java
rename to core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SystemClockTimestamp.java
index dc8817c..d79797e 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/impl/SystemClockTimestamp.java
+++ b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SystemClockTimestamp.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.onosproject.store.impl;
+package org.onosproject.store.trivial.impl;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ComparisonChain;