Committed by
Gerrit Code Review
Initial implementation of distributed intent batch queue
Change-Id: I7ffed03651569ade1be1e8dca905bfaf369b7e03
Showing
18 changed files
with
611 additions
and
156 deletions
... | @@ -308,7 +308,7 @@ public class DemoInstaller implements DemoAPI { | ... | @@ -308,7 +308,7 @@ public class DemoInstaller implements DemoAPI { |
308 | } | 308 | } |
309 | 309 | ||
310 | private void installIntents(List<HostPair> toInstall) { | 310 | private void installIntents(List<HostPair> toInstall) { |
311 | - IntentOperations.Builder builder = IntentOperations.builder(); | 311 | + IntentOperations.Builder builder = IntentOperations.builder(appId); |
312 | for (HostPair pair : toInstall) { | 312 | for (HostPair pair : toInstall) { |
313 | installed.add(pair); | 313 | installed.add(pair); |
314 | uninstalledOrWithdrawn.remove(pair); | 314 | uninstalledOrWithdrawn.remove(pair); |
... | @@ -318,7 +318,7 @@ public class DemoInstaller implements DemoAPI { | ... | @@ -318,7 +318,7 @@ public class DemoInstaller implements DemoAPI { |
318 | } | 318 | } |
319 | 319 | ||
320 | private void uninstallIntents(Collection<HostPair> toRemove) { | 320 | private void uninstallIntents(Collection<HostPair> toRemove) { |
321 | - IntentOperations.Builder builder = IntentOperations.builder(); | 321 | + IntentOperations.Builder builder = IntentOperations.builder(appId); |
322 | for (HostPair pair : toRemove) { | 322 | for (HostPair pair : toRemove) { |
323 | installed.remove(pair); | 323 | installed.remove(pair); |
324 | uninstalledOrWithdrawn.add(pair); | 324 | uninstalledOrWithdrawn.add(pair); |
... | @@ -333,7 +333,7 @@ public class DemoInstaller implements DemoAPI { | ... | @@ -333,7 +333,7 @@ public class DemoInstaller implements DemoAPI { |
333 | private void cleanUp() { | 333 | private void cleanUp() { |
334 | List<HostPair> allPairs = Lists.newArrayList(installed); | 334 | List<HostPair> allPairs = Lists.newArrayList(installed); |
335 | allPairs.addAll(uninstalledOrWithdrawn); | 335 | allPairs.addAll(uninstalledOrWithdrawn); |
336 | - IntentOperations.Builder builder = IntentOperations.builder(); | 336 | + IntentOperations.Builder builder = IntentOperations.builder(appId); |
337 | for (HostPair pair : allPairs) { | 337 | for (HostPair pair : allPairs) { |
338 | builder.addWithdrawOperation(pair.h2hIntent().id()); | 338 | builder.addWithdrawOperation(pair.h2hIntent().id()); |
339 | } | 339 | } | ... | ... |
... | @@ -129,7 +129,7 @@ public class OpticalPathProvisioner { | ... | @@ -129,7 +129,7 @@ public class OpticalPathProvisioner { |
129 | } | 129 | } |
130 | 130 | ||
131 | // Build the intent batch | 131 | // Build the intent batch |
132 | - IntentOperations.Builder ops = IntentOperations.builder(); | 132 | + IntentOperations.Builder ops = IntentOperations.builder(appId); |
133 | for (Intent i : intents) { | 133 | for (Intent i : intents) { |
134 | // TODO: don't allow duplicate intents between the same points for now | 134 | // TODO: don't allow duplicate intents between the same points for now |
135 | // we may want to allow this carefully in future to increase capacity | 135 | // we may want to allow this carefully in future to increase capacity | ... | ... |
... | @@ -221,7 +221,7 @@ public class IntentSynchronizer { | ... | @@ -221,7 +221,7 @@ public class IntentSynchronizer { |
221 | // Push the intents | 221 | // Push the intents |
222 | if (isElectedLeader && isActivatedLeader) { | 222 | if (isElectedLeader && isActivatedLeader) { |
223 | log.debug("SDN-IP Submitting all Peer Intents..."); | 223 | log.debug("SDN-IP Submitting all Peer Intents..."); |
224 | - IntentOperations.Builder builder = IntentOperations.builder(); | 224 | + IntentOperations.Builder builder = IntentOperations.builder(appId); |
225 | for (Intent intent : intents) { | 225 | for (Intent intent : intents) { |
226 | builder.addSubmitOperation(intent); | 226 | builder.addSubmitOperation(intent); |
227 | } | 227 | } |
... | @@ -370,7 +370,7 @@ public class IntentSynchronizer { | ... | @@ -370,7 +370,7 @@ public class IntentSynchronizer { |
370 | } | 370 | } |
371 | 371 | ||
372 | // Withdraw Intents | 372 | // Withdraw Intents |
373 | - IntentOperations.Builder builder = IntentOperations.builder(); | 373 | + IntentOperations.Builder builder = IntentOperations.builder(appId); |
374 | for (Intent intent : deleteIntents) { | 374 | for (Intent intent : deleteIntents) { |
375 | builder.addWithdrawOperation(intent.id()); | 375 | builder.addWithdrawOperation(intent.id()); |
376 | log.debug("SDN-IP Intent Synchronizer: withdrawing intent: {}", | 376 | log.debug("SDN-IP Intent Synchronizer: withdrawing intent: {}", |
... | @@ -386,7 +386,7 @@ public class IntentSynchronizer { | ... | @@ -386,7 +386,7 @@ public class IntentSynchronizer { |
386 | intentService.execute(intentOperations); | 386 | intentService.execute(intentOperations); |
387 | 387 | ||
388 | // Add Intents | 388 | // Add Intents |
389 | - builder = IntentOperations.builder(); | 389 | + builder = IntentOperations.builder(appId); |
390 | for (Intent intent : addIntents) { | 390 | for (Intent intent : addIntents) { |
391 | builder.addSubmitOperation(intent); | 391 | builder.addSubmitOperation(intent); |
392 | log.debug("SDN-IP Intent Synchronizer: submitting intent: {}", | 392 | log.debug("SDN-IP Intent Synchronizer: submitting intent: {}", | ... | ... |
... | @@ -325,13 +325,13 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -325,13 +325,13 @@ public class IntentSyncTest extends AbstractIntentTest { |
325 | .andReturn(IntentState.WITHDRAWING).anyTimes(); | 325 | .andReturn(IntentState.WITHDRAWING).anyTimes(); |
326 | expect(intentService.getIntents()).andReturn(intents).anyTimes(); | 326 | expect(intentService.getIntents()).andReturn(intents).anyTimes(); |
327 | 327 | ||
328 | - IntentOperations.Builder builder = IntentOperations.builder(); | 328 | + IntentOperations.Builder builder = IntentOperations.builder(null); //FIXME null |
329 | builder.addWithdrawOperation(intent2.id()); | 329 | builder.addWithdrawOperation(intent2.id()); |
330 | builder.addWithdrawOperation(intent4.id()); | 330 | builder.addWithdrawOperation(intent4.id()); |
331 | intentService.execute(TestIntentServiceHelper.eqExceptId( | 331 | intentService.execute(TestIntentServiceHelper.eqExceptId( |
332 | builder.build())); | 332 | builder.build())); |
333 | 333 | ||
334 | - builder = IntentOperations.builder(); | 334 | + builder = IntentOperations.builder(null); //FIXME null |
335 | builder.addSubmitOperation(intent3); | 335 | builder.addSubmitOperation(intent3); |
336 | builder.addSubmitOperation(intent4Update); | 336 | builder.addSubmitOperation(intent4Update); |
337 | builder.addSubmitOperation(intent6); | 337 | builder.addSubmitOperation(intent6); | ... | ... |
... | @@ -566,7 +566,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -566,7 +566,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
566 | reset(intentService); | 566 | reset(intentService); |
567 | 567 | ||
568 | // Setup the expected intents | 568 | // Setup the expected intents |
569 | - IntentOperations.Builder builder = IntentOperations.builder(); | 569 | + IntentOperations.Builder builder = IntentOperations.builder(null); //FIXME null |
570 | for (Intent intent : intentList) { | 570 | for (Intent intent : intentList) { |
571 | builder.addSubmitOperation(intent); | 571 | builder.addSubmitOperation(intent); |
572 | } | 572 | } |
... | @@ -601,9 +601,9 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -601,9 +601,9 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
601 | replay(configInfoService); | 601 | replay(configInfoService); |
602 | 602 | ||
603 | reset(intentService); | 603 | reset(intentService); |
604 | - IntentOperations.Builder builder = IntentOperations.builder(); | 604 | + IntentOperations.Builder builder = IntentOperations.builder(null); //FIXME null |
605 | intentService.execute(TestIntentServiceHelper.eqExceptId( | 605 | intentService.execute(TestIntentServiceHelper.eqExceptId( |
606 | - builder.build())); | 606 | + builder.build())); |
607 | replay(intentService); | 607 | replay(intentService); |
608 | peerConnectivityManager.start(); | 608 | peerConnectivityManager.start(); |
609 | verify(intentService); | 609 | verify(intentService); |
... | @@ -627,9 +627,9 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -627,9 +627,9 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
627 | replay(configInfoService); | 627 | replay(configInfoService); |
628 | 628 | ||
629 | reset(intentService); | 629 | reset(intentService); |
630 | - IntentOperations.Builder builder = IntentOperations.builder(); | 630 | + IntentOperations.Builder builder = IntentOperations.builder(null); //FIXME null |
631 | intentService.execute(TestIntentServiceHelper.eqExceptId( | 631 | intentService.execute(TestIntentServiceHelper.eqExceptId( |
632 | - builder.build())); | 632 | + builder.build())); |
633 | replay(intentService); | 633 | replay(intentService); |
634 | peerConnectivityManager.start(); | 634 | peerConnectivityManager.start(); |
635 | verify(intentService); | 635 | verify(intentService); | ... | ... |
... | @@ -119,7 +119,7 @@ public class IntentPushTestCommand extends AbstractShellCommand | ... | @@ -119,7 +119,7 @@ public class IntentPushTestCommand extends AbstractShellCommand |
119 | } | 119 | } |
120 | 120 | ||
121 | private void submitIntents(List<Intent> intents) { | 121 | private void submitIntents(List<Intent> intents) { |
122 | - IntentOperations.Builder builder = IntentOperations.builder(); | 122 | + IntentOperations.Builder builder = IntentOperations.builder(appId()); |
123 | for (Intent intent : intents) { | 123 | for (Intent intent : intents) { |
124 | if (add) { | 124 | if (add) { |
125 | builder.addSubmitOperation(intent); | 125 | builder.addSubmitOperation(intent); |
... | @@ -132,7 +132,7 @@ public class IntentPushTestCommand extends AbstractShellCommand | ... | @@ -132,7 +132,7 @@ public class IntentPushTestCommand extends AbstractShellCommand |
132 | start = System.currentTimeMillis(); | 132 | start = System.currentTimeMillis(); |
133 | service.execute(ops); | 133 | service.execute(ops); |
134 | try { | 134 | try { |
135 | - if (latch.await(10, TimeUnit.SECONDS)) { | 135 | + if (latch.await(30, TimeUnit.SECONDS)) { |
136 | printResults(count); | 136 | printResults(count); |
137 | } else { | 137 | } else { |
138 | print("Failure: %d intents not installed", latch.getCount()); | 138 | print("Failure: %d intents not installed", latch.getCount()); | ... | ... |
... | @@ -86,7 +86,7 @@ public class RandomIntentCommand extends AbstractShellCommand { | ... | @@ -86,7 +86,7 @@ public class RandomIntentCommand extends AbstractShellCommand { |
86 | } | 86 | } |
87 | 87 | ||
88 | private void submitIntents(Collection<Intent> intents) { | 88 | private void submitIntents(Collection<Intent> intents) { |
89 | - IntentOperations.Builder builder = IntentOperations.builder(); | 89 | + IntentOperations.Builder builder = IntentOperations.builder(appId()); |
90 | for (Intent intent : intents) { | 90 | for (Intent intent : intents) { |
91 | builder.addSubmitOperation(intent); | 91 | builder.addSubmitOperation(intent); |
92 | } | 92 | } |
... | @@ -95,7 +95,7 @@ public class RandomIntentCommand extends AbstractShellCommand { | ... | @@ -95,7 +95,7 @@ public class RandomIntentCommand extends AbstractShellCommand { |
95 | } | 95 | } |
96 | 96 | ||
97 | private void withdrawIntents() { | 97 | private void withdrawIntents() { |
98 | - IntentOperations.Builder builder = IntentOperations.builder(); | 98 | + IntentOperations.Builder builder = IntentOperations.builder(appId()); |
99 | for (Intent intent : service.getIntents()) { | 99 | for (Intent intent : service.getIntents()) { |
100 | if (appId().equals(intent.appId())) { | 100 | if (appId().equals(intent.appId())) { |
101 | builder.addWithdrawOperation(intent.id()); | 101 | builder.addWithdrawOperation(intent.id()); | ... | ... |
... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.intent; | 16 | package org.onlab.onos.net.intent; |
17 | 17 | ||
18 | +import org.onlab.onos.core.ApplicationId; | ||
19 | + | ||
18 | import java.util.Set; | 20 | import java.util.Set; |
19 | 21 | ||
20 | /** | 22 | /** |
... | @@ -46,9 +48,20 @@ public interface IntentBatchService { | ... | @@ -46,9 +48,20 @@ public interface IntentBatchService { |
46 | * Returns the set of intent batches currently being processed. | 48 | * Returns the set of intent batches currently being processed. |
47 | * @return set of batches | 49 | * @return set of batches |
48 | */ | 50 | */ |
51 | + //TODO we may want to get rid of this method | ||
52 | + @Deprecated | ||
49 | Set<IntentOperations> getCurrentOperations(); | 53 | Set<IntentOperations> getCurrentOperations(); |
50 | 54 | ||
51 | /** | 55 | /** |
56 | + * Return true if this instance is the local leader for batch | ||
57 | + * processing a given application id. | ||
58 | + * | ||
59 | + * @param applicationId | ||
60 | + * @return | ||
61 | + */ | ||
62 | + boolean isLocalLeader(ApplicationId applicationId); | ||
63 | + | ||
64 | + /** | ||
52 | * Sets the batch service delegate. | 65 | * Sets the batch service delegate. |
53 | * | 66 | * |
54 | * @param delegate delegate to apply | 67 | * @param delegate delegate to apply | ... | ... |
... | @@ -19,6 +19,7 @@ import java.util.List; | ... | @@ -19,6 +19,7 @@ import java.util.List; |
19 | import java.util.Objects; | 19 | import java.util.Objects; |
20 | 20 | ||
21 | import com.google.common.collect.ImmutableList; | 21 | import com.google.common.collect.ImmutableList; |
22 | +import org.onlab.onos.core.ApplicationId; | ||
22 | 23 | ||
23 | import static com.google.common.base.MoreObjects.toStringHelper; | 24 | import static com.google.common.base.MoreObjects.toStringHelper; |
24 | import static com.google.common.base.Preconditions.checkNotNull; | 25 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -33,14 +34,16 @@ import static org.onlab.onos.net.intent.IntentOperation.Type.WITHDRAW; | ... | @@ -33,14 +34,16 @@ import static org.onlab.onos.net.intent.IntentOperation.Type.WITHDRAW; |
33 | public final class IntentOperations { | 34 | public final class IntentOperations { |
34 | 35 | ||
35 | private final List<IntentOperation> operations; | 36 | private final List<IntentOperation> operations; |
37 | + private final ApplicationId appId; | ||
36 | 38 | ||
37 | /** | 39 | /** |
38 | * Creates a batch of intent operations using the supplied list. | 40 | * Creates a batch of intent operations using the supplied list. |
39 | * | 41 | * |
40 | * @param operations list of intent operations | 42 | * @param operations list of intent operations |
41 | */ | 43 | */ |
42 | - private IntentOperations(List<IntentOperation> operations) { | 44 | + private IntentOperations(List<IntentOperation> operations, ApplicationId appId) { |
43 | this.operations = operations; | 45 | this.operations = operations; |
46 | + this.appId = appId; | ||
44 | } | 47 | } |
45 | 48 | ||
46 | /** | 49 | /** |
... | @@ -52,16 +55,20 @@ public final class IntentOperations { | ... | @@ -52,16 +55,20 @@ public final class IntentOperations { |
52 | return operations; | 55 | return operations; |
53 | } | 56 | } |
54 | 57 | ||
58 | + public ApplicationId appId() { | ||
59 | + return appId; | ||
60 | + } | ||
61 | + | ||
55 | /** | 62 | /** |
56 | * Returns a builder for intent operation batches. | 63 | * Returns a builder for intent operation batches. |
57 | * | 64 | * |
58 | * @return intent operations builder | 65 | * @return intent operations builder |
66 | + * @param applicationId application id | ||
59 | */ | 67 | */ |
60 | - public static Builder builder() { | 68 | + public static Builder builder(ApplicationId applicationId) { |
61 | - return new Builder(); | 69 | + return new Builder(applicationId); |
62 | } | 70 | } |
63 | 71 | ||
64 | - | ||
65 | @Override | 72 | @Override |
66 | public int hashCode() { | 73 | public int hashCode() { |
67 | return Objects.hash(operations); | 74 | return Objects.hash(operations); |
... | @@ -92,9 +99,11 @@ public final class IntentOperations { | ... | @@ -92,9 +99,11 @@ public final class IntentOperations { |
92 | public static final class Builder { | 99 | public static final class Builder { |
93 | 100 | ||
94 | private final ImmutableList.Builder<IntentOperation> builder = ImmutableList.builder(); | 101 | private final ImmutableList.Builder<IntentOperation> builder = ImmutableList.builder(); |
102 | + private final ApplicationId appId; | ||
95 | 103 | ||
96 | // Public construction is forbidden. | 104 | // Public construction is forbidden. |
97 | - private Builder() { | 105 | + private Builder(ApplicationId appId) { |
106 | + this.appId = appId; | ||
98 | } | 107 | } |
99 | 108 | ||
100 | /** | 109 | /** |
... | @@ -153,7 +162,7 @@ public final class IntentOperations { | ... | @@ -153,7 +162,7 @@ public final class IntentOperations { |
153 | * @return immutable batch of intent operations | 162 | * @return immutable batch of intent operations |
154 | */ | 163 | */ |
155 | public IntentOperations build() { | 164 | public IntentOperations build() { |
156 | - return new IntentOperations(builder.build()); | 165 | + return new IntentOperations(builder.build(), appId); |
157 | } | 166 | } |
158 | 167 | ||
159 | } | 168 | } | ... | ... |
... | @@ -82,7 +82,7 @@ public interface Lock { | ... | @@ -82,7 +82,7 @@ public interface Lock { |
82 | * lock acquisition events | 82 | * lock acquisition events |
83 | * @return epoch | 83 | * @return epoch |
84 | */ | 84 | */ |
85 | - long epoch(); | 85 | + long epoch(); |
86 | 86 | ||
87 | /** | 87 | /** |
88 | * Releases the lock. | 88 | * Releases the lock. | ... | ... |
... | @@ -78,15 +78,15 @@ public class IntentOperationsTest { | ... | @@ -78,15 +78,15 @@ public class IntentOperationsTest { |
78 | @Test | 78 | @Test |
79 | public void testEquals() { | 79 | public void testEquals() { |
80 | final IntentOperations operations1 = | 80 | final IntentOperations operations1 = |
81 | - IntentOperations.builder() | 81 | + IntentOperations.builder(null) //FIXME null |
82 | .addSubmitOperation(intent) | 82 | .addSubmitOperation(intent) |
83 | .build(); | 83 | .build(); |
84 | final IntentOperations sameAsOperations1 = | 84 | final IntentOperations sameAsOperations1 = |
85 | - IntentOperations.builder() | 85 | + IntentOperations.builder(null) //FIXME null |
86 | .addSubmitOperation(intent) | 86 | .addSubmitOperation(intent) |
87 | .build(); | 87 | .build(); |
88 | final IntentOperations operations2 = | 88 | final IntentOperations operations2 = |
89 | - IntentOperations.builder() | 89 | + IntentOperations.builder(null) //FIXME null |
90 | .addReplaceOperation(intent.id(), intent) | 90 | .addReplaceOperation(intent.id(), intent) |
91 | .build(); | 91 | .build(); |
92 | 92 | ||
... | @@ -102,7 +102,7 @@ public class IntentOperationsTest { | ... | @@ -102,7 +102,7 @@ public class IntentOperationsTest { |
102 | @Test | 102 | @Test |
103 | public void testConstruction() { | 103 | public void testConstruction() { |
104 | final IntentOperations operations = | 104 | final IntentOperations operations = |
105 | - IntentOperations.builder() | 105 | + IntentOperations.builder(null) //FIXME |
106 | .addUpdateOperation(intent.id()) | 106 | .addUpdateOperation(intent.id()) |
107 | .addWithdrawOperation(intent.id()) | 107 | .addWithdrawOperation(intent.id()) |
108 | .build(); | 108 | .build(); | ... | ... |
... | @@ -33,6 +33,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -33,6 +33,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
33 | import org.apache.felix.scr.annotations.Reference; | 33 | import org.apache.felix.scr.annotations.Reference; |
34 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 34 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
35 | import org.apache.felix.scr.annotations.Service; | 35 | import org.apache.felix.scr.annotations.Service; |
36 | +import org.onlab.onos.core.ApplicationId; | ||
36 | import org.onlab.onos.core.CoreService; | 37 | import org.onlab.onos.core.CoreService; |
37 | import org.onlab.onos.core.IdGenerator; | 38 | import org.onlab.onos.core.IdGenerator; |
38 | import org.onlab.onos.event.AbstractListenerRegistry; | 39 | import org.onlab.onos.event.AbstractListenerRegistry; |
... | @@ -151,20 +152,22 @@ public class IntentManager | ... | @@ -151,20 +152,22 @@ public class IntentManager |
151 | @Override | 152 | @Override |
152 | public void submit(Intent intent) { | 153 | public void submit(Intent intent) { |
153 | checkNotNull(intent, INTENT_NULL); | 154 | checkNotNull(intent, INTENT_NULL); |
154 | - execute(IntentOperations.builder().addSubmitOperation(intent).build()); | 155 | + execute(IntentOperations.builder(intent.appId()) |
156 | + .addSubmitOperation(intent).build()); | ||
155 | } | 157 | } |
156 | 158 | ||
157 | @Override | 159 | @Override |
158 | public void withdraw(Intent intent) { | 160 | public void withdraw(Intent intent) { |
159 | checkNotNull(intent, INTENT_NULL); | 161 | checkNotNull(intent, INTENT_NULL); |
160 | - execute(IntentOperations.builder().addWithdrawOperation(intent.id()).build()); | 162 | + execute(IntentOperations.builder(intent.appId()) |
163 | + .addWithdrawOperation(intent.id()).build()); | ||
161 | } | 164 | } |
162 | 165 | ||
163 | @Override | 166 | @Override |
164 | public void replace(IntentId oldIntentId, Intent newIntent) { | 167 | public void replace(IntentId oldIntentId, Intent newIntent) { |
165 | checkNotNull(oldIntentId, INTENT_ID_NULL); | 168 | checkNotNull(oldIntentId, INTENT_ID_NULL); |
166 | checkNotNull(newIntent, INTENT_NULL); | 169 | checkNotNull(newIntent, INTENT_NULL); |
167 | - execute(IntentOperations.builder() | 170 | + execute(IntentOperations.builder(newIntent.appId()) |
168 | .addReplaceOperation(oldIntentId, newIntent) | 171 | .addReplaceOperation(oldIntentId, newIntent) |
169 | .build()); | 172 | .build()); |
170 | } | 173 | } |
... | @@ -489,26 +492,50 @@ public class IntentManager | ... | @@ -489,26 +492,50 @@ public class IntentManager |
489 | } | 492 | } |
490 | } | 493 | } |
491 | 494 | ||
492 | - // Topology change delegate | 495 | + private void buildAndSubmitBatches(Iterable<IntentId> intentIds, |
493 | - private class InternalTopoChangeDelegate implements TopologyChangeDelegate { | 496 | + boolean compileAllFailed) { |
494 | - @Override | 497 | + Map<ApplicationId, IntentOperations.Builder> batches = Maps.newHashMap(); |
495 | - public void triggerCompile(Iterable<IntentId> intentIds, | 498 | + // Attempt recompilation of the specified intents first. |
496 | - boolean compileAllFailed) { | 499 | + for (IntentId id : intentIds) { |
497 | - // Attempt recompilation of the specified intents first. | 500 | + Intent intent = store.getIntent(id); |
498 | - IntentOperations.Builder builder = IntentOperations.builder(); | 501 | + if (intent == null) { |
499 | - for (IntentId id : intentIds) { | 502 | + continue; |
500 | - builder.addUpdateOperation(id); | ||
501 | } | 503 | } |
504 | + IntentOperations.Builder builder = batches.get(intent.appId()); | ||
505 | + if (builder == null) { | ||
506 | + builder = IntentOperations.builder(intent.appId()); | ||
507 | + batches.put(intent.appId(), builder); | ||
508 | + } | ||
509 | + builder.addUpdateOperation(id); | ||
510 | + } | ||
502 | 511 | ||
503 | - if (compileAllFailed) { | 512 | + if (compileAllFailed) { |
504 | - // If required, compile all currently failed intents. | 513 | + // If required, compile all currently failed intents. |
505 | - for (Intent intent : getIntents()) { | 514 | + for (Intent intent : getIntents()) { |
506 | - if (getIntentState(intent.id()) == FAILED) { | 515 | + if (getIntentState(intent.id()) == FAILED) { |
507 | - builder.addUpdateOperation(intent.id()); | 516 | + IntentOperations.Builder builder = batches.get(intent.appId()); |
517 | + if (builder == null) { | ||
518 | + builder = IntentOperations.builder(intent.appId()); | ||
519 | + batches.put(intent.appId(), builder); | ||
508 | } | 520 | } |
521 | + builder.addUpdateOperation(intent.id()); | ||
509 | } | 522 | } |
510 | } | 523 | } |
511 | - execute(builder.build()); | 524 | + } |
525 | + | ||
526 | + for (ApplicationId appId : batches.keySet()) { | ||
527 | + if (batchService.isLocalLeader(appId)) { | ||
528 | + execute(batches.get(appId).build()); | ||
529 | + } | ||
530 | + } | ||
531 | + } | ||
532 | + | ||
533 | + // Topology change delegate | ||
534 | + private class InternalTopoChangeDelegate implements TopologyChangeDelegate { | ||
535 | + @Override | ||
536 | + public void triggerCompile(Iterable<IntentId> intentIds, | ||
537 | + boolean compileAllFailed) { | ||
538 | + buildAndSubmitBatches(intentIds, compileAllFailed); | ||
512 | } | 539 | } |
513 | } | 540 | } |
514 | 541 | ... | ... |
... | @@ -216,5 +216,8 @@ public class ObjectiveTracker implements ObjectiveTrackerService { | ... | @@ -216,5 +216,8 @@ public class ObjectiveTracker implements ObjectiveTrackerService { |
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | + //TODO consider adding flow rule event tracking | ||
219 | 220 | ||
221 | + //FIXME the only intents that will be tracked are events that were | ||
222 | + //executed on this instance. Need to have some backup trackers... | ||
220 | } | 223 | } | ... | ... |
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.store.hz; | ||
17 | + | ||
18 | +import com.hazelcast.core.IQueue; | ||
19 | +import com.hazelcast.core.ItemListener; | ||
20 | +import com.hazelcast.monitor.LocalQueueStats; | ||
21 | +import org.onlab.onos.store.serializers.StoreSerializer; | ||
22 | + | ||
23 | +import java.util.Collection; | ||
24 | +import java.util.Iterator; | ||
25 | +import java.util.concurrent.TimeUnit; | ||
26 | + | ||
27 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
28 | + | ||
29 | +// TODO: implementation is incomplete | ||
30 | + | ||
31 | +/** | ||
32 | + * Wrapper around IQueue<byte[]> which serializes/deserializes | ||
33 | + * key and value using StoreSerializer. | ||
34 | + * | ||
35 | + * @param <T> type | ||
36 | + */ | ||
37 | +public class SQueue<T> implements IQueue<T> { | ||
38 | + | ||
39 | + private final IQueue<byte[]> q; | ||
40 | + private final StoreSerializer serializer; | ||
41 | + | ||
42 | + /** | ||
43 | + * Creates a SQueue instance. | ||
44 | + * | ||
45 | + * @param baseQueue base IQueue to use | ||
46 | + * @param serializer serializer to use for both key and value | ||
47 | + */ | ||
48 | + public SQueue(IQueue<byte[]> baseQueue, StoreSerializer serializer) { | ||
49 | + this.q = checkNotNull(baseQueue); | ||
50 | + this.serializer = checkNotNull(serializer); | ||
51 | + } | ||
52 | + | ||
53 | + private byte[] serialize(Object key) { | ||
54 | + return serializer.encode(key); | ||
55 | + } | ||
56 | + | ||
57 | + private T deserialize(byte[] key) { | ||
58 | + return serializer.decode(key); | ||
59 | + } | ||
60 | + | ||
61 | + @Override | ||
62 | + public boolean add(T t) { | ||
63 | + return q.add(serialize(t)); | ||
64 | + } | ||
65 | + | ||
66 | + @Override | ||
67 | + public boolean offer(T t) { | ||
68 | + return q.offer(serialize(t)); | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
72 | + public void put(T t) throws InterruptedException { | ||
73 | + q.put(serialize(t)); | ||
74 | + } | ||
75 | + | ||
76 | + @Override | ||
77 | + public boolean offer(T t, long l, TimeUnit timeUnit) throws InterruptedException { | ||
78 | + return q.offer(serialize(t), l, timeUnit); | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + public T take() throws InterruptedException { | ||
83 | + return deserialize(q.take()); | ||
84 | + } | ||
85 | + | ||
86 | + @Override | ||
87 | + public T poll(long l, TimeUnit timeUnit) throws InterruptedException { | ||
88 | + return deserialize(q.poll(l, timeUnit)); | ||
89 | + } | ||
90 | + | ||
91 | + @Override | ||
92 | + public int remainingCapacity() { | ||
93 | + return q.remainingCapacity(); | ||
94 | + } | ||
95 | + | ||
96 | + @Override | ||
97 | + public boolean remove(Object o) { | ||
98 | + return q.remove(serialize(o)); | ||
99 | + } | ||
100 | + | ||
101 | + @Override | ||
102 | + public boolean contains(Object o) { | ||
103 | + return q.contains(serialize(o)); | ||
104 | + } | ||
105 | + | ||
106 | + @Override | ||
107 | + public int drainTo(Collection<? super T> collection) { | ||
108 | + throw new UnsupportedOperationException(); | ||
109 | + } | ||
110 | + | ||
111 | + @Override | ||
112 | + public int drainTo(Collection<? super T> collection, int i) { | ||
113 | + throw new UnsupportedOperationException(); | ||
114 | + } | ||
115 | + | ||
116 | + @Override | ||
117 | + public T remove() { | ||
118 | + return deserialize(q.remove()); | ||
119 | + } | ||
120 | + | ||
121 | + @Override | ||
122 | + public T poll() { | ||
123 | + return deserialize(q.poll()); | ||
124 | + } | ||
125 | + | ||
126 | + @Override | ||
127 | + public T element() { | ||
128 | + return deserialize(q.element()); | ||
129 | + } | ||
130 | + | ||
131 | + @Override | ||
132 | + public T peek() { | ||
133 | + return deserialize(q.peek()); | ||
134 | + } | ||
135 | + | ||
136 | + @Override | ||
137 | + public int size() { | ||
138 | + return q.size(); | ||
139 | + } | ||
140 | + | ||
141 | + @Override | ||
142 | + public boolean isEmpty() { | ||
143 | + return q.isEmpty(); | ||
144 | + } | ||
145 | + | ||
146 | + @Override | ||
147 | + public Iterator<T> iterator() { | ||
148 | + throw new UnsupportedOperationException(); | ||
149 | + } | ||
150 | + | ||
151 | + @Override | ||
152 | + public Object[] toArray() { | ||
153 | + throw new UnsupportedOperationException(); | ||
154 | + } | ||
155 | + | ||
156 | + @Override | ||
157 | + public <T1> T1[] toArray(T1[] t1s) { | ||
158 | + throw new UnsupportedOperationException(); | ||
159 | + } | ||
160 | + | ||
161 | + @Override | ||
162 | + public boolean containsAll(Collection<?> collection) { | ||
163 | + throw new UnsupportedOperationException(); | ||
164 | + } | ||
165 | + | ||
166 | + @Override | ||
167 | + public boolean addAll(Collection<? extends T> collection) { | ||
168 | + throw new UnsupportedOperationException(); | ||
169 | + } | ||
170 | + | ||
171 | + @Override | ||
172 | + public boolean removeAll(Collection<?> collection) { | ||
173 | + throw new UnsupportedOperationException(); | ||
174 | + } | ||
175 | + | ||
176 | + @Override | ||
177 | + public boolean retainAll(Collection<?> collection) { | ||
178 | + throw new UnsupportedOperationException(); | ||
179 | + } | ||
180 | + | ||
181 | + @Override | ||
182 | + public void clear() { | ||
183 | + q.clear(); | ||
184 | + } | ||
185 | + | ||
186 | + @Override | ||
187 | + public LocalQueueStats getLocalQueueStats() { | ||
188 | + return q.getLocalQueueStats(); | ||
189 | + } | ||
190 | + | ||
191 | + @Override | ||
192 | + public String addItemListener(ItemListener<T> itemListener, boolean b) { | ||
193 | + throw new UnsupportedOperationException(); | ||
194 | + } | ||
195 | + | ||
196 | + @Override | ||
197 | + public boolean removeItemListener(String s) { | ||
198 | + throw new UnsupportedOperationException(); | ||
199 | + } | ||
200 | + | ||
201 | + @Deprecated | ||
202 | + @Override | ||
203 | + public Object getId() { | ||
204 | + return q.getId(); | ||
205 | + } | ||
206 | + | ||
207 | + @Override | ||
208 | + public String getPartitionKey() { | ||
209 | + return q.getPartitionKey(); | ||
210 | + } | ||
211 | + | ||
212 | + @Override | ||
213 | + public String getName() { | ||
214 | + return q.getName(); | ||
215 | + } | ||
216 | + | ||
217 | + @Override | ||
218 | + public String getServiceName() { | ||
219 | + return q.getServiceName(); | ||
220 | + } | ||
221 | + | ||
222 | + @Override | ||
223 | + public void destroy() { | ||
224 | + q.destroy(); | ||
225 | + } | ||
226 | +} |
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.store.intent.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.onlab.onos.net.intent.IntentBatchDelegate; | ||
24 | -import org.onlab.onos.net.intent.IntentBatchService; | ||
25 | -import org.onlab.onos.net.intent.IntentOperations; | ||
26 | -import org.slf4j.Logger; | ||
27 | - | ||
28 | -import java.util.LinkedList; | ||
29 | -import java.util.Queue; | ||
30 | -import java.util.Set; | ||
31 | - | ||
32 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
33 | -import static com.google.common.base.Preconditions.checkState; | ||
34 | -import static org.slf4j.LoggerFactory.getLogger; | ||
35 | - | ||
36 | -// FIXME This is not distributed yet. | ||
37 | -@Component(immediate = true) | ||
38 | -@Service | ||
39 | -public class DistributedIntentBatchQueue implements IntentBatchService { | ||
40 | - | ||
41 | - private final Logger log = getLogger(getClass()); | ||
42 | - private final Queue<IntentOperations> pendingBatches = new LinkedList<>(); | ||
43 | - private final Set<IntentOperations> currentBatches = Sets.newHashSet(); | ||
44 | - private IntentBatchDelegate delegate; | ||
45 | - | ||
46 | - @Activate | ||
47 | - public void activate() { | ||
48 | - log.info("Started"); | ||
49 | - } | ||
50 | - | ||
51 | - @Deactivate | ||
52 | - public void deactivate() { | ||
53 | - log.info("Stopped"); | ||
54 | - } | ||
55 | - | ||
56 | - @Override | ||
57 | - public void addIntentOperations(IntentOperations operations) { | ||
58 | - checkState(delegate != null, "No delegate set"); | ||
59 | - synchronized (this) { | ||
60 | - pendingBatches.add(operations); | ||
61 | - if (currentBatches.isEmpty()) { | ||
62 | - IntentOperations work = pendingBatches.poll(); | ||
63 | - currentBatches.add(work); | ||
64 | - delegate.execute(work); | ||
65 | - } | ||
66 | - } | ||
67 | - } | ||
68 | - | ||
69 | - @Override | ||
70 | - public void removeIntentOperations(IntentOperations operations) { | ||
71 | - // we allow at most one outstanding batch at a time | ||
72 | - synchronized (this) { | ||
73 | - checkState(currentBatches.remove(operations), "Operations not found in current ops."); | ||
74 | - checkState(currentBatches.isEmpty(), "More than one outstanding batch."); | ||
75 | - IntentOperations work = pendingBatches.poll(); | ||
76 | - if (work != null) { | ||
77 | - currentBatches.add(work); | ||
78 | - delegate.execute(work); | ||
79 | - } | ||
80 | - } | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public Set<IntentOperations> getPendingOperations() { | ||
85 | - synchronized (this) { | ||
86 | - return Sets.newHashSet(pendingBatches); | ||
87 | - } | ||
88 | - } | ||
89 | - | ||
90 | - @Override | ||
91 | - public Set<IntentOperations> getCurrentOperations() { | ||
92 | - synchronized (this) { | ||
93 | - return Sets.newHashSet(currentBatches); | ||
94 | - } | ||
95 | - } | ||
96 | - | ||
97 | - @Override | ||
98 | - public void setDelegate(IntentBatchDelegate delegate) { | ||
99 | - this.delegate = checkNotNull(delegate, "Delegate cannot be null"); | ||
100 | - } | ||
101 | - | ||
102 | - @Override | ||
103 | - public void unsetDelegate(IntentBatchDelegate delegate) { | ||
104 | - if (this.delegate != null && this.delegate.equals(delegate)) { | ||
105 | - this.delegate = null; | ||
106 | - } | ||
107 | - } | ||
108 | -} |
core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/HazelcastIntentBatchQueue.java
0 → 100644
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.store.intent.impl; | ||
17 | + | ||
18 | +import com.google.common.collect.Maps; | ||
19 | +import com.google.common.collect.Sets; | ||
20 | +import com.hazelcast.core.HazelcastInstance; | ||
21 | +import com.hazelcast.core.IQueue; | ||
22 | +import org.apache.felix.scr.annotations.Activate; | ||
23 | +import org.apache.felix.scr.annotations.Component; | ||
24 | +import org.apache.felix.scr.annotations.Deactivate; | ||
25 | +import org.apache.felix.scr.annotations.Reference; | ||
26 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
27 | +import org.apache.felix.scr.annotations.Service; | ||
28 | +import org.onlab.onos.cluster.ClusterService; | ||
29 | +import org.onlab.onos.cluster.ControllerNode; | ||
30 | +import org.onlab.onos.cluster.LeadershipEvent; | ||
31 | +import org.onlab.onos.cluster.LeadershipEventListener; | ||
32 | +import org.onlab.onos.cluster.LeadershipService; | ||
33 | +import org.onlab.onos.core.ApplicationId; | ||
34 | +import org.onlab.onos.core.CoreService; | ||
35 | +import org.onlab.onos.net.intent.IntentBatchDelegate; | ||
36 | +import org.onlab.onos.net.intent.IntentBatchService; | ||
37 | +import org.onlab.onos.net.intent.IntentOperations; | ||
38 | +import org.onlab.onos.store.hz.SQueue; | ||
39 | +import org.onlab.onos.store.hz.StoreService; | ||
40 | +import org.onlab.onos.store.serializers.KryoNamespaces; | ||
41 | +import org.onlab.onos.store.serializers.KryoSerializer; | ||
42 | +import org.onlab.onos.store.serializers.StoreSerializer; | ||
43 | +import org.onlab.util.KryoNamespace; | ||
44 | +import org.slf4j.Logger; | ||
45 | + | ||
46 | +import java.util.Collections; | ||
47 | +import java.util.Map; | ||
48 | +import java.util.Set; | ||
49 | + | ||
50 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
51 | +import static com.google.common.base.Preconditions.checkState; | ||
52 | +import static org.slf4j.LoggerFactory.getLogger; | ||
53 | + | ||
54 | +@Component(immediate = true) | ||
55 | +@Service | ||
56 | +public class HazelcastIntentBatchQueue | ||
57 | + implements IntentBatchService { | ||
58 | + | ||
59 | + private final Logger log = getLogger(getClass()); | ||
60 | + private static final String TOPIC_BASE = "intent-batch-"; | ||
61 | + | ||
62 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
63 | + protected CoreService coreService; | ||
64 | + | ||
65 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
66 | + protected ClusterService clusterService; | ||
67 | + | ||
68 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
69 | + protected LeadershipService leadershipService; | ||
70 | + | ||
71 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
72 | + protected StoreService storeService; | ||
73 | + | ||
74 | + private HazelcastInstance theInstance; | ||
75 | + private ControllerNode localControllerNode; | ||
76 | + protected StoreSerializer serializer; | ||
77 | + private IntentBatchDelegate delegate; | ||
78 | + private InternalLeaderListener leaderListener = new InternalLeaderListener(); | ||
79 | + private final Map<ApplicationId, SQueue<IntentOperations>> batchQueues | ||
80 | + = Maps.newHashMap(); // FIXME make distributed? | ||
81 | + private final Set<ApplicationId> myTopics = Sets.newHashSet(); | ||
82 | + private final Map<ApplicationId, IntentOperations> outstandingOps | ||
83 | + = Maps.newHashMap(); | ||
84 | + | ||
85 | + @Activate | ||
86 | + public void activate() { | ||
87 | + theInstance = storeService.getHazelcastInstance(); | ||
88 | + localControllerNode = clusterService.getLocalNode(); | ||
89 | + leadershipService.addListener(leaderListener); | ||
90 | + | ||
91 | + serializer = new KryoSerializer() { | ||
92 | + | ||
93 | + @Override | ||
94 | + protected void setupKryoPool() { | ||
95 | + serializerPool = KryoNamespace.newBuilder() | ||
96 | + .setRegistrationRequired(false) | ||
97 | + .register(KryoNamespaces.API) | ||
98 | + .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID) | ||
99 | + .build(); | ||
100 | + } | ||
101 | + | ||
102 | + }; | ||
103 | + log.info("Started"); | ||
104 | + } | ||
105 | + | ||
106 | + @Deactivate | ||
107 | + public void deactivate() { | ||
108 | + leadershipService.removeListener(leaderListener); | ||
109 | + log.info("Stopped"); | ||
110 | + } | ||
111 | + | ||
112 | + public static String getTopic(ApplicationId appId) { | ||
113 | + return TOPIC_BASE + checkNotNull(appId.id()); | ||
114 | + } | ||
115 | + | ||
116 | + public ApplicationId getAppId(String topic) { | ||
117 | + checkState(topic.startsWith(TOPIC_BASE), | ||
118 | + "Trying to get app id for invalid topic: {}", topic); | ||
119 | + Short id = Short.parseShort(topic.substring(TOPIC_BASE.length())); | ||
120 | + return coreService.getAppId(id); | ||
121 | + } | ||
122 | + | ||
123 | + private SQueue<IntentOperations> getQueue(ApplicationId appId) { | ||
124 | + SQueue<IntentOperations> queue = batchQueues.get(appId); | ||
125 | + if (queue == null) { | ||
126 | + synchronized (this) { | ||
127 | + // FIXME how will other instances find out about new queues | ||
128 | + String topic = getTopic(appId); | ||
129 | + IQueue<byte[]> rawQueue = theInstance.getQueue(topic); | ||
130 | + queue = new SQueue<>(rawQueue, serializer); | ||
131 | + batchQueues.putIfAbsent(appId, queue); | ||
132 | + // TODO others should run for leadership when they hear about this topic | ||
133 | + leadershipService.runForLeadership(topic); | ||
134 | + } | ||
135 | + } | ||
136 | + return queue; | ||
137 | + } | ||
138 | + | ||
139 | + @Override | ||
140 | + public void addIntentOperations(IntentOperations ops) { | ||
141 | + checkNotNull(ops, "Intent operations cannot be null."); | ||
142 | + ApplicationId appId = ops.appId(); | ||
143 | + getQueue(appId).add(ops); // TODO consider using put here | ||
144 | + dispatchNextOperation(appId); | ||
145 | + } | ||
146 | + | ||
147 | + @Override | ||
148 | + public void removeIntentOperations(IntentOperations ops) { | ||
149 | + ApplicationId appId = ops.appId(); | ||
150 | + synchronized (this) { | ||
151 | + checkState(outstandingOps.get(appId).equals(ops), | ||
152 | + "Operations not found."); | ||
153 | + SQueue<IntentOperations> queue = batchQueues.get(appId); | ||
154 | + // TODO consider alternatives to remove | ||
155 | + checkState(queue.remove().equals(ops), | ||
156 | + "Operations are wrong."); | ||
157 | + outstandingOps.remove(appId); | ||
158 | + dispatchNextOperation(appId); | ||
159 | + } | ||
160 | + } | ||
161 | + | ||
162 | + /** | ||
163 | + * Dispatches the next available operations to the delegate, unless | ||
164 | + * we are not the leader for this application id or there is an | ||
165 | + * outstanding operations for this application id. | ||
166 | + * | ||
167 | + * @param appId application id | ||
168 | + */ | ||
169 | + private void dispatchNextOperation(ApplicationId appId) { | ||
170 | + synchronized (this) { | ||
171 | + if (!myTopics.contains(appId) || | ||
172 | + outstandingOps.containsKey(appId)) { | ||
173 | + return; | ||
174 | + } | ||
175 | + IntentOperations ops = batchQueues.get(appId).peek(); | ||
176 | + if (ops != null) { | ||
177 | + outstandingOps.put(appId, ops); | ||
178 | + delegate.execute(ops); | ||
179 | + } | ||
180 | + } | ||
181 | + } | ||
182 | + | ||
183 | + /** | ||
184 | + * Record the leadership change for the given topic. If we have become the | ||
185 | + * leader, then dispatch the next operations. If we have lost leadership, | ||
186 | + * then cancel the last operations. | ||
187 | + * | ||
188 | + * @param topic topic based on application id | ||
189 | + * @param leader true if we have become the leader, false otherwise | ||
190 | + */ | ||
191 | + private void leaderChanged(String topic, boolean leader) { | ||
192 | + ApplicationId appId = getAppId(topic); | ||
193 | + //TODO we are using the event caller's thread, should we use our own? | ||
194 | + synchronized (this) { | ||
195 | + if (leader) { | ||
196 | + myTopics.add(appId); | ||
197 | + checkState(!outstandingOps.containsKey(appId), | ||
198 | + "Existing intent ops for app id: {}", appId); | ||
199 | + dispatchNextOperation(appId); | ||
200 | + } else { | ||
201 | + myTopics.remove(appId); | ||
202 | + IntentOperations ops = outstandingOps.get(appId); | ||
203 | + if (ops != null) { | ||
204 | + delegate.cancel(ops); | ||
205 | + } | ||
206 | + outstandingOps.remove(appId); | ||
207 | + } | ||
208 | + } | ||
209 | + } | ||
210 | + | ||
211 | + private class InternalLeaderListener implements LeadershipEventListener { | ||
212 | + @Override | ||
213 | + public void event(LeadershipEvent event) { | ||
214 | + log.debug("Leadership Event: time = {} type = {} event = {}", | ||
215 | + event.time(), event.type(), event); | ||
216 | + | ||
217 | + String topic = event.subject().topic(); | ||
218 | + if (!topic.startsWith(TOPIC_BASE)) { | ||
219 | + return; // Not our topic: ignore | ||
220 | + } | ||
221 | + if (!event.subject().leader().id().equals(localControllerNode.id())) { | ||
222 | + return; // The event is not about this instance: ignore | ||
223 | + } | ||
224 | + | ||
225 | + switch (event.type()) { | ||
226 | + case LEADER_ELECTED: | ||
227 | + log.info("Elected leader for app {}", getAppId(topic)); | ||
228 | + leaderChanged(topic, true); | ||
229 | + break; | ||
230 | + case LEADER_BOOTED: | ||
231 | + log.info("Lost leader election for app {}", getAppId(topic)); | ||
232 | + leaderChanged(topic, false); | ||
233 | + break; | ||
234 | + case LEADER_REELECTED: | ||
235 | + break; | ||
236 | + default: | ||
237 | + break; | ||
238 | + } | ||
239 | + } | ||
240 | + } | ||
241 | + | ||
242 | + @Override | ||
243 | + public Set<IntentOperations> getPendingOperations() { | ||
244 | + Set<IntentOperations> ops = Sets.newHashSet(); | ||
245 | + synchronized (this) { | ||
246 | + for (SQueue<IntentOperations> queue : batchQueues.values()) { | ||
247 | + ops.addAll(queue); | ||
248 | + } | ||
249 | + return ops; | ||
250 | + } | ||
251 | + } | ||
252 | + | ||
253 | + @Override | ||
254 | + public Set<IntentOperations> getCurrentOperations() { | ||
255 | + //FIXME this is not really implemented | ||
256 | + return Collections.emptySet(); | ||
257 | + } | ||
258 | + | ||
259 | + @Override | ||
260 | + public boolean isLocalLeader(ApplicationId applicationId) { | ||
261 | + return myTopics.contains(applicationId); | ||
262 | + } | ||
263 | + | ||
264 | + @Override | ||
265 | + public void setDelegate(IntentBatchDelegate delegate) { | ||
266 | + this.delegate = checkNotNull(delegate, "Delegate cannot be null"); | ||
267 | + } | ||
268 | + | ||
269 | + @Override | ||
270 | + public void unsetDelegate(IntentBatchDelegate delegate) { | ||
271 | + if (this.delegate != null && this.delegate.equals(delegate)) { | ||
272 | + this.delegate = null; | ||
273 | + } | ||
274 | + } | ||
275 | +} |
... | @@ -73,6 +73,8 @@ import org.onlab.onos.net.intent.ConnectivityIntent; | ... | @@ -73,6 +73,8 @@ import org.onlab.onos.net.intent.ConnectivityIntent; |
73 | import org.onlab.onos.net.intent.HostToHostIntent; | 73 | import org.onlab.onos.net.intent.HostToHostIntent; |
74 | import org.onlab.onos.net.intent.Intent; | 74 | import org.onlab.onos.net.intent.Intent; |
75 | import org.onlab.onos.net.intent.IntentId; | 75 | import org.onlab.onos.net.intent.IntentId; |
76 | +import org.onlab.onos.net.intent.IntentOperation; | ||
77 | +import org.onlab.onos.net.intent.IntentOperations; | ||
76 | import org.onlab.onos.net.intent.IntentState; | 78 | import org.onlab.onos.net.intent.IntentState; |
77 | import org.onlab.onos.net.intent.LinkCollectionIntent; | 79 | import org.onlab.onos.net.intent.LinkCollectionIntent; |
78 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | 80 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; |
... | @@ -275,7 +277,9 @@ public final class KryoNamespaces { | ... | @@ -275,7 +277,9 @@ public final class KryoNamespaces { |
275 | WaypointConstraint.class, | 277 | WaypointConstraint.class, |
276 | ObstacleConstraint.class, | 278 | ObstacleConstraint.class, |
277 | AnnotationConstraint.class, | 279 | AnnotationConstraint.class, |
278 | - BooleanConstraint.class | 280 | + BooleanConstraint.class, |
281 | + IntentOperation.class, | ||
282 | + IntentOperations.class | ||
279 | ) | 283 | ) |
280 | .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) | 284 | .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) |
281 | .register(new URISerializer(), URI.class) | 285 | .register(new URISerializer(), URI.class) | ... | ... |
... | @@ -20,6 +20,7 @@ import org.apache.felix.scr.annotations.Activate; | ... | @@ -20,6 +20,7 @@ import org.apache.felix.scr.annotations.Activate; |
20 | import org.apache.felix.scr.annotations.Component; | 20 | import org.apache.felix.scr.annotations.Component; |
21 | import org.apache.felix.scr.annotations.Deactivate; | 21 | 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.net.intent.IntentBatchDelegate; | 24 | import org.onlab.onos.net.intent.IntentBatchDelegate; |
24 | import org.onlab.onos.net.intent.IntentBatchService; | 25 | import org.onlab.onos.net.intent.IntentBatchService; |
25 | import org.onlab.onos.net.intent.IntentOperations; | 26 | import org.onlab.onos.net.intent.IntentOperations; |
... | @@ -94,6 +95,11 @@ public class SimpleIntentBatchQueue implements IntentBatchService { | ... | @@ -94,6 +95,11 @@ public class SimpleIntentBatchQueue implements IntentBatchService { |
94 | } | 95 | } |
95 | 96 | ||
96 | @Override | 97 | @Override |
98 | + public boolean isLocalLeader(ApplicationId applicationId) { | ||
99 | + return true; | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
97 | public void setDelegate(IntentBatchDelegate delegate) { | 103 | public void setDelegate(IntentBatchDelegate delegate) { |
98 | this.delegate = checkNotNull(delegate, "Delegate cannot be null"); | 104 | this.delegate = checkNotNull(delegate, "Delegate cannot be null"); |
99 | } | 105 | } | ... | ... |
-
Please register or login to post a comment