alshabib
Committed by Gerrit Code Review

fix intent issues yuta observed

Change-Id: I7dc4a19d49a1b3fc18ecce02a4018cbc9a3043fc
...@@ -14,6 +14,7 @@ public interface DemoAPI { ...@@ -14,6 +14,7 @@ public interface DemoAPI {
14 /** 14 /**
15 * Installs intents based on the installation type. 15 * Installs intents based on the installation type.
16 * @param type the installation type. 16 * @param type the installation type.
17 + * @param runParams run params
17 */ 18 */
18 void setup(InstallType type, Optional<JsonNode> runParams); 19 void setup(InstallType type, Optional<JsonNode> runParams);
19 20
......
...@@ -199,6 +199,7 @@ public class IntentPushTestCommand extends AbstractShellCommand ...@@ -199,6 +199,7 @@ public class IntentPushTestCommand extends AbstractShellCommand
199 /** 199 /**
200 * Returns application ID for the CLI. 200 * Returns application ID for the CLI.
201 * 201 *
202 + * @param id application id
202 * @return command-line application identifier 203 * @return command-line application identifier
203 */ 204 */
204 protected ApplicationId appId(Integer id) { 205 protected ApplicationId appId(Integer id) {
......
...@@ -56,8 +56,8 @@ public interface IntentBatchService { ...@@ -56,8 +56,8 @@ public interface IntentBatchService {
56 * Return true if this instance is the local leader for batch 56 * Return true if this instance is the local leader for batch
57 * processing a given application id. 57 * processing a given application id.
58 * 58 *
59 - * @param applicationId 59 + * @param applicationId an application id
60 - * @return 60 + * @return true if this instance is the local leader for batch
61 */ 61 */
62 boolean isLocalLeader(ApplicationId applicationId); 62 boolean isLocalLeader(ApplicationId applicationId);
63 63
......
...@@ -67,4 +67,32 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> { ...@@ -67,4 +67,32 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> {
67 super(type, intent); 67 super(type, intent);
68 } 68 }
69 69
70 + public static IntentEvent getEvent(IntentState state, Intent intent) {
71 + Type type;
72 + switch (state) {
73 + case SUBMITTED:
74 + type = Type.SUBMITTED;
75 + break;
76 + case INSTALLED:
77 + type = Type.INSTALLED;
78 + break;
79 + case WITHDRAWN:
80 + type = Type.WITHDRAWN;
81 + break;
82 + case FAILED:
83 + type = Type.FAILED;
84 + break;
85 +
86 + //fallthrough to default from here
87 + case COMPILING:
88 + case INSTALLING:
89 + case RECOMPILING:
90 + case WITHDRAWING:
91 + default:
92 + throw new IllegalArgumentException(
93 + "Intent event cannot have transient state: " + state);
94 + }
95 + return new IntentEvent(type, intent);
96 + }
97 +
70 } 98 }
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
15 */ 15 */
16 package org.onlab.onos.net.intent; 16 package org.onlab.onos.net.intent;
17 17
18 -import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.base.Preconditions.checkNotNull;
20 19
21 import org.onlab.onos.net.intent.IntentStore.BatchWrite.Operation; 20 import org.onlab.onos.net.intent.IntentStore.BatchWrite.Operation;
...@@ -42,16 +41,16 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { ...@@ -42,16 +41,16 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
42 * mechanism. 41 * mechanism.
43 * 42 *
44 * @param intent intent to be submitted 43 * @param intent intent to be submitted
45 - * @return event indicating the intent was submitted or null if no
46 - * change resulted, e.g. duplicate intent
47 */ 44 */
48 - IntentEvent createIntent(Intent intent); 45 + @Deprecated
46 + void createIntent(Intent intent);
49 47
50 /** 48 /**
51 * Removes the specified intent from the inventory. 49 * Removes the specified intent from the inventory.
52 * 50 *
53 * @param intentId intent identification 51 * @param intentId intent identification
54 */ 52 */
53 + @Deprecated
55 void removeIntent(IntentId intentId); 54 void removeIntent(IntentId intentId);
56 55
57 /** 56 /**
...@@ -89,9 +88,8 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { ...@@ -89,9 +88,8 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
89 * 88 *
90 * @param intent intent whose state is to be changed 89 * @param intent intent whose state is to be changed
91 * @param newState new state 90 * @param newState new state
92 - * @return state transition event
93 */ 91 */
94 - IntentEvent setState(Intent intent, IntentState newState); 92 + void setState(Intent intent, IntentState newState);
95 93
96 /** 94 /**
97 * Sets the installable intents which resulted from compilation of the 95 * Sets the installable intents which resulted from compilation of the
...@@ -129,64 +127,13 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { ...@@ -129,64 +127,13 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
129 return new BatchWrite(); 127 return new BatchWrite();
130 } 128 }
131 129
132 - // default implementation simply executes them sequentially.
133 - // Store implementation should override and implement actual batch write.
134 /** 130 /**
135 * Execute writes in a batch. 131 * Execute writes in a batch.
136 * 132 *
137 * @param batch BatchWrite to execute 133 * @param batch BatchWrite to execute
138 * @return failed operations 134 * @return failed operations
139 */ 135 */
140 - default List<Operation> batchWrite(BatchWrite batch) { 136 + List<Operation> batchWrite(BatchWrite batch);
141 - List<Operation> failed = new ArrayList<>();
142 - for (Operation op : batch.operations) {
143 - switch (op.type) {
144 - case CREATE_INTENT:
145 - checkArgument(op.args.size() == 1,
146 - "CREATE_INTENT takes 1 argument. %s", op);
147 - Intent intent = (Intent) op.args.get(0);
148 - if (createIntent(intent) == null) {
149 - failed.add(op);
150 - }
151 - break;
152 -
153 - case REMOVE_INTENT:
154 - checkArgument(op.args.size() == 1,
155 - "REMOVE_INTENT takes 1 argument. %s", op);
156 - IntentId intentId = (IntentId) op.args.get(0);
157 - removeIntent(intentId);
158 - break;
159 -
160 - case REMOVE_INSTALLED:
161 - checkArgument(op.args.size() == 1,
162 - "REMOVE_INSTALLED takes 1 argument. %s", op);
163 - intentId = (IntentId) op.args.get(0);
164 - removeInstalledIntents(intentId);
165 - break;
166 -
167 - case SET_INSTALLABLE:
168 - checkArgument(op.args.size() == 2,
169 - "SET_INSTALLABLE takes 2 arguments. %s", op);
170 - intentId = (IntentId) op.args.get(0);
171 - @SuppressWarnings("unchecked")
172 - List<Intent> installableIntents = (List<Intent>) op.args.get(1);
173 - setInstallableIntents(intentId, installableIntents);
174 - break;
175 -
176 - case SET_STATE:
177 - checkArgument(op.args.size() == 2,
178 - "SET_STATE takes 2 arguments. %s", op);
179 - intent = (Intent) op.args.get(0);
180 - IntentState newState = (IntentState) op.args.get(1);
181 - setState(intent, newState);
182 - break;
183 -
184 - default:
185 - break;
186 - }
187 - }
188 - return failed;
189 - }
190 137
191 public static class BatchWrite { 138 public static class BatchWrite {
192 139
......
...@@ -128,7 +128,7 @@ public class IntentManager ...@@ -128,7 +128,7 @@ public class IntentManager
128 trackerService.setDelegate(topoDelegate); 128 trackerService.setDelegate(topoDelegate);
129 batchService.setDelegate(batchDelegate); 129 batchService.setDelegate(batchDelegate);
130 eventDispatcher.addSink(IntentEvent.class, listenerRegistry); 130 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
131 - executor = newFixedThreadPool(NUM_THREADS, namedThreads("onos-intent-monitor")); 131 + executor = newFixedThreadPool(NUM_THREADS, namedThreads("onos-intent"));
132 idGenerator = coreService.getIdGenerator("intent-ids"); 132 idGenerator = coreService.getIdGenerator("intent-ids");
133 Intent.bindIdGenerator(idGenerator); 133 Intent.bindIdGenerator(idGenerator);
134 log.info("Started"); 134 log.info("Started");
...@@ -646,12 +646,11 @@ public class IntentManager ...@@ -646,12 +646,11 @@ public class IntentManager
646 return !isComplete() ? batches.get(currentBatch) : null; 646 return !isComplete() ? batches.get(currentBatch) : null;
647 } 647 }
648 648
649 - List<IntentEvent> batchSuccess(BatchWrite batchWrite) { 649 + void batchSuccess(BatchWrite batchWrite) {
650 // move on to next Batch 650 // move on to next Batch
651 if (++currentBatch == batches.size()) { 651 if (++currentBatch == batches.size()) {
652 - return finalizeStates(batchWrite); 652 + finalizeStates(batchWrite);
653 } 653 }
654 - return Collections.emptyList();
655 } 654 }
656 655
657 void batchFailed() { 656 void batchFailed() {
...@@ -673,19 +672,16 @@ public class IntentManager ...@@ -673,19 +672,16 @@ public class IntentManager
673 } 672 }
674 673
675 // FIXME make sure this is called!!! 674 // FIXME make sure this is called!!!
676 - private List<IntentEvent> finalizeStates(BatchWrite batchWrite) { 675 + private void finalizeStates(BatchWrite batchWrite) {
677 // events to be triggered on successful write 676 // events to be triggered on successful write
678 - List<IntentEvent> events = new ArrayList<>();
679 for (Intent intent : stateMap.keySet()) { 677 for (Intent intent : stateMap.keySet()) {
680 switch (getInflightState(intent)) { 678 switch (getInflightState(intent)) {
681 case INSTALLING: 679 case INSTALLING:
682 batchWrite.setState(intent, INSTALLED); 680 batchWrite.setState(intent, INSTALLED);
683 batchWrite.setInstallableIntents(newIntent.id(), newInstallables); 681 batchWrite.setInstallableIntents(newIntent.id(), newInstallables);
684 - events.add(new IntentEvent(Type.INSTALLED, intent));
685 break; 682 break;
686 case WITHDRAWING: 683 case WITHDRAWING:
687 batchWrite.setState(intent, WITHDRAWN); 684 batchWrite.setState(intent, WITHDRAWN);
688 - events.add(new IntentEvent(Type.WITHDRAWN, intent));
689 batchWrite.removeInstalledIntents(intent.id()); 685 batchWrite.removeInstalledIntents(intent.id());
690 batchWrite.removeIntent(intent.id()); 686 batchWrite.removeIntent(intent.id());
691 break; 687 break;
...@@ -705,7 +701,6 @@ public class IntentManager ...@@ -705,7 +701,6 @@ public class IntentManager
705 break; 701 break;
706 } 702 }
707 } 703 }
708 - return events;
709 } 704 }
710 705
711 List<FlowRuleBatchOperation> batches() { 706 List<FlowRuleBatchOperation> batches() {
...@@ -737,10 +732,10 @@ public class IntentManager ...@@ -737,10 +732,10 @@ public class IntentManager
737 intent.id(), oldState, newState); 732 intent.id(), oldState, newState);
738 733
739 stateMap.put(intent, newState); 734 stateMap.put(intent, newState);
740 - IntentEvent event = store.setState(intent, newState); 735 +// IntentEvent event = store.setState(intent, newState);
741 - if (event != null) { 736 +// if (event != null) {
742 - eventDispatcher.post(event); 737 +// eventDispatcher.post(event);
743 - } 738 +// }
744 } 739 }
745 740
746 Map<Intent, IntentState> stateMap() { 741 Map<Intent, IntentState> stateMap() {
...@@ -822,7 +817,7 @@ public class IntentManager ...@@ -822,7 +817,7 @@ public class IntentManager
822 BatchWrite batchWrite = store.newBatchWrite(); 817 BatchWrite batchWrite = store.newBatchWrite();
823 List<IntentEvent> events = new ArrayList<>(); 818 List<IntentEvent> events = new ArrayList<>();
824 for (IntentUpdate update : intentUpdates) { 819 for (IntentUpdate update : intentUpdates) {
825 - events.addAll(update.batchSuccess(batchWrite)); 820 + update.batchSuccess(batchWrite);
826 } 821 }
827 if (!batchWrite.isEmpty()) { 822 if (!batchWrite.isEmpty()) {
828 store.batchWrite(batchWrite); 823 store.batchWrite(batchWrite);
......
...@@ -5,6 +5,7 @@ import com.google.common.collect.Lists; ...@@ -5,6 +5,7 @@ import com.google.common.collect.Lists;
5 import com.google.common.collect.Maps; 5 import com.google.common.collect.Maps;
6 import com.google.common.collect.Multimap; 6 import com.google.common.collect.Multimap;
7 import com.google.common.collect.Sets; 7 import com.google.common.collect.Sets;
8 +
8 import org.hamcrest.Description; 9 import org.hamcrest.Description;
9 import org.hamcrest.Matchers; 10 import org.hamcrest.Matchers;
10 import org.hamcrest.TypeSafeMatcher; 11 import org.hamcrest.TypeSafeMatcher;
...@@ -40,6 +41,7 @@ import java.util.List; ...@@ -40,6 +41,7 @@ import java.util.List;
40 import java.util.Map; 41 import java.util.Map;
41 import java.util.Set; 42 import java.util.Set;
42 import java.util.concurrent.CountDownLatch; 43 import java.util.concurrent.CountDownLatch;
44 +import java.util.concurrent.TimeUnit;
43 import java.util.concurrent.atomic.AtomicLong; 45 import java.util.concurrent.atomic.AtomicLong;
44 46
45 import static org.hamcrest.Matchers.equalTo; 47 import static org.hamcrest.Matchers.equalTo;
...@@ -229,7 +231,8 @@ public class IntentManagerTest { ...@@ -229,7 +231,8 @@ public class IntentManagerTest {
229 231
230 public void await(IntentEvent.Type type) { 232 public void await(IntentEvent.Type type) {
231 try { 233 try {
232 - latchMap.get(type).await(); 234 + assertTrue("Timed out waiting for: " + type,
235 + latchMap.get(type).await(5, TimeUnit.SECONDS));
233 } catch (InterruptedException e) { 236 } catch (InterruptedException e) {
234 e.printStackTrace(); 237 e.printStackTrace();
235 } 238 }
......
...@@ -18,6 +18,7 @@ package org.onlab.onos.store.hz; ...@@ -18,6 +18,7 @@ package org.onlab.onos.store.hz;
18 import com.google.common.base.Function; 18 import com.google.common.base.Function;
19 import com.google.common.collect.FluentIterable; 19 import com.google.common.collect.FluentIterable;
20 import com.hazelcast.core.IQueue; 20 import com.hazelcast.core.IQueue;
21 +import com.hazelcast.core.ItemEvent;
21 import com.hazelcast.core.ItemListener; 22 import com.hazelcast.core.ItemListener;
22 import com.hazelcast.monitor.LocalQueueStats; 23 import com.hazelcast.monitor.LocalQueueStats;
23 24
...@@ -201,16 +202,39 @@ public class SQueue<T> implements IQueue<T> { ...@@ -201,16 +202,39 @@ public class SQueue<T> implements IQueue<T> {
201 return q.getLocalQueueStats(); 202 return q.getLocalQueueStats();
202 } 203 }
203 204
204 - @Deprecated // not implemented yet 205 +
205 @Override 206 @Override
206 - public String addItemListener(ItemListener<T> itemListener, boolean b) { 207 + public String addItemListener(ItemListener<T> itemListener, boolean withValue) {
207 - throw new UnsupportedOperationException(); 208 + ItemListener<byte[]> il = new ItemListener<byte[]>() {
209 + @Override
210 + public void itemAdded(ItemEvent<byte[]> item) {
211 + itemListener.itemAdded(new ItemEvent<T>(getName(item),
212 + item.getEventType(),
213 + deserialize(item.getItem()),
214 + item.getMember()));
215 + }
216 +
217 + @Override
218 + public void itemRemoved(ItemEvent<byte[]> item) {
219 + itemListener.itemRemoved(new ItemEvent<T>(getName(item),
220 + item.getEventType(),
221 + deserialize(item.getItem()),
222 + item.getMember()));
223 + }
224 +
225 + private String getName(ItemEvent<byte[]> item) {
226 + return (item.getSource() instanceof String) ?
227 + (String) item.getSource() : item.getSource().toString();
228 +
229 + }
230 + };
231 + return q.addItemListener(il, withValue);
208 } 232 }
209 233
210 - @Deprecated // not implemented yet 234 +
211 @Override 235 @Override
212 - public boolean removeItemListener(String s) { 236 + public boolean removeItemListener(String registrationId) {
213 - throw new UnsupportedOperationException(); 237 + return q.removeItemListener(registrationId);
214 } 238 }
215 239
216 @Deprecated 240 @Deprecated
......
...@@ -23,6 +23,7 @@ import com.google.common.cache.CacheLoader; ...@@ -23,6 +23,7 @@ import com.google.common.cache.CacheLoader;
23 import com.google.common.cache.LoadingCache; 23 import com.google.common.cache.LoadingCache;
24 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.ImmutableSet;
25 25
26 +import com.google.common.collect.Lists;
26 import org.apache.felix.scr.annotations.Activate; 27 import org.apache.felix.scr.annotations.Activate;
27 import org.apache.felix.scr.annotations.Component; 28 import org.apache.felix.scr.annotations.Component;
28 import org.apache.felix.scr.annotations.Deactivate; 29 import org.apache.felix.scr.annotations.Deactivate;
...@@ -187,15 +188,16 @@ public class DistributedIntentStore ...@@ -187,15 +188,16 @@ public class DistributedIntentStore
187 } 188 }
188 189
189 @Override 190 @Override
190 - public IntentEvent createIntent(Intent intent) { 191 + public void createIntent(Intent intent) {
191 Context timer = startTimer(createIntentTimer); 192 Context timer = startTimer(createIntentTimer);
192 try { 193 try {
193 boolean absent = intents.putIfAbsent(intent.id(), intent); 194 boolean absent = intents.putIfAbsent(intent.id(), intent);
194 if (!absent) { 195 if (!absent) {
195 // duplicate, ignore 196 // duplicate, ignore
196 - return null; 197 + return;
197 } else { 198 } else {
198 - return this.setState(intent, IntentState.SUBMITTED); 199 + this.setState(intent, IntentState.SUBMITTED);
200 + return;
199 } 201 }
200 } finally { 202 } finally {
201 stopTimer(timer); 203 stopTimer(timer);
...@@ -273,7 +275,7 @@ public class DistributedIntentStore ...@@ -273,7 +275,7 @@ public class DistributedIntentStore
273 } 275 }
274 276
275 @Override 277 @Override
276 - public IntentEvent setState(Intent intent, IntentState state) { 278 + public void setState(Intent intent, IntentState state) {
277 Context timer = startTimer(setStateTimer); 279 Context timer = startTimer(setStateTimer);
278 try { 280 try {
279 final IntentId id = intent.id(); 281 final IntentId id = intent.id();
...@@ -341,10 +343,10 @@ public class DistributedIntentStore ...@@ -341,10 +343,10 @@ public class DistributedIntentStore
341 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state); 343 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state);
342 } 344 }
343 345
344 - if (evtType == null) { 346 + if (evtType != null) {
345 - return null; 347 + notifyDelegate(new IntentEvent(evtType, intent));
346 } 348 }
347 - return new IntentEvent(evtType, intent); 349 + return;
348 } finally { 350 } finally {
349 stopTimer(timer); 351 stopTimer(timer);
350 } 352 }
...@@ -417,6 +419,7 @@ public class DistributedIntentStore ...@@ -417,6 +419,7 @@ public class DistributedIntentStore
417 419
418 List<Operation> failed = new ArrayList<>(); 420 List<Operation> failed = new ArrayList<>();
419 final Builder builder = BatchWriteRequest.newBuilder(); 421 final Builder builder = BatchWriteRequest.newBuilder();
422 + List<IntentEvent> events = Lists.newArrayList();
420 423
421 final Set<IntentId> transitionedToParking = new HashSet<>(); 424 final Set<IntentId> transitionedToParking = new HashSet<>();
422 425
...@@ -428,6 +431,7 @@ public class DistributedIntentStore ...@@ -428,6 +431,7 @@ public class DistributedIntentStore
428 Intent intent = op.arg(0); 431 Intent intent = op.arg(0);
429 builder.putIfAbsent(INTENTS_TABLE, strIntentId(intent.id()), serializer.encode(intent)); 432 builder.putIfAbsent(INTENTS_TABLE, strIntentId(intent.id()), serializer.encode(intent));
430 builder.putIfAbsent(STATES_TABLE, strIntentId(intent.id()), serializer.encode(SUBMITTED)); 433 builder.putIfAbsent(STATES_TABLE, strIntentId(intent.id()), serializer.encode(SUBMITTED));
434 + events.add(IntentEvent.getEvent(SUBMITTED, intent));
431 break; 435 break;
432 436
433 case REMOVE_INTENT: 437 case REMOVE_INTENT:
...@@ -450,6 +454,7 @@ public class DistributedIntentStore ...@@ -450,6 +454,7 @@ public class DistributedIntentStore
450 } else { 454 } else {
451 transitionedToParking.remove(intent.id()); 455 transitionedToParking.remove(intent.id());
452 } 456 }
457 + events.add(IntentEvent.getEvent(newState, intent));
453 break; 458 break;
454 459
455 case SET_INSTALLABLE: 460 case SET_INSTALLABLE:
...@@ -478,9 +483,11 @@ public class DistributedIntentStore ...@@ -478,9 +483,11 @@ public class DistributedIntentStore
478 if (batchWriteResult.isSuccessful()) { 483 if (batchWriteResult.isSuccessful()) {
479 // no-failure (except for invalid input) 484 // no-failure (except for invalid input)
480 transitionedToParking.forEach((intentId) -> transientStates.remove(intentId)); 485 transitionedToParking.forEach((intentId) -> transientStates.remove(intentId));
486 + notifyDelegate(events);
481 return failed; 487 return failed;
482 } else { 488 } else {
483 // everything failed 489 // everything failed
490 + // FIXME what to do with events?
484 return batch.operations(); 491 return batch.operations();
485 } 492 }
486 } 493 }
......
...@@ -19,6 +19,9 @@ import com.google.common.collect.Maps; ...@@ -19,6 +19,9 @@ import com.google.common.collect.Maps;
19 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
20 import com.hazelcast.core.HazelcastInstance; 20 import com.hazelcast.core.HazelcastInstance;
21 import com.hazelcast.core.IQueue; 21 import com.hazelcast.core.IQueue;
22 +import com.hazelcast.core.ItemEvent;
23 +import com.hazelcast.core.ItemListener;
24 +
22 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
23 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
24 import org.apache.felix.scr.annotations.Deactivate; 27 import org.apache.felix.scr.annotations.Deactivate;
...@@ -47,7 +50,6 @@ import java.util.Collections; ...@@ -47,7 +50,6 @@ import java.util.Collections;
47 import java.util.Map; 50 import java.util.Map;
48 import java.util.Set; 51 import java.util.Set;
49 52
50 -
51 import static com.google.common.base.Preconditions.checkNotNull; 53 import static com.google.common.base.Preconditions.checkNotNull;
52 import static com.google.common.base.Preconditions.checkState; 54 import static com.google.common.base.Preconditions.checkState;
53 import static org.slf4j.LoggerFactory.getLogger; 55 import static org.slf4j.LoggerFactory.getLogger;
...@@ -107,6 +109,9 @@ public class HazelcastIntentBatchQueue ...@@ -107,6 +109,9 @@ public class HazelcastIntentBatchQueue
107 @Deactivate 109 @Deactivate
108 public void deactivate() { 110 public void deactivate() {
109 leadershipService.removeListener(leaderListener); 111 leadershipService.removeListener(leaderListener);
112 + for (ApplicationId appId: batchQueues.keySet()) {
113 + leadershipService.withdraw(getTopic(appId));
114 + }
110 log.info("Stopped"); 115 log.info("Stopped");
111 } 116 }
112 117
...@@ -125,12 +130,11 @@ public class HazelcastIntentBatchQueue ...@@ -125,12 +130,11 @@ public class HazelcastIntentBatchQueue
125 SQueue<IntentOperations> queue = batchQueues.get(appId); 130 SQueue<IntentOperations> queue = batchQueues.get(appId);
126 if (queue == null) { 131 if (queue == null) {
127 synchronized (this) { 132 synchronized (this) {
128 - // FIXME how will other instances find out about new queues
129 String topic = getTopic(appId); 133 String topic = getTopic(appId);
130 IQueue<byte[]> rawQueue = theInstance.getQueue(topic); 134 IQueue<byte[]> rawQueue = theInstance.getQueue(topic);
131 queue = new SQueue<>(rawQueue, serializer); 135 queue = new SQueue<>(rawQueue, serializer);
136 + queue.addItemListener(new InternalItemListener(appId), false);
132 batchQueues.putIfAbsent(appId, queue); 137 batchQueues.putIfAbsent(appId, queue);
133 - // TODO others should run for leadership when they hear about this topic
134 leadershipService.runForLeadership(topic); 138 leadershipService.runForLeadership(topic);
135 } 139 }
136 } 140 }
...@@ -209,6 +213,25 @@ public class HazelcastIntentBatchQueue ...@@ -209,6 +213,25 @@ public class HazelcastIntentBatchQueue
209 } 213 }
210 } 214 }
211 215
216 + private class InternalItemListener implements ItemListener<IntentOperations> {
217 +
218 + private final ApplicationId appId;
219 +
220 + public InternalItemListener(ApplicationId appId) {
221 + this.appId = appId;
222 + }
223 +
224 + @Override
225 + public void itemAdded(ItemEvent<IntentOperations> item) {
226 + dispatchNextOperation(appId);
227 + }
228 +
229 + @Override
230 + public void itemRemoved(ItemEvent<IntentOperations> item) {
231 + // no-op
232 + }
233 + }
234 +
212 private class InternalLeaderListener implements LeadershipEventListener { 235 private class InternalLeaderListener implements LeadershipEventListener {
213 @Override 236 @Override
214 public void event(LeadershipEvent event) { 237 public void event(LeadershipEvent event) {
...@@ -220,6 +243,8 @@ public class HazelcastIntentBatchQueue ...@@ -220,6 +243,8 @@ public class HazelcastIntentBatchQueue
220 return; // Not our topic: ignore 243 return; // Not our topic: ignore
221 } 244 }
222 if (!event.subject().leader().id().equals(localControllerNode.id())) { 245 if (!event.subject().leader().id().equals(localControllerNode.id())) {
246 + // run for leadership
247 + getQueue(getAppId(topic));
223 return; // The event is not about this instance: ignore 248 return; // The event is not about this instance: ignore
224 } 249 }
225 250
......
...@@ -20,6 +20,7 @@ import com.codahale.metrics.Timer.Context; ...@@ -20,6 +20,7 @@ import com.codahale.metrics.Timer.Context;
20 import com.google.common.base.Verify; 20 import com.google.common.base.Verify;
21 import com.google.common.collect.ImmutableList; 21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableSet; 22 import com.google.common.collect.ImmutableSet;
23 +import com.google.common.collect.Lists;
23 import com.hazelcast.core.EntryAdapter; 24 import com.hazelcast.core.EntryAdapter;
24 import com.hazelcast.core.EntryEvent; 25 import com.hazelcast.core.EntryEvent;
25 import com.hazelcast.core.EntryListener; 26 import com.hazelcast.core.EntryListener;
...@@ -171,15 +172,16 @@ public class HazelcastIntentStore ...@@ -171,15 +172,16 @@ public class HazelcastIntentStore
171 } 172 }
172 173
173 @Override 174 @Override
174 - public IntentEvent createIntent(Intent intent) { 175 + public void createIntent(Intent intent) {
175 Context timer = startTimer(createIntentTimer); 176 Context timer = startTimer(createIntentTimer);
176 try { 177 try {
177 Intent existing = intents.putIfAbsent(intent.id(), intent); 178 Intent existing = intents.putIfAbsent(intent.id(), intent);
178 if (existing != null) { 179 if (existing != null) {
179 // duplicate, ignore 180 // duplicate, ignore
180 - return null; 181 + return;
181 } else { 182 } else {
182 - return this.setState(intent, IntentState.SUBMITTED); 183 + this.setState(intent, IntentState.SUBMITTED);
184 + return;
183 } 185 }
184 } finally { 186 } finally {
185 stopTimer(timer); 187 stopTimer(timer);
...@@ -256,7 +258,7 @@ public class HazelcastIntentStore ...@@ -256,7 +258,7 @@ public class HazelcastIntentStore
256 } 258 }
257 259
258 @Override 260 @Override
259 - public IntentEvent setState(Intent intent, IntentState state) { 261 + public void setState(Intent intent, IntentState state) {
260 Context timer = startTimer(setStateTimer); 262 Context timer = startTimer(setStateTimer);
261 try { 263 try {
262 264
...@@ -311,10 +313,10 @@ public class HazelcastIntentStore ...@@ -311,10 +313,10 @@ public class HazelcastIntentStore
311 final IntentState prevTransient = transientStates.put(id, state); 313 final IntentState prevTransient = transientStates.put(id, state);
312 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state); 314 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state);
313 315
314 - if (type == null) { 316 + if (type != null) {
315 - return null; 317 + notifyDelegate(new IntentEvent(type, intent));
316 } 318 }
317 - return new IntentEvent(type, intent); 319 + return;
318 } finally { 320 } finally {
319 stopTimer(timer); 321 stopTimer(timer);
320 } 322 }
...@@ -358,6 +360,7 @@ public class HazelcastIntentStore ...@@ -358,6 +360,7 @@ public class HazelcastIntentStore
358 List<Operation> failed = new ArrayList<>(); 360 List<Operation> failed = new ArrayList<>();
359 361
360 List<Pair<Operation, List<Future<?>>>> futures = new ArrayList<>(batch.operations().size()); 362 List<Pair<Operation, List<Future<?>>>> futures = new ArrayList<>(batch.operations().size());
363 + List<IntentEvent> events = Lists.newArrayList();
361 364
362 for (Operation op : batch.operations()) { 365 for (Operation op : batch.operations()) {
363 switch (op.type()) { 366 switch (op.type()) {
...@@ -434,6 +437,7 @@ public class HazelcastIntentStore ...@@ -434,6 +437,7 @@ public class HazelcastIntentStore
434 prevIntent, prevIntentState, 437 prevIntent, prevIntentState,
435 intent, newIntentState); 438 intent, newIntentState);
436 } 439 }
440 + events.add(IntentEvent.getEvent(SUBMITTED, intent));
437 } catch (InterruptedException e) { 441 } catch (InterruptedException e) {
438 log.error("Batch write was interrupted while processing {}", op, e); 442 log.error("Batch write was interrupted while processing {}", op, e);
439 failed.add(op); 443 failed.add(op);
...@@ -487,6 +491,8 @@ public class HazelcastIntentStore ...@@ -487,6 +491,8 @@ public class HazelcastIntentStore
487 if (PARKING.contains(newState)) { 491 if (PARKING.contains(newState)) {
488 transientStates.remove(intentId); 492 transientStates.remove(intentId);
489 } 493 }
494 + events.add(IntentEvent.getEvent(newState, intent));
495 +
490 log.trace("{} - {} -> {}", intentId, prevIntentState, newState); 496 log.trace("{} - {} -> {}", intentId, prevIntentState, newState);
491 // TODO sanity check and log? 497 // TODO sanity check and log?
492 } catch (InterruptedException e) { 498 } catch (InterruptedException e) {
...@@ -554,6 +560,9 @@ public class HazelcastIntentStore ...@@ -554,6 +560,9 @@ public class HazelcastIntentStore
554 break; 560 break;
555 } 561 }
556 } 562 }
563 +
564 + notifyDelegate(events);
565 +
557 return failed; 566 return failed;
558 } 567 }
559 568
...@@ -571,6 +580,8 @@ public class HazelcastIntentStore ...@@ -571,6 +580,8 @@ public class HazelcastIntentStore
571 log.debug("{} state updated remotely, removing transient state {}", 580 log.debug("{} state updated remotely, removing transient state {}",
572 intentId, oldState); 581 intentId, oldState);
573 } 582 }
583 +
584 + notifyDelegate(IntentEvent.getEvent(event.getValue(), getIntent(intentId)));
574 } 585 }
575 } 586 }
576 } 587 }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
16 package org.onlab.onos.store.trivial.impl; 16 package org.onlab.onos.store.trivial.impl;
17 17
18 import com.google.common.collect.ImmutableSet; 18 import com.google.common.collect.ImmutableSet;
19 +import com.google.common.collect.Lists;
20 +
19 import org.apache.felix.scr.annotations.Activate; 21 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 22 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Deactivate; 23 import org.apache.felix.scr.annotations.Deactivate;
...@@ -26,6 +28,7 @@ import org.onlab.onos.net.intent.IntentId; ...@@ -26,6 +28,7 @@ import org.onlab.onos.net.intent.IntentId;
26 import org.onlab.onos.net.intent.IntentState; 28 import org.onlab.onos.net.intent.IntentState;
27 import org.onlab.onos.net.intent.IntentStore; 29 import org.onlab.onos.net.intent.IntentStore;
28 import org.onlab.onos.net.intent.IntentStoreDelegate; 30 import org.onlab.onos.net.intent.IntentStoreDelegate;
31 +import org.onlab.onos.net.intent.IntentStore.BatchWrite.Operation;
29 import org.onlab.onos.store.AbstractStore; 32 import org.onlab.onos.store.AbstractStore;
30 import org.slf4j.Logger; 33 import org.slf4j.Logger;
31 34
...@@ -33,6 +36,7 @@ import java.util.List; ...@@ -33,6 +36,7 @@ import java.util.List;
33 import java.util.Map; 36 import java.util.Map;
34 import java.util.concurrent.ConcurrentHashMap; 37 import java.util.concurrent.ConcurrentHashMap;
35 38
39 +import static com.google.common.base.Preconditions.checkArgument;
36 import static com.google.common.base.Preconditions.checkState; 40 import static com.google.common.base.Preconditions.checkState;
37 import static org.onlab.onos.net.intent.IntentState.WITHDRAWN; 41 import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
38 import static org.slf4j.LoggerFactory.getLogger; 42 import static org.slf4j.LoggerFactory.getLogger;
...@@ -60,12 +64,13 @@ public class SimpleIntentStore ...@@ -60,12 +64,13 @@ public class SimpleIntentStore
60 } 64 }
61 65
62 @Override 66 @Override
63 - public IntentEvent createIntent(Intent intent) { 67 + public void createIntent(Intent intent) {
64 if (intents.containsKey(intent.id())) { 68 if (intents.containsKey(intent.id())) {
65 - return null; 69 + return;
66 } 70 }
67 intents.put(intent.id(), intent); 71 intents.put(intent.id(), intent);
68 - return this.setState(intent, IntentState.SUBMITTED); 72 + this.setState(intent, IntentState.SUBMITTED);
73 + return;
69 } 74 }
70 75
71 @Override 76 @Override
...@@ -98,7 +103,7 @@ public class SimpleIntentStore ...@@ -98,7 +103,7 @@ public class SimpleIntentStore
98 } 103 }
99 104
100 @Override 105 @Override
101 - public IntentEvent setState(Intent intent, IntentState state) { 106 + public void setState(Intent intent, IntentState state) {
102 IntentId id = intent.id(); 107 IntentId id = intent.id();
103 states.put(id, state); 108 states.put(id, state);
104 IntentEvent.Type type = null; 109 IntentEvent.Type type = null;
...@@ -119,10 +124,9 @@ public class SimpleIntentStore ...@@ -119,10 +124,9 @@ public class SimpleIntentStore
119 default: 124 default:
120 break; 125 break;
121 } 126 }
122 - if (type == null) { 127 + if (type != null) {
123 - return null; 128 + notifyDelegate(new IntentEvent(type, intent));
124 } 129 }
125 - return new IntentEvent(type, intent);
126 } 130 }
127 131
128 @Override 132 @Override
...@@ -139,5 +143,60 @@ public class SimpleIntentStore ...@@ -139,5 +143,60 @@ public class SimpleIntentStore
139 public void removeInstalledIntents(IntentId intentId) { 143 public void removeInstalledIntents(IntentId intentId) {
140 installable.remove(intentId); 144 installable.remove(intentId);
141 } 145 }
142 - 146 + /**
147 + * Execute writes in a batch.
148 + *
149 + * @param batch BatchWrite to execute
150 + * @return failed operations
151 + */
152 + @Override
153 + public List<Operation> batchWrite(BatchWrite batch) {
154 + List<Operation> failed = Lists.newArrayList();
155 + for (Operation op : batch.operations()) {
156 + switch (op.type()) {
157 + case CREATE_INTENT:
158 + checkArgument(op.args().size() == 1,
159 + "CREATE_INTENT takes 1 argument. %s", op);
160 + Intent intent = (Intent) op.args().get(0);
161 + // TODO: what if it failed?
162 + createIntent(intent);
163 + break;
164 +
165 + case REMOVE_INTENT:
166 + checkArgument(op.args().size() == 1,
167 + "REMOVE_INTENT takes 1 argument. %s", op);
168 + IntentId intentId = (IntentId) op.args().get(0);
169 + removeIntent(intentId);
170 + break;
171 +
172 + case REMOVE_INSTALLED:
173 + checkArgument(op.args().size() == 1,
174 + "REMOVE_INSTALLED takes 1 argument. %s", op);
175 + intentId = (IntentId) op.args().get(0);
176 + removeInstalledIntents(intentId);
177 + break;
178 +
179 + case SET_INSTALLABLE:
180 + checkArgument(op.args().size() == 2,
181 + "SET_INSTALLABLE takes 2 arguments. %s", op);
182 + intentId = (IntentId) op.args().get(0);
183 + @SuppressWarnings("unchecked")
184 + List<Intent> installableIntents = (List<Intent>) op.args().get(1);
185 + setInstallableIntents(intentId, installableIntents);
186 + break;
187 +
188 + case SET_STATE:
189 + checkArgument(op.args().size() == 2,
190 + "SET_STATE takes 2 arguments. %s", op);
191 + intent = (Intent) op.args().get(0);
192 + IntentState newState = (IntentState) op.args().get(1);
193 + setState(intent, newState);
194 + break;
195 +
196 + default:
197 + break;
198 + }
199 + }
200 + return failed;
201 + }
143 } 202 }
......
...@@ -19,7 +19,7 @@ import org.onlab.onos.cluster.LeadershipService; ...@@ -19,7 +19,7 @@ import org.onlab.onos.cluster.LeadershipService;
19 19
20 /** 20 /**
21 * A trivial implementation of the leadership service. 21 * A trivial implementation of the leadership service.
22 - * <p></p> 22 + * <p>
23 * The service is not distributed, so it can assume there's a single leadership 23 * The service is not distributed, so it can assume there's a single leadership
24 * contender. This contender is always granted leadership whenever it asks. 24 * contender. This contender is always granted leadership whenever it asks.
25 */ 25 */
......