Yuta HIGUCHI
Committed by Jonathan Hart

Lazily populate Pipeliner cache

Change-Id: Ibbb9312b47c2c61df9ed15370b46fb07a8c7a16c
...@@ -27,9 +27,6 @@ import org.onlab.osgi.DefaultServiceDirectory; ...@@ -27,9 +27,6 @@ import org.onlab.osgi.DefaultServiceDirectory;
27 import org.onlab.osgi.ServiceDirectory; 27 import org.onlab.osgi.ServiceDirectory;
28 import org.onlab.util.ItemNotFoundException; 28 import org.onlab.util.ItemNotFoundException;
29 import org.onosproject.cluster.ClusterService; 29 import org.onosproject.cluster.ClusterService;
30 -import org.onosproject.mastership.MastershipEvent;
31 -import org.onosproject.mastership.MastershipListener;
32 -import org.onosproject.mastership.MastershipService;
33 import org.onosproject.net.DeviceId; 30 import org.onosproject.net.DeviceId;
34 import org.onosproject.net.behaviour.NextGroup; 31 import org.onosproject.net.behaviour.NextGroup;
35 import org.onosproject.net.behaviour.Pipeliner; 32 import org.onosproject.net.behaviour.Pipeliner;
...@@ -87,9 +84,6 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -87,9 +84,6 @@ public class FlowObjectiveManager implements FlowObjectiveService {
87 protected DeviceService deviceService; 84 protected DeviceService deviceService;
88 85
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 - protected MastershipService mastershipService;
91 -
92 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected ClusterService clusterService; 87 protected ClusterService clusterService;
94 88
95 // Note: The following dependencies are added on behalf of the pipeline 89 // Note: The following dependencies are added on behalf of the pipeline
...@@ -116,7 +110,6 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -116,7 +110,6 @@ public class FlowObjectiveManager implements FlowObjectiveService {
116 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap(); 110 private final Map<DeviceId, Pipeliner> pipeliners = Maps.newConcurrentMap();
117 111
118 private final PipelinerContext context = new InnerPipelineContext(); 112 private final PipelinerContext context = new InnerPipelineContext();
119 - private final MastershipListener mastershipListener = new InnerMastershipListener();
120 private final DeviceListener deviceListener = new InnerDeviceListener(); 113 private final DeviceListener deviceListener = new InnerDeviceListener();
121 114
122 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); 115 protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
...@@ -133,16 +126,13 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -133,16 +126,13 @@ public class FlowObjectiveManager implements FlowObjectiveService {
133 protected void activate() { 126 protected void activate() {
134 executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d", log)); 127 executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d", log));
135 flowObjectiveStore.setDelegate(delegate); 128 flowObjectiveStore.setDelegate(delegate);
136 - mastershipService.addListener(mastershipListener);
137 deviceService.addListener(deviceListener); 129 deviceService.addListener(deviceListener);
138 - deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id()));
139 log.info("Started"); 130 log.info("Started");
140 } 131 }
141 132
142 @Deactivate 133 @Deactivate
143 protected void deactivate() { 134 protected void deactivate() {
144 flowObjectiveStore.unsetDelegate(delegate); 135 flowObjectiveStore.unsetDelegate(delegate);
145 - mastershipService.removeListener(mastershipListener);
146 deviceService.removeListener(deviceListener); 136 deviceService.removeListener(deviceListener);
147 executorService.shutdown(); 137 executorService.shutdown();
148 pipeliners.clear(); 138 pipeliners.clear();
...@@ -265,13 +255,24 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -265,13 +255,24 @@ public class FlowObjectiveManager implements FlowObjectiveService {
265 255
266 // Retrieves the device pipeline behaviour from the cache. 256 // Retrieves the device pipeline behaviour from the cache.
267 private Pipeliner getDevicePipeliner(DeviceId deviceId) { 257 private Pipeliner getDevicePipeliner(DeviceId deviceId) {
268 - return pipeliners.get(deviceId); 258 + return pipeliners.computeIfAbsent(deviceId, this::initPipelineHandler);
269 } 259 }
270 260
271 - private void setupPipelineHandler(DeviceId deviceId) { 261 + /**
262 + * Creates and initialize {@link Pipeliner}.
263 + * <p>
264 + * Note: Expected to be called under per-Device lock.
265 + * e.g., {@code pipeliners}' Map#compute family methods
266 + *
267 + * @param deviceId Device to initialize pipeliner
268 + * @return {@link Pipeliner} instance or null
269 + */
270 + private Pipeliner initPipelineHandler(DeviceId deviceId) {
271 + start = now();
272 + // ?? We never use defaultDriverService, do we still need this check?
272 if (defaultDriverService == null) { 273 if (defaultDriverService == null) {
273 // We're not ready to go to work yet. 274 // We're not ready to go to work yet.
274 - return; 275 + return null;
275 } 276 }
276 277
277 // Attempt to lookup the handler in the cache 278 // Attempt to lookup the handler in the cache
...@@ -286,11 +287,11 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -286,11 +287,11 @@ public class FlowObjectiveManager implements FlowObjectiveService {
286 if (!handler.driver().hasBehaviour(Pipeliner.class)) { 287 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
287 log.warn("Pipeline behaviour not supported for device {}", 288 log.warn("Pipeline behaviour not supported for device {}",
288 deviceId); 289 deviceId);
289 - return; 290 + return null;
290 } 291 }
291 } catch (ItemNotFoundException e) { 292 } catch (ItemNotFoundException e) {
292 log.warn("No applicable driver for device {}", deviceId); 293 log.warn("No applicable driver for device {}", deviceId);
293 - return; 294 + return null;
294 } 295 }
295 296
296 driverHandlers.put(deviceId, handler); 297 driverHandlers.put(deviceId, handler);
...@@ -304,28 +305,8 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -304,28 +305,8 @@ public class FlowObjectiveManager implements FlowObjectiveService {
304 Pipeliner pipeliner = handler.behaviour(Pipeliner.class); 305 Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
305 hbTime = now(); 306 hbTime = now();
306 pipeliner.init(deviceId, context); 307 pipeliner.init(deviceId, context);
307 - pipeliners.put(deviceId, pipeliner);
308 - }
309 -
310 - // Triggers driver setup when the local node becomes a device master.
311 - private class InnerMastershipListener implements MastershipListener {
312 - @Override
313 - public void event(MastershipEvent event) {
314 - switch (event.type()) {
315 - case MASTER_CHANGED:
316 - log.debug("mastership changed on device {}", event.subject());
317 - start = now();
318 - if (deviceService.isAvailable(event.subject())) {
319 - setupPipelineHandler(event.subject());
320 - }
321 stopWatch(); 308 stopWatch();
322 - break; 309 + return pipeliner;
323 - case BACKUPS_CHANGED:
324 - break;
325 - default:
326 - break;
327 - }
328 - }
329 } 310 }
330 311
331 // Triggers driver setup when a device is (re)detected. 312 // Triggers driver setup when a device is (re)detected.
...@@ -337,18 +318,23 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -337,18 +318,23 @@ public class FlowObjectiveManager implements FlowObjectiveService {
337 case DEVICE_AVAILABILITY_CHANGED: 318 case DEVICE_AVAILABILITY_CHANGED:
338 log.debug("Device either added or availability changed {}", 319 log.debug("Device either added or availability changed {}",
339 event.subject().id()); 320 event.subject().id());
340 - start = now();
341 if (deviceService.isAvailable(event.subject().id())) { 321 if (deviceService.isAvailable(event.subject().id())) {
342 log.debug("Device is now available {}", event.subject().id()); 322 log.debug("Device is now available {}", event.subject().id());
343 - setupPipelineHandler(event.subject().id()); 323 + getDevicePipeliner(event.subject().id());
324 + } else {
325 + log.debug("Device is no longer available {}", event.subject().id());
326 + // evict Pipeliner cache.
327 + // User might restart Device to assign new Driver/Pipeliner
328 + // loaded afterwards.
329 + pipeliners.remove(event.subject().id());
344 } 330 }
345 - stopWatch();
346 break; 331 break;
347 case DEVICE_UPDATED: 332 case DEVICE_UPDATED:
348 break; 333 break;
349 case DEVICE_REMOVED: 334 case DEVICE_REMOVED:
350 - break;
351 case DEVICE_SUSPENDED: 335 case DEVICE_SUSPENDED:
336 + // evict Pipeliner cache.
337 + pipeliners.remove(event.subject().id());
352 break; 338 break;
353 case PORT_ADDED: 339 case PORT_ADDED:
354 break; 340 break;
......
...@@ -23,9 +23,6 @@ import org.junit.Before; ...@@ -23,9 +23,6 @@ import org.junit.Before;
23 import org.junit.Test; 23 import org.junit.Test;
24 import org.onlab.junit.TestUtils; 24 import org.onlab.junit.TestUtils;
25 import org.onlab.packet.ChassisId; 25 import org.onlab.packet.ChassisId;
26 -import org.onosproject.mastership.MastershipEvent;
27 -import org.onosproject.mastership.MastershipListener;
28 -import org.onosproject.mastership.MastershipServiceAdapter;
29 import org.onosproject.net.DefaultAnnotations; 26 import org.onosproject.net.DefaultAnnotations;
30 import org.onosproject.net.DefaultDevice; 27 import org.onosproject.net.DefaultDevice;
31 import org.onosproject.net.Device; 28 import org.onosproject.net.Device;
...@@ -190,7 +187,6 @@ public class FlowObjectiveManagerTest { ...@@ -190,7 +187,6 @@ public class FlowObjectiveManagerTest {
190 public void initializeTest() { 187 public void initializeTest() {
191 manager = new FlowObjectiveManager(); 188 manager = new FlowObjectiveManager();
192 manager.flowObjectiveStore = new TestFlowObjectiveStore(); 189 manager.flowObjectiveStore = new TestFlowObjectiveStore();
193 - manager.mastershipService = new MastershipServiceAdapter();
194 manager.deviceService = new TestDeviceService(); 190 manager.deviceService = new TestDeviceService();
195 manager.defaultDriverService = new TestDriversLoader(); 191 manager.defaultDriverService = new TestDriversLoader();
196 manager.driverService = new TestDriverService(); 192 manager.driverService = new TestDriverService();
...@@ -377,40 +373,4 @@ public class FlowObjectiveManagerTest { ...@@ -377,40 +373,4 @@ public class FlowObjectiveManagerTest {
377 assertThat(filteringObjectives, hasSize(0)); 373 assertThat(filteringObjectives, hasSize(0));
378 assertThat(nextObjectives, hasSize(0)); 374 assertThat(nextObjectives, hasSize(0));
379 } 375 }
380 -
381 - /**
382 - * Tests recepit of a device mastership event.
383 - *
384 - * @throws TestUtilsException if lookup of a field fails
385 - */
386 - @Test
387 - public void deviceMastershipEvent() throws TestUtilsException {
388 - TrafficSelector selector = DefaultTrafficSelector.emptySelector();
389 - TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
390 -
391 - MastershipEvent event =
392 - new MastershipEvent(MastershipEvent.Type.MASTER_CHANGED, id2, null);
393 - MastershipListener listener = TestUtils.getField(manager, "mastershipListener");
394 - assertThat(listener, notNullValue());
395 -
396 - listener.event(event);
397 -
398 - ForwardingObjective forward =
399 - DefaultForwardingObjective.builder()
400 - .fromApp(NetTestTools.APP_ID)
401 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
402 - .withSelector(selector)
403 - .withTreatment(treatment)
404 - .makePermanent()
405 - .add();
406 - manager.forward(id2, forward);
407 -
408 - // new device should have an objective now
409 - TestTools.assertAfter(RETRY_MS, () ->
410 - assertThat(forwardingObjectives, hasSize(1)));
411 -
412 - assertThat(forwardingObjectives, hasItem("of:d2"));
413 - assertThat(filteringObjectives, hasSize(0));
414 - assertThat(nextObjectives, hasSize(0));
415 - }
416 } 376 }
......