tom

Reworked AbstractDistributedStore RemoteEventHandler to allow delegating various…

… events to accommodate cache-specific behaviours.
...@@ -8,6 +8,11 @@ import org.onlab.onos.event.Event; ...@@ -8,6 +8,11 @@ import org.onlab.onos.event.Event;
8 */ 8 */
9 public interface StoreDelegate<E extends Event> { 9 public interface StoreDelegate<E extends Event> {
10 10
11 + /**
12 + * Notifies the delegate via the specified event.
13 + *
14 + * @param event store generated event
15 + */
11 void notify(E event); 16 void notify(E event);
12 17
13 } 18 }
......
...@@ -160,7 +160,7 @@ public class DistributedDeviceManagerTest { ...@@ -160,7 +160,7 @@ public class DistributedDeviceManagerTest {
160 public void deviceDisconnected() { 160 public void deviceDisconnected() {
161 connectDevice(DID1, SW1); 161 connectDevice(DID1, SW1);
162 connectDevice(DID2, SW1); 162 connectDevice(DID2, SW1);
163 - validateEvents(DEVICE_ADDED, DEVICE_ADDED); 163 + validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED);
164 assertTrue("device should be available", service.isAvailable(DID1)); 164 assertTrue("device should be available", service.isAvailable(DID1));
165 165
166 // Disconnect 166 // Disconnect
...@@ -179,7 +179,7 @@ public class DistributedDeviceManagerTest { ...@@ -179,7 +179,7 @@ public class DistributedDeviceManagerTest {
179 @Test 179 @Test
180 public void deviceUpdated() { 180 public void deviceUpdated() {
181 connectDevice(DID1, SW1); 181 connectDevice(DID1, SW1);
182 - validateEvents(DEVICE_ADDED); 182 + validateEvents(DEVICE_ADDED, DEVICE_ADDED);
183 183
184 connectDevice(DID1, SW2); 184 connectDevice(DID1, SW2);
185 validateEvents(DEVICE_UPDATED); 185 validateEvents(DEVICE_UPDATED);
...@@ -199,7 +199,7 @@ public class DistributedDeviceManagerTest { ...@@ -199,7 +199,7 @@ public class DistributedDeviceManagerTest {
199 pds.add(new DefaultPortDescription(P2, true)); 199 pds.add(new DefaultPortDescription(P2, true));
200 pds.add(new DefaultPortDescription(P3, true)); 200 pds.add(new DefaultPortDescription(P3, true));
201 providerService.updatePorts(DID1, pds); 201 providerService.updatePorts(DID1, pds);
202 - validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED); 202 + validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED);
203 pds.clear(); 203 pds.clear();
204 204
205 pds.add(new DefaultPortDescription(P1, false)); 205 pds.add(new DefaultPortDescription(P1, false));
...@@ -215,7 +215,7 @@ public class DistributedDeviceManagerTest { ...@@ -215,7 +215,7 @@ public class DistributedDeviceManagerTest {
215 pds.add(new DefaultPortDescription(P1, true)); 215 pds.add(new DefaultPortDescription(P1, true));
216 pds.add(new DefaultPortDescription(P2, true)); 216 pds.add(new DefaultPortDescription(P2, true));
217 providerService.updatePorts(DID1, pds); 217 providerService.updatePorts(DID1, pds);
218 - validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED); 218 + validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
219 219
220 providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false)); 220 providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
221 validateEvents(PORT_UPDATED); 221 validateEvents(PORT_UPDATED);
...@@ -230,7 +230,7 @@ public class DistributedDeviceManagerTest { ...@@ -230,7 +230,7 @@ public class DistributedDeviceManagerTest {
230 pds.add(new DefaultPortDescription(P1, true)); 230 pds.add(new DefaultPortDescription(P1, true));
231 pds.add(new DefaultPortDescription(P2, true)); 231 pds.add(new DefaultPortDescription(P2, true));
232 providerService.updatePorts(DID1, pds); 232 providerService.updatePorts(DID1, pds);
233 - validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED); 233 + validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
234 assertEquals("wrong port count", 2, service.getPorts(DID1).size()); 234 assertEquals("wrong port count", 2, service.getPorts(DID1).size());
235 235
236 Port port = service.getPort(DID1, P1); 236 Port port = service.getPort(DID1, P1);
...@@ -244,10 +244,10 @@ public class DistributedDeviceManagerTest { ...@@ -244,10 +244,10 @@ public class DistributedDeviceManagerTest {
244 connectDevice(DID2, SW2); 244 connectDevice(DID2, SW2);
245 assertEquals("incorrect device count", 2, service.getDeviceCount()); 245 assertEquals("incorrect device count", 2, service.getDeviceCount());
246 admin.removeDevice(DID1); 246 admin.removeDevice(DID1);
247 + validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_REMOVED, DEVICE_REMOVED);
247 assertNull("device should not be found", service.getDevice(DID1)); 248 assertNull("device should not be found", service.getDevice(DID1));
248 assertNotNull("device should be found", service.getDevice(DID2)); 249 assertNotNull("device should be found", service.getDevice(DID2));
249 assertEquals("incorrect device count", 1, service.getDeviceCount()); 250 assertEquals("incorrect device count", 1, service.getDeviceCount());
250 -
251 } 251 }
252 252
253 protected void validateEvents(Enum... types) { 253 protected void validateEvents(Enum... types) {
......
...@@ -7,7 +7,6 @@ import com.google.common.collect.ImmutableSet; ...@@ -7,7 +7,6 @@ import com.google.common.collect.ImmutableSet;
7 import com.google.common.collect.ImmutableSet.Builder; 7 import com.google.common.collect.ImmutableSet.Builder;
8 import com.hazelcast.core.IMap; 8 import com.hazelcast.core.IMap;
9 import com.hazelcast.core.ISet; 9 import com.hazelcast.core.ISet;
10 -
11 import org.apache.felix.scr.annotations.Activate; 10 import org.apache.felix.scr.annotations.Activate;
12 import org.apache.felix.scr.annotations.Component; 11 import org.apache.felix.scr.annotations.Component;
13 import org.apache.felix.scr.annotations.Deactivate; 12 import org.apache.felix.scr.annotations.Deactivate;
...@@ -38,6 +37,7 @@ import java.util.List; ...@@ -38,6 +37,7 @@ import java.util.List;
38 import java.util.Map; 37 import java.util.Map;
39 import java.util.Objects; 38 import java.util.Objects;
40 import java.util.Set; 39 import java.util.Set;
40 +
41 import static com.google.common.base.Preconditions.checkArgument; 41 import static com.google.common.base.Preconditions.checkArgument;
42 import static com.google.common.cache.CacheBuilder.newBuilder; 42 import static com.google.common.cache.CacheBuilder.newBuilder;
43 import static org.onlab.onos.net.device.DeviceEvent.Type.*; 43 import static org.onlab.onos.net.device.DeviceEvent.Type.*;
...@@ -82,7 +82,7 @@ public class DistributedDeviceStore ...@@ -82,7 +82,7 @@ public class DistributedDeviceStore
82 = new OptionalCacheLoader<>(storeService, rawDevices); 82 = new OptionalCacheLoader<>(storeService, rawDevices);
83 devices = new AbsentInvalidatingLoadingCache<>(newBuilder().build(deviceLoader)); 83 devices = new AbsentInvalidatingLoadingCache<>(newBuilder().build(deviceLoader));
84 // refresh/populate cache based on notification from other instance 84 // refresh/populate cache based on notification from other instance
85 - rawDevices.addEntryListener(new RemoteEventHandler<>(devices), includeValue); 85 + rawDevices.addEntryListener(new RemoteDeviceEventHandler(devices), includeValue);
86 86
87 // TODO cache availableDevices 87 // TODO cache availableDevices
88 availableDevices = theInstance.getSet("availableDevices"); 88 availableDevices = theInstance.getSet("availableDevices");
...@@ -92,35 +92,25 @@ public class DistributedDeviceStore ...@@ -92,35 +92,25 @@ public class DistributedDeviceStore
92 = new OptionalCacheLoader<>(storeService, rawDevicePorts); 92 = new OptionalCacheLoader<>(storeService, rawDevicePorts);
93 devicePorts = new AbsentInvalidatingLoadingCache<>(newBuilder().build(devicePortLoader)); 93 devicePorts = new AbsentInvalidatingLoadingCache<>(newBuilder().build(devicePortLoader));
94 // refresh/populate cache based on notification from other instance 94 // refresh/populate cache based on notification from other instance
95 - rawDevicePorts.addEntryListener(new RemoteEventHandler<>(devicePorts), includeValue); 95 + rawDevicePorts.addEntryListener(new RemotePortEventHandler(devicePorts), includeValue);
96 +
97 + loadDeviceCache();
96 98
97 log.info("Started"); 99 log.info("Started");
98 } 100 }
99 101
100 @Deactivate 102 @Deactivate
101 public void deactivate() { 103 public void deactivate() {
102 -
103 log.info("Stopped"); 104 log.info("Stopped");
104 } 105 }
105 106
106 @Override 107 @Override
107 public int getDeviceCount() { 108 public int getDeviceCount() {
108 - // TODO IMap size or cache size? 109 + return devices.asMap().size();
109 - return rawDevices.size();
110 } 110 }
111 111
112 @Override 112 @Override
113 public Iterable<Device> getDevices() { 113 public Iterable<Device> getDevices() {
114 -// TODO Revisit if we ever need to do this.
115 -// log.info("{}:{}", rawMap.size(), cache.size());
116 -// if (rawMap.size() != cache.size()) {
117 -// for (Entry<byte[], byte[]> e : rawMap.entrySet()) {
118 -// final DeviceId key = deserialize(e.getKey());
119 -// final DefaultDevice val = deserialize(e.getValue());
120 -// cache.put(key, val);
121 -// }
122 -// }
123 -
124 // TODO builder v.s. copyOf. Guava semms to be using copyOf? 114 // TODO builder v.s. copyOf. Guava semms to be using copyOf?
125 Builder<Device> builder = ImmutableSet.builder(); 115 Builder<Device> builder = ImmutableSet.builder();
126 for (Optional<DefaultDevice> e : devices.asMap().values()) { 116 for (Optional<DefaultDevice> e : devices.asMap().values()) {
...@@ -131,6 +121,17 @@ public class DistributedDeviceStore ...@@ -131,6 +121,17 @@ public class DistributedDeviceStore
131 return builder.build(); 121 return builder.build();
132 } 122 }
133 123
124 + private void loadDeviceCache() {
125 + log.info("{}:{}", rawDevices.size(), devices.size());
126 + if (rawDevices.size() != devices.size()) {
127 + for (Map.Entry<byte[], byte[]> e : rawDevices.entrySet()) {
128 + final DeviceId key = deserialize(e.getKey());
129 + final DefaultDevice val = deserialize(e.getValue());
130 + devices.put(key, Optional.of(val));
131 + }
132 + }
133 + }
134 +
134 @Override 135 @Override
135 public Device getDevice(DeviceId deviceId) { 136 public Device getDevice(DeviceId deviceId) {
136 // TODO revisit if ignoring exception is safe. 137 // TODO revisit if ignoring exception is safe.
...@@ -162,7 +163,7 @@ public class DistributedDeviceStore ...@@ -162,7 +163,7 @@ public class DistributedDeviceStore
162 163
163 availableDevices.add(deviceIdBytes); 164 availableDevices.add(deviceIdBytes);
164 } 165 }
165 - return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null); 166 + return new DeviceEvent(DEVICE_ADDED, device, null);
166 } 167 }
167 168
168 // Updates the device and returns the appropriate event if necessary. 169 // Updates the device and returns the appropriate event if necessary.
...@@ -343,5 +344,48 @@ public class DistributedDeviceStore ...@@ -343,5 +344,48 @@ public class DistributedDeviceStore
343 } 344 }
344 } 345 }
345 346
347 + private class RemoteDeviceEventHandler extends RemoteEventHandler<DeviceId, DefaultDevice> {
348 + public RemoteDeviceEventHandler(LoadingCache<DeviceId, Optional<DefaultDevice>> cache) {
349 + super(cache);
350 + }
351 +
352 + @Override
353 + protected void onAdd(DeviceId deviceId, DefaultDevice device) {
354 + delegate.notify(new DeviceEvent(DEVICE_ADDED, device));
355 + }
356 +
357 + @Override
358 + protected void onRemove(DeviceId deviceId, DefaultDevice device) {
359 + delegate.notify(new DeviceEvent(DEVICE_REMOVED, device));
360 + }
361 +
362 + @Override
363 + protected void onUpdate(DeviceId deviceId, DefaultDevice device) {
364 + delegate.notify(new DeviceEvent(DEVICE_UPDATED, device));
365 + }
366 + }
367 +
368 + private class RemotePortEventHandler extends RemoteEventHandler<DeviceId, Map<PortNumber, Port>> {
369 + public RemotePortEventHandler(LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> cache) {
370 + super(cache);
371 + }
372 +
373 + @Override
374 + protected void onAdd(DeviceId deviceId, Map<PortNumber, Port> ports) {
375 +// delegate.notify(new DeviceEvent(PORT_ADDED, getDevice(deviceId)));
376 + }
377 +
378 + @Override
379 + protected void onRemove(DeviceId deviceId, Map<PortNumber, Port> ports) {
380 +// delegate.notify(new DeviceEvent(PORT_REMOVED, getDevice(deviceId)));
381 + }
382 +
383 + @Override
384 + protected void onUpdate(DeviceId deviceId, Map<PortNumber, Port> ports) {
385 +// delegate.notify(new DeviceEvent(PORT_UPDATED, getDevice(deviceId)));
386 + }
387 + }
388 +
389 +
346 // TODO cache serialized DeviceID if we suffer from serialization cost 390 // TODO cache serialized DeviceID if we suffer from serialization cost
347 } 391 }
......
...@@ -6,7 +6,6 @@ import com.hazelcast.core.EntryAdapter; ...@@ -6,7 +6,6 @@ import com.hazelcast.core.EntryAdapter;
6 import com.hazelcast.core.EntryEvent; 6 import com.hazelcast.core.EntryEvent;
7 import com.hazelcast.core.HazelcastInstance; 7 import com.hazelcast.core.HazelcastInstance;
8 import com.hazelcast.core.MapEvent; 8 import com.hazelcast.core.MapEvent;
9 -
10 import org.apache.felix.scr.annotations.Activate; 9 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 10 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Reference; 11 import org.apache.felix.scr.annotations.Reference;
...@@ -25,7 +24,7 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -25,7 +24,7 @@ import static org.slf4j.LoggerFactory.getLogger;
25 */ 24 */
26 @Component(componentAbstract = true) 25 @Component(componentAbstract = true)
27 public abstract class AbstractDistributedStore<E extends Event, D extends StoreDelegate<E>> 26 public abstract class AbstractDistributedStore<E extends Event, D extends StoreDelegate<E>>
28 - extends AbstractStore<E, D> { 27 + extends AbstractStore<E, D> {
29 28
30 protected final Logger log = getLogger(getClass()); 29 protected final Logger log = getLogger(getClass());
31 30
...@@ -67,7 +66,7 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD ...@@ -67,7 +66,7 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD
67 * @param <K> IMap key type after deserialization 66 * @param <K> IMap key type after deserialization
68 * @param <V> IMap value type after deserialization 67 * @param <V> IMap value type after deserialization
69 */ 68 */
70 - public final class RemoteEventHandler<K, V> extends EntryAdapter<byte[], byte[]> { 69 + public class RemoteEventHandler<K, V> extends EntryAdapter<byte[], byte[]> {
71 70
72 private LoadingCache<K, Optional<V>> cache; 71 private LoadingCache<K, Optional<V>> cache;
73 72
...@@ -86,26 +85,58 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD ...@@ -86,26 +85,58 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD
86 } 85 }
87 86
88 @Override 87 @Override
88 + public void entryAdded(EntryEvent<byte[], byte[]> event) {
89 + K key = deserialize(event.getKey());
90 + V newVal = deserialize(event.getValue());
91 + Optional<V> newValue = Optional.of(newVal);
92 + cache.asMap().putIfAbsent(key, newValue);
93 + onAdd(key, newVal);
94 + }
95 +
96 + @Override
89 public void entryUpdated(EntryEvent<byte[], byte[]> event) { 97 public void entryUpdated(EntryEvent<byte[], byte[]> event) {
90 - K key = storeService.<K>deserialize(event.getKey()); 98 + K key = deserialize(event.getKey());
91 - final V oldVal = storeService.<V>deserialize(event.getOldValue()); 99 + V oldVal = deserialize(event.getOldValue());
92 Optional<V> oldValue = Optional.fromNullable(oldVal); 100 Optional<V> oldValue = Optional.fromNullable(oldVal);
93 - final V newVal = storeService.<V>deserialize(event.getValue()); 101 + V newVal = deserialize(event.getValue());
94 Optional<V> newValue = Optional.of(newVal); 102 Optional<V> newValue = Optional.of(newVal);
95 cache.asMap().replace(key, oldValue, newValue); 103 cache.asMap().replace(key, oldValue, newValue);
104 + onUpdate(key, newVal);
96 } 105 }
97 106
98 @Override 107 @Override
99 public void entryRemoved(EntryEvent<byte[], byte[]> event) { 108 public void entryRemoved(EntryEvent<byte[], byte[]> event) {
100 - cache.invalidate(storeService.<K>deserialize(event.getKey())); 109 + K key = deserialize(event.getKey());
110 + V val = deserialize(event.getValue());
111 + cache.invalidate(key);
112 + onRemove(key, val);
101 } 113 }
102 114
103 - @Override 115 + /**
104 - public void entryAdded(EntryEvent<byte[], byte[]> event) { 116 + * Cache entry addition hook.
105 - K key = storeService.<K>deserialize(event.getKey()); 117 + *
106 - final V newVal = storeService.<V>deserialize(event.getValue()); 118 + * @param key new key
107 - Optional<V> newValue = Optional.of(newVal); 119 + * @param newVal new value
108 - cache.asMap().putIfAbsent(key, newValue); 120 + */
121 + protected void onAdd(K key, V newVal) {
122 + }
123 +
124 + /**
125 + * Cache entry update hook.
126 + *
127 + * @param key new key
128 + * @param newVal new value
129 + */
130 + protected void onUpdate(K key, V newVal) {
131 + }
132 +
133 + /**
134 + * Cache entry remove hook.
135 + *
136 + * @param key new key
137 + * @param val old value
138 + */
139 + protected void onRemove(K key, V val) {
109 } 140 }
110 } 141 }
111 142
......