Ray Milkey
Committed by Brian O'Connor

Start IntentOperations removal

Change-Id: Ib5fb9c19b37e447a62c61fa33bb98f3d789cbefa
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.onosproject.net.intent;
17 -
18 -import java.util.List;
19 -
20 -import org.junit.After;
21 -import org.junit.Before;
22 -import org.junit.Test;
23 -import org.onosproject.core.ApplicationId;
24 -import org.onosproject.core.DefaultApplicationId;
25 -import org.onosproject.core.IdGenerator;
26 -import org.onosproject.net.ConnectPoint;
27 -import org.onosproject.net.NetTestTools;
28 -import org.onosproject.net.flow.TrafficSelector;
29 -
30 -import com.google.common.testing.EqualsTester;
31 -
32 -import static org.hamcrest.MatcherAssert.assertThat;
33 -import static org.hamcrest.Matchers.hasSize;
34 -import static org.hamcrest.Matchers.is;
35 -import static org.hamcrest.Matchers.isOneOf;
36 -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
37 -
38 -/**
39 - * Tests for the IntentOperations class.
40 - */
41 -public class IntentOperationsTest {
42 -
43 - final ConnectPoint egress = NetTestTools.connectPoint("egress", 3);
44 - final ConnectPoint ingress = NetTestTools.connectPoint("ingress", 3);
45 - final TrafficSelector selector = new IntentTestsMocks.MockSelector();
46 - final IntentTestsMocks.MockTreatment treatment = new IntentTestsMocks.MockTreatment();
47 -
48 - private final ApplicationId appId = new DefaultApplicationId(1, "IntentOperationsTest");
49 -
50 - private Intent intent;
51 - protected IdGenerator idGenerator = new MockIdGenerator();
52 -
53 - @Before
54 - public void setUp() {
55 - Intent.bindIdGenerator(idGenerator);
56 -
57 - intent = new PointToPointIntent(NetTestTools.APP_ID,
58 - selector,
59 - treatment,
60 - ingress,
61 - egress);
62 - }
63 -
64 - @After
65 - public void tearDown() {
66 - Intent.unbindIdGenerator(idGenerator);
67 - }
68 -
69 - /**
70 - * Checks that the IntentOperation and IntentOperations classes are immutable.
71 - */
72 - @Test
73 - public void testImmutability() {
74 - assertThatClassIsImmutable(IntentOperations.class);
75 - assertThatClassIsImmutable(IntentOperations.Builder.class);
76 - assertThatClassIsImmutable(IntentOperation.class);
77 - }
78 -
79 - /**
80 - * Tests equals(), hashCode() and toString() methods.
81 - */
82 - @Test
83 - public void testEquals() {
84 - final IntentOperations operations1 =
85 - IntentOperations.builder(appId)
86 - .addSubmitOperation(intent)
87 - .build();
88 - final IntentOperations sameAsOperations1 =
89 - IntentOperations.builder(appId)
90 - .addSubmitOperation(intent)
91 - .build();
92 - final IntentOperations operations2 =
93 - IntentOperations.builder(appId)
94 - .addReplaceOperation(intent.id(), intent)
95 - .build();
96 -
97 - new EqualsTester()
98 - .addEqualityGroup(operations1, sameAsOperations1)
99 - .addEqualityGroup(operations2)
100 - .testEquals();
101 - }
102 -
103 - /**
104 - * Checks that objects are created correctly.
105 - */
106 - @Test
107 - public void testConstruction() {
108 - final IntentOperations operations =
109 - IntentOperations.builder(appId)
110 - .addUpdateOperation(intent.id())
111 - .addWithdrawOperation(intent.id())
112 - .build();
113 - final List<IntentOperation> operationList = operations.operations();
114 - assertThat(operationList, hasSize(2));
115 - for (final IntentOperation operation : operationList) {
116 - assertThat(operation.type(),
117 - isOneOf(IntentOperation.Type.UPDATE,
118 - IntentOperation.Type.WITHDRAW));
119 - assertThat(operation.intent(), is((Intent) null));
120 - assertThat(operation.intentId(), is(intent.id()));
121 - }
122 - }
123 -}
...@@ -50,7 +50,6 @@ import org.onosproject.net.intent.IntentService; ...@@ -50,7 +50,6 @@ import org.onosproject.net.intent.IntentService;
50 import org.onosproject.net.intent.IntentState; 50 import org.onosproject.net.intent.IntentState;
51 import org.onosproject.net.intent.IntentTestsMocks; 51 import org.onosproject.net.intent.IntentTestsMocks;
52 import org.onosproject.net.resource.LinkResourceAllocations; 52 import org.onosproject.net.resource.LinkResourceAllocations;
53 -import org.onosproject.store.trivial.impl.SimpleIntentBatchQueue;
54 import org.onosproject.store.trivial.impl.SimpleIntentStore; 53 import org.onosproject.store.trivial.impl.SimpleIntentStore;
55 54
56 import com.google.common.collect.HashMultimap; 55 import com.google.common.collect.HashMultimap;
...@@ -278,7 +277,6 @@ public class IntentManagerTest { ...@@ -278,7 +277,6 @@ public class IntentManagerTest {
278 manager = new IntentManager(); 277 manager = new IntentManager();
279 flowRuleService = new MockFlowRuleService(); 278 flowRuleService = new MockFlowRuleService();
280 manager.store = new SimpleIntentStore(); 279 manager.store = new SimpleIntentStore();
281 - manager.batchService = new SimpleIntentBatchQueue();
282 manager.eventDispatcher = new TestEventDispatcher(); 280 manager.eventDispatcher = new TestEventDispatcher();
283 manager.trackerService = new TestIntentTracker(); 281 manager.trackerService = new TestIntentTracker();
284 manager.flowRuleService = flowRuleService; 282 manager.flowRuleService = flowRuleService;
......
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.onosproject.store.intent.impl;
17 -
18 -import static com.google.common.base.Preconditions.checkNotNull;
19 -import static com.google.common.base.Preconditions.checkState;
20 -import static org.slf4j.LoggerFactory.getLogger;
21 -
22 -import java.util.Map;
23 -import java.util.Objects;
24 -import java.util.Set;
25 -
26 -import org.apache.felix.scr.annotations.Activate;
27 -import org.apache.felix.scr.annotations.Component;
28 -import org.apache.felix.scr.annotations.Deactivate;
29 -import org.apache.felix.scr.annotations.Reference;
30 -import org.apache.felix.scr.annotations.ReferenceCardinality;
31 -import org.apache.felix.scr.annotations.Service;
32 -import org.onosproject.cluster.ClusterService;
33 -import org.onosproject.cluster.LeadershipEvent;
34 -import org.onosproject.cluster.LeadershipEventListener;
35 -import org.onosproject.cluster.LeadershipService;
36 -import org.onosproject.cluster.NodeId;
37 -import org.onosproject.core.ApplicationId;
38 -import org.onosproject.core.CoreService;
39 -import org.onosproject.event.AbstractListenerRegistry;
40 -import org.onosproject.event.EventDeliveryService;
41 -import org.onosproject.net.intent.IntentBatchDelegate;
42 -import org.onosproject.net.intent.IntentBatchLeaderEvent;
43 -import org.onosproject.net.intent.IntentBatchListener;
44 -import org.onosproject.net.intent.IntentBatchService;
45 -import org.onosproject.net.intent.IntentOperations;
46 -import org.onosproject.store.hz.SQueue;
47 -import org.onosproject.store.hz.StoreService;
48 -import org.onosproject.store.serializers.KryoNamespaces;
49 -import org.onosproject.store.serializers.KryoSerializer;
50 -import org.onosproject.store.serializers.StoreSerializer;
51 -import org.onlab.util.KryoNamespace;
52 -import org.slf4j.Logger;
53 -
54 -import com.google.common.collect.Maps;
55 -import com.google.common.collect.Sets;
56 -import com.hazelcast.core.HazelcastInstance;
57 -import com.hazelcast.core.IQueue;
58 -import com.hazelcast.core.ItemEvent;
59 -import com.hazelcast.core.ItemListener;
60 -
61 -@Component(immediate = true)
62 -@Service
63 -public class HazelcastIntentBatchQueue
64 - implements IntentBatchService {
65 -
66 - private final Logger log = getLogger(getClass());
67 - private static final String TOPIC_BASE = "intent-batch-";
68 -
69 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 - protected CoreService coreService;
71 -
72 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 - protected ClusterService clusterService;
74 -
75 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 - protected LeadershipService leadershipService;
77 -
78 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 - protected StoreService storeService;
80 -
81 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 - protected EventDeliveryService eventDispatcher;
83 -
84 -
85 - private HazelcastInstance theInstance;
86 - private NodeId localControllerNodeId;
87 - protected StoreSerializer serializer;
88 - private IntentBatchDelegate delegate;
89 - private InternalLeaderListener leaderListener = new InternalLeaderListener();
90 - private final Map<ApplicationId, SQueue<IntentOperations>> batchQueues
91 - = Maps.newHashMap();
92 - private final Set<ApplicationId> myTopics = Sets.newHashSet();
93 - private final Map<ApplicationId, IntentOperations> outstandingOps
94 - = Maps.newHashMap();
95 -
96 - private final AbstractListenerRegistry<IntentBatchLeaderEvent, IntentBatchListener>
97 - listenerRegistry = new AbstractListenerRegistry<>();
98 -
99 - @Activate
100 - public void activate() {
101 - theInstance = storeService.getHazelcastInstance();
102 - localControllerNodeId = clusterService.getLocalNode().id();
103 - leadershipService.addListener(leaderListener);
104 -
105 - serializer = new KryoSerializer() {
106 -
107 - @Override
108 - protected void setupKryoPool() {
109 - serializerPool = KryoNamespace.newBuilder()
110 - .setRegistrationRequired(false)
111 - .register(KryoNamespaces.API)
112 - .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
113 - .build();
114 - }
115 -
116 - };
117 - eventDispatcher.addSink(IntentBatchLeaderEvent.class, listenerRegistry);
118 - log.info("Started");
119 - }
120 -
121 - @Deactivate
122 - public void deactivate() {
123 - eventDispatcher.removeSink(IntentBatchLeaderEvent.class);
124 - leadershipService.removeListener(leaderListener);
125 - for (ApplicationId appId: batchQueues.keySet()) {
126 - leadershipService.withdraw(getTopic(appId));
127 - }
128 - log.info("Stopped");
129 - }
130 -
131 - public static String getTopic(ApplicationId appId) {
132 - return TOPIC_BASE + checkNotNull(appId.id());
133 - }
134 -
135 - public ApplicationId getAppId(String topic) {
136 - checkState(topic.startsWith(TOPIC_BASE),
137 - "Trying to get app id for invalid topic: {}", topic);
138 - Short id = Short.parseShort(topic.substring(TOPIC_BASE.length()));
139 - return coreService.getAppId(id);
140 - }
141 -
142 - private SQueue<IntentOperations> getQueue(ApplicationId appId) {
143 - SQueue<IntentOperations> queue = batchQueues.get(appId);
144 - if (queue == null) {
145 - synchronized (this) {
146 - String topic = getTopic(appId);
147 - IQueue<byte[]> rawQueue = theInstance.getQueue(topic);
148 - queue = new SQueue<>(rawQueue, serializer);
149 - queue.addItemListener(new InternalItemListener(appId), false);
150 - batchQueues.putIfAbsent(appId, queue);
151 - leadershipService.runForLeadership(topic);
152 - }
153 - }
154 - return queue;
155 - }
156 -
157 - @Override
158 - public void addIntentOperations(IntentOperations ops) {
159 - checkNotNull(ops, "Intent operations cannot be null.");
160 - ApplicationId appId = ops.appId();
161 - getQueue(appId).add(ops);
162 - dispatchNextOperation(appId);
163 - }
164 -
165 - @Override
166 - public void removeIntentOperations(IntentOperations ops) {
167 - ApplicationId appId = ops.appId();
168 - synchronized (this) {
169 - IntentOperations outstanding = outstandingOps.get(appId);
170 - if (outstanding != null) {
171 - checkState(Objects.equals(ops, outstanding),
172 - "Operation {} does not match outstanding operation {}",
173 - ops, outstanding);
174 - } else {
175 - log.warn("Operation {} not found", ops);
176 - }
177 - SQueue<IntentOperations> queue = batchQueues.get(appId);
178 - checkState(queue.remove().equals(ops),
179 - "Operations are wrong.");
180 - outstandingOps.remove(appId);
181 - dispatchNextOperation(appId);
182 - }
183 - }
184 -
185 - /**
186 - * Dispatches the next available operations to the delegate, unless
187 - * we are not the leader for this application id or there is an
188 - * outstanding operations for this application id.
189 - *
190 - * @param appId application id
191 - */
192 - private void dispatchNextOperation(ApplicationId appId) {
193 - synchronized (this) {
194 - if (!myTopics.contains(appId) ||
195 - outstandingOps.containsKey(appId)) {
196 - return;
197 - }
198 - IntentOperations ops = batchQueues.get(appId).peek();
199 - if (ops != null) {
200 - outstandingOps.put(appId, ops);
201 - delegate.execute(ops);
202 - }
203 - }
204 - }
205 -
206 - /**
207 - * Record the leadership change for the given topic. If we have become the
208 - * leader, then dispatch the next operations. If we have lost leadership,
209 - * then cancel the last operations.
210 - *
211 - * @param topic topic based on application id
212 - * @param leader true if we have become the leader, false otherwise
213 - */
214 - private void leaderChanged(String topic, boolean leader) {
215 - ApplicationId appId = getAppId(topic);
216 - synchronized (this) {
217 - if (leader) {
218 - myTopics.add(appId);
219 - checkState(!outstandingOps.containsKey(appId),
220 - "Existing intent ops for app id: {}", appId);
221 - dispatchNextOperation(appId);
222 - } else {
223 - myTopics.remove(appId);
224 - IntentOperations ops = outstandingOps.get(appId);
225 - if (ops != null) {
226 - delegate.cancel(ops);
227 - }
228 - outstandingOps.remove(appId);
229 - }
230 - }
231 - }
232 -
233 - private class InternalItemListener implements ItemListener<IntentOperations> {
234 -
235 - private final ApplicationId appId;
236 -
237 - public InternalItemListener(ApplicationId appId) {
238 - this.appId = appId;
239 - }
240 -
241 - @Override
242 - public void itemAdded(ItemEvent<IntentOperations> item) {
243 - dispatchNextOperation(appId);
244 - }
245 -
246 - @Override
247 - public void itemRemoved(ItemEvent<IntentOperations> item) {
248 - // no-op
249 - }
250 - }
251 -
252 - private class InternalLeaderListener implements LeadershipEventListener {
253 - @Override
254 - public void event(LeadershipEvent event) {
255 - log.trace("Leadership Event: time = {} type = {} event = {}",
256 - event.time(), event.type(), event);
257 -
258 - String topic = event.subject().topic();
259 - if (!topic.startsWith(TOPIC_BASE)) {
260 - return; // Not our topic: ignore
261 - }
262 - if (!event.subject().leader().equals(localControllerNodeId)) {
263 - // run for leadership
264 - getQueue(getAppId(topic));
265 - return; // The event is not about this instance: ignore
266 - }
267 -
268 - switch (event.type()) {
269 - case LEADER_ELECTED:
270 - log.info("Elected leader for app {}", getAppId(topic));
271 - leaderChanged(topic, true);
272 - break;
273 - case LEADER_BOOTED:
274 - log.info("Lost leader election for app {}", getAppId(topic));
275 - leaderChanged(topic, false);
276 - break;
277 - case LEADER_REELECTED:
278 - break;
279 - default:
280 - break;
281 - }
282 - }
283 - }
284 -
285 - @Override
286 - public Set<IntentOperations> getPendingOperations() {
287 - Set<IntentOperations> ops = Sets.newHashSet();
288 - synchronized (this) {
289 - for (SQueue<IntentOperations> queue : batchQueues.values()) {
290 - ops.addAll(queue);
291 - }
292 - return ops;
293 - }
294 - }
295 -
296 - @Override
297 - public boolean isLocalLeader(ApplicationId applicationId) {
298 - return myTopics.contains(applicationId);
299 - }
300 -
301 - @Override
302 - public void setDelegate(IntentBatchDelegate delegate) {
303 - this.delegate = checkNotNull(delegate, "Delegate cannot be null");
304 - }
305 -
306 - @Override
307 - public void unsetDelegate(IntentBatchDelegate delegate) {
308 - if (this.delegate != null && this.delegate.equals(delegate)) {
309 - this.delegate = null;
310 - }
311 - }
312 -
313 - @Override
314 - public void addListener(IntentBatchListener listener) {
315 - listenerRegistry.addListener(listener);
316 - }
317 -
318 - @Override
319 - public void removeListener(IntentBatchListener listener) {
320 - listenerRegistry.removeListener(listener);
321 - }
322 -}
...@@ -84,7 +84,6 @@ import org.onosproject.net.intent.HostToHostIntent; ...@@ -84,7 +84,6 @@ import org.onosproject.net.intent.HostToHostIntent;
84 import org.onosproject.net.intent.Intent; 84 import org.onosproject.net.intent.Intent;
85 import org.onosproject.net.intent.IntentId; 85 import org.onosproject.net.intent.IntentId;
86 import org.onosproject.net.intent.IntentOperation; 86 import org.onosproject.net.intent.IntentOperation;
87 -import org.onosproject.net.intent.IntentOperations;
88 import org.onosproject.net.intent.IntentState; 87 import org.onosproject.net.intent.IntentState;
89 import org.onosproject.net.intent.LinkCollectionIntent; 88 import org.onosproject.net.intent.LinkCollectionIntent;
90 import org.onosproject.net.intent.MultiPointToSinglePointIntent; 89 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
...@@ -316,8 +315,7 @@ public final class KryoNamespaces { ...@@ -316,8 +315,7 @@ public final class KryoNamespaces {
316 ObstacleConstraint.class, 315 ObstacleConstraint.class,
317 AnnotationConstraint.class, 316 AnnotationConstraint.class,
318 BooleanConstraint.class, 317 BooleanConstraint.class,
319 - IntentOperation.class, 318 + IntentOperation.class
320 - IntentOperations.class
321 ) 319 )
322 .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) 320 .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class)
323 .register(new URISerializer(), URI.class) 321 .register(new URISerializer(), URI.class)
......
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.onosproject.store.trivial.impl;
17 -
18 -import com.google.common.collect.Sets;
19 -import org.apache.felix.scr.annotations.Activate;
20 -import org.apache.felix.scr.annotations.Component;
21 -import org.apache.felix.scr.annotations.Deactivate;
22 -import org.apache.felix.scr.annotations.Service;
23 -import org.onosproject.core.ApplicationId;
24 -import org.onosproject.net.intent.IntentBatchDelegate;
25 -import org.onosproject.net.intent.IntentBatchListener;
26 -import org.onosproject.net.intent.IntentBatchService;
27 -import org.onosproject.net.intent.IntentOperations;
28 -import org.slf4j.Logger;
29 -
30 -import java.util.LinkedList;
31 -import java.util.Queue;
32 -import java.util.Set;
33 -
34 -import static com.google.common.base.Preconditions.checkNotNull;
35 -import static com.google.common.base.Preconditions.checkState;
36 -import static org.slf4j.LoggerFactory.getLogger;
37 -
38 -@Component(immediate = true)
39 -@Service
40 -public class SimpleIntentBatchQueue implements IntentBatchService {
41 -
42 - private final Logger log = getLogger(getClass());
43 - private final Queue<IntentOperations> pendingBatches = new LinkedList<>();
44 - private final Set<IntentOperations> currentBatches = Sets.newHashSet();
45 - private IntentBatchDelegate delegate;
46 -
47 - @Activate
48 - public void activate() {
49 - log.info("Started");
50 - }
51 -
52 - @Deactivate
53 - public void deactivate() {
54 - log.info("Stopped");
55 - }
56 -
57 - @Override
58 - public void addIntentOperations(IntentOperations operations) {
59 - checkState(delegate != null, "No delegate set");
60 - synchronized (this) {
61 - pendingBatches.add(operations);
62 - if (currentBatches.isEmpty()) {
63 - IntentOperations work = pendingBatches.poll();
64 - currentBatches.add(work);
65 - delegate.execute(work);
66 - }
67 - }
68 - }
69 -
70 - @Override
71 - public void removeIntentOperations(IntentOperations operations) {
72 - // we allow at most one outstanding batch at a time
73 - synchronized (this) {
74 - checkState(currentBatches.remove(operations), "Operations not found in current ops.");
75 - checkState(currentBatches.isEmpty(), "More than one outstanding batch.");
76 - IntentOperations work = pendingBatches.poll();
77 - if (work != null) {
78 - currentBatches.add(work);
79 - delegate.execute(work);
80 - }
81 - }
82 - }
83 -
84 - @Override
85 - public Set<IntentOperations> getPendingOperations() {
86 - synchronized (this) {
87 - Set<IntentOperations> set = Sets.newHashSet(pendingBatches);
88 - set.addAll(currentBatches); // TODO refactor this current vs. pending
89 - return set;
90 - }
91 - }
92 -
93 - @Override
94 - public boolean isLocalLeader(ApplicationId applicationId) {
95 - return true;
96 - }
97 -
98 - @Override
99 - public void setDelegate(IntentBatchDelegate delegate) {
100 - this.delegate = checkNotNull(delegate, "Delegate cannot be null");
101 - }
102 -
103 - @Override
104 - public void unsetDelegate(IntentBatchDelegate delegate) {
105 - if (this.delegate != null && this.delegate.equals(delegate)) {
106 - this.delegate = null;
107 - }
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 - }
121 -}