Brian O'Connor

Pulling PartitionService into API and making IntentPerfInstaller configurable

Change-Id: I9fde28986b6714c0ca4d635d5a3699094e2f0081
...@@ -15,21 +15,28 @@ ...@@ -15,21 +15,28 @@
15 */ 15 */
16 package org.onosproject.intentperf; 16 package org.onosproject.intentperf;
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 com.google.common.collect.Maps; 20 import com.google.common.collect.Maps;
21 +import com.google.common.collect.Multimap;
20 import com.google.common.collect.Sets; 22 import com.google.common.collect.Sets;
23 +import org.apache.commons.lang.math.RandomUtils;
21 import org.apache.felix.scr.annotations.Activate; 24 import org.apache.felix.scr.annotations.Activate;
22 import org.apache.felix.scr.annotations.Component; 25 import org.apache.felix.scr.annotations.Component;
23 import org.apache.felix.scr.annotations.Deactivate; 26 import org.apache.felix.scr.annotations.Deactivate;
27 +import org.apache.felix.scr.annotations.Property;
24 import org.apache.felix.scr.annotations.Reference; 28 import org.apache.felix.scr.annotations.Reference;
25 import org.onlab.packet.MacAddress; 29 import org.onlab.packet.MacAddress;
26 import org.onlab.util.Counter; 30 import org.onlab.util.Counter;
31 +import org.onosproject.cfg.ComponentConfigService;
27 import org.onosproject.cluster.ClusterService; 32 import org.onosproject.cluster.ClusterService;
33 +import org.onosproject.cluster.ControllerNode;
34 +import org.onosproject.cluster.NodeId;
28 import org.onosproject.core.ApplicationId; 35 import org.onosproject.core.ApplicationId;
29 import org.onosproject.core.CoreService; 36 import org.onosproject.core.CoreService;
37 +import org.onosproject.mastership.MastershipService;
30 import org.onosproject.net.ConnectPoint; 38 import org.onosproject.net.ConnectPoint;
31 import org.onosproject.net.Device; 39 import org.onosproject.net.Device;
32 -import org.onosproject.net.MastershipRole;
33 import org.onosproject.net.PortNumber; 40 import org.onosproject.net.PortNumber;
34 import org.onosproject.net.device.DeviceService; 41 import org.onosproject.net.device.DeviceService;
35 import org.onosproject.net.flow.DefaultTrafficSelector; 42 import org.onosproject.net.flow.DefaultTrafficSelector;
...@@ -41,12 +48,12 @@ import org.onosproject.net.intent.IntentEvent; ...@@ -41,12 +48,12 @@ import org.onosproject.net.intent.IntentEvent;
41 import org.onosproject.net.intent.IntentListener; 48 import org.onosproject.net.intent.IntentListener;
42 import org.onosproject.net.intent.IntentService; 49 import org.onosproject.net.intent.IntentService;
43 import org.onosproject.net.intent.Key; 50 import org.onosproject.net.intent.Key;
51 +import org.onosproject.net.intent.PartitionService;
44 import org.onosproject.net.intent.PointToPointIntent; 52 import org.onosproject.net.intent.PointToPointIntent;
45 import org.slf4j.Logger; 53 import org.slf4j.Logger;
46 54
55 +import java.util.ArrayList;
47 import java.util.Collections; 56 import java.util.Collections;
48 -import java.util.HashSet;
49 -import java.util.Iterator;
50 import java.util.List; 57 import java.util.List;
51 import java.util.Map; 58 import java.util.Map;
52 import java.util.Set; 59 import java.util.Set;
...@@ -55,6 +62,7 @@ import java.util.TimerTask; ...@@ -55,6 +62,7 @@ import java.util.TimerTask;
55 import java.util.concurrent.ExecutorService; 62 import java.util.concurrent.ExecutorService;
56 import java.util.concurrent.Executors; 63 import java.util.concurrent.Executors;
57 import java.util.concurrent.TimeUnit; 64 import java.util.concurrent.TimeUnit;
65 +import java.util.stream.Collectors;
58 66
59 import static com.google.common.base.Preconditions.checkState; 67 import static com.google.common.base.Preconditions.checkState;
60 import static java.lang.String.format; 68 import static java.lang.String.format;
...@@ -71,15 +79,36 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -71,15 +79,36 @@ import static org.slf4j.LoggerFactory.getLogger;
71 @Component(immediate = true) 79 @Component(immediate = true)
72 public class IntentPerfInstaller { 80 public class IntentPerfInstaller {
73 81
74 - //FIXME make this configurable 82 + private final Logger log = getLogger(getClass());
75 - private static final int NUM_WORKERS = 1; 83 +
76 - private static final int NUM_KEYS = 40_000; 84 + private static final int DEFAULT_NUM_WORKERS = 1;
85 +
86 + private static final int DEFAULT_NUM_KEYS = 40_000;
87 + private static final int DEFAULT_GOAL_CYCLE_PERIOD = 1_000; //ms
77 88
78 - public static final int START_DELAY = 5_000; // ms 89 + private static final int DEFAULT_NUM_NEIGHBORS = 0;
90 +
91 + private static final int START_DELAY = 5_000; // ms
79 private static final int REPORT_PERIOD = 5_000; //ms 92 private static final int REPORT_PERIOD = 5_000; //ms
80 - private static final int GOAL_CYCLE_PERIOD = 1_000; //ms
81 93
82 - private final Logger log = getLogger(getClass()); 94 + //FIXME add path length
95 +
96 + @Property(name = "numKeys", intValue = DEFAULT_NUM_KEYS,
97 + label = "Number of keys (i.e. unique intents) to generate per instance")
98 + private int numKeys = DEFAULT_NUM_KEYS;
99 +
100 + //TODO implement numWorkers property
101 +// @Property(name = "numThreads", intValue = DEFAULT_NUM_WORKERS,
102 +// label = "Number of installer threads per instance")
103 +// private int numWokers = DEFAULT_NUM_WORKERS;
104 +
105 + @Property(name = "cyclePeriod", intValue = DEFAULT_GOAL_CYCLE_PERIOD,
106 + label = "Goal for cycle period (in ms)")
107 + private int cyclePeriod = DEFAULT_GOAL_CYCLE_PERIOD;
108 +
109 + @Property(name = "numNeighbors", intValue = DEFAULT_NUM_NEIGHBORS,
110 + label = "Number of neighbors to generate intents for")
111 + private int numNeighbors = DEFAULT_NUM_NEIGHBORS;
83 112
84 @Reference(cardinality = MANDATORY_UNARY) 113 @Reference(cardinality = MANDATORY_UNARY)
85 protected CoreService coreService; 114 protected CoreService coreService;
...@@ -93,6 +122,15 @@ public class IntentPerfInstaller { ...@@ -93,6 +122,15 @@ public class IntentPerfInstaller {
93 @Reference(cardinality = MANDATORY_UNARY) 122 @Reference(cardinality = MANDATORY_UNARY)
94 protected DeviceService deviceService; 123 protected DeviceService deviceService;
95 124
125 + @Reference(cardinality = MANDATORY_UNARY)
126 + protected MastershipService mastershipService;
127 +
128 + @Reference(cardinality = MANDATORY_UNARY)
129 + protected PartitionService partitionService;
130 +
131 + @Reference(cardinality = MANDATORY_UNARY)
132 + protected ComponentConfigService configService;
133 +
96 private ExecutorService workers; 134 private ExecutorService workers;
97 private ApplicationId appId; 135 private ApplicationId appId;
98 private Listener listener; 136 private Listener listener;
...@@ -105,12 +143,20 @@ public class IntentPerfInstaller { ...@@ -105,12 +143,20 @@ public class IntentPerfInstaller {
105 143
106 @Activate 144 @Activate
107 public void activate() { 145 public void activate() {
146 + configService.registerProperties(getClass());
147 +
108 String nodeId = clusterService.getLocalNode().ip().toString(); 148 String nodeId = clusterService.getLocalNode().ip().toString();
109 appId = coreService.registerApplication("org.onosproject.intentperf." + nodeId); 149 appId = coreService.registerApplication("org.onosproject.intentperf." + nodeId);
110 150
111 reportTimer = new Timer("onos-intent-perf-reporter"); 151 reportTimer = new Timer("onos-intent-perf-reporter");
112 - workers = Executors.newFixedThreadPool(NUM_WORKERS, groupedThreads("onos/intent-perf", "worker-%d")); 152 + workers = Executors.newFixedThreadPool(DEFAULT_NUM_WORKERS, groupedThreads("onos/intent-perf", "worker-%d"));
113 - log.info("Started with Application ID {}", appId.id()); 153 +
154 +
155 + // disable flow backups for testing
156 + log.info("flow props: {}",
157 + configService.getProperties("org.onosproject.store.flow.impl.DistributedFlowRuleStore"));
158 + configService.setProperty("org.onosproject.store.flow.impl.DistributedFlowRuleStore",
159 + "backupEnabled", "false");
114 160
115 // Schedule delayed start 161 // Schedule delayed start
116 reportTimer.schedule(new TimerTask() { 162 reportTimer.schedule(new TimerTask() {
...@@ -123,11 +169,22 @@ public class IntentPerfInstaller { ...@@ -123,11 +169,22 @@ public class IntentPerfInstaller {
123 169
124 @Deactivate 170 @Deactivate
125 public void deactivate() { 171 public void deactivate() {
172 + configService.unregisterProperties(getClass(), false);
126 stop(); 173 stop();
127 - log.info("Stopped"); 174 + }
175 +
176 + //FIXME add modified
177 +
178 + private void logConfig(String prefix) {
179 + log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}",
180 + prefix, appId.id(), numKeys, cyclePeriod, numNeighbors);
128 } 181 }
129 182
130 public void start() { 183 public void start() {
184 + // TODO perhaps move to start(), but need to call before logConfig
185 + // adjust numNeighbors and generate list of neighbors
186 + numNeighbors = Math.min(clusterService.getNodes().size() - 1, numNeighbors);
187 +
131 // perhaps we want to prime before listening... 188 // perhaps we want to prime before listening...
132 // we will need to discard the first few results for priming and warmup 189 // we will need to discard the first few results for priming and warmup
133 listener = new Listener(); 190 listener = new Listener();
...@@ -144,25 +201,62 @@ public class IntentPerfInstaller { ...@@ -144,25 +201,62 @@ public class IntentPerfInstaller {
144 201
145 // Submit workers 202 // Submit workers
146 stopped = false; 203 stopped = false;
147 - Set<Device> devices = new HashSet<>(); 204 + for (int i = 0; i < DEFAULT_NUM_WORKERS; i++) {
148 - for (int i = 0; i < NUM_WORKERS; i++) { 205 + workers.submit(new Submitter(createIntents(numKeys, /*FIXME*/ 2, lastKey)));
149 - workers.submit(new Submitter(createIntents(NUM_KEYS, 2, lastKey, devices)));
150 } 206 }
207 + logConfig("Started");
151 } 208 }
152 209
153 public void stop() { 210 public void stop() {
211 + stopped = true;
154 if (listener != null) { 212 if (listener != null) {
155 reportTimer.cancel(); 213 reportTimer.cancel();
156 intentService.removeListener(listener); 214 intentService.removeListener(listener);
157 listener = null; 215 listener = null;
158 reportTimer = null; 216 reportTimer = null;
159 } 217 }
160 - stopped = true;
161 try { 218 try {
162 workers.awaitTermination(5, TimeUnit.SECONDS); 219 workers.awaitTermination(5, TimeUnit.SECONDS);
163 } catch (InterruptedException e) { 220 } catch (InterruptedException e) {
164 log.warn("Failed to stop worker", e); 221 log.warn("Failed to stop worker", e);
165 } 222 }
223 + log.info("Stopped");
224 + }
225 +
226 + private List<NodeId> getNeighbors() {
227 + List<NodeId> nodes = clusterService.getNodes().stream()
228 + .map(ControllerNode::id)
229 + .collect(Collectors.toCollection(ArrayList::new));
230 + // sort neighbors by id
231 + Collections.sort(nodes, (node1, node2) ->
232 + node1.toString().compareTo(node2.toString()));
233 + // rotate the local node to index 0
234 + Collections.rotate(nodes, -1 * nodes.indexOf(clusterService.getLocalNode().id()));
235 + log.info("neighbors (raw): {}", nodes); //TODO remove
236 + // generate the sub-list that will contain local node and selected neighbors
237 + nodes = nodes.subList(0, numNeighbors + 1);
238 + log.info("neighbors: {}", nodes); //TODO remove
239 + return nodes;
240 + }
241 +
242 +
243 + private Intent createIntent(Key key, long mac, NodeId node, Multimap<NodeId, Device> devices) {
244 + // choose a random device for which this node is master
245 + List<Device> deviceList = devices.get(node).stream().collect(Collectors.toList());
246 + Device device = deviceList.get(RandomUtils.nextInt(deviceList.size()));
247 +
248 + //FIXME we currently ignore the path length and always use the same device
249 + TrafficSelector selector = DefaultTrafficSelector.builder()
250 + .matchEthDst(MacAddress.valueOf(mac)).build();
251 + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
252 + ConnectPoint ingress = new ConnectPoint(device.id(), PortNumber.portNumber(1));
253 + ConnectPoint egress = new ConnectPoint(device.id(), PortNumber.portNumber(2));
254 +
255 + return new PointToPointIntent(appId, key,
256 + selector, treatment,
257 + ingress, egress,
258 + Collections.emptyList(),
259 + Intent.DEFAULT_INTENT_PRIORITY);
166 } 260 }
167 261
168 /** 262 /**
...@@ -171,58 +265,55 @@ public class IntentPerfInstaller { ...@@ -171,58 +265,55 @@ public class IntentPerfInstaller {
171 * @param numberOfKeys number of intents 265 * @param numberOfKeys number of intents
172 * @param pathLength path depth 266 * @param pathLength path depth
173 * @param firstKey first key to attempt 267 * @param firstKey first key to attempt
174 - * @param devices set of previously utilized devices @return set of intents 268 + * @return set of intents
175 */ 269 */
176 - private Set<Intent> createIntents(int numberOfKeys, int pathLength, 270 + private Set<Intent> createIntents(int numberOfKeys, int pathLength, int firstKey) {
177 - int firstKey, Set<Device> devices) { 271 + //Set<Intent> result = new HashSet<>();
178 - Iterator<Device> deviceItr = deviceService.getAvailableDevices().iterator(); 272 +
179 - Set<Intent> result = new HashSet<>(); 273 + List<NodeId> neighbors = getNeighbors();
180 - 274 +
181 - Device ingressDevice = null; 275 + Multimap<NodeId, Device> devices = ArrayListMultimap.create();
182 - while (deviceItr.hasNext()) { 276 + deviceService.getAvailableDevices().forEach(device ->
183 - Device device = deviceItr.next(); 277 + devices.put(mastershipService.getMasterFor(device.id()), device));
184 - if (deviceService.getRole(device.id()) == MastershipRole.MASTER && 278 +
185 - !devices.contains(device)) { 279 + // ensure that we have at least one device per neighbor
186 - ingressDevice = device; 280 + neighbors.forEach(node ->
187 - devices.add(device); 281 + checkState(devices.get(node).size() > 0,
188 - break; 282 + "There are no devices for {}", node));
189 - } 283 +
190 - } 284 +
191 - checkState(ingressDevice != null, "There are no local devices"); 285 + // TODO pull this outside so that createIntent can use it
286 + // prefix based on node id for keys generated on this instance
287 + long keyPrefix = ((long) clusterService.getLocalNode().ip().getIp4Address().toInt()) << 32;
288 +
289 + int maxKeysPerNode = (int) Math.ceil((double) numberOfKeys / neighbors.size());
290 + Multimap<NodeId, Intent> intents = ArrayListMultimap.create();
192 291
193 - // prefix based on node id
194 - long prefix = ((long) clusterService.getLocalNode().ip().getIp4Address().toInt()) << 32;
195 for (int count = 0, k = firstKey; count < numberOfKeys; k++) { 292 for (int count = 0, k = firstKey; count < numberOfKeys; k++) {
196 - Key key = Key.of(prefix + k, appId); 293 + Key key = Key.of(keyPrefix + k, appId);
197 - //FIXME comment this out for spread of keys 294 +
198 - if (!intentService.isLocal(key)) { 295 + NodeId leader = partitionService.getLeader(key);
199 - // Bail if the key is not local 296 + if (!neighbors.contains(leader) || intents.get(leader).size() >= maxKeysPerNode) {
297 + // Bail if we are not sending to this node or we have enough for this node
200 continue; 298 continue;
201 } 299 }
202 - 300 + intents.put(leader, createIntent(key, keyPrefix + k, leader, devices));
203 - //FIXME we currently ignore the path length and always use the same device
204 - TrafficSelector selector = DefaultTrafficSelector.builder()
205 - .matchEthDst(MacAddress.valueOf(count)).build();
206 - TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
207 - ConnectPoint ingress = new ConnectPoint(ingressDevice.id(), PortNumber.portNumber(1));
208 - ConnectPoint egress = new ConnectPoint(ingressDevice.id(), PortNumber.portNumber(2));
209 -
210 - Intent intent = new PointToPointIntent(appId, key,
211 - selector, treatment,
212 - ingress, egress,
213 - Collections.emptyList(),
214 - Intent.DEFAULT_INTENT_PRIORITY);
215 - result.add(intent);
216 301
217 // Bump up the counter and remember this as the last key used. 302 // Bump up the counter and remember this as the last key used.
218 count++; 303 count++;
219 lastKey = k; 304 lastKey = k;
220 - if (lastKey % 1000 == 0) { 305 + if (count % 1000 == 0) {
221 - log.info("Building intents... {} (attempt: {})", lastKey, count); 306 + log.info("Building intents... {} (attempt: {})", count, lastKey);
222 } 307 }
223 } 308 }
309 + checkState(intents.values().size() == numberOfKeys,
310 + "Generated wrong number of intents");
224 log.info("Created {} intents", numberOfKeys); 311 log.info("Created {} intents", numberOfKeys);
225 - return result; 312 +
313 + //FIXME remove this
314 + intents.keySet().forEach(node -> log.info("\t{}\t{}", node, intents.get(node).size()));
315 +
316 + return Sets.newHashSet(intents.values());
226 } 317 }
227 318
228 // Submits intent operations. 319 // Submits intent operations.
...@@ -237,8 +328,8 @@ public class IntentPerfInstaller { ...@@ -237,8 +328,8 @@ public class IntentPerfInstaller {
237 328
238 private Submitter(Set<Intent> intents) { 329 private Submitter(Set<Intent> intents) {
239 this.intents = intents; 330 this.intents = intents;
240 - lastCount = NUM_KEYS / 4; 331 + lastCount = numKeys / 4;
241 - lastDuration = 1000; // 1 second 332 + lastDuration = 1_000; // 1 second
242 } 333 }
243 334
244 @Override 335 @Override
...@@ -247,6 +338,7 @@ public class IntentPerfInstaller { ...@@ -247,6 +338,7 @@ public class IntentPerfInstaller {
247 while (!stopped) { 338 while (!stopped) {
248 cycle(); 339 cycle();
249 } 340 }
341 + clear();
250 } 342 }
251 343
252 private Iterable<Intent> subset(Set<Intent> intents) { 344 private Iterable<Intent> subset(Set<Intent> intents) {
...@@ -282,6 +374,10 @@ public class IntentPerfInstaller { ...@@ -282,6 +374,10 @@ public class IntentPerfInstaller {
282 } 374 }
283 } 375 }
284 376
377 + private void clear() {
378 + submitted.forEach(this::withdraw);
379 + }
380 +
285 // Runs a single operation cycle. 381 // Runs a single operation cycle.
286 private void cycle() { 382 private void cycle() {
287 //TODO consider running without rate adjustment 383 //TODO consider running without rate adjustment
...@@ -292,11 +388,11 @@ public class IntentPerfInstaller { ...@@ -292,11 +388,11 @@ public class IntentPerfInstaller {
292 subset(withdrawn).forEach(this::submit); 388 subset(withdrawn).forEach(this::submit);
293 long delta = currentTimeMillis() - start; 389 long delta = currentTimeMillis() - start;
294 390
295 - if (delta > GOAL_CYCLE_PERIOD * 3 || delta < 0) { 391 + if (delta > cyclePeriod * 3 || delta < 0) {
296 log.warn("Cycle took {} ms", delta); 392 log.warn("Cycle took {} ms", delta);
297 } 393 }
298 394
299 - int difference = GOAL_CYCLE_PERIOD - (int) delta; 395 + int difference = cyclePeriod - (int) delta;
300 if (difference > 0) { 396 if (difference > 0) {
301 delay(difference); 397 delay(difference);
302 } 398 }
...@@ -307,9 +403,10 @@ public class IntentPerfInstaller { ...@@ -307,9 +403,10 @@ public class IntentPerfInstaller {
307 int cycleCount = 0; 403 int cycleCount = 0;
308 private void adjustRates() { 404 private void adjustRates() {
309 //FIXME need to iron out the rate adjustment 405 //FIXME need to iron out the rate adjustment
406 + //FIXME we should taper the adjustments over time
310 if (++cycleCount % 5 == 0) { //TODO: maybe use a timer (we should do this every 5-10 sec) 407 if (++cycleCount % 5 == 0) { //TODO: maybe use a timer (we should do this every 5-10 sec)
311 if (listener.requestThroughput() - listener.processedThroughput() <= 2000 && //was 500 408 if (listener.requestThroughput() - listener.processedThroughput() <= 2000 && //was 500
312 - lastDuration <= GOAL_CYCLE_PERIOD) { 409 + lastDuration <= cyclePeriod) {
313 lastCount = Math.min(lastCount + 1000, intents.size() / 2); 410 lastCount = Math.min(lastCount + 1000, intents.size() / 2);
314 } else { 411 } else {
315 lastCount *= 0.8; 412 lastCount *= 0.8;
...@@ -324,8 +421,8 @@ public class IntentPerfInstaller { ...@@ -324,8 +421,8 @@ public class IntentPerfInstaller {
324 // Event listener to monitor throughput. 421 // Event listener to monitor throughput.
325 final class Listener implements IntentListener { 422 final class Listener implements IntentListener {
326 423
327 - private Map<IntentEvent.Type, Counter> counters;
328 private final Counter runningTotal = new Counter(); 424 private final Counter runningTotal = new Counter();
425 + private volatile Map<IntentEvent.Type, Counter> counters;
329 426
330 private volatile double processedThroughput = 0; 427 private volatile double processedThroughput = 0;
331 private volatile double requestThroughput = 0; 428 private volatile double requestThroughput = 0;
......
...@@ -13,10 +13,9 @@ ...@@ -13,10 +13,9 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.store.intent.impl; 16 +package org.onosproject.net.intent;
17 17
18 import org.onosproject.cluster.NodeId; 18 import org.onosproject.cluster.NodeId;
19 -import org.onosproject.net.intent.Key;
20 19
21 /** 20 /**
22 * Service for interacting with the partition-to-instance assignments. 21 * Service for interacting with the partition-to-instance assignments.
......
...@@ -33,6 +33,7 @@ import org.onosproject.net.intent.IntentState; ...@@ -33,6 +33,7 @@ import org.onosproject.net.intent.IntentState;
33 import org.onosproject.net.intent.IntentStore; 33 import org.onosproject.net.intent.IntentStore;
34 import org.onosproject.net.intent.IntentStoreDelegate; 34 import org.onosproject.net.intent.IntentStoreDelegate;
35 import org.onosproject.net.intent.Key; 35 import org.onosproject.net.intent.Key;
36 +import org.onosproject.net.intent.PartitionService;
36 import org.onosproject.store.AbstractStore; 37 import org.onosproject.store.AbstractStore;
37 import org.onosproject.store.cluster.messaging.ClusterCommunicationService; 38 import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
38 import org.onosproject.store.ecmap.EventuallyConsistentMap; 39 import org.onosproject.store.ecmap.EventuallyConsistentMap;
......
...@@ -31,6 +31,7 @@ import org.onosproject.cluster.LeadershipEventListener; ...@@ -31,6 +31,7 @@ import org.onosproject.cluster.LeadershipEventListener;
31 import org.onosproject.cluster.LeadershipService; 31 import org.onosproject.cluster.LeadershipService;
32 import org.onosproject.cluster.NodeId; 32 import org.onosproject.cluster.NodeId;
33 import org.onosproject.net.intent.Key; 33 import org.onosproject.net.intent.Key;
34 +import org.onosproject.net.intent.PartitionService;
34 import org.slf4j.Logger; 35 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory; 36 import org.slf4j.LoggerFactory;
36 37
......