Committed by
Gerrit Code Review
Initial implementation of distributed intent batch queue
Change-Id: I7ffed03651569ade1be1e8dca905bfaf369b7e03
Showing
18 changed files
with
599 additions
and
144 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,7 +601,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -601,7 +601,7 @@ 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); |
| ... | @@ -627,7 +627,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -627,7 +627,7 @@ 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); | ... | ... |
| ... | @@ -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 | } | ... | ... |
| ... | @@ -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,14 +492,20 @@ public class IntentManager | ... | @@ -489,14 +492,20 @@ 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 { | ||
| 494 | - @Override | ||
| 495 | - public void triggerCompile(Iterable<IntentId> intentIds, | ||
| 496 | boolean compileAllFailed) { | 496 | boolean compileAllFailed) { |
| 497 | + Map<ApplicationId, IntentOperations.Builder> batches = Maps.newHashMap(); | ||
| 497 | // Attempt recompilation of the specified intents first. | 498 | // Attempt recompilation of the specified intents first. |
| 498 | - IntentOperations.Builder builder = IntentOperations.builder(); | ||
| 499 | for (IntentId id : intentIds) { | 499 | for (IntentId id : intentIds) { |
| 500 | + Intent intent = store.getIntent(id); | ||
| 501 | + if (intent == null) { | ||
| 502 | + continue; | ||
| 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 | + } | ||
| 500 | builder.addUpdateOperation(id); | 509 | builder.addUpdateOperation(id); |
| 501 | } | 510 | } |
| 502 | 511 | ||
| ... | @@ -504,11 +513,29 @@ public class IntentManager | ... | @@ -504,11 +513,29 @@ public class IntentManager |
| 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) { |
| 516 | + IntentOperations.Builder builder = batches.get(intent.appId()); | ||
| 517 | + if (builder == null) { | ||
| 518 | + builder = IntentOperations.builder(intent.appId()); | ||
| 519 | + batches.put(intent.appId(), builder); | ||
| 520 | + } | ||
| 507 | builder.addUpdateOperation(intent.id()); | 521 | builder.addUpdateOperation(intent.id()); |
| 508 | } | 522 | } |
| 509 | } | 523 | } |
| 510 | } | 524 | } |
| 511 | - execute(builder.build()); | 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