Committed by
Brian O'Connor
IntentManager: use IntentStore batch APIs
Change-Id: Ie60f3e53f48fa6acbcaf5cf6837bdef12b36a98d
Showing
7 changed files
with
238 additions
and
83 deletions
| ... | @@ -159,6 +159,12 @@ public class SdnIpLeadershipService implements LeadershipService { | ... | @@ -159,6 +159,12 @@ public class SdnIpLeadershipService implements LeadershipService { |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | @Override | 161 | @Override |
| 162 | + public Map<String, Leadership> getLeaderBoard() { | ||
| 163 | + throw new UnsupportedOperationException("I don't know what to do." + | ||
| 164 | + " I wish you luck."); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + @Override | ||
| 162 | public void addListener(LeadershipEventListener listener) { | 168 | public void addListener(LeadershipEventListener listener) { |
| 163 | listenerRegistry.addListener(listener); | 169 | listenerRegistry.addListener(listener); |
| 164 | } | 170 | } | ... | ... |
| ... | @@ -15,10 +15,13 @@ | ... | @@ -15,10 +15,13 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onlab.onos.cli.net; | 16 | package org.onlab.onos.cli.net; |
| 17 | 17 | ||
| 18 | +import com.google.common.collect.ArrayListMultimap; | ||
| 18 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
| 19 | import org.apache.karaf.shell.commands.Argument; | 20 | import org.apache.karaf.shell.commands.Argument; |
| 20 | import org.apache.karaf.shell.commands.Command; | 21 | import org.apache.karaf.shell.commands.Command; |
| 21 | import org.onlab.onos.cli.AbstractShellCommand; | 22 | import org.onlab.onos.cli.AbstractShellCommand; |
| 23 | +import org.onlab.onos.core.ApplicationId; | ||
| 24 | +import org.onlab.onos.core.CoreService; | ||
| 22 | import org.onlab.onos.net.ConnectPoint; | 25 | import org.onlab.onos.net.ConnectPoint; |
| 23 | import org.onlab.onos.net.DeviceId; | 26 | import org.onlab.onos.net.DeviceId; |
| 24 | import org.onlab.onos.net.PortNumber; | 27 | import org.onlab.onos.net.PortNumber; |
| ... | @@ -61,17 +64,27 @@ public class IntentPushTestCommand extends AbstractShellCommand | ... | @@ -61,17 +64,27 @@ public class IntentPushTestCommand extends AbstractShellCommand |
| 61 | required = true, multiValued = false) | 64 | required = true, multiValued = false) |
| 62 | String egressDeviceString = null; | 65 | String egressDeviceString = null; |
| 63 | 66 | ||
| 64 | - @Argument(index = 2, name = "count", | 67 | + |
| 65 | - description = "Number of intents to push", | 68 | + @Argument(index = 2, name = "Intents per appId", |
| 69 | + description = "Number of intents per appId", | ||
| 66 | required = true, multiValued = false) | 70 | required = true, multiValued = false) |
| 67 | - String countString = null; | 71 | + String intentsPerAppId = null; |
| 72 | + | ||
| 73 | + @Argument(index = 3, name = "apps", | ||
| 74 | + description = "Number of appIds", | ||
| 75 | + required = false, multiValued = false) | ||
| 76 | + String appIds = null; | ||
| 77 | + | ||
| 68 | 78 | ||
| 69 | private IntentService service; | 79 | private IntentService service; |
| 70 | private CountDownLatch latch; | 80 | private CountDownLatch latch; |
| 71 | private long start, end; | 81 | private long start, end; |
| 82 | + private int apps; | ||
| 83 | + private int intentsPerApp; | ||
| 72 | private int count; | 84 | private int count; |
| 73 | private boolean add; | 85 | private boolean add; |
| 74 | 86 | ||
| 87 | + | ||
| 75 | @Override | 88 | @Override |
| 76 | protected void execute() { | 89 | protected void execute() { |
| 77 | service = get(IntentService.class); | 90 | service = get(IntentService.class); |
| ... | @@ -85,13 +98,18 @@ public class IntentPushTestCommand extends AbstractShellCommand | ... | @@ -85,13 +98,18 @@ public class IntentPushTestCommand extends AbstractShellCommand |
| 85 | PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString)); | 98 | PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString)); |
| 86 | ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); | 99 | ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); |
| 87 | 100 | ||
| 88 | - count = Integer.parseInt(countString); | 101 | + apps = appIds != null ? Integer.parseInt(appIds) : 1; |
| 102 | + intentsPerApp = Integer.parseInt(intentsPerAppId); | ||
| 103 | + | ||
| 104 | + count = intentsPerApp * apps; | ||
| 105 | + | ||
| 89 | 106 | ||
| 90 | service.addListener(this); | 107 | service.addListener(this); |
| 91 | 108 | ||
| 109 | + ArrayListMultimap<Integer, Intent> operations = generateIntents(ingress, egress); | ||
| 110 | + | ||
| 92 | add = true; | 111 | add = true; |
| 93 | latch = new CountDownLatch(count); | 112 | latch = new CountDownLatch(count); |
| 94 | - List<Intent> operations = generateIntents(ingress, egress); | ||
| 95 | submitIntents(operations); | 113 | submitIntents(operations); |
| 96 | 114 | ||
| 97 | add = false; | 115 | add = false; |
| ... | @@ -101,36 +119,41 @@ public class IntentPushTestCommand extends AbstractShellCommand | ... | @@ -101,36 +119,41 @@ public class IntentPushTestCommand extends AbstractShellCommand |
| 101 | service.removeListener(this); | 119 | service.removeListener(this); |
| 102 | } | 120 | } |
| 103 | 121 | ||
| 104 | - private List<Intent> generateIntents(ConnectPoint ingress, ConnectPoint egress) { | 122 | + private ArrayListMultimap<Integer, Intent> generateIntents(ConnectPoint ingress, ConnectPoint egress) { |
| 105 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder() | 123 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder() |
| 106 | .matchEthType(Ethernet.TYPE_IPV4); | 124 | .matchEthType(Ethernet.TYPE_IPV4); |
| 107 | TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); | 125 | TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); |
| 108 | 126 | ||
| 109 | - List<Intent> intents = Lists.newArrayList(); | 127 | + ArrayListMultimap<Integer, Intent> intents = ArrayListMultimap.create(); |
| 110 | - for (int i = 1; i <= count; i++) { | 128 | + for (int app = 1; app <= apps; app++) { |
| 129 | + for (int i = 1; i <= intentsPerApp; i++) { | ||
| 111 | TrafficSelector s = selector | 130 | TrafficSelector s = selector |
| 112 | .matchEthSrc(MacAddress.valueOf(i)) | 131 | .matchEthSrc(MacAddress.valueOf(i)) |
| 113 | .build(); | 132 | .build(); |
| 114 | - intents.add(new PointToPointIntent(appId(), s, treatment, | 133 | + intents.put(app, new PointToPointIntent(appId(), s, treatment, |
| 115 | ingress, egress)); | 134 | ingress, egress)); |
| 116 | 135 | ||
| 117 | } | 136 | } |
| 137 | + } | ||
| 118 | return intents; | 138 | return intents; |
| 119 | } | 139 | } |
| 120 | 140 | ||
| 121 | - private void submitIntents(List<Intent> intents) { | 141 | + private void submitIntents(ArrayListMultimap<Integer, Intent> intents) { |
| 122 | - IntentOperations.Builder builder = IntentOperations.builder(appId()); | 142 | + List<IntentOperations> opList = Lists.newArrayList(); |
| 123 | - for (Intent intent : intents) { | 143 | + for (Integer app : intents.keySet()) { |
| 144 | + IntentOperations.Builder builder = IntentOperations.builder(appId(app)); | ||
| 145 | + for (Intent intent : intents.get(app)) { | ||
| 124 | if (add) { | 146 | if (add) { |
| 125 | builder.addSubmitOperation(intent); | 147 | builder.addSubmitOperation(intent); |
| 126 | } else { | 148 | } else { |
| 127 | builder.addWithdrawOperation(intent.id()); | 149 | builder.addWithdrawOperation(intent.id()); |
| 128 | } | 150 | } |
| 129 | } | 151 | } |
| 130 | - IntentOperations ops = builder.build(); | 152 | + opList.add(builder.build()); |
| 153 | + } | ||
| 131 | 154 | ||
| 132 | start = System.currentTimeMillis(); | 155 | start = System.currentTimeMillis(); |
| 133 | - service.execute(ops); | 156 | + opList.forEach(ops -> service.execute(ops)); |
| 134 | try { | 157 | try { |
| 135 | if (latch.await(100 + count * 200, TimeUnit.MILLISECONDS)) { | 158 | if (latch.await(100 + count * 200, TimeUnit.MILLISECONDS)) { |
| 136 | printResults(count); | 159 | printResults(count); |
| ... | @@ -148,6 +171,16 @@ public class IntentPushTestCommand extends AbstractShellCommand | ... | @@ -148,6 +171,16 @@ public class IntentPushTestCommand extends AbstractShellCommand |
| 148 | print("Time to %s %d intents: %d ms", text, count, delta); | 171 | print("Time to %s %d intents: %d ms", text, count, delta); |
| 149 | } | 172 | } |
| 150 | 173 | ||
| 174 | + | ||
| 175 | + /** | ||
| 176 | + * Returns application ID for the CLI. | ||
| 177 | + * | ||
| 178 | + * @return command-line application identifier | ||
| 179 | + */ | ||
| 180 | + protected ApplicationId appId(Integer id) { | ||
| 181 | + return get(CoreService.class).registerApplication("org.onlab.onos.cli-" + id); | ||
| 182 | + } | ||
| 183 | + | ||
| 151 | /** | 184 | /** |
| 152 | * Extracts the port number portion of the ConnectPoint. | 185 | * Extracts the port number portion of the ConnectPoint. |
| 153 | * | 186 | * | ... | ... |
| 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.cli.net; | ||
| 17 | + | ||
| 18 | +import org.apache.karaf.shell.commands.Command; | ||
| 19 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
| 20 | +import org.onlab.onos.cluster.Leadership; | ||
| 21 | +import org.onlab.onos.cluster.LeadershipService; | ||
| 22 | + | ||
| 23 | +import java.util.Map; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * Prints the leader for every topic. | ||
| 27 | + */ | ||
| 28 | +@Command(scope = "onos", name = "leaders", | ||
| 29 | + description = "Finds the leader for particular topic.") | ||
| 30 | +public class LeaderCommand extends AbstractShellCommand { | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + protected void execute() { | ||
| 34 | + LeadershipService leaderService = get(LeadershipService.class); | ||
| 35 | + Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard(); | ||
| 36 | + print("Topic:\t\tLeader"); | ||
| 37 | + for (String topic : leaderBoard.keySet()) { | ||
| 38 | + print("%s:\t%s", topic, leaderBoard.get(topic).leader().id()); | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | +} |
| ... | @@ -258,6 +258,9 @@ | ... | @@ -258,6 +258,9 @@ |
| 258 | <command> | 258 | <command> |
| 259 | <action class="org.onlab.onos.cli.net.AddFlowsCommand"/> | 259 | <action class="org.onlab.onos.cli.net.AddFlowsCommand"/> |
| 260 | </command> | 260 | </command> |
| 261 | + <command> | ||
| 262 | + <action class="org.onlab.onos.cli.net.LeaderCommand"/> | ||
| 263 | + </command> | ||
| 261 | 264 | ||
| 262 | <command> | 265 | <command> |
| 263 | <action class="org.onlab.onos.cli.net.WipeOutCommand"/> | 266 | <action class="org.onlab.onos.cli.net.WipeOutCommand"/> | ... | ... |
| ... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onlab.onos.cluster; | 16 | package org.onlab.onos.cluster; |
| 17 | 17 | ||
| 18 | +import java.util.Map; | ||
| 19 | + | ||
| 18 | /** | 20 | /** |
| 19 | * Service for leader election. | 21 | * Service for leader election. |
| 20 | * Leadership contests are organized around topics. A instance can join the | 22 | * Leadership contests are organized around topics. A instance can join the |
| ... | @@ -43,6 +45,8 @@ public interface LeadershipService { | ... | @@ -43,6 +45,8 @@ public interface LeadershipService { |
| 43 | */ | 45 | */ |
| 44 | void withdraw(String path); | 46 | void withdraw(String path); |
| 45 | 47 | ||
| 48 | + Map<String, Leadership> getLeaderBoard(); | ||
| 49 | + | ||
| 46 | /** | 50 | /** |
| 47 | * Registers a event listener to be notified of leadership events. | 51 | * Registers a event listener to be notified of leadership events. |
| 48 | * @param listener listener that will asynchronously notified of leadership events. | 52 | * @param listener listener that will asynchronously notified of leadership events. | ... | ... |
| ... | @@ -15,18 +15,10 @@ | ... | @@ -15,18 +15,10 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onlab.onos.net.intent.impl; | 16 | package org.onlab.onos.net.intent.impl; |
| 17 | 17 | ||
| 18 | -import java.util.ArrayList; | 18 | +import com.google.common.collect.ImmutableList; |
| 19 | -import java.util.Collections; | 19 | +import com.google.common.collect.ImmutableMap; |
| 20 | -import java.util.List; | 20 | +import com.google.common.collect.Lists; |
| 21 | -import java.util.Map; | 21 | +import com.google.common.collect.Maps; |
| 22 | -import java.util.concurrent.ConcurrentHashMap; | ||
| 23 | -import java.util.concurrent.ConcurrentMap; | ||
| 24 | -import java.util.concurrent.ExecutionException; | ||
| 25 | -import java.util.concurrent.ExecutorService; | ||
| 26 | -import java.util.concurrent.Future; | ||
| 27 | -import java.util.concurrent.TimeUnit; | ||
| 28 | -import java.util.concurrent.TimeoutException; | ||
| 29 | - | ||
| 30 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
| 31 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
| 32 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -46,6 +38,7 @@ import org.onlab.onos.net.intent.IntentBatchDelegate; | ... | @@ -46,6 +38,7 @@ import org.onlab.onos.net.intent.IntentBatchDelegate; |
| 46 | import org.onlab.onos.net.intent.IntentBatchService; | 38 | import org.onlab.onos.net.intent.IntentBatchService; |
| 47 | import org.onlab.onos.net.intent.IntentCompiler; | 39 | import org.onlab.onos.net.intent.IntentCompiler; |
| 48 | import org.onlab.onos.net.intent.IntentEvent; | 40 | import org.onlab.onos.net.intent.IntentEvent; |
| 41 | +import org.onlab.onos.net.intent.IntentEvent.Type; | ||
| 49 | import org.onlab.onos.net.intent.IntentException; | 42 | import org.onlab.onos.net.intent.IntentException; |
| 50 | import org.onlab.onos.net.intent.IntentExtensionService; | 43 | import org.onlab.onos.net.intent.IntentExtensionService; |
| 51 | import org.onlab.onos.net.intent.IntentId; | 44 | import org.onlab.onos.net.intent.IntentId; |
| ... | @@ -56,23 +49,27 @@ import org.onlab.onos.net.intent.IntentOperations; | ... | @@ -56,23 +49,27 @@ import org.onlab.onos.net.intent.IntentOperations; |
| 56 | import org.onlab.onos.net.intent.IntentService; | 49 | import org.onlab.onos.net.intent.IntentService; |
| 57 | import org.onlab.onos.net.intent.IntentState; | 50 | import org.onlab.onos.net.intent.IntentState; |
| 58 | import org.onlab.onos.net.intent.IntentStore; | 51 | import org.onlab.onos.net.intent.IntentStore; |
| 52 | +import org.onlab.onos.net.intent.IntentStore.BatchWrite; | ||
| 59 | import org.onlab.onos.net.intent.IntentStoreDelegate; | 53 | import org.onlab.onos.net.intent.IntentStoreDelegate; |
| 60 | import org.slf4j.Logger; | 54 | import org.slf4j.Logger; |
| 61 | 55 | ||
| 62 | -import com.google.common.collect.ImmutableList; | 56 | +import java.util.ArrayList; |
| 63 | -import com.google.common.collect.ImmutableMap; | 57 | +import java.util.Collections; |
| 64 | -import com.google.common.collect.Lists; | 58 | +import java.util.EnumSet; |
| 65 | -import com.google.common.collect.Maps; | 59 | +import java.util.List; |
| 60 | +import java.util.Map; | ||
| 61 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 62 | +import java.util.concurrent.ConcurrentMap; | ||
| 63 | +import java.util.concurrent.ExecutionException; | ||
| 64 | +import java.util.concurrent.ExecutorService; | ||
| 65 | +import java.util.concurrent.Future; | ||
| 66 | +import java.util.concurrent.TimeUnit; | ||
| 67 | +import java.util.concurrent.TimeoutException; | ||
| 66 | 68 | ||
| 67 | import static com.google.common.base.Preconditions.checkArgument; | 69 | import static com.google.common.base.Preconditions.checkArgument; |
| 68 | import static com.google.common.base.Preconditions.checkNotNull; | 70 | import static com.google.common.base.Preconditions.checkNotNull; |
| 69 | -import static java.util.concurrent.Executors.newSingleThreadExecutor; | 71 | +import static java.util.concurrent.Executors.newFixedThreadPool; |
| 70 | -import static org.onlab.onos.net.intent.IntentState.COMPILING; | 72 | +import static org.onlab.onos.net.intent.IntentState.*; |
| 71 | -import static org.onlab.onos.net.intent.IntentState.FAILED; | ||
| 72 | -import static org.onlab.onos.net.intent.IntentState.INSTALLED; | ||
| 73 | -import static org.onlab.onos.net.intent.IntentState.INSTALLING; | ||
| 74 | -import static org.onlab.onos.net.intent.IntentState.WITHDRAWING; | ||
| 75 | -import static org.onlab.onos.net.intent.IntentState.WITHDRAWN; | ||
| 76 | import static org.onlab.util.Tools.namedThreads; | 73 | import static org.onlab.util.Tools.namedThreads; |
| 77 | import static org.slf4j.LoggerFactory.getLogger; | 74 | import static org.slf4j.LoggerFactory.getLogger; |
| 78 | 75 | ||
| ... | @@ -88,6 +85,8 @@ public class IntentManager | ... | @@ -88,6 +85,8 @@ public class IntentManager |
| 88 | public static final String INTENT_NULL = "Intent cannot be null"; | 85 | public static final String INTENT_NULL = "Intent cannot be null"; |
| 89 | public static final String INTENT_ID_NULL = "Intent ID cannot be null"; | 86 | public static final String INTENT_ID_NULL = "Intent ID cannot be null"; |
| 90 | 87 | ||
| 88 | + private static final int NUM_THREADS = 12; | ||
| 89 | + | ||
| 91 | // Collections for compiler, installer, and listener are ONOS instance local | 90 | // Collections for compiler, installer, and listener are ONOS instance local |
| 92 | private final ConcurrentMap<Class<? extends Intent>, | 91 | private final ConcurrentMap<Class<? extends Intent>, |
| 93 | IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>(); | 92 | IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>(); |
| ... | @@ -117,7 +116,6 @@ public class IntentManager | ... | @@ -117,7 +116,6 @@ public class IntentManager |
| 117 | 116 | ||
| 118 | 117 | ||
| 119 | private ExecutorService executor; | 118 | private ExecutorService executor; |
| 120 | - private ExecutorService monitorExecutor; | ||
| 121 | 119 | ||
| 122 | private final IntentStoreDelegate delegate = new InternalStoreDelegate(); | 120 | private final IntentStoreDelegate delegate = new InternalStoreDelegate(); |
| 123 | private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate(); | 121 | private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate(); |
| ... | @@ -130,8 +128,7 @@ public class IntentManager | ... | @@ -130,8 +128,7 @@ public class IntentManager |
| 130 | trackerService.setDelegate(topoDelegate); | 128 | trackerService.setDelegate(topoDelegate); |
| 131 | batchService.setDelegate(batchDelegate); | 129 | batchService.setDelegate(batchDelegate); |
| 132 | eventDispatcher.addSink(IntentEvent.class, listenerRegistry); | 130 | eventDispatcher.addSink(IntentEvent.class, listenerRegistry); |
| 133 | - executor = newSingleThreadExecutor(namedThreads("onos-intents")); | 131 | + executor = newFixedThreadPool(NUM_THREADS, namedThreads("onos-intent-monitor")); |
| 134 | - monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor")); | ||
| 135 | idGenerator = coreService.getIdGenerator("intent-ids"); | 132 | idGenerator = coreService.getIdGenerator("intent-ids"); |
| 136 | Intent.bindIdGenerator(idGenerator); | 133 | Intent.bindIdGenerator(idGenerator); |
| 137 | log.info("Started"); | 134 | log.info("Started"); |
| ... | @@ -144,7 +141,6 @@ public class IntentManager | ... | @@ -144,7 +141,6 @@ public class IntentManager |
| 144 | batchService.unsetDelegate(batchDelegate); | 141 | batchService.unsetDelegate(batchDelegate); |
| 145 | eventDispatcher.removeSink(IntentEvent.class); | 142 | eventDispatcher.removeSink(IntentEvent.class); |
| 146 | executor.shutdown(); | 143 | executor.shutdown(); |
| 147 | - monitorExecutor.shutdown(); | ||
| 148 | Intent.unbindIdGenerator(idGenerator); | 144 | Intent.unbindIdGenerator(idGenerator); |
| 149 | log.info("Stopped"); | 145 | log.info("Stopped"); |
| 150 | } | 146 | } |
| ... | @@ -288,7 +284,7 @@ public class IntentManager | ... | @@ -288,7 +284,7 @@ public class IntentManager |
| 288 | private void executeCompilingPhase(IntentUpdate update) { | 284 | private void executeCompilingPhase(IntentUpdate update) { |
| 289 | Intent intent = update.newIntent(); | 285 | Intent intent = update.newIntent(); |
| 290 | // Indicate that the intent is entering the compiling phase. | 286 | // Indicate that the intent is entering the compiling phase. |
| 291 | - update.setState(intent, COMPILING); | 287 | + update.setInflightState(intent, COMPILING); |
| 292 | 288 | ||
| 293 | try { | 289 | try { |
| 294 | // Compile the intent into installable derivatives. | 290 | // Compile the intent into installable derivatives. |
| ... | @@ -301,7 +297,7 @@ public class IntentManager | ... | @@ -301,7 +297,7 @@ public class IntentManager |
| 301 | log.warn("Unable to compile intent {} due to:", intent.id(), e); | 297 | log.warn("Unable to compile intent {} due to:", intent.id(), e); |
| 302 | 298 | ||
| 303 | // If compilation failed, mark the intent as failed. | 299 | // If compilation failed, mark the intent as failed. |
| 304 | - update.setState(intent, FAILED); | 300 | + update.setInflightState(intent, FAILED); |
| 305 | } | 301 | } |
| 306 | } | 302 | } |
| 307 | 303 | ||
| ... | @@ -338,7 +334,7 @@ public class IntentManager | ... | @@ -338,7 +334,7 @@ public class IntentManager |
| 338 | return; | 334 | return; |
| 339 | } | 335 | } |
| 340 | // Indicate that the intent is entering the installing phase. | 336 | // Indicate that the intent is entering the installing phase. |
| 341 | - update.setState(update.newIntent(), INSTALLING); | 337 | + update.setInflightState(update.newIntent(), INSTALLING); |
| 342 | 338 | ||
| 343 | List<FlowRuleBatchOperation> batches = Lists.newArrayList(); | 339 | List<FlowRuleBatchOperation> batches = Lists.newArrayList(); |
| 344 | for (Intent installable : update.newInstallables()) { | 340 | for (Intent installable : update.newInstallables()) { |
| ... | @@ -365,7 +361,7 @@ public class IntentManager | ... | @@ -365,7 +361,7 @@ public class IntentManager |
| 365 | */ | 361 | */ |
| 366 | private void executeWithdrawingPhase(IntentUpdate update) { | 362 | private void executeWithdrawingPhase(IntentUpdate update) { |
| 367 | if (!update.oldIntent().equals(update.newIntent())) { | 363 | if (!update.oldIntent().equals(update.newIntent())) { |
| 368 | - update.setState(update.oldIntent(), WITHDRAWING); | 364 | + update.setInflightState(update.oldIntent(), WITHDRAWING); |
| 369 | } // else newIntent is FAILED | 365 | } // else newIntent is FAILED |
| 370 | update.addBatches(uninstallIntent(update.oldIntent(), update.oldInstallables())); | 366 | update.addBatches(uninstallIntent(update.oldIntent(), update.oldInstallables())); |
| 371 | } | 367 | } |
| ... | @@ -405,9 +401,9 @@ public class IntentManager | ... | @@ -405,9 +401,9 @@ public class IntentManager |
| 405 | "Old and New Intent must have equivalent installable intents."); | 401 | "Old and New Intent must have equivalent installable intents."); |
| 406 | if (!update.oldIntent().equals(update.newIntent())) { | 402 | if (!update.oldIntent().equals(update.newIntent())) { |
| 407 | // only set the old intent's state if it is different | 403 | // only set the old intent's state if it is different |
| 408 | - update.setState(update.oldIntent(), WITHDRAWING); | 404 | + update.setInflightState(update.oldIntent(), WITHDRAWING); |
| 409 | } | 405 | } |
| 410 | - update.setState(update.newIntent(), INSTALLING); | 406 | + update.setInflightState(update.newIntent(), INSTALLING); |
| 411 | 407 | ||
| 412 | List<FlowRuleBatchOperation> batches = Lists.newArrayList(); | 408 | List<FlowRuleBatchOperation> batches = Lists.newArrayList(); |
| 413 | for (int i = 0; i < update.oldInstallables().size(); i++) { | 409 | for (int i = 0; i < update.oldInstallables().size(); i++) { |
| ... | @@ -427,7 +423,7 @@ public class IntentManager | ... | @@ -427,7 +423,7 @@ public class IntentManager |
| 427 | log.warn("Unable to update intent {} due to:", update.oldIntent().id(), e); | 423 | log.warn("Unable to update intent {} due to:", update.oldIntent().id(), e); |
| 428 | //FIXME... we failed. need to uninstall (if same) or revert (if different) | 424 | //FIXME... we failed. need to uninstall (if same) or revert (if different) |
| 429 | trackerService.removeTrackedResources(update.newIntent().id(), newInstallable.resources()); | 425 | trackerService.removeTrackedResources(update.newIntent().id(), newInstallable.resources()); |
| 430 | - update.setState(update.newIntent(), FAILED); | 426 | + update.setInflightState(update.newIntent(), FAILED); |
| 431 | batches = uninstallIntent(update.oldIntent(), update.oldInstallables()); | 427 | batches = uninstallIntent(update.oldIntent(), update.oldInstallables()); |
| 432 | } | 428 | } |
| 433 | } | 429 | } |
| ... | @@ -539,6 +535,7 @@ public class IntentManager | ... | @@ -539,6 +535,7 @@ public class IntentManager |
| 539 | } | 535 | } |
| 540 | } | 536 | } |
| 541 | 537 | ||
| 538 | + // TODO move this inside IntentUpdate? | ||
| 542 | /** | 539 | /** |
| 543 | * TODO. rename this... | 540 | * TODO. rename this... |
| 544 | * @param update intent update | 541 | * @param update intent update |
| ... | @@ -560,7 +557,7 @@ public class IntentManager | ... | @@ -560,7 +557,7 @@ public class IntentManager |
| 560 | if (update.oldIntent() != null && | 557 | if (update.oldIntent() != null && |
| 561 | !update.oldIntent().equals(update.newIntent())) { | 558 | !update.oldIntent().equals(update.newIntent())) { |
| 562 | // removing failed intent | 559 | // removing failed intent |
| 563 | - update.setState(update.oldIntent(), WITHDRAWING); | 560 | + update.setInflightState(update.oldIntent(), WITHDRAWING); |
| 564 | } | 561 | } |
| 565 | // if (update.newIntent() != null) { | 562 | // if (update.newIntent() != null) { |
| 566 | // // TODO assert that next state is failed | 563 | // // TODO assert that next state is failed |
| ... | @@ -602,13 +599,6 @@ public class IntentManager | ... | @@ -602,13 +599,6 @@ public class IntentManager |
| 602 | newIntent = null; | 599 | newIntent = null; |
| 603 | break; | 600 | break; |
| 604 | } | 601 | } |
| 605 | - // add new intent to store (if required) | ||
| 606 | - if (newIntent != null) { | ||
| 607 | - IntentEvent event = store.createIntent(newIntent); | ||
| 608 | - if (event != null) { | ||
| 609 | - eventDispatcher.post(event); | ||
| 610 | - } | ||
| 611 | - } | ||
| 612 | // fetch the old intent's installables from the store | 602 | // fetch the old intent's installables from the store |
| 613 | if (oldIntent != null) { | 603 | if (oldIntent != null) { |
| 614 | oldInstallables = store.getInstallableIntents(oldIntent.id()); | 604 | oldInstallables = store.getInstallableIntents(oldIntent.id()); |
| ... | @@ -617,6 +607,13 @@ public class IntentManager | ... | @@ -617,6 +607,13 @@ public class IntentManager |
| 617 | } | 607 | } |
| 618 | } | 608 | } |
| 619 | 609 | ||
| 610 | + void init(BatchWrite batchWrite) { | ||
| 611 | + // add new intent to store (if required) | ||
| 612 | + if (newIntent != null) { | ||
| 613 | + batchWrite.createIntent(newIntent); | ||
| 614 | + } | ||
| 615 | + } | ||
| 616 | + | ||
| 620 | Intent oldIntent() { | 617 | Intent oldIntent() { |
| 621 | return oldIntent; | 618 | return oldIntent; |
| 622 | } | 619 | } |
| ... | @@ -635,7 +632,10 @@ public class IntentManager | ... | @@ -635,7 +632,10 @@ public class IntentManager |
| 635 | 632 | ||
| 636 | void setInstallables(List<Intent> installables) { | 633 | void setInstallables(List<Intent> installables) { |
| 637 | newInstallables = installables; | 634 | newInstallables = installables; |
| 638 | - store.setInstallableIntents(newIntent.id(), installables); | 635 | + //FIXME batch this |
| 636 | + | ||
| 637 | + //store.setInstallableIntents(newIntent.id(), installables); | ||
| 638 | + | ||
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | boolean isComplete() { | 641 | boolean isComplete() { |
| ... | @@ -646,12 +646,17 @@ public class IntentManager | ... | @@ -646,12 +646,17 @@ public class IntentManager |
| 646 | return !isComplete() ? batches.get(currentBatch) : null; | 646 | return !isComplete() ? batches.get(currentBatch) : null; |
| 647 | } | 647 | } |
| 648 | 648 | ||
| 649 | - void incrementBatch(boolean success) { | 649 | + List<IntentEvent> batchSuccess(BatchWrite batchWrite) { |
| 650 | - if (success) { // actually increment | 650 | + // move on to next Batch |
| 651 | if (++currentBatch == batches.size()) { | 651 | if (++currentBatch == batches.size()) { |
| 652 | - finalizeStates(); | 652 | + return finalizeStates(batchWrite); |
| 653 | + } | ||
| 654 | + return Collections.emptyList(); | ||
| 653 | } | 655 | } |
| 654 | - } else { // the current batch has failed, so recompile | 656 | + |
| 657 | + void batchFailed() { | ||
| 658 | + | ||
| 659 | + // the current batch has failed, so recompile | ||
| 655 | // remove the current batch and all remaining | 660 | // remove the current batch and all remaining |
| 656 | for (int i = currentBatch; i < batches.size(); i++) { | 661 | for (int i = currentBatch; i < batches.size(); i++) { |
| 657 | batches.remove(i); | 662 | batches.remove(i); |
| ... | @@ -660,28 +665,32 @@ public class IntentManager | ... | @@ -660,28 +665,32 @@ public class IntentManager |
| 660 | executeWithdrawingPhase(this); // remove the old intent | 665 | executeWithdrawingPhase(this); // remove the old intent |
| 661 | } | 666 | } |
| 662 | if (newIntent != null) { | 667 | if (newIntent != null) { |
| 663 | - setState(newIntent, FAILED); | 668 | + setInflightState(newIntent, FAILED); |
| 664 | batches.addAll(uninstallIntent(newIntent, newInstallables())); | 669 | batches.addAll(uninstallIntent(newIntent, newInstallables())); |
| 665 | } | 670 | } |
| 666 | 671 | ||
| 667 | // FIXME: should we try to recompile? | 672 | // FIXME: should we try to recompile? |
| 668 | } | 673 | } |
| 669 | - } | ||
| 670 | 674 | ||
| 671 | // FIXME make sure this is called!!! | 675 | // FIXME make sure this is called!!! |
| 672 | - private void finalizeStates() { | 676 | + private List<IntentEvent> finalizeStates(BatchWrite batchWrite) { |
| 677 | + // events to be triggered on successful write | ||
| 678 | + List<IntentEvent> events = new ArrayList<>(); | ||
| 673 | for (Intent intent : stateMap.keySet()) { | 679 | for (Intent intent : stateMap.keySet()) { |
| 674 | - switch (getState(intent)) { | 680 | + switch (getInflightState(intent)) { |
| 675 | case INSTALLING: | 681 | case INSTALLING: |
| 676 | - setState(intent, INSTALLED); | 682 | + batchWrite.setState(intent, INSTALLED); |
| 683 | + batchWrite.setInstallableIntents(newIntent.id(), newInstallables); | ||
| 684 | + events.add(new IntentEvent(Type.INSTALLED, intent)); | ||
| 677 | break; | 685 | break; |
| 678 | case WITHDRAWING: | 686 | case WITHDRAWING: |
| 679 | - setState(intent, WITHDRAWN); | 687 | + batchWrite.setState(intent, WITHDRAWN); |
| 680 | - store.removeInstalledIntents(intent.id()); | 688 | + events.add(new IntentEvent(Type.WITHDRAWN, intent)); |
| 681 | - //store.removeIntent(intent.id()); // FIXME we die a horrible death here | 689 | + batchWrite.removeInstalledIntents(intent.id()); |
| 690 | + batchWrite.removeIntent(intent.id()); | ||
| 682 | break; | 691 | break; |
| 683 | case FAILED: | 692 | case FAILED: |
| 684 | - store.removeInstalledIntents(intent.id()); | 693 | + batchWrite.removeInstalledIntents(intent.id()); |
| 685 | break; | 694 | break; |
| 686 | 695 | ||
| 687 | // FALLTHROUGH to default from here | 696 | // FALLTHROUGH to default from here |
| ... | @@ -692,10 +701,11 @@ public class IntentManager | ... | @@ -692,10 +701,11 @@ public class IntentManager |
| 692 | case INSTALLED: | 701 | case INSTALLED: |
| 693 | default: | 702 | default: |
| 694 | //FIXME clean this up (we shouldn't ever get here) | 703 | //FIXME clean this up (we shouldn't ever get here) |
| 695 | - log.warn("Bad state: {} for {}", getState(intent), intent); | 704 | + log.warn("Bad state: {} for {}", getInflightState(intent), intent); |
| 696 | break; | 705 | break; |
| 697 | } | 706 | } |
| 698 | } | 707 | } |
| 708 | + return events; | ||
| 699 | } | 709 | } |
| 700 | 710 | ||
| 701 | List<FlowRuleBatchOperation> batches() { | 711 | List<FlowRuleBatchOperation> batches() { |
| ... | @@ -706,11 +716,21 @@ public class IntentManager | ... | @@ -706,11 +716,21 @@ public class IntentManager |
| 706 | this.batches.addAll(batches); | 716 | this.batches.addAll(batches); |
| 707 | } | 717 | } |
| 708 | 718 | ||
| 709 | - IntentState getState(Intent intent) { | 719 | + IntentState getInflightState(Intent intent) { |
| 710 | return stateMap.get(intent); | 720 | return stateMap.get(intent); |
| 711 | } | 721 | } |
| 712 | 722 | ||
| 713 | - void setState(Intent intent, IntentState newState) { | 723 | + |
| 724 | + // set transient state during intent update process | ||
| 725 | + void setInflightState(Intent intent, IntentState newState) { | ||
| 726 | + // This method should be called for | ||
| 727 | + // transition to non-parking or Failed only | ||
| 728 | + EnumSet<IntentState> nonParkingOrFailed | ||
| 729 | + = EnumSet.complementOf(EnumSet.of(SUBMITTED, INSTALLED, WITHDRAWN)); | ||
| 730 | + if (!nonParkingOrFailed.contains(newState)) { | ||
| 731 | + log.error("Unexpected transition to {}", newState); | ||
| 732 | + } | ||
| 733 | + | ||
| 714 | // TODO: clean this up, or set to debug | 734 | // TODO: clean this up, or set to debug |
| 715 | IntentState oldState = stateMap.get(intent); | 735 | IntentState oldState = stateMap.get(intent); |
| 716 | log.debug("intent id: {}, old state: {}, new state: {}", | 736 | log.debug("intent id: {}, old state: {}, new state: {}", |
| ... | @@ -721,10 +741,6 @@ public class IntentManager | ... | @@ -721,10 +741,6 @@ public class IntentManager |
| 721 | if (event != null) { | 741 | if (event != null) { |
| 722 | eventDispatcher.post(event); | 742 | eventDispatcher.post(event); |
| 723 | } | 743 | } |
| 724 | - | ||
| 725 | - if (newState == WITHDRAWN) { | ||
| 726 | - store.removeIntent(intent.id()); | ||
| 727 | - } | ||
| 728 | } | 744 | } |
| 729 | 745 | ||
| 730 | Map<Intent, IntentState> stateMap() { | 746 | Map<Intent, IntentState> stateMap() { |
| ... | @@ -741,6 +757,7 @@ public class IntentManager | ... | @@ -741,6 +757,7 @@ public class IntentManager |
| 741 | private final IntentOperations ops; | 757 | private final IntentOperations ops; |
| 742 | private final List<IntentUpdate> intentUpdates = Lists.newArrayList(); | 758 | private final List<IntentUpdate> intentUpdates = Lists.newArrayList(); |
| 743 | 759 | ||
| 760 | + // future holding current FlowRuleBatch installation result | ||
| 744 | private Future<CompletedBatchOperation> future; | 761 | private Future<CompletedBatchOperation> future; |
| 745 | private long startTime = System.currentTimeMillis(); | 762 | private long startTime = System.currentTimeMillis(); |
| 746 | private long endTime; | 763 | private long endTime; |
| ... | @@ -758,9 +775,27 @@ public class IntentManager | ... | @@ -758,9 +775,27 @@ public class IntentManager |
| 758 | } | 775 | } |
| 759 | 776 | ||
| 760 | private void buildIntentUpdates() { | 777 | private void buildIntentUpdates() { |
| 778 | + BatchWrite batchWrite = store.newBatchWrite(); | ||
| 779 | + | ||
| 780 | + // create context and record new request to store | ||
| 761 | for (IntentOperation op : ops.operations()) { | 781 | for (IntentOperation op : ops.operations()) { |
| 762 | IntentUpdate update = new IntentUpdate(op); | 782 | IntentUpdate update = new IntentUpdate(op); |
| 783 | + update.init(batchWrite); | ||
| 763 | intentUpdates.add(update); | 784 | intentUpdates.add(update); |
| 785 | + } | ||
| 786 | + | ||
| 787 | + if (!batchWrite.isEmpty()) { | ||
| 788 | + store.batchWrite(batchWrite); | ||
| 789 | + } | ||
| 790 | + | ||
| 791 | + // start processing each Intents | ||
| 792 | + for (IntentUpdate update : intentUpdates) { | ||
| 793 | + if (update.newIntent() != null) { | ||
| 794 | + IntentState state = store.getIntentState(update.newIntent().id()); | ||
| 795 | + if (state == SUBMITTED) { | ||
| 796 | + eventDispatcher.post(new IntentEvent(Type.SUBMITTED, update.newIntent)); | ||
| 797 | + } | ||
| 798 | + } | ||
| 764 | processIntentUpdate(update); | 799 | processIntentUpdate(update); |
| 765 | } | 800 | } |
| 766 | future = applyNextBatch(); | 801 | future = applyNextBatch(); |
| ... | @@ -784,8 +819,16 @@ public class IntentManager | ... | @@ -784,8 +819,16 @@ public class IntentManager |
| 784 | 819 | ||
| 785 | private void updateBatches(CompletedBatchOperation completed) { | 820 | private void updateBatches(CompletedBatchOperation completed) { |
| 786 | if (completed.isSuccess()) { | 821 | if (completed.isSuccess()) { |
| 822 | + BatchWrite batchWrite = store.newBatchWrite(); | ||
| 823 | + List<IntentEvent> events = new ArrayList<>(); | ||
| 787 | for (IntentUpdate update : intentUpdates) { | 824 | for (IntentUpdate update : intentUpdates) { |
| 788 | - update.incrementBatch(true); | 825 | + events.addAll(update.batchSuccess(batchWrite)); |
| 826 | + } | ||
| 827 | + if (!batchWrite.isEmpty()) { | ||
| 828 | + store.batchWrite(batchWrite); | ||
| 829 | + for (IntentEvent event : events) { | ||
| 830 | + eventDispatcher.post(event); | ||
| 831 | + } | ||
| 789 | } | 832 | } |
| 790 | } else { | 833 | } else { |
| 791 | // entire batch has been reverted... | 834 | // entire batch has been reverted... |
| ... | @@ -798,7 +841,7 @@ public class IntentManager | ... | @@ -798,7 +841,7 @@ public class IntentManager |
| 798 | installables.addAll(update.oldInstallables()); | 841 | installables.addAll(update.oldInstallables()); |
| 799 | for (Intent intent : installables) { | 842 | for (Intent intent : installables) { |
| 800 | if (intent.id().equals(targetId)) { | 843 | if (intent.id().equals(targetId)) { |
| 801 | - update.incrementBatch(false); | 844 | + update.batchFailed(); |
| 802 | break; | 845 | break; |
| 803 | } | 846 | } |
| 804 | } | 847 | } |
| ... | @@ -834,12 +877,13 @@ public class IntentManager | ... | @@ -834,12 +877,13 @@ public class IntentManager |
| 834 | if (installAttempt++ >= MAX_ATTEMPTS) { | 877 | if (installAttempt++ >= MAX_ATTEMPTS) { |
| 835 | log.warn("Install request timed out: {}", ops); | 878 | log.warn("Install request timed out: {}", ops); |
| 836 | for (IntentUpdate update : intentUpdates) { | 879 | for (IntentUpdate update : intentUpdates) { |
| 837 | - update.incrementBatch(false); | 880 | + update.batchFailed(); |
| 838 | } | 881 | } |
| 839 | } // else just resubmit the work | 882 | } // else just resubmit the work |
| 840 | future = applyNextBatch(); | 883 | future = applyNextBatch(); |
| 841 | - monitorExecutor.submit(this); | 884 | + executor.submit(this); |
| 842 | } else { | 885 | } else { |
| 886 | + log.error("Cancelling FlowRuleBatch failed."); | ||
| 843 | // FIXME | 887 | // FIXME |
| 844 | // cancel failed... batch is broken; shouldn't happen! | 888 | // cancel failed... batch is broken; shouldn't happen! |
| 845 | // we could manually reverse everything | 889 | // we could manually reverse everything |
| ... | @@ -859,20 +903,37 @@ public class IntentManager | ... | @@ -859,20 +903,37 @@ public class IntentManager |
| 859 | if (intentUpdates.isEmpty()) { | 903 | if (intentUpdates.isEmpty()) { |
| 860 | // this should only be called on the first iteration | 904 | // this should only be called on the first iteration |
| 861 | // note: this a "expensive", so it is not done in the constructor | 905 | // note: this a "expensive", so it is not done in the constructor |
| 906 | + | ||
| 907 | + // - creates per Intent installation context (IntentUpdate) | ||
| 908 | + // - write Intents to store | ||
| 909 | + // - process (compile, install, etc.) each Intents | ||
| 910 | + // - generate FlowRuleBatch for this phase | ||
| 862 | buildIntentUpdates(); | 911 | buildIntentUpdates(); |
| 863 | } | 912 | } |
| 913 | + | ||
| 914 | + // - peek if current FlowRuleBatch is complete | ||
| 915 | + // -- If complete OK: | ||
| 916 | + // step each IntentUpdate forward | ||
| 917 | + // If phase left: generate next FlowRuleBatch | ||
| 918 | + // If no more phase: write parking states | ||
| 919 | + // -- If complete FAIL: | ||
| 920 | + // Intent which failed: transition Intent to FAILED | ||
| 921 | + // Other Intents: resubmit same FlowRuleBatch for this phase | ||
| 864 | processFutures(); | 922 | processFutures(); |
| 865 | if (isComplete()) { | 923 | if (isComplete()) { |
| 866 | // there are no outstanding batches; we are done | 924 | // there are no outstanding batches; we are done |
| 867 | batchService.removeIntentOperations(ops); | 925 | batchService.removeIntentOperations(ops); |
| 868 | } else if (endTime < System.currentTimeMillis()) { | 926 | } else if (endTime < System.currentTimeMillis()) { |
| 927 | + // - cancel current FlowRuleBatch and resubmit again | ||
| 869 | retry(); | 928 | retry(); |
| 870 | } else { | 929 | } else { |
| 871 | // we are not done yet, yield the thread by resubmitting ourselves | 930 | // we are not done yet, yield the thread by resubmitting ourselves |
| 872 | - monitorExecutor.submit(this); | 931 | + executor.submit(this); |
| 873 | } | 932 | } |
| 874 | } catch (Exception e) { | 933 | } catch (Exception e) { |
| 875 | log.error("Error submitting batches:", e); | 934 | log.error("Error submitting batches:", e); |
| 935 | + // FIXME incomplete Intents should be cleaned up | ||
| 936 | + // (transition to FAILED, etc.) | ||
| 876 | } | 937 | } |
| 877 | } | 938 | } |
| 878 | } | 939 | } |
| ... | @@ -883,7 +944,7 @@ public class IntentManager | ... | @@ -883,7 +944,7 @@ public class IntentManager |
| 883 | log.info("Execute {} operation(s).", operations.operations().size()); | 944 | log.info("Execute {} operation(s).", operations.operations().size()); |
| 884 | log.debug("Execute operations: {}", operations.operations()); | 945 | log.debug("Execute operations: {}", operations.operations()); |
| 885 | //FIXME: perhaps we want to track this task so that we can cancel it. | 946 | //FIXME: perhaps we want to track this task so that we can cancel it. |
| 886 | - monitorExecutor.execute(new IntentInstallMonitor(operations)); | 947 | + executor.execute(new IntentInstallMonitor(operations)); |
| 887 | } | 948 | } |
| 888 | 949 | ||
| 889 | @Override | 950 | @Override | ... | ... |
| ... | @@ -11,6 +11,7 @@ import java.util.concurrent.Executors; | ... | @@ -11,6 +11,7 @@ import java.util.concurrent.Executors; |
| 11 | import java.util.concurrent.ScheduledExecutorService; | 11 | import java.util.concurrent.ScheduledExecutorService; |
| 12 | import java.util.concurrent.TimeUnit; | 12 | import java.util.concurrent.TimeUnit; |
| 13 | 13 | ||
| 14 | +import com.google.common.collect.ImmutableMap; | ||
| 14 | import org.apache.felix.scr.annotations.Activate; | 15 | import org.apache.felix.scr.annotations.Activate; |
| 15 | import org.apache.felix.scr.annotations.Component; | 16 | import org.apache.felix.scr.annotations.Component; |
| 16 | import org.apache.felix.scr.annotations.Deactivate; | 17 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -159,6 +160,11 @@ public class LeadershipManager implements LeadershipService { | ... | @@ -159,6 +160,11 @@ public class LeadershipManager implements LeadershipService { |
| 159 | } | 160 | } |
| 160 | 161 | ||
| 161 | @Override | 162 | @Override |
| 163 | + public Map<String, Leadership> getLeaderBoard() { | ||
| 164 | + return ImmutableMap.copyOf(leaderBoard); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + @Override | ||
| 162 | public void addListener(LeadershipEventListener listener) { | 168 | public void addListener(LeadershipEventListener listener) { |
| 163 | checkArgument(listener != null); | 169 | checkArgument(listener != null); |
| 164 | listeners.add(listener); | 170 | listeners.add(listener); | ... | ... |
-
Please register or login to post a comment