Ray Milkey
Committed by Gerrit Code Review

ONOS-239 Retrigger compilation when new resources are available

When an intent is withdrawn and frees up resources, trigger
recompilation of any failed intents to allow the ones waiting
for resources to be installed.

Change-Id: Ic15678378ce41516a7eab890b4b4898aeb901f78
/*
* 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.onlab.onos.net.resource;
import java.util.Collection;
import org.onlab.onos.event.AbstractEvent;
import com.google.common.collect.ImmutableList;
/**
* Describes an event related to a Link Resource.
*/
public final class LinkResourceEvent
extends AbstractEvent<LinkResourceEvent.Type, Collection<LinkResourceAllocations>> {
/**
* Type of resource this event is for.
*/
public enum Type {
/** Additional resources are now available. */
ADDITIONAL_RESOURCES_AVAILABLE
}
/**
* Constructs a link resource event.
*
* @param type type of resource event to create
* @param linkResourceAllocations allocations that are now available
*/
public LinkResourceEvent(Type type,
Collection<LinkResourceAllocations> linkResourceAllocations) {
super(type, ImmutableList.copyOf(linkResourceAllocations));
}
}
/*
* 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.onlab.onos.net.resource;
import org.onlab.onos.event.EventListener;
/**
* Entity for receiving link resource events.
*/
public interface LinkResourceListener extends EventListener<LinkResourceEvent> {
}
......@@ -89,4 +89,18 @@ public interface LinkResourceService {
Iterable<ResourceRequest> getAvailableResources(Link link,
LinkResourceAllocations allocations);
/**
* Adds a listener for resource related events.
*
* @param listener listener to add
*/
void addListener(LinkResourceListener listener);
/**
* Removes a listener for resource related events.
*
* @param listener listener to remove.
*/
void removeListener(LinkResourceListener listener);
}
......
......@@ -44,7 +44,7 @@ public interface LinkResourceStore {
*
* @param allocations resources to be released
*/
void releaseResources(LinkResourceAllocations allocations);
LinkResourceEvent releaseResources(LinkResourceAllocations allocations);
/**
* Returns resources allocated for an Intent.
......
/*
* 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.onlab.onos.net.resource;
import org.onlab.onos.store.StoreDelegate;
/**
* Link resource store delegate abstraction.
*/
public interface LinkResourceStoreDelegate extends StoreDelegate<LinkResourceEvent> {
}
......@@ -43,6 +43,7 @@ import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.resource.BandwidthResourceRequest;
import org.onlab.onos.net.resource.LambdaResourceRequest;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceListener;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.ResourceAllocation;
......@@ -273,6 +274,16 @@ public class IntentTestsMocks {
public Iterable<ResourceRequest> getAvailableResources(Link link, LinkResourceAllocations allocations) {
return null;
}
@Override
public void addListener(LinkResourceListener listener) {
}
@Override
public void removeListener(LinkResourceListener listener) {
}
}
private static final IntentTestsMocks.MockSelector SELECTOR =
......
......@@ -15,10 +15,18 @@
*/
package org.onlab.onos.net.intent.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -50,22 +58,20 @@ import org.onlab.onos.net.intent.IntentStore;
import org.onlab.onos.net.intent.IntentStoreDelegate;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.onos.net.intent.IntentState.*;
import static org.onlab.onos.net.intent.IntentState.COMPILING;
import static org.onlab.onos.net.intent.IntentState.FAILED;
import static org.onlab.onos.net.intent.IntentState.INSTALLED;
import static org.onlab.onos.net.intent.IntentState.INSTALLING;
import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -159,8 +165,8 @@ public class IntentManager
checkNotNull(oldIntentId, INTENT_ID_NULL);
checkNotNull(newIntent, INTENT_NULL);
execute(IntentOperations.builder()
.addReplaceOperation(oldIntentId, newIntent)
.build());
.addReplaceOperation(oldIntentId, newIntent)
.build());
}
@Override
......@@ -681,7 +687,7 @@ public class IntentManager
// TODO: clean this up, or set to debug
IntentState oldState = stateMap.get(intent);
log.debug("intent id: {}, old state: {}, new state: {}",
intent.id(), oldState, newState);
intent.id(), oldState, newState);
stateMap.put(intent, newState);
IntentEvent event = store.setState(intent, newState);
......@@ -845,4 +851,5 @@ public class IntentManager
log.warn("NOT IMPLEMENTED -- Cancel operations: {}", operations);
}
}
}
......
......@@ -15,8 +15,11 @@
*/
package org.onlab.onos.net.intent.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -29,15 +32,16 @@ import org.onlab.onos.net.LinkKey;
import org.onlab.onos.net.NetworkResource;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.link.LinkEvent;
import org.onlab.onos.net.resource.LinkResourceEvent;
import org.onlab.onos.net.resource.LinkResourceListener;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.topology.TopologyEvent;
import org.onlab.onos.net.topology.TopologyListener;
import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -53,7 +57,7 @@ import static org.slf4j.LoggerFactory.getLogger;
* Entity responsible for tracking installed flows and for monitoring topology
* events to determine what flows are affected by topology changes.
*/
@Component
@Component(immediate = true)
@Service
public class ObjectiveTracker implements ObjectiveTrackerService {
......@@ -65,21 +69,28 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceManager;
private ExecutorService executorService =
newSingleThreadExecutor(namedThreads("onos-flowtracker"));
private TopologyListener listener = new InternalTopologyListener();
private LinkResourceListener linkResourceListener =
new InternalLinkResourceListener();
private TopologyChangeDelegate delegate;
@Activate
public void activate() {
topologyService.addListener(listener);
resourceManager.addListener(linkResourceListener);
log.info("Started");
}
@Deactivate
public void deactivate() {
topologyService.removeListener(listener);
resourceManager.removeListener(linkResourceListener);
log.info("Stopped");
}
......@@ -173,4 +184,37 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
}
}
/**
* Internal re-actor to resource available events.
*/
private class InternalLinkResourceListener implements LinkResourceListener {
@Override
public void event(LinkResourceEvent event) {
executorService.execute(new ResourceAvailableHandler(event));
}
}
/*
* Re-dispatcher of resource available events.
*/
private class ResourceAvailableHandler implements Runnable {
private final LinkResourceEvent event;
ResourceAvailableHandler(LinkResourceEvent event) {
this.event = event;
}
@Override
public void run() {
// If there is no delegate, why bother? Just bail.
if (delegate == null) {
return;
}
delegate.triggerCompile(new HashSet<>(), true);
}
}
}
......
......@@ -32,6 +32,8 @@ 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.onos.event.AbstractListenerRegistry;
import org.onlab.onos.event.EventDeliveryService;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.resource.BandwidthResourceAllocation;
......@@ -41,9 +43,12 @@ import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LambdaResourceRequest;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceEvent;
import org.onlab.onos.net.resource.LinkResourceListener;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.net.resource.LinkResourceService;
import org.onlab.onos.net.resource.LinkResourceStore;
import org.onlab.onos.net.resource.LinkResourceStoreDelegate;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceRequest;
import org.onlab.onos.net.resource.ResourceType;
......@@ -58,11 +63,18 @@ public class LinkResourceManager implements LinkResourceService {
private final Logger log = getLogger(getClass());
protected final AbstractListenerRegistry<LinkResourceEvent, LinkResourceListener>
listenerRegistry = new AbstractListenerRegistry<>();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private LinkResourceStore store;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected EventDeliveryService eventDispatcher;
@Activate
public void activate() {
eventDispatcher.addSink(LinkResourceEvent.class, listenerRegistry);
log.info("Started");
}
......@@ -150,7 +162,10 @@ public class LinkResourceManager implements LinkResourceService {
@Override
public void releaseResources(LinkResourceAllocations allocations) {
store.releaseResources(allocations);
final LinkResourceEvent event = store.releaseResources(allocations);
if (event != null) {
post(event);
}
}
@Override
......@@ -205,4 +220,32 @@ public class LinkResourceManager implements LinkResourceService {
return result;
}
@Override
public void addListener(LinkResourceListener listener) {
listenerRegistry.addListener(listener);
}
@Override
public void removeListener(LinkResourceListener listener) {
listenerRegistry.removeListener(listener);
}
/**
* Posts the specified event to the local event dispatcher.
*/
private void post(LinkResourceEvent event) {
if (event != null) {
eventDispatcher.post(event);
}
}
/**
* Store delegate to re-post events emitted from the store.
*/
private class InternalStoreDelegate implements LinkResourceStoreDelegate {
@Override
public void notify(LinkResourceEvent event) {
post(event);
}
}
}
......
......@@ -15,6 +15,14 @@
*/
package org.onlab.onos.store.resource.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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;
......@@ -30,6 +38,7 @@ import org.onlab.onos.net.resource.BandwidthResourceAllocation;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceEvent;
import org.onlab.onos.net.resource.LinkResourceStore;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
......@@ -48,17 +57,10 @@ import org.slf4j.Logger;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
......@@ -98,7 +100,7 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
// Link annotation key name to use as bandwidth
private String bandwidthAnnotation = "bandwidth";
// Link annotation key name to use as max lamda
// Link annotation key name to use as max lambda
private String wavesAnnotation = "optical.waves";
private StoreSerializer serializer;
......@@ -423,7 +425,7 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
}
@Override
public void releaseResources(LinkResourceAllocations allocations) {
public LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
final IntentId intendId = allocations.intendId();
......@@ -458,6 +460,14 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
BatchWriteResult batchWrite = databaseService.batchWrite(tx.build());
success = batchWrite.isSuccessful();
} while (!success);
// Issue events to force recompilation of intents.
final List<LinkResourceAllocations> releasedResources =
ImmutableList.of(allocations);
return new LinkResourceEvent(
LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
releasedResources);
}
@Override
......@@ -565,5 +575,4 @@ public class DistributedLinkResourceStore implements LinkResourceStore {
})
.filter(notNull());
}
}
......
......@@ -15,13 +15,10 @@
*/
package org.onlab.onos.store.trivial.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -38,11 +35,18 @@ import org.onlab.onos.net.resource.BandwidthResourceAllocation;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceEvent;
import org.onlab.onos.net.resource.LinkResourceStore;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
import org.slf4j.Logger;
import com.google.common.collect.ImmutableList;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Manages link resources using trivial in-memory structures implementation.
*/
......@@ -51,6 +55,7 @@ import org.slf4j.Logger;
public class SimpleLinkResourceStore implements LinkResourceStore {
private static final int DEFAULT_BANDWIDTH = 1_000;
private final Logger log = getLogger(getClass());
private Map<IntentId, LinkResourceAllocations> linkResourceAllocationsMap;
private Map<Link, Set<LinkResourceAllocations>> allocatedResources;
private Map<Link, Set<ResourceAllocation>> freeResources;
......@@ -213,7 +218,7 @@ public class SimpleLinkResourceStore implements LinkResourceStore {
}
@Override
public synchronized void releaseResources(LinkResourceAllocations allocations) {
public synchronized LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
linkResourceAllocationsMap.remove(allocations.intendId());
for (Link link : allocations.links()) {
......@@ -226,6 +231,13 @@ public class SimpleLinkResourceStore implements LinkResourceStore {
}
allocatedResources.put(link, linkAllocs);
}
final List<LinkResourceAllocations> releasedResources =
ImmutableList.of(allocations);
return new LinkResourceEvent(
LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
releasedResources);
}
@Override
......@@ -249,4 +261,5 @@ public class SimpleLinkResourceStore implements LinkResourceStore {
return Collections.unmodifiableCollection(linkResourceAllocationsMap.values());
}
}
......
......@@ -15,13 +15,6 @@
*/
package org.onlab.onos.store.trivial.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.Link.Type.DIRECT;
import static org.onlab.onos.net.PortNumber.portNumber;
import java.util.HashSet;
import java.util.Set;
......@@ -43,6 +36,13 @@ import org.onlab.onos.net.resource.LinkResourceStore;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.Link.Type.DIRECT;
import static org.onlab.onos.net.PortNumber.portNumber;
/**
* Test of the simple LinkResourceStore implementation.
*/
......