Brian O'Connor

Adding Leadership Listener to IntentBatchService

ObjectiveTracker uses Leadership Listener to track intents that
it has become the leader of.

Change-Id: I039accb30d27ad718d79a9fec3f546dbdc78e62e
...@@ -266,9 +266,8 @@ public class DemoInstaller implements DemoAPI { ...@@ -266,9 +266,8 @@ public class DemoInstaller implements DemoAPI {
266 } 266 }
267 count++; 267 count++;
268 if (count > ITERATIONMAX) { 268 if (count > ITERATIONMAX) {
269 - log.warn("A batch is stuck processing. current : {}" + 269 + log.warn("A batch is stuck processing. " +
270 - ", pending : {}", 270 + "pending : {}",
271 - intentBatchService.getCurrentOperations(),
272 intentBatchService.getPendingOperations()); 271 intentBatchService.getPendingOperations());
273 shutdownAndAwaitTermination(randomWorker); 272 shutdownAndAwaitTermination(randomWorker);
274 } 273 }
......
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onlab.onos.net.intent;
17 +
18 +import org.onlab.onos.core.ApplicationId;
19 +import org.onlab.onos.event.AbstractEvent;
20 +
21 +/**
22 + * A class to represent an intent related event.
23 + */
24 +public class IntentBatchLeaderEvent extends AbstractEvent<IntentBatchLeaderEvent.Type, ApplicationId> {
25 +
26 + public enum Type {
27 + /**
28 + * Signifies that this instance has become the leader for the given application id.
29 + */
30 + ELECTED,
31 +
32 + /**
33 + * Signifies that instance is no longer the leader for a given application id.
34 + */
35 + BOOTED
36 + }
37 +
38 + /**
39 + * Creates an event of a given type and for the specified appId and the
40 + * current time.
41 + *
42 + * @param type event type
43 + * @param appId subject appId
44 + * @param time time the event created in milliseconds since start of epoch
45 + */
46 + public IntentBatchLeaderEvent(Type type, ApplicationId appId, long time) {
47 + super(type, appId, time);
48 + }
49 +
50 + /**
51 + * Creates an event of a given type and for the specified appId and the
52 + * current time.
53 + *
54 + * @param type event type
55 + * @param appId subject appId
56 + */
57 + public IntentBatchLeaderEvent(Type type, ApplicationId appId) {
58 + super(type, appId);
59 + }
60 +
61 +}
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onlab.onos.net.intent;
17 +
18 +import org.onlab.onos.event.EventListener;
19 +
20 +/**
21 + * Listener for {@link org.onlab.onos.net.intent.IntentEvent intent events}.
22 + */
23 +public interface IntentBatchListener extends EventListener<IntentBatchLeaderEvent> {
24 +}
...@@ -45,14 +45,6 @@ public interface IntentBatchService { ...@@ -45,14 +45,6 @@ public interface IntentBatchService {
45 Set<IntentOperations> getPendingOperations(); 45 Set<IntentOperations> getPendingOperations();
46 46
47 /** 47 /**
48 - * Returns the set of intent batches currently being processed.
49 - * @return set of batches
50 - */
51 - //TODO we may want to get rid of this method
52 - @Deprecated
53 - Set<IntentOperations> getCurrentOperations();
54 -
55 - /**
56 * Return true if this instance is the local leader for batch 48 * Return true if this instance is the local leader for batch
57 * processing a given application id. 49 * processing a given application id.
58 * 50 *
...@@ -75,4 +67,17 @@ public interface IntentBatchService { ...@@ -75,4 +67,17 @@ public interface IntentBatchService {
75 */ 67 */
76 void unsetDelegate(IntentBatchDelegate delegate); 68 void unsetDelegate(IntentBatchDelegate delegate);
77 69
70 + /**
71 + * Adds the specified listener for intent batch leadership events.
72 + *
73 + * @param listener listener to be added
74 + */
75 + void addListener(IntentBatchListener listener);
76 +
77 + /**
78 + * Removes the specified listener for intent batch leadership events.
79 + *
80 + * @param listener listener to be removed
81 + */
82 + void removeListener(IntentBatchListener listener);
78 } 83 }
......
...@@ -15,22 +15,25 @@ ...@@ -15,22 +15,25 @@
15 */ 15 */
16 package org.onlab.onos.net.intent.impl; 16 package org.onlab.onos.net.intent.impl;
17 17
18 -import java.util.Collection; 18 +import com.google.common.collect.HashMultimap;
19 -import java.util.HashSet; 19 +import com.google.common.collect.Lists;
20 -import java.util.Set; 20 +import com.google.common.collect.SetMultimap;
21 -import java.util.concurrent.ExecutorService;
22 -
23 import org.apache.felix.scr.annotations.Activate; 21 import org.apache.felix.scr.annotations.Activate;
24 import org.apache.felix.scr.annotations.Component; 22 import org.apache.felix.scr.annotations.Component;
25 import org.apache.felix.scr.annotations.Deactivate; 23 import org.apache.felix.scr.annotations.Deactivate;
26 import org.apache.felix.scr.annotations.Reference; 24 import org.apache.felix.scr.annotations.Reference;
27 import org.apache.felix.scr.annotations.ReferenceCardinality; 25 import org.apache.felix.scr.annotations.ReferenceCardinality;
28 import org.apache.felix.scr.annotations.Service; 26 import org.apache.felix.scr.annotations.Service;
27 +import org.onlab.onos.core.ApplicationId;
29 import org.onlab.onos.event.Event; 28 import org.onlab.onos.event.Event;
30 import org.onlab.onos.net.Link; 29 import org.onlab.onos.net.Link;
31 import org.onlab.onos.net.LinkKey; 30 import org.onlab.onos.net.LinkKey;
32 import org.onlab.onos.net.NetworkResource; 31 import org.onlab.onos.net.NetworkResource;
32 +import org.onlab.onos.net.intent.IntentBatchLeaderEvent;
33 +import org.onlab.onos.net.intent.IntentBatchListener;
34 +import org.onlab.onos.net.intent.IntentBatchService;
33 import org.onlab.onos.net.intent.IntentId; 35 import org.onlab.onos.net.intent.IntentId;
36 +import org.onlab.onos.net.intent.IntentService;
34 import org.onlab.onos.net.link.LinkEvent; 37 import org.onlab.onos.net.link.LinkEvent;
35 import org.onlab.onos.net.resource.LinkResourceEvent; 38 import org.onlab.onos.net.resource.LinkResourceEvent;
36 import org.onlab.onos.net.resource.LinkResourceListener; 39 import org.onlab.onos.net.resource.LinkResourceListener;
...@@ -40,8 +43,10 @@ import org.onlab.onos.net.topology.TopologyListener; ...@@ -40,8 +43,10 @@ import org.onlab.onos.net.topology.TopologyListener;
40 import org.onlab.onos.net.topology.TopologyService; 43 import org.onlab.onos.net.topology.TopologyService;
41 import org.slf4j.Logger; 44 import org.slf4j.Logger;
42 45
43 -import com.google.common.collect.HashMultimap; 46 +import java.util.Collection;
44 -import com.google.common.collect.SetMultimap; 47 +import java.util.HashSet;
48 +import java.util.Set;
49 +import java.util.concurrent.ExecutorService;
45 50
46 import static com.google.common.base.Preconditions.checkArgument; 51 import static com.google.common.base.Preconditions.checkArgument;
47 import static com.google.common.base.Preconditions.checkNotNull; 52 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -72,18 +77,26 @@ public class ObjectiveTracker implements ObjectiveTrackerService { ...@@ -72,18 +77,26 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected LinkResourceService resourceManager; 78 protected LinkResourceService resourceManager;
74 79
80 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 + protected IntentService intentService;
82 +
83 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 + protected IntentBatchService batchService;
85 +
75 private ExecutorService executorService = 86 private ExecutorService executorService =
76 newSingleThreadExecutor(namedThreads("onos-flowtracker")); 87 newSingleThreadExecutor(namedThreads("onos-flowtracker"));
77 88
78 private TopologyListener listener = new InternalTopologyListener(); 89 private TopologyListener listener = new InternalTopologyListener();
79 private LinkResourceListener linkResourceListener = 90 private LinkResourceListener linkResourceListener =
80 new InternalLinkResourceListener(); 91 new InternalLinkResourceListener();
92 + private final LeadershipListener leaderListener = new LeadershipListener();
81 private TopologyChangeDelegate delegate; 93 private TopologyChangeDelegate delegate;
82 94
83 @Activate 95 @Activate
84 public void activate() { 96 public void activate() {
85 topologyService.addListener(listener); 97 topologyService.addListener(listener);
86 resourceManager.addListener(linkResourceListener); 98 resourceManager.addListener(linkResourceListener);
99 + batchService.addListener(leaderListener);
87 log.info("Started"); 100 log.info("Started");
88 } 101 }
89 102
...@@ -91,6 +104,7 @@ public class ObjectiveTracker implements ObjectiveTrackerService { ...@@ -91,6 +104,7 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
91 public void deactivate() { 104 public void deactivate() {
92 topologyService.removeListener(listener); 105 topologyService.removeListener(listener);
93 resourceManager.removeListener(linkResourceListener); 106 resourceManager.removeListener(linkResourceListener);
107 + batchService.removeListener(leaderListener);
94 log.info("Stopped"); 108 log.info("Stopped");
95 } 109 }
96 110
...@@ -220,6 +234,38 @@ public class ObjectiveTracker implements ObjectiveTrackerService { ...@@ -220,6 +234,38 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
220 234
221 //TODO consider adding flow rule event tracking 235 //TODO consider adding flow rule event tracking
222 236
223 - //FIXME the only intents that will be tracked are events that were 237 + private void updateTrackedResources(ApplicationId appId, boolean track) {
224 - //executed on this instance. Need to have some backup trackers... 238 + intentService.getIntents().forEach(intent -> {
239 + if (intent.appId().equals(appId)) {
240 + IntentId id = intent.id();
241 + Collection<NetworkResource> resources = Lists.newArrayList();
242 + intentService.getInstallableIntents(id).stream()
243 + .map(installable -> installable.resources())
244 + .forEach(resources::addAll);
245 + if (track) {
246 + addTrackedResources(id, resources);
247 + } else {
248 + removeTrackedResources(id, resources);
249 + }
250 + }
251 + });
252 + }
253 +
254 + private class LeadershipListener implements IntentBatchListener {
255 + @Override
256 + public void event(IntentBatchLeaderEvent event) {
257 + log.debug("leadership event: {}", event);
258 + ApplicationId appId = event.subject();
259 + switch (event.type()) {
260 + case ELECTED:
261 + updateTrackedResources(appId, true);
262 + break;
263 + case BOOTED:
264 + updateTrackedResources(appId, false);
265 + break;
266 + default:
267 + break;
268 + }
269 + }
270 + }
225 } 271 }
......
...@@ -111,16 +111,13 @@ public class IntentManagerTest { ...@@ -111,16 +111,13 @@ public class IntentManagerTest {
111 //the batch has not yet been removed when we receive the last event 111 //the batch has not yet been removed when we receive the last event
112 // FIXME: this doesn't guarantee to avoid the race 112 // FIXME: this doesn't guarantee to avoid the race
113 for (int tries = 0; tries < 10; tries++) { 113 for (int tries = 0; tries < 10; tries++) {
114 - if (manager.batchService.getPendingOperations().isEmpty() && 114 + if (manager.batchService.getPendingOperations().isEmpty()) {
115 - manager.batchService.getCurrentOperations().isEmpty()) {
116 break; 115 break;
117 } 116 }
118 delay(10); 117 delay(10);
119 } 118 }
120 assertTrue("There are still pending batch operations.", 119 assertTrue("There are still pending batch operations.",
121 manager.batchService.getPendingOperations().isEmpty()); 120 manager.batchService.getPendingOperations().isEmpty());
122 - assertTrue("There are still outstanding batch operations.",
123 - manager.batchService.getCurrentOperations().isEmpty());
124 121
125 extensionService.unregisterCompiler(MockIntent.class); 122 extensionService.unregisterCompiler(MockIntent.class);
126 extensionService.unregisterInstaller(MockInstallableIntent.class); 123 extensionService.unregisterInstaller(MockInstallableIntent.class);
......
...@@ -35,7 +35,11 @@ import org.onlab.onos.cluster.LeadershipEventListener; ...@@ -35,7 +35,11 @@ import org.onlab.onos.cluster.LeadershipEventListener;
35 import org.onlab.onos.cluster.LeadershipService; 35 import org.onlab.onos.cluster.LeadershipService;
36 import org.onlab.onos.core.ApplicationId; 36 import org.onlab.onos.core.ApplicationId;
37 import org.onlab.onos.core.CoreService; 37 import org.onlab.onos.core.CoreService;
38 +import org.onlab.onos.event.AbstractListenerRegistry;
39 +import org.onlab.onos.event.EventDeliveryService;
38 import org.onlab.onos.net.intent.IntentBatchDelegate; 40 import org.onlab.onos.net.intent.IntentBatchDelegate;
41 +import org.onlab.onos.net.intent.IntentBatchLeaderEvent;
42 +import org.onlab.onos.net.intent.IntentBatchListener;
39 import org.onlab.onos.net.intent.IntentBatchService; 43 import org.onlab.onos.net.intent.IntentBatchService;
40 import org.onlab.onos.net.intent.IntentOperations; 44 import org.onlab.onos.net.intent.IntentOperations;
41 import org.onlab.onos.store.hz.SQueue; 45 import org.onlab.onos.store.hz.SQueue;
...@@ -46,7 +50,6 @@ import org.onlab.onos.store.serializers.StoreSerializer; ...@@ -46,7 +50,6 @@ import org.onlab.onos.store.serializers.StoreSerializer;
46 import org.onlab.util.KryoNamespace; 50 import org.onlab.util.KryoNamespace;
47 import org.slf4j.Logger; 51 import org.slf4j.Logger;
48 52
49 -import java.util.Collections;
50 import java.util.Map; 53 import java.util.Map;
51 import java.util.Set; 54 import java.util.Set;
52 55
...@@ -74,6 +77,10 @@ public class HazelcastIntentBatchQueue ...@@ -74,6 +77,10 @@ public class HazelcastIntentBatchQueue
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected StoreService storeService; 78 protected StoreService storeService;
76 79
80 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 + protected EventDeliveryService eventDispatcher;
82 +
83 +
77 private HazelcastInstance theInstance; 84 private HazelcastInstance theInstance;
78 private ControllerNode localControllerNode; 85 private ControllerNode localControllerNode;
79 protected StoreSerializer serializer; 86 protected StoreSerializer serializer;
...@@ -85,6 +92,9 @@ public class HazelcastIntentBatchQueue ...@@ -85,6 +92,9 @@ public class HazelcastIntentBatchQueue
85 private final Map<ApplicationId, IntentOperations> outstandingOps 92 private final Map<ApplicationId, IntentOperations> outstandingOps
86 = Maps.newHashMap(); 93 = Maps.newHashMap();
87 94
95 + private final AbstractListenerRegistry<IntentBatchLeaderEvent, IntentBatchListener>
96 + listenerRegistry = new AbstractListenerRegistry<>();
97 +
88 @Activate 98 @Activate
89 public void activate() { 99 public void activate() {
90 theInstance = storeService.getHazelcastInstance(); 100 theInstance = storeService.getHazelcastInstance();
...@@ -103,11 +113,13 @@ public class HazelcastIntentBatchQueue ...@@ -103,11 +113,13 @@ public class HazelcastIntentBatchQueue
103 } 113 }
104 114
105 }; 115 };
116 + eventDispatcher.addSink(IntentBatchLeaderEvent.class, listenerRegistry);
106 log.info("Started"); 117 log.info("Started");
107 } 118 }
108 119
109 @Deactivate 120 @Deactivate
110 public void deactivate() { 121 public void deactivate() {
122 + eventDispatcher.removeSink(IntentBatchLeaderEvent.class);
111 leadershipService.removeListener(leaderListener); 123 leadershipService.removeListener(leaderListener);
112 for (ApplicationId appId: batchQueues.keySet()) { 124 for (ApplicationId appId: batchQueues.keySet()) {
113 leadershipService.withdraw(getTopic(appId)); 125 leadershipService.withdraw(getTopic(appId));
...@@ -277,12 +289,6 @@ public class HazelcastIntentBatchQueue ...@@ -277,12 +289,6 @@ public class HazelcastIntentBatchQueue
277 } 289 }
278 290
279 @Override 291 @Override
280 - public Set<IntentOperations> getCurrentOperations() {
281 - //FIXME this is not really implemented
282 - return Collections.emptySet();
283 - }
284 -
285 - @Override
286 public boolean isLocalLeader(ApplicationId applicationId) { 292 public boolean isLocalLeader(ApplicationId applicationId) {
287 return myTopics.contains(applicationId); 293 return myTopics.contains(applicationId);
288 } 294 }
...@@ -298,4 +304,14 @@ public class HazelcastIntentBatchQueue ...@@ -298,4 +304,14 @@ public class HazelcastIntentBatchQueue
298 this.delegate = null; 304 this.delegate = null;
299 } 305 }
300 } 306 }
307 +
308 + @Override
309 + public void addListener(IntentBatchListener listener) {
310 + listenerRegistry.addListener(listener);
311 + }
312 +
313 + @Override
314 + public void removeListener(IntentBatchListener listener) {
315 + listenerRegistry.removeListener(listener);
316 + }
301 } 317 }
......
...@@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Deactivate;
22 import org.apache.felix.scr.annotations.Service; 22 import org.apache.felix.scr.annotations.Service;
23 import org.onlab.onos.core.ApplicationId; 23 import org.onlab.onos.core.ApplicationId;
24 import org.onlab.onos.net.intent.IntentBatchDelegate; 24 import org.onlab.onos.net.intent.IntentBatchDelegate;
25 +import org.onlab.onos.net.intent.IntentBatchListener;
25 import org.onlab.onos.net.intent.IntentBatchService; 26 import org.onlab.onos.net.intent.IntentBatchService;
26 import org.onlab.onos.net.intent.IntentOperations; 27 import org.onlab.onos.net.intent.IntentOperations;
27 import org.slf4j.Logger; 28 import org.slf4j.Logger;
...@@ -83,14 +84,9 @@ public class SimpleIntentBatchQueue implements IntentBatchService { ...@@ -83,14 +84,9 @@ public class SimpleIntentBatchQueue implements IntentBatchService {
83 @Override 84 @Override
84 public Set<IntentOperations> getPendingOperations() { 85 public Set<IntentOperations> getPendingOperations() {
85 synchronized (this) { 86 synchronized (this) {
86 - return Sets.newHashSet(pendingBatches); 87 + Set<IntentOperations> set = Sets.newHashSet(pendingBatches);
87 - } 88 + set.addAll(currentBatches); // TODO refactor this current vs. pending
88 - } 89 + return set;
89 -
90 - @Override
91 - public Set<IntentOperations> getCurrentOperations() {
92 - synchronized (this) {
93 - return Sets.newHashSet(currentBatches);
94 } 90 }
95 } 91 }
96 92
...@@ -110,4 +106,16 @@ public class SimpleIntentBatchQueue implements IntentBatchService { ...@@ -110,4 +106,16 @@ public class SimpleIntentBatchQueue implements IntentBatchService {
110 this.delegate = null; 106 this.delegate = null;
111 } 107 }
112 } 108 }
109 +
110 + @Override
111 + public void addListener(IntentBatchListener listener) {
112 + // no-op
113 + //TODO: we are always the master
114 + }
115 +
116 + @Override
117 + public void removeListener(IntentBatchListener listener) {
118 + // no-op
119 + //TODO: we are always the master
120 + }
113 } 121 }
......