tom

Merge remote-tracking branch 'origin/master'

...@@ -44,6 +44,13 @@ ...@@ -44,6 +44,13 @@
44 <version>${project.version}</version> 44 <version>${project.version}</version>
45 <scope>test</scope> 45 <scope>test</scope>
46 </dependency> 46 </dependency>
47 + <dependency>
48 + <groupId>org.onlab.onos</groupId>
49 + <artifactId>onos-core-store</artifactId>
50 + <version>${project.version}</version>
51 + <classifier>tests</classifier>
52 + <scope>test</scope>
53 + </dependency>
47 54
48 <dependency> 55 <dependency>
49 <groupId>org.apache.felix</groupId> 56 <groupId>org.apache.felix</groupId>
......
...@@ -4,13 +4,15 @@ import com.google.common.collect.Iterables; ...@@ -4,13 +4,15 @@ import com.google.common.collect.Iterables;
4 import com.google.common.collect.Sets; 4 import com.google.common.collect.Sets;
5 import com.hazelcast.config.Config; 5 import com.hazelcast.config.Config;
6 import com.hazelcast.core.Hazelcast; 6 import com.hazelcast.core.Hazelcast;
7 -import com.hazelcast.core.HazelcastInstance; 7 +
8 import org.junit.After; 8 import org.junit.After;
9 import org.junit.Before; 9 import org.junit.Before;
10 import org.junit.Test; 10 import org.junit.Test;
11 +import org.onlab.onos.cluster.DefaultControllerNode;
11 import org.onlab.onos.cluster.MastershipServiceAdapter; 12 import org.onlab.onos.cluster.MastershipServiceAdapter;
12 import org.onlab.onos.cluster.NodeId; 13 import org.onlab.onos.cluster.NodeId;
13 import org.onlab.onos.event.Event; 14 import org.onlab.onos.event.Event;
15 +import org.onlab.onos.event.EventDeliveryService;
14 import org.onlab.onos.event.impl.TestEventDispatcher; 16 import org.onlab.onos.event.impl.TestEventDispatcher;
15 import org.onlab.onos.net.Device; 17 import org.onlab.onos.net.Device;
16 import org.onlab.onos.net.DeviceId; 18 import org.onlab.onos.net.DeviceId;
...@@ -30,23 +32,26 @@ import org.onlab.onos.net.device.DeviceService; ...@@ -30,23 +32,26 @@ import org.onlab.onos.net.device.DeviceService;
30 import org.onlab.onos.net.device.PortDescription; 32 import org.onlab.onos.net.device.PortDescription;
31 import org.onlab.onos.net.provider.AbstractProvider; 33 import org.onlab.onos.net.provider.AbstractProvider;
32 import org.onlab.onos.net.provider.ProviderId; 34 import org.onlab.onos.net.provider.ProviderId;
33 -import org.onlab.onos.store.common.StoreService;
34 import org.onlab.onos.store.device.impl.DistributedDeviceStore; 35 import org.onlab.onos.store.device.impl.DistributedDeviceStore;
35 import org.onlab.onos.store.impl.StoreManager; 36 import org.onlab.onos.store.impl.StoreManager;
37 +import org.onlab.onos.store.impl.TestStoreManager;
38 +import org.onlab.packet.IpPrefix;
36 39
37 import java.util.ArrayList; 40 import java.util.ArrayList;
41 +import java.util.HashSet;
38 import java.util.Iterator; 42 import java.util.Iterator;
39 import java.util.List; 43 import java.util.List;
44 +import java.util.Map.Entry;
40 import java.util.Set; 45 import java.util.Set;
41 -import java.util.UUID; 46 +import java.util.concurrent.ConcurrentHashMap;
47 +import java.util.concurrent.ConcurrentMap;
42 48
43 import static org.junit.Assert.*; 49 import static org.junit.Assert.*;
44 import static org.onlab.onos.net.Device.Type.SWITCH; 50 import static org.onlab.onos.net.Device.Type.SWITCH;
45 import static org.onlab.onos.net.DeviceId.deviceId; 51 import static org.onlab.onos.net.DeviceId.deviceId;
46 import static org.onlab.onos.net.device.DeviceEvent.Type.*; 52 import static org.onlab.onos.net.device.DeviceEvent.Type.*;
47 53
48 -// FIXME This test is painfully slow starting up Hazelcast on each test cases, 54 +// FIXME This test is slow starting up Hazelcast on each test cases.
49 -// turning it off in repository for now.
50 // FIXME DistributedDeviceStore should have it's own test cases. 55 // FIXME DistributedDeviceStore should have it's own test cases.
51 56
52 /** 57 /**
...@@ -67,6 +72,11 @@ public class DistributedDeviceManagerTest { ...@@ -67,6 +72,11 @@ public class DistributedDeviceManagerTest {
67 private static final PortNumber P2 = PortNumber.portNumber(2); 72 private static final PortNumber P2 = PortNumber.portNumber(2);
68 private static final PortNumber P3 = PortNumber.portNumber(3); 73 private static final PortNumber P3 = PortNumber.portNumber(3);
69 74
75 + private static final DefaultControllerNode SELF
76 + = new DefaultControllerNode(new NodeId("foobar"),
77 + IpPrefix.valueOf("127.0.0.1"));
78 +
79 +
70 private DeviceManager mgr; 80 private DeviceManager mgr;
71 81
72 protected StoreManager storeManager; 82 protected StoreManager storeManager;
...@@ -77,6 +87,8 @@ public class DistributedDeviceManagerTest { ...@@ -77,6 +87,8 @@ public class DistributedDeviceManagerTest {
77 protected TestProvider provider; 87 protected TestProvider provider;
78 protected TestListener listener = new TestListener(); 88 protected TestListener listener = new TestListener();
79 private DistributedDeviceStore dstore; 89 private DistributedDeviceStore dstore;
90 + private TestMastershipManager masterManager;
91 + private EventDeliveryService eventService;
80 92
81 @Before 93 @Before
82 public void setUp() { 94 public void setUp() {
...@@ -84,26 +96,21 @@ public class DistributedDeviceManagerTest { ...@@ -84,26 +96,21 @@ public class DistributedDeviceManagerTest {
84 service = mgr; 96 service = mgr;
85 admin = mgr; 97 admin = mgr;
86 registry = mgr; 98 registry = mgr;
87 - // FIXME should be reading the hazelcast.xml 99 + // TODO should find a way to clean Hazelcast instance without shutdown.
88 - Config config = new Config(); 100 + Config config = TestStoreManager.getTestConfig();
89 - // avoid accidentally joining other cluster 101 +
90 - config.getGroupConfig().setName(UUID.randomUUID().toString()); 102 + masterManager = new TestMastershipManager();
91 - // quickly form single node cluster
92 - config.getNetworkConfig().getJoin()
93 - .getTcpIpConfig()
94 - .setEnabled(true).setConnectionTimeoutSeconds(0);
95 - config.getNetworkConfig().getJoin()
96 - .getMulticastConfig()
97 - .setEnabled(false);
98 103
99 storeManager = new TestStoreManager(Hazelcast.newHazelcastInstance(config)); 104 storeManager = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
100 storeManager.activate(); 105 storeManager.activate();
101 106
102 - dstore = new TestDistributedDeviceStore(storeManager); 107 + dstore = new TestDistributedDeviceStore();
103 dstore.activate(); 108 dstore.activate();
109 +
104 mgr.store = dstore; 110 mgr.store = dstore;
105 - mgr.eventDispatcher = new TestEventDispatcher(); 111 + eventService = new TestEventDispatcher();
106 - mgr.mastershipService = new TestMastershipService(); 112 + mgr.eventDispatcher = eventService;
113 + mgr.mastershipService = masterManager;
107 mgr.activate(); 114 mgr.activate();
108 115
109 service.addListener(listener); 116 service.addListener(listener);
...@@ -283,23 +290,21 @@ public class DistributedDeviceManagerTest { ...@@ -283,23 +290,21 @@ public class DistributedDeviceManagerTest {
283 } 290 }
284 291
285 private class TestDistributedDeviceStore extends DistributedDeviceStore { 292 private class TestDistributedDeviceStore extends DistributedDeviceStore {
286 - public TestDistributedDeviceStore(StoreService storeService) { 293 +
287 - this.storeService = storeService; 294 + public TestDistributedDeviceStore() {
295 + this.storeService = storeManager;
288 } 296 }
289 } 297 }
290 298
291 - private class TestStoreManager extends StoreManager { 299 + private static class TestMastershipManager extends MastershipServiceAdapter {
292 - TestStoreManager(HazelcastInstance instance) {
293 - this.instance = instance;
294 - }
295 300
296 - @Override 301 + private ConcurrentMap<DeviceId, NodeId> masters = new ConcurrentHashMap<>();
297 - public void activate() {
298 - setupKryoPool();
299 - }
300 - }
301 302
302 - private static class TestMastershipService extends MastershipServiceAdapter { 303 + public TestMastershipManager() {
304 + // SELF master of all initially
305 + masters.put(DID1, SELF.id());
306 + masters.put(DID1, SELF.id());
307 + }
303 @Override 308 @Override
304 public MastershipRole getLocalRole(DeviceId deviceId) { 309 public MastershipRole getLocalRole(DeviceId deviceId) {
305 return MastershipRole.MASTER; 310 return MastershipRole.MASTER;
...@@ -307,13 +312,27 @@ public class DistributedDeviceManagerTest { ...@@ -307,13 +312,27 @@ public class DistributedDeviceManagerTest {
307 312
308 @Override 313 @Override
309 public Set<DeviceId> getDevicesOf(NodeId nodeId) { 314 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
310 - return Sets.newHashSet(DID1, DID2); 315 + HashSet<DeviceId> set = Sets.newHashSet();
316 + for (Entry<DeviceId, NodeId> e : masters.entrySet()) {
317 + if (e.getValue().equals(nodeId)) {
318 + set.add(e.getKey());
319 + }
320 + }
321 + return set;
311 } 322 }
312 323
313 @Override 324 @Override
314 public MastershipRole requestRoleFor(DeviceId deviceId) { 325 public MastershipRole requestRoleFor(DeviceId deviceId) {
315 - return MastershipRole.MASTER; 326 + if (SELF.id().equals(masters.get(deviceId))) {
327 + return MastershipRole.MASTER;
328 + } else {
329 + return MastershipRole.STANDBY;
330 + }
316 } 331 }
317 - }
318 332
333 + @Override
334 + public void relinquishMastership(DeviceId deviceId) {
335 + masters.remove(deviceId, SELF.id());
336 + }
337 + }
319 } 338 }
......
...@@ -7,6 +7,7 @@ import com.google.common.collect.ImmutableSet; ...@@ -7,6 +7,7 @@ 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 +
10 import org.apache.felix.scr.annotations.Activate; 11 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 12 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Deactivate; 13 import org.apache.felix.scr.annotations.Deactivate;
...@@ -15,7 +16,6 @@ import org.onlab.onos.net.DefaultDevice; ...@@ -15,7 +16,6 @@ import org.onlab.onos.net.DefaultDevice;
15 import org.onlab.onos.net.DefaultPort; 16 import org.onlab.onos.net.DefaultPort;
16 import org.onlab.onos.net.Device; 17 import org.onlab.onos.net.Device;
17 import org.onlab.onos.net.DeviceId; 18 import org.onlab.onos.net.DeviceId;
18 -import org.onlab.onos.net.MastershipRole;
19 import org.onlab.onos.net.Port; 19 import org.onlab.onos.net.Port;
20 import org.onlab.onos.net.PortNumber; 20 import org.onlab.onos.net.PortNumber;
21 import org.onlab.onos.net.device.DeviceDescription; 21 import org.onlab.onos.net.device.DeviceDescription;
...@@ -38,7 +38,6 @@ import java.util.List; ...@@ -38,7 +38,6 @@ import java.util.List;
38 import java.util.Map; 38 import java.util.Map;
39 import java.util.Objects; 39 import java.util.Objects;
40 import java.util.Set; 40 import java.util.Set;
41 -
42 import static com.google.common.base.Preconditions.checkArgument; 41 import static com.google.common.base.Preconditions.checkArgument;
43 import static com.google.common.cache.CacheBuilder.newBuilder; 42 import static com.google.common.cache.CacheBuilder.newBuilder;
44 import static org.onlab.onos.net.device.DeviceEvent.Type.*; 43 import static org.onlab.onos.net.device.DeviceEvent.Type.*;
...@@ -61,10 +60,6 @@ public class DistributedDeviceStore ...@@ -61,10 +60,6 @@ public class DistributedDeviceStore
61 private IMap<byte[], byte[]> rawDevices; 60 private IMap<byte[], byte[]> rawDevices;
62 private LoadingCache<DeviceId, Optional<DefaultDevice>> devices; 61 private LoadingCache<DeviceId, Optional<DefaultDevice>> devices;
63 62
64 - // private IMap<DeviceId, MastershipRole> roles;
65 - private IMap<byte[], byte[]> rawRoles;
66 - private LoadingCache<DeviceId, Optional<MastershipRole>> roles;
67 -
68 // private ISet<DeviceId> availableDevices; 63 // private ISet<DeviceId> availableDevices;
69 private ISet<byte[]> availableDevices; 64 private ISet<byte[]> availableDevices;
70 65
...@@ -73,6 +68,7 @@ public class DistributedDeviceStore ...@@ -73,6 +68,7 @@ public class DistributedDeviceStore
73 private IMap<byte[], byte[]> rawDevicePorts; 68 private IMap<byte[], byte[]> rawDevicePorts;
74 private LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> devicePorts; 69 private LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> devicePorts;
75 70
71 + @Override
76 @Activate 72 @Activate
77 public void activate() { 73 public void activate() {
78 super.activate(); 74 super.activate();
...@@ -88,13 +84,6 @@ public class DistributedDeviceStore ...@@ -88,13 +84,6 @@ public class DistributedDeviceStore
88 // refresh/populate cache based on notification from other instance 84 // refresh/populate cache based on notification from other instance
89 rawDevices.addEntryListener(new RemoteEventHandler<>(devices), includeValue); 85 rawDevices.addEntryListener(new RemoteEventHandler<>(devices), includeValue);
90 86
91 - rawRoles = theInstance.getMap("roles");
92 - final OptionalCacheLoader<DeviceId, MastershipRole> rolesLoader
93 - = new OptionalCacheLoader<>(storeService, rawRoles);
94 - roles = new AbsentInvalidatingLoadingCache<>(newBuilder().build(rolesLoader));
95 - // refresh/populate cache based on notification from other instance
96 - rawRoles.addEntryListener(new RemoteEventHandler<>(roles), includeValue);
97 -
98 // TODO cache availableDevices 87 // TODO cache availableDevices
99 availableDevices = theInstance.getSet("availableDevices"); 88 availableDevices = theInstance.getSet("availableDevices");
100 89
...@@ -110,6 +99,7 @@ public class DistributedDeviceStore ...@@ -110,6 +99,7 @@ public class DistributedDeviceStore
110 99
111 @Deactivate 100 @Deactivate
112 public void deactivate() { 101 public void deactivate() {
102 +
113 log.info("Stopped"); 103 log.info("Stopped");
114 } 104 }
115 105
...@@ -171,10 +161,6 @@ public class DistributedDeviceStore ...@@ -171,10 +161,6 @@ public class DistributedDeviceStore
171 devices.put(deviceId, Optional.of(device)); 161 devices.put(deviceId, Optional.of(device));
172 162
173 availableDevices.add(deviceIdBytes); 163 availableDevices.add(deviceIdBytes);
174 -
175 - // For now claim the device as a master automatically.
176 - //rawRoles.put(deviceIdBytes, serialize(MastershipRole.MASTER));
177 - //roles.put(deviceId, Optional.of(MastershipRole.MASTER));
178 } 164 }
179 return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null); 165 return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null);
180 } 166 }
...@@ -348,8 +334,6 @@ public class DistributedDeviceStore ...@@ -348,8 +334,6 @@ public class DistributedDeviceStore
348 public DeviceEvent removeDevice(DeviceId deviceId) { 334 public DeviceEvent removeDevice(DeviceId deviceId) {
349 synchronized (this) { 335 synchronized (this) {
350 byte[] deviceIdBytes = serialize(deviceId); 336 byte[] deviceIdBytes = serialize(deviceId);
351 - rawRoles.remove(deviceIdBytes);
352 - roles.invalidate(deviceId);
353 337
354 // TODO conditional remove? 338 // TODO conditional remove?
355 Device device = deserialize(rawDevices.remove(deviceIdBytes)); 339 Device device = deserialize(rawDevices.remove(deviceIdBytes));
...@@ -360,5 +344,4 @@ public class DistributedDeviceStore ...@@ -360,5 +344,4 @@ public class DistributedDeviceStore
360 } 344 }
361 345
362 // TODO cache serialized DeviceID if we suffer from serialization cost 346 // TODO cache serialized DeviceID if we suffer from serialization cost
363 -
364 } 347 }
......
...@@ -6,6 +6,7 @@ import com.hazelcast.core.EntryAdapter; ...@@ -6,6 +6,7 @@ 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 +
9 import org.apache.felix.scr.annotations.Activate; 10 import org.apache.felix.scr.annotations.Activate;
10 import org.apache.felix.scr.annotations.Component; 11 import org.apache.felix.scr.annotations.Component;
11 import org.apache.felix.scr.annotations.Reference; 12 import org.apache.felix.scr.annotations.Reference;
...@@ -86,8 +87,12 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD ...@@ -86,8 +87,12 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD
86 87
87 @Override 88 @Override
88 public void entryUpdated(EntryEvent<byte[], byte[]> event) { 89 public void entryUpdated(EntryEvent<byte[], byte[]> event) {
89 - cache.put(storeService.<K>deserialize(event.getKey()), 90 + K key = storeService.<K>deserialize(event.getKey());
90 - Optional.of(storeService.<V>deserialize(event.getValue()))); 91 + final V oldVal = storeService.<V>deserialize(event.getOldValue());
92 + Optional<V> oldValue = Optional.fromNullable(oldVal);
93 + final V newVal = storeService.<V>deserialize(event.getValue());
94 + Optional<V> newValue = Optional.of(newVal);
95 + cache.asMap().replace(key, oldValue, newValue);
91 } 96 }
92 97
93 @Override 98 @Override
...@@ -97,7 +102,10 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD ...@@ -97,7 +102,10 @@ public abstract class AbstractDistributedStore<E extends Event, D extends StoreD
97 102
98 @Override 103 @Override
99 public void entryAdded(EntryEvent<byte[], byte[]> event) { 104 public void entryAdded(EntryEvent<byte[], byte[]> event) {
100 - entryUpdated(event); 105 + K key = storeService.<K>deserialize(event.getKey());
106 + final V newVal = storeService.<V>deserialize(event.getValue());
107 + Optional<V> newValue = Optional.of(newVal);
108 + cache.asMap().putIfAbsent(key, newValue);
101 } 109 }
102 } 110 }
103 111
......
...@@ -45,7 +45,7 @@ import java.util.HashMap; ...@@ -45,7 +45,7 @@ import java.util.HashMap;
45 @Service 45 @Service
46 public class StoreManager implements StoreService { 46 public class StoreManager implements StoreService {
47 47
48 - private static final String HAZELCAST_XML_FILE = "etc/hazelcast.xml"; 48 + protected static final String HAZELCAST_XML_FILE = "etc/hazelcast.xml";
49 49
50 private final Logger log = LoggerFactory.getLogger(getClass()); 50 private final Logger log = LoggerFactory.getLogger(getClass());
51 51
......
1 +package org.onlab.onos.store.impl;
2 +
3 +import java.io.FileNotFoundException;
4 +import java.util.UUID;
5 +
6 +import com.hazelcast.config.Config;
7 +import com.hazelcast.config.FileSystemXmlConfig;
8 +import com.hazelcast.core.HazelcastInstance;
9 +
10 +/**
11 + * Dummy StoreManager to use specified Hazelcast instance.
12 + */
13 +public class TestStoreManager extends StoreManager {
14 +
15 + /**
16 + * Gets the Hazelcast Config for testing.
17 + *
18 + * @return
19 + */
20 + public static Config getTestConfig() {
21 + Config config;
22 + try {
23 + config = new FileSystemXmlConfig(HAZELCAST_XML_FILE);
24 + } catch (FileNotFoundException e) {
25 + // falling back to default
26 + config = new Config();
27 + }
28 + // avoid accidentally joining other cluster
29 + config.getGroupConfig().setName(UUID.randomUUID().toString());
30 + // quickly form single node cluster
31 + config.getNetworkConfig().getJoin()
32 + .getTcpIpConfig()
33 + .setEnabled(true).setConnectionTimeoutSeconds(0);
34 + config.getNetworkConfig().getJoin()
35 + .getMulticastConfig()
36 + .setEnabled(false);
37 + return config;
38 + }
39 +
40 + /**
41 + * Constructor.
42 + *
43 + * @param instance Hazelast instance to return on #getHazelcastInstance()
44 + */
45 + public TestStoreManager(HazelcastInstance instance) {
46 + this.instance = instance;
47 + }
48 +
49 + // Hazelcast setup removed from original code.
50 + @Override
51 + public void activate() {
52 + setupKryoPool();
53 + }
54 +}
...@@ -16,6 +16,18 @@ ...@@ -16,6 +16,18 @@
16 16
17 <description>ONOS OpenFlow controller subsystem API</description> 17 <description>ONOS OpenFlow controller subsystem API</description>
18 18
19 + <repositories>
20 + <!-- FIXME: for Loxigen. Decide how to use Loxigen before release. -->
21 + <repository>
22 + <id>sonatype-oss-snapshot</id>
23 + <name>Sonatype OSS snapshot repository</name>
24 + <url>https://oss.sonatype.org/content/repositories/snapshots</url>
25 + <releases>
26 + <enabled>false</enabled>
27 + </releases>
28 + </repository>
29 + </repositories>
30 +
19 <dependencies> 31 <dependencies>
20 <dependency> 32 <dependency>
21 <groupId>org.projectfloodlight</groupId> 33 <groupId>org.projectfloodlight</groupId>
......