Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
64 changed files
with
1213 additions
and
105 deletions
... | @@ -56,7 +56,8 @@ public interface MastershipService { | ... | @@ -56,7 +56,8 @@ public interface MastershipService { |
56 | Set<DeviceId> getDevicesOf(NodeId nodeId); | 56 | Set<DeviceId> getDevicesOf(NodeId nodeId); |
57 | 57 | ||
58 | /** | 58 | /** |
59 | - * Returns the mastership term service for getting term information. | 59 | + * Returns the mastership term service for getting read-only |
60 | + * term information. | ||
60 | * | 61 | * |
61 | * @return the MastershipTermService for this mastership manager | 62 | * @return the MastershipTermService for this mastership manager |
62 | */ | 63 | */ | ... | ... |
... | @@ -64,4 +64,14 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD | ... | @@ -64,4 +64,14 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD |
64 | * @return the current master's ID and the term value for device, or null | 64 | * @return the current master's ID and the term value for device, or null |
65 | */ | 65 | */ |
66 | MastershipTerm getTermFor(DeviceId deviceId); | 66 | MastershipTerm getTermFor(DeviceId deviceId); |
67 | + | ||
68 | + /** | ||
69 | + * Revokes a controller instance's mastership over a device and hands | ||
70 | + * over mastership to another controller instance. | ||
71 | + * | ||
72 | + * @param nodeId the controller instance identifier | ||
73 | + * @param deviceId device to revoke mastership for | ||
74 | + * @return a mastership event | ||
75 | + */ | ||
76 | + MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId); | ||
67 | } | 77 | } | ... | ... |
... | @@ -48,6 +48,7 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -48,6 +48,7 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
48 | DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | 48 | DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, |
49 | DeviceDescription deviceDescription); | 49 | DeviceDescription deviceDescription); |
50 | 50 | ||
51 | + // TODO: We may need to enforce that ancillary cannot interfere this state | ||
51 | /** | 52 | /** |
52 | * Removes the specified infrastructure device. | 53 | * Removes the specified infrastructure device. |
53 | * | 54 | * |
... | @@ -60,22 +61,24 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -60,22 +61,24 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
60 | * Updates the ports of the specified infrastructure device using the given | 61 | * Updates the ports of the specified infrastructure device using the given |
61 | * list of port descriptions. The list is assumed to be comprehensive. | 62 | * list of port descriptions. The list is assumed to be comprehensive. |
62 | * | 63 | * |
64 | + * @param providerId provider identifier | ||
63 | * @param deviceId device identifier | 65 | * @param deviceId device identifier |
64 | * @param portDescriptions list of port descriptions | 66 | * @param portDescriptions list of port descriptions |
65 | * @return ready to send events describing what occurred; empty list if no change | 67 | * @return ready to send events describing what occurred; empty list if no change |
66 | */ | 68 | */ |
67 | - List<DeviceEvent> updatePorts(DeviceId deviceId, | 69 | + List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
68 | List<PortDescription> portDescriptions); | 70 | List<PortDescription> portDescriptions); |
69 | 71 | ||
70 | /** | 72 | /** |
71 | * Updates the port status of the specified infrastructure device using the | 73 | * Updates the port status of the specified infrastructure device using the |
72 | * given port description. | 74 | * given port description. |
73 | * | 75 | * |
76 | + * @param providerId provider identifier | ||
74 | * @param deviceId device identifier | 77 | * @param deviceId device identifier |
75 | * @param portDescription port description | 78 | * @param portDescription port description |
76 | * @return ready to send event describing what occurred; null if no change | 79 | * @return ready to send event describing what occurred; null if no change |
77 | */ | 80 | */ |
78 | - DeviceEvent updatePortStatus(DeviceId deviceId, | 81 | + DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
79 | PortDescription portDescription); | 82 | PortDescription portDescription); |
80 | 83 | ||
81 | /** | 84 | /** | ... | ... |
... | @@ -35,10 +35,22 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro | ... | @@ -35,10 +35,22 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro |
35 | public synchronized S register(P provider) { | 35 | public synchronized S register(P provider) { |
36 | checkNotNull(provider, "Provider cannot be null"); | 36 | checkNotNull(provider, "Provider cannot be null"); |
37 | checkState(!services.containsKey(provider.id()), "Provider %s already registered", provider.id()); | 37 | checkState(!services.containsKey(provider.id()), "Provider %s already registered", provider.id()); |
38 | + | ||
39 | + // If the provider is a primary one, check for a conflict. | ||
40 | + ProviderId pid = provider.id(); | ||
41 | + checkState(pid.isAncillary() || !providersByScheme.containsKey(pid.scheme()), | ||
42 | + "A primary provider with id %s is already registered", | ||
43 | + providersByScheme.get(pid.scheme())); | ||
44 | + | ||
38 | S service = createProviderService(provider); | 45 | S service = createProviderService(provider); |
39 | services.put(provider.id(), service); | 46 | services.put(provider.id(), service); |
40 | providers.put(provider.id(), provider); | 47 | providers.put(provider.id(), provider); |
41 | - // FIXME populate scheme look-up | 48 | + |
49 | + // Register the provider by URI scheme only if it is not ancillary. | ||
50 | + if (!pid.isAncillary()) { | ||
51 | + providersByScheme.put(pid.scheme(), provider); | ||
52 | + } | ||
53 | + | ||
42 | return service; | 54 | return service; |
43 | } | 55 | } |
44 | 56 | ... | ... |
... | @@ -11,6 +11,7 @@ public class ProviderId { | ... | @@ -11,6 +11,7 @@ public class ProviderId { |
11 | 11 | ||
12 | private final String scheme; | 12 | private final String scheme; |
13 | private final String id; | 13 | private final String id; |
14 | + private final boolean ancillary; | ||
14 | 15 | ||
15 | /** | 16 | /** |
16 | * Creates a new provider identifier from the specified string. | 17 | * Creates a new provider identifier from the specified string. |
... | @@ -21,8 +22,22 @@ public class ProviderId { | ... | @@ -21,8 +22,22 @@ public class ProviderId { |
21 | * @param id string identifier | 22 | * @param id string identifier |
22 | */ | 23 | */ |
23 | public ProviderId(String scheme, String id) { | 24 | public ProviderId(String scheme, String id) { |
25 | + this(scheme, id, false); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * Creates a new provider identifier from the specified string. | ||
30 | + * The providers are expected to follow the reverse DNS convention, e.g. | ||
31 | + * {@code org.onlab.onos.provider.of.device} | ||
32 | + * | ||
33 | + * @param scheme device URI scheme to which this provider is bound, e.g. "of", "snmp" | ||
34 | + * @param id string identifier | ||
35 | + * @param ancillary ancillary provider indicator | ||
36 | + */ | ||
37 | + public ProviderId(String scheme, String id, boolean ancillary) { | ||
24 | this.scheme = scheme; | 38 | this.scheme = scheme; |
25 | this.id = id; | 39 | this.id = id; |
40 | + this.ancillary = ancillary; | ||
26 | } | 41 | } |
27 | 42 | ||
28 | /** | 43 | /** |
... | @@ -35,6 +50,15 @@ public class ProviderId { | ... | @@ -35,6 +50,15 @@ public class ProviderId { |
35 | } | 50 | } |
36 | 51 | ||
37 | /** | 52 | /** |
53 | + * Indicates whether the provider id belongs to an ancillary provider. | ||
54 | + * | ||
55 | + * @return true for ancillary; false for primary provider | ||
56 | + */ | ||
57 | + public boolean isAncillary() { | ||
58 | + return ancillary; | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
38 | * Returns the device URI scheme specific id portion. | 62 | * Returns the device URI scheme specific id portion. |
39 | * | 63 | * |
40 | * @return id | 64 | * @return id |
... | @@ -56,14 +80,16 @@ public class ProviderId { | ... | @@ -56,14 +80,16 @@ public class ProviderId { |
56 | if (obj instanceof ProviderId) { | 80 | if (obj instanceof ProviderId) { |
57 | final ProviderId other = (ProviderId) obj; | 81 | final ProviderId other = (ProviderId) obj; |
58 | return Objects.equals(this.scheme, other.scheme) && | 82 | return Objects.equals(this.scheme, other.scheme) && |
59 | - Objects.equals(this.id, other.id); | 83 | + Objects.equals(this.id, other.id) && |
84 | + this.ancillary == other.ancillary; | ||
60 | } | 85 | } |
61 | return false; | 86 | return false; |
62 | } | 87 | } |
63 | 88 | ||
64 | @Override | 89 | @Override |
65 | public String toString() { | 90 | public String toString() { |
66 | - return toStringHelper(this).add("scheme", scheme).add("id", id).toString(); | 91 | + return toStringHelper(this).add("scheme", scheme).add("id", id) |
92 | + .add("ancillary", ancillary).toString(); | ||
67 | } | 93 | } |
68 | 94 | ||
69 | } | 95 | } | ... | ... |
1 | +package org.onlab.onos.cluster; | ||
2 | + | ||
3 | +import static org.junit.Assert.assertEquals; | ||
4 | + | ||
5 | +import org.junit.Test; | ||
6 | + | ||
7 | +import com.google.common.testing.EqualsTester; | ||
8 | + | ||
9 | +public class MastershipTermTest { | ||
10 | + | ||
11 | + private static final NodeId N1 = new NodeId("foo"); | ||
12 | + private static final NodeId N2 = new NodeId("bar"); | ||
13 | + | ||
14 | + private static final MastershipTerm TERM1 = MastershipTerm.of(N1, 0); | ||
15 | + private static final MastershipTerm TERM2 = MastershipTerm.of(N2, 1); | ||
16 | + private static final MastershipTerm TERM3 = MastershipTerm.of(N2, 1); | ||
17 | + private static final MastershipTerm TERM4 = MastershipTerm.of(N1, 1); | ||
18 | + | ||
19 | + @Test | ||
20 | + public void basics() { | ||
21 | + assertEquals("incorrect term number", 0, TERM1.termNumber()); | ||
22 | + assertEquals("incorrect master", new NodeId("foo"), TERM1.master()); | ||
23 | + } | ||
24 | + | ||
25 | + @Test | ||
26 | + public void testEquality() { | ||
27 | + new EqualsTester().addEqualityGroup(MastershipTerm.of(N1, 0), TERM1) | ||
28 | + .addEqualityGroup(TERM2, TERM3) | ||
29 | + .addEqualityGroup(TERM4); | ||
30 | + } | ||
31 | + | ||
32 | +} |
... | @@ -35,7 +35,7 @@ public class AbstractProviderRegistryTest { | ... | @@ -35,7 +35,7 @@ public class AbstractProviderRegistryTest { |
35 | assertThat("provider not found", registry.getProviders().contains(fooId)); | 35 | assertThat("provider not found", registry.getProviders().contains(fooId)); |
36 | assertEquals("incorrect provider", psFoo.provider(), pFoo); | 36 | assertEquals("incorrect provider", psFoo.provider(), pFoo); |
37 | 37 | ||
38 | - ProviderId barId = new ProviderId("of", "bar"); | 38 | + ProviderId barId = new ProviderId("snmp", "bar"); |
39 | TestProvider pBar = new TestProvider(barId); | 39 | TestProvider pBar = new TestProvider(barId); |
40 | TestProviderService psBar = registry.register(pBar); | 40 | TestProviderService psBar = registry.register(pBar); |
41 | assertEquals("incorrect provider count", 2, registry.getProviders().size()); | 41 | assertEquals("incorrect provider count", 2, registry.getProviders().size()); |
... | @@ -49,6 +49,16 @@ public class AbstractProviderRegistryTest { | ... | @@ -49,6 +49,16 @@ public class AbstractProviderRegistryTest { |
49 | assertThat("provider not found", registry.getProviders().contains(barId)); | 49 | assertThat("provider not found", registry.getProviders().contains(barId)); |
50 | } | 50 | } |
51 | 51 | ||
52 | + @Test | ||
53 | + public void ancillaryProviders() { | ||
54 | + TestProviderRegistry registry = new TestProviderRegistry(); | ||
55 | + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); | ||
56 | + TestProvider pBar = new TestProvider(new ProviderId("of", "bar", true)); | ||
57 | + registry.register(pFoo); | ||
58 | + registry.register(pBar); | ||
59 | + assertEquals("incorrect provider count", 2, registry.getProviders().size()); | ||
60 | + } | ||
61 | + | ||
52 | @Test(expected = IllegalStateException.class) | 62 | @Test(expected = IllegalStateException.class) |
53 | public void duplicateRegistration() { | 63 | public void duplicateRegistration() { |
54 | TestProviderRegistry registry = new TestProviderRegistry(); | 64 | TestProviderRegistry registry = new TestProviderRegistry(); |
... | @@ -57,6 +67,15 @@ public class AbstractProviderRegistryTest { | ... | @@ -57,6 +67,15 @@ public class AbstractProviderRegistryTest { |
57 | registry.register(pFoo); | 67 | registry.register(pFoo); |
58 | } | 68 | } |
59 | 69 | ||
70 | + @Test(expected = IllegalStateException.class) | ||
71 | + public void duplicateSchemeRegistration() { | ||
72 | + TestProviderRegistry registry = new TestProviderRegistry(); | ||
73 | + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); | ||
74 | + TestProvider pBar = new TestProvider(new ProviderId("of", "bar")); | ||
75 | + registry.register(pFoo); | ||
76 | + registry.register(pBar); | ||
77 | + } | ||
78 | + | ||
60 | @Test | 79 | @Test |
61 | public void voidUnregistration() { | 80 | public void voidUnregistration() { |
62 | TestProviderRegistry registry = new TestProviderRegistry(); | 81 | TestProviderRegistry registry = new TestProviderRegistry(); | ... | ... |
... | @@ -11,6 +11,8 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -11,6 +11,8 @@ import org.apache.felix.scr.annotations.Deactivate; |
11 | import org.apache.felix.scr.annotations.Reference; | 11 | import org.apache.felix.scr.annotations.Reference; |
12 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 12 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
13 | import org.apache.felix.scr.annotations.Service; | 13 | import org.apache.felix.scr.annotations.Service; |
14 | +import org.onlab.onos.cluster.ClusterEvent; | ||
15 | +import org.onlab.onos.cluster.ClusterEventListener; | ||
14 | import org.onlab.onos.cluster.ClusterService; | 16 | import org.onlab.onos.cluster.ClusterService; |
15 | import org.onlab.onos.cluster.MastershipAdminService; | 17 | import org.onlab.onos.cluster.MastershipAdminService; |
16 | import org.onlab.onos.cluster.MastershipEvent; | 18 | import org.onlab.onos.cluster.MastershipEvent; |
... | @@ -52,9 +54,12 @@ implements MastershipService, MastershipAdminService { | ... | @@ -52,9 +54,12 @@ implements MastershipService, MastershipAdminService { |
52 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 54 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
53 | protected ClusterService clusterService; | 55 | protected ClusterService clusterService; |
54 | 56 | ||
57 | + private ClusterEventListener clusterListener = new InternalClusterEventListener(); | ||
58 | + | ||
55 | @Activate | 59 | @Activate |
56 | public void activate() { | 60 | public void activate() { |
57 | eventDispatcher.addSink(MastershipEvent.class, listenerRegistry); | 61 | eventDispatcher.addSink(MastershipEvent.class, listenerRegistry); |
62 | + clusterService.addListener(clusterListener); | ||
58 | store.setDelegate(delegate); | 63 | store.setDelegate(delegate); |
59 | log.info("Started"); | 64 | log.info("Started"); |
60 | } | 65 | } |
... | @@ -62,6 +67,7 @@ implements MastershipService, MastershipAdminService { | ... | @@ -62,6 +67,7 @@ implements MastershipService, MastershipAdminService { |
62 | @Deactivate | 67 | @Deactivate |
63 | public void deactivate() { | 68 | public void deactivate() { |
64 | eventDispatcher.removeSink(MastershipEvent.class); | 69 | eventDispatcher.removeSink(MastershipEvent.class); |
70 | + clusterService.removeListener(clusterListener); | ||
65 | store.unsetDelegate(delegate); | 71 | store.unsetDelegate(delegate); |
66 | log.info("Stopped"); | 72 | log.info("Stopped"); |
67 | } | 73 | } |
... | @@ -71,14 +77,18 @@ implements MastershipService, MastershipAdminService { | ... | @@ -71,14 +77,18 @@ implements MastershipService, MastershipAdminService { |
71 | checkNotNull(nodeId, NODE_ID_NULL); | 77 | checkNotNull(nodeId, NODE_ID_NULL); |
72 | checkNotNull(deviceId, DEVICE_ID_NULL); | 78 | checkNotNull(deviceId, DEVICE_ID_NULL); |
73 | checkNotNull(role, ROLE_NULL); | 79 | checkNotNull(role, ROLE_NULL); |
74 | - //TODO figure out appropriate action for non-MASTER roles, if we even set those | 80 | + |
81 | + MastershipEvent event = null; | ||
75 | if (role.equals(MastershipRole.MASTER)) { | 82 | if (role.equals(MastershipRole.MASTER)) { |
76 | - MastershipEvent event = store.setMaster(nodeId, deviceId); | 83 | + event = store.setMaster(nodeId, deviceId); |
84 | + } else { | ||
85 | + event = store.unsetMaster(nodeId, deviceId); | ||
86 | + } | ||
87 | + | ||
77 | if (event != null) { | 88 | if (event != null) { |
78 | post(event); | 89 | post(event); |
79 | } | 90 | } |
80 | } | 91 | } |
81 | - } | ||
82 | 92 | ||
83 | @Override | 93 | @Override |
84 | public MastershipRole getLocalRole(DeviceId deviceId) { | 94 | public MastershipRole getLocalRole(DeviceId deviceId) { |
... | @@ -88,8 +98,16 @@ implements MastershipService, MastershipAdminService { | ... | @@ -88,8 +98,16 @@ implements MastershipService, MastershipAdminService { |
88 | 98 | ||
89 | @Override | 99 | @Override |
90 | public void relinquishMastership(DeviceId deviceId) { | 100 | public void relinquishMastership(DeviceId deviceId) { |
91 | - checkNotNull(deviceId, DEVICE_ID_NULL); | 101 | + MastershipRole role = getLocalRole(deviceId); |
92 | - // FIXME: add method to store to give up mastership and trigger new master selection process | 102 | + if (!role.equals(MastershipRole.MASTER)) { |
103 | + return; | ||
104 | + } | ||
105 | + | ||
106 | + MastershipEvent event = store.unsetMaster( | ||
107 | + clusterService.getLocalNode().id(), deviceId); | ||
108 | + if (event != null) { | ||
109 | + post(event); | ||
110 | + } | ||
93 | } | 111 | } |
94 | 112 | ||
95 | @Override | 113 | @Override |
... | @@ -146,6 +164,26 @@ implements MastershipService, MastershipAdminService { | ... | @@ -146,6 +164,26 @@ implements MastershipService, MastershipAdminService { |
146 | 164 | ||
147 | } | 165 | } |
148 | 166 | ||
167 | + //callback for reacting to cluster events | ||
168 | + private class InternalClusterEventListener implements ClusterEventListener { | ||
169 | + | ||
170 | + @Override | ||
171 | + public void event(ClusterEvent event) { | ||
172 | + switch (event.type()) { | ||
173 | + //FIXME: worry about addition when the time comes | ||
174 | + case INSTANCE_ADDED: | ||
175 | + case INSTANCE_ACTIVATED: | ||
176 | + break; | ||
177 | + case INSTANCE_REMOVED: | ||
178 | + case INSTANCE_DEACTIVATED: | ||
179 | + break; | ||
180 | + default: | ||
181 | + log.warn("unknown cluster event {}", event); | ||
182 | + } | ||
183 | + } | ||
184 | + | ||
185 | + } | ||
186 | + | ||
149 | public class InternalDelegate implements MastershipStoreDelegate { | 187 | public class InternalDelegate implements MastershipStoreDelegate { |
150 | 188 | ||
151 | @Override | 189 | @Override | ... | ... |
... | @@ -16,6 +16,7 @@ import org.onlab.onos.cluster.ClusterService; | ... | @@ -16,6 +16,7 @@ import org.onlab.onos.cluster.ClusterService; |
16 | import org.onlab.onos.cluster.MastershipEvent; | 16 | import org.onlab.onos.cluster.MastershipEvent; |
17 | import org.onlab.onos.cluster.MastershipListener; | 17 | import org.onlab.onos.cluster.MastershipListener; |
18 | import org.onlab.onos.cluster.MastershipService; | 18 | import org.onlab.onos.cluster.MastershipService; |
19 | +import org.onlab.onos.cluster.MastershipTermService; | ||
19 | import org.onlab.onos.cluster.MastershipTerm; | 20 | import org.onlab.onos.cluster.MastershipTerm; |
20 | import org.onlab.onos.event.AbstractListenerRegistry; | 21 | import org.onlab.onos.event.AbstractListenerRegistry; |
21 | import org.onlab.onos.event.EventDeliveryService; | 22 | import org.onlab.onos.event.EventDeliveryService; |
... | @@ -76,6 +77,8 @@ public class DeviceManager | ... | @@ -76,6 +77,8 @@ public class DeviceManager |
76 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 77 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
77 | protected MastershipService mastershipService; | 78 | protected MastershipService mastershipService; |
78 | 79 | ||
80 | + protected MastershipTermService termService; | ||
81 | + | ||
79 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
80 | protected ClockService clockService; | 83 | protected ClockService clockService; |
81 | 84 | ||
... | @@ -84,6 +87,7 @@ public class DeviceManager | ... | @@ -84,6 +87,7 @@ public class DeviceManager |
84 | store.setDelegate(delegate); | 87 | store.setDelegate(delegate); |
85 | eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); | 88 | eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); |
86 | mastershipService.addListener(mastershipListener); | 89 | mastershipService.addListener(mastershipListener); |
90 | + termService = mastershipService.requestTermService(); | ||
87 | log.info("Started"); | 91 | log.info("Started"); |
88 | } | 92 | } |
89 | 93 | ||
... | @@ -198,7 +202,7 @@ public class DeviceManager | ... | @@ -198,7 +202,7 @@ public class DeviceManager |
198 | log.info("Device {} connected", deviceId); | 202 | log.info("Device {} connected", deviceId); |
199 | mastershipService.requestRoleFor(deviceId); | 203 | mastershipService.requestRoleFor(deviceId); |
200 | provider().roleChanged(event.subject(), | 204 | provider().roleChanged(event.subject(), |
201 | - mastershipService.getLocalRole(deviceId)); | 205 | + mastershipService.requestRoleFor(deviceId)); |
202 | post(event); | 206 | post(event); |
203 | } | 207 | } |
204 | } | 208 | } |
... | @@ -208,8 +212,11 @@ public class DeviceManager | ... | @@ -208,8 +212,11 @@ public class DeviceManager |
208 | checkNotNull(deviceId, DEVICE_ID_NULL); | 212 | checkNotNull(deviceId, DEVICE_ID_NULL); |
209 | checkValidity(); | 213 | checkValidity(); |
210 | DeviceEvent event = store.markOffline(deviceId); | 214 | DeviceEvent event = store.markOffline(deviceId); |
215 | + | ||
216 | + //we're no longer capable of mastership. | ||
211 | if (event != null) { | 217 | if (event != null) { |
212 | log.info("Device {} disconnected", deviceId); | 218 | log.info("Device {} disconnected", deviceId); |
219 | + mastershipService.relinquishMastership(deviceId); | ||
213 | post(event); | 220 | post(event); |
214 | } | 221 | } |
215 | } | 222 | } |
... | @@ -221,8 +228,9 @@ public class DeviceManager | ... | @@ -221,8 +228,9 @@ public class DeviceManager |
221 | checkNotNull(portDescriptions, | 228 | checkNotNull(portDescriptions, |
222 | "Port descriptions list cannot be null"); | 229 | "Port descriptions list cannot be null"); |
223 | checkValidity(); | 230 | checkValidity(); |
224 | - List<DeviceEvent> events = store.updatePorts(deviceId, | 231 | + this.provider().id(); |
225 | - portDescriptions); | 232 | + List<DeviceEvent> events = store.updatePorts(this.provider().id(), |
233 | + deviceId, portDescriptions); | ||
226 | for (DeviceEvent event : events) { | 234 | for (DeviceEvent event : events) { |
227 | post(event); | 235 | post(event); |
228 | } | 236 | } |
... | @@ -234,8 +242,8 @@ public class DeviceManager | ... | @@ -234,8 +242,8 @@ public class DeviceManager |
234 | checkNotNull(deviceId, DEVICE_ID_NULL); | 242 | checkNotNull(deviceId, DEVICE_ID_NULL); |
235 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); | 243 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); |
236 | checkValidity(); | 244 | checkValidity(); |
237 | - DeviceEvent event = store.updatePortStatus(deviceId, | 245 | + DeviceEvent event = store.updatePortStatus(this.provider().id(), |
238 | - portDescription); | 246 | + deviceId, portDescription); |
239 | if (event != null) { | 247 | if (event != null) { |
240 | log.info("Device {} port {} status changed", deviceId, event | 248 | log.info("Device {} port {} status changed", deviceId, event |
241 | .port().number()); | 249 | .port().number()); | ... | ... |
... | @@ -65,8 +65,8 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -65,8 +65,8 @@ public class DefaultTopologyProvider extends AbstractProvider |
65 | private volatile boolean isStarted = false; | 65 | private volatile boolean isStarted = false; |
66 | 66 | ||
67 | private TopologyProviderService providerService; | 67 | private TopologyProviderService providerService; |
68 | - private DeviceListener deviceListener = new InnerDeviceListener(); | 68 | + private DeviceListener deviceListener = new InternalDeviceListener(); |
69 | - private LinkListener linkListener = new InnerLinkListener(); | 69 | + private LinkListener linkListener = new InternalLinkListener(); |
70 | 70 | ||
71 | private EventAccumulator accumulator; | 71 | private EventAccumulator accumulator; |
72 | private ExecutorService executor; | 72 | private ExecutorService executor; |
... | @@ -132,7 +132,7 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -132,7 +132,7 @@ public class DefaultTopologyProvider extends AbstractProvider |
132 | } | 132 | } |
133 | 133 | ||
134 | // Callback for device events | 134 | // Callback for device events |
135 | - private class InnerDeviceListener implements DeviceListener { | 135 | + private class InternalDeviceListener implements DeviceListener { |
136 | @Override | 136 | @Override |
137 | public void event(DeviceEvent event) { | 137 | public void event(DeviceEvent event) { |
138 | DeviceEvent.Type type = event.type(); | 138 | DeviceEvent.Type type = event.type(); |
... | @@ -144,7 +144,7 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -144,7 +144,7 @@ public class DefaultTopologyProvider extends AbstractProvider |
144 | } | 144 | } |
145 | 145 | ||
146 | // Callback for link events | 146 | // Callback for link events |
147 | - private class InnerLinkListener implements LinkListener { | 147 | + private class InternalLinkListener implements LinkListener { |
148 | @Override | 148 | @Override |
149 | public void event(LinkEvent event) { | 149 | public void event(LinkEvent event) { |
150 | accumulator.add(event); | 150 | accumulator.add(event); | ... | ... |
... | @@ -15,10 +15,11 @@ import org.onlab.onos.cluster.MastershipTermService; | ... | @@ -15,10 +15,11 @@ import org.onlab.onos.cluster.MastershipTermService; |
15 | import org.onlab.onos.cluster.NodeId; | 15 | import org.onlab.onos.cluster.NodeId; |
16 | import org.onlab.onos.event.impl.TestEventDispatcher; | 16 | import org.onlab.onos.event.impl.TestEventDispatcher; |
17 | import org.onlab.onos.net.DeviceId; | 17 | import org.onlab.onos.net.DeviceId; |
18 | -import org.onlab.onos.net.trivial.impl.SimpleMastershipStore; | 18 | +import org.onlab.onos.store.trivial.impl.SimpleMastershipStore; |
19 | import org.onlab.packet.IpPrefix; | 19 | import org.onlab.packet.IpPrefix; |
20 | 20 | ||
21 | import static org.junit.Assert.assertEquals; | 21 | import static org.junit.Assert.assertEquals; |
22 | +import static org.junit.Assert.assertNull; | ||
22 | import static org.onlab.onos.net.MastershipRole.*; | 23 | import static org.onlab.onos.net.MastershipRole.*; |
23 | 24 | ||
24 | /** | 25 | /** |
... | @@ -65,7 +66,24 @@ public class MastershipManagerTest { | ... | @@ -65,7 +66,24 @@ public class MastershipManagerTest { |
65 | 66 | ||
66 | @Test | 67 | @Test |
67 | public void relinquishMastership() { | 68 | public void relinquishMastership() { |
68 | - //TODO | 69 | + //no backups - should turn to standby and no master for device |
70 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
71 | + assertEquals("wrong role:", MASTER, mgr.getLocalRole(DEV_MASTER)); | ||
72 | + mgr.relinquishMastership(DEV_MASTER); | ||
73 | + assertNull("wrong master:", mgr.getMasterFor(DEV_OTHER)); | ||
74 | + assertEquals("wrong role:", STANDBY, mgr.getLocalRole(DEV_MASTER)); | ||
75 | + | ||
76 | + //not master, nothing should happen | ||
77 | + mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); | ||
78 | + mgr.relinquishMastership(DEV_OTHER); | ||
79 | + assertNull("wrong role:", mgr.getMasterFor(DEV_OTHER)); | ||
80 | + | ||
81 | + //provide NID_OTHER as backup and relinquish | ||
82 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
83 | + assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER)); | ||
84 | + mgr.setRole(NID_OTHER, DEV_MASTER, STANDBY); | ||
85 | + mgr.relinquishMastership(DEV_MASTER); | ||
86 | + assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_MASTER)); | ||
69 | } | 87 | } |
70 | 88 | ||
71 | @Test | 89 | @Test |
... | @@ -95,7 +113,6 @@ public class MastershipManagerTest { | ... | @@ -95,7 +113,6 @@ public class MastershipManagerTest { |
95 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | 113 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); |
96 | mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); | 114 | mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); |
97 | assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); | 115 | assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); |
98 | - | ||
99 | //hand both devices to NID_LOCAL | 116 | //hand both devices to NID_LOCAL |
100 | mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); | 117 | mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); |
101 | assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | 118 | assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | ... | ... |
... | @@ -27,7 +27,7 @@ import org.onlab.onos.net.device.DeviceService; | ... | @@ -27,7 +27,7 @@ import org.onlab.onos.net.device.DeviceService; |
27 | import org.onlab.onos.net.device.PortDescription; | 27 | import org.onlab.onos.net.device.PortDescription; |
28 | import org.onlab.onos.net.provider.AbstractProvider; | 28 | import org.onlab.onos.net.provider.AbstractProvider; |
29 | import org.onlab.onos.net.provider.ProviderId; | 29 | import org.onlab.onos.net.provider.ProviderId; |
30 | -import org.onlab.onos.net.trivial.impl.SimpleDeviceStore; | 30 | +import org.onlab.onos.store.trivial.impl.SimpleDeviceStore; |
31 | 31 | ||
32 | import java.util.ArrayList; | 32 | import java.util.ArrayList; |
33 | import java.util.Iterator; | 33 | import java.util.Iterator; | ... | ... |
... | @@ -40,7 +40,7 @@ import org.onlab.onos.net.flow.criteria.Criterion; | ... | @@ -40,7 +40,7 @@ import org.onlab.onos.net.flow.criteria.Criterion; |
40 | import org.onlab.onos.net.flow.instructions.Instruction; | 40 | import org.onlab.onos.net.flow.instructions.Instruction; |
41 | import org.onlab.onos.net.provider.AbstractProvider; | 41 | import org.onlab.onos.net.provider.AbstractProvider; |
42 | import org.onlab.onos.net.provider.ProviderId; | 42 | import org.onlab.onos.net.provider.ProviderId; |
43 | -import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore; | 43 | +import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; |
44 | 44 | ||
45 | import com.google.common.collect.Lists; | 45 | import com.google.common.collect.Lists; |
46 | import com.google.common.collect.Sets; | 46 | import com.google.common.collect.Sets; | ... | ... |
... | @@ -34,7 +34,7 @@ import org.onlab.onos.net.host.HostProviderService; | ... | @@ -34,7 +34,7 @@ import org.onlab.onos.net.host.HostProviderService; |
34 | import org.onlab.onos.net.host.PortAddresses; | 34 | import org.onlab.onos.net.host.PortAddresses; |
35 | import org.onlab.onos.net.provider.AbstractProvider; | 35 | import org.onlab.onos.net.provider.AbstractProvider; |
36 | import org.onlab.onos.net.provider.ProviderId; | 36 | import org.onlab.onos.net.provider.ProviderId; |
37 | -import org.onlab.onos.net.trivial.impl.SimpleHostStore; | 37 | +import org.onlab.onos.store.trivial.impl.SimpleHostStore; |
38 | import org.onlab.packet.IpPrefix; | 38 | import org.onlab.packet.IpPrefix; |
39 | import org.onlab.packet.MacAddress; | 39 | import org.onlab.packet.MacAddress; |
40 | import org.onlab.packet.VlanId; | 40 | import org.onlab.packet.VlanId; | ... | ... |
... | @@ -23,7 +23,7 @@ import org.onlab.onos.net.provider.AbstractProvider; | ... | @@ -23,7 +23,7 @@ import org.onlab.onos.net.provider.AbstractProvider; |
23 | import org.onlab.onos.net.provider.ProviderId; | 23 | import org.onlab.onos.net.provider.ProviderId; |
24 | import org.onlab.onos.event.impl.TestEventDispatcher; | 24 | import org.onlab.onos.event.impl.TestEventDispatcher; |
25 | import org.onlab.onos.net.device.impl.DeviceManager; | 25 | import org.onlab.onos.net.device.impl.DeviceManager; |
26 | -import org.onlab.onos.net.trivial.impl.SimpleLinkStore; | 26 | +import org.onlab.onos.store.trivial.impl.SimpleLinkStore; |
27 | 27 | ||
28 | import java.util.ArrayList; | 28 | import java.util.ArrayList; |
29 | import java.util.Iterator; | 29 | import java.util.Iterator; | ... | ... |
... | @@ -24,7 +24,7 @@ import org.onlab.onos.net.topology.TopologyProvider; | ... | @@ -24,7 +24,7 @@ import org.onlab.onos.net.topology.TopologyProvider; |
24 | import org.onlab.onos.net.topology.TopologyProviderRegistry; | 24 | import org.onlab.onos.net.topology.TopologyProviderRegistry; |
25 | import org.onlab.onos.net.topology.TopologyProviderService; | 25 | import org.onlab.onos.net.topology.TopologyProviderService; |
26 | import org.onlab.onos.net.topology.TopologyService; | 26 | import org.onlab.onos.net.topology.TopologyService; |
27 | -import org.onlab.onos.net.trivial.impl.SimpleTopologyStore; | 27 | +import org.onlab.onos.store.trivial.impl.SimpleTopologyStore; |
28 | 28 | ||
29 | import java.util.ArrayList; | 29 | import java.util.ArrayList; |
30 | import java.util.List; | 30 | import java.util.List; | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/AntiEntropyAdvertisement.java
0 → 100644
1 | +package org.onlab.onos.store.cluster.messaging; | ||
2 | + | ||
3 | +import static org.onlab.onos.store.cluster.messaging.MessageSubject.AE_ADVERTISEMENT; | ||
4 | +import java.util.Map; | ||
5 | + | ||
6 | +import org.onlab.onos.cluster.NodeId; | ||
7 | +import org.onlab.onos.store.Timestamp; | ||
8 | + | ||
9 | +import com.google.common.collect.ImmutableMap; | ||
10 | + | ||
11 | +/** | ||
12 | + * Anti-Entropy advertisement message. | ||
13 | + * <p> | ||
14 | + * Message to advertise the information this node holds. | ||
15 | + * | ||
16 | + * @param <ID> ID type | ||
17 | + */ | ||
18 | +public class AntiEntropyAdvertisement<ID> extends ClusterMessage { | ||
19 | + | ||
20 | + private final NodeId sender; | ||
21 | + private final ImmutableMap<ID, Timestamp> advertisement; | ||
22 | + | ||
23 | + /** | ||
24 | + * Creates anti-entropy advertisement message. | ||
25 | + * | ||
26 | + * @param sender sender of this message | ||
27 | + * @param advertisement timestamp information of the data sender holds | ||
28 | + */ | ||
29 | + public AntiEntropyAdvertisement(NodeId sender, Map<ID, Timestamp> advertisement) { | ||
30 | + super(AE_ADVERTISEMENT); | ||
31 | + this.sender = sender; | ||
32 | + this.advertisement = ImmutableMap.copyOf(advertisement); | ||
33 | + } | ||
34 | + | ||
35 | + public NodeId sender() { | ||
36 | + return sender; | ||
37 | + } | ||
38 | + | ||
39 | + public ImmutableMap<ID, Timestamp> advertisement() { | ||
40 | + return advertisement; | ||
41 | + } | ||
42 | + | ||
43 | + // Default constructor for serializer | ||
44 | + protected AntiEntropyAdvertisement() { | ||
45 | + super(AE_ADVERTISEMENT); | ||
46 | + this.sender = null; | ||
47 | + this.advertisement = null; | ||
48 | + } | ||
49 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/AntiEntropyReply.java
0 → 100644
1 | +package org.onlab.onos.store.cluster.messaging; | ||
2 | + | ||
3 | +import static org.onlab.onos.store.cluster.messaging.MessageSubject.AE_REPLY; | ||
4 | + | ||
5 | +import java.util.Map; | ||
6 | +import java.util.Set; | ||
7 | + | ||
8 | +import org.onlab.onos.cluster.NodeId; | ||
9 | +import org.onlab.onos.store.device.impl.VersionedValue; | ||
10 | + | ||
11 | +import com.google.common.collect.ImmutableMap; | ||
12 | +import com.google.common.collect.ImmutableSet; | ||
13 | + | ||
14 | +/** | ||
15 | + * Anti-Entropy reply message. | ||
16 | + * <p> | ||
17 | + * Message to send in reply to advertisement or another reply. | ||
18 | + * Suggest to the sender about the more up-to-date data this node has, | ||
19 | + * and request for more recent data that the receiver has. | ||
20 | + */ | ||
21 | +public class AntiEntropyReply<ID, V extends VersionedValue<?>> extends ClusterMessage { | ||
22 | + | ||
23 | + private final NodeId sender; | ||
24 | + private final ImmutableMap<ID, V> suggestion; | ||
25 | + private final ImmutableSet<ID> request; | ||
26 | + | ||
27 | + /** | ||
28 | + * Creates a reply to anti-entropy message. | ||
29 | + * | ||
30 | + * @param sender sender of this message | ||
31 | + * @param suggestion collection of more recent values, sender had | ||
32 | + * @param request Collection of identifiers | ||
33 | + */ | ||
34 | + public AntiEntropyReply(NodeId sender, | ||
35 | + Map<ID, V> suggestion, | ||
36 | + Set<ID> request) { | ||
37 | + super(AE_REPLY); | ||
38 | + this.sender = sender; | ||
39 | + this.suggestion = ImmutableMap.copyOf(suggestion); | ||
40 | + this.request = ImmutableSet.copyOf(request); | ||
41 | + } | ||
42 | + | ||
43 | + public NodeId sender() { | ||
44 | + return sender; | ||
45 | + } | ||
46 | + | ||
47 | + /** | ||
48 | + * Returns collection of values, which the recipient of this reply is likely | ||
49 | + * to be missing or has outdated version. | ||
50 | + * | ||
51 | + * @return | ||
52 | + */ | ||
53 | + public ImmutableMap<ID, V> suggestion() { | ||
54 | + return suggestion; | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Returns collection of identifier to request. | ||
59 | + * | ||
60 | + * @return collection of identifier to request | ||
61 | + */ | ||
62 | + public ImmutableSet<ID> request() { | ||
63 | + return request; | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Checks if reply contains any suggestion or request. | ||
68 | + * | ||
69 | + * @return true if nothing is suggested and requested | ||
70 | + */ | ||
71 | + public boolean isEmpty() { | ||
72 | + return suggestion.isEmpty() && request.isEmpty(); | ||
73 | + } | ||
74 | + | ||
75 | + // Default constructor for serializer | ||
76 | + protected AntiEntropyReply() { | ||
77 | + super(AE_REPLY); | ||
78 | + this.sender = null; | ||
79 | + this.suggestion = null; | ||
80 | + this.request = null; | ||
81 | + } | ||
82 | +} |
... | @@ -15,6 +15,12 @@ public enum MessageSubject { | ... | @@ -15,6 +15,12 @@ public enum MessageSubject { |
15 | LEAVING_MEMBER, | 15 | LEAVING_MEMBER, |
16 | 16 | ||
17 | /** Signifies a heart-beat message. */ | 17 | /** Signifies a heart-beat message. */ |
18 | - ECHO | 18 | + ECHO, |
19 | + | ||
20 | + /** Anti-Entropy advertisement message. */ | ||
21 | + AE_ADVERTISEMENT, | ||
22 | + | ||
23 | + /** Anti-Entropy reply message. */ | ||
24 | + AE_REPLY, | ||
19 | 25 | ||
20 | } | 26 | } | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceAntiEntropyAdvertisement.java
0 → 100644
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.Map; | ||
6 | + | ||
7 | +import org.onlab.onos.cluster.NodeId; | ||
8 | +import org.onlab.onos.net.Device; | ||
9 | +import org.onlab.onos.net.DeviceId; | ||
10 | +import org.onlab.onos.store.Timestamp; | ||
11 | +import org.onlab.onos.store.cluster.messaging.AntiEntropyAdvertisement; | ||
12 | + | ||
13 | +// TODO DeviceID needs to be changed to something like (ProviderID, DeviceID) | ||
14 | +// TODO: Handle Port as part of these messages, or separate messages for Ports? | ||
15 | + | ||
16 | +public class DeviceAntiEntropyAdvertisement | ||
17 | + extends AntiEntropyAdvertisement<DeviceId> { | ||
18 | + | ||
19 | + | ||
20 | + public DeviceAntiEntropyAdvertisement(NodeId sender, | ||
21 | + Map<DeviceId, Timestamp> advertisement) { | ||
22 | + super(sender, advertisement); | ||
23 | + } | ||
24 | + | ||
25 | + // May need to add ProviderID, etc. | ||
26 | + public static DeviceAntiEntropyAdvertisement create( | ||
27 | + NodeId self, | ||
28 | + Collection<VersionedValue<Device>> localValues) { | ||
29 | + | ||
30 | + Map<DeviceId, Timestamp> ads = new HashMap<>(localValues.size()); | ||
31 | + for (VersionedValue<Device> e : localValues) { | ||
32 | + ads.put(e.entity().id(), e.timestamp()); | ||
33 | + } | ||
34 | + return new DeviceAntiEntropyAdvertisement(self, ads); | ||
35 | + } | ||
36 | + | ||
37 | + // For serializer | ||
38 | + protected DeviceAntiEntropyAdvertisement() {} | ||
39 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceAntiEntropyReply.java
0 → 100644
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.HashSet; | ||
6 | +import java.util.Map; | ||
7 | +import java.util.Set; | ||
8 | + | ||
9 | +import org.onlab.onos.cluster.NodeId; | ||
10 | +import org.onlab.onos.net.Device; | ||
11 | +import org.onlab.onos.net.DeviceId; | ||
12 | +import org.onlab.onos.store.Timestamp; | ||
13 | +import org.onlab.onos.store.cluster.messaging.AntiEntropyReply; | ||
14 | + | ||
15 | +import com.google.common.collect.ImmutableMap; | ||
16 | +import com.google.common.collect.ImmutableSet; | ||
17 | + | ||
18 | +public class DeviceAntiEntropyReply | ||
19 | + extends AntiEntropyReply<DeviceId, VersionedValue<Device>> { | ||
20 | + | ||
21 | + | ||
22 | + public DeviceAntiEntropyReply(NodeId sender, | ||
23 | + Map<DeviceId, VersionedValue<Device>> suggestion, | ||
24 | + Set<DeviceId> request) { | ||
25 | + super(sender, suggestion, request); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * Creates a reply to Anti-Entropy advertisement. | ||
30 | + * | ||
31 | + * @param advertisement to respond to | ||
32 | + * @param self node identifier representing local node | ||
33 | + * @param localValues local values held on this node | ||
34 | + * @return reply message | ||
35 | + */ | ||
36 | + public static DeviceAntiEntropyReply reply( | ||
37 | + DeviceAntiEntropyAdvertisement advertisement, | ||
38 | + NodeId self, | ||
39 | + Collection<VersionedValue<Device>> localValues | ||
40 | + ) { | ||
41 | + | ||
42 | + ImmutableMap<DeviceId, Timestamp> ads = advertisement.advertisement(); | ||
43 | + | ||
44 | + ImmutableMap.Builder<DeviceId, VersionedValue<Device>> | ||
45 | + sug = ImmutableMap.builder(); | ||
46 | + | ||
47 | + Set<DeviceId> req = new HashSet<>(ads.keySet()); | ||
48 | + | ||
49 | + for (VersionedValue<Device> e : localValues) { | ||
50 | + final DeviceId id = e.entity().id(); | ||
51 | + final Timestamp local = e.timestamp(); | ||
52 | + final Timestamp theirs = ads.get(id); | ||
53 | + if (theirs == null) { | ||
54 | + // they don't have it, suggest | ||
55 | + sug.put(id, e); | ||
56 | + // don't need theirs | ||
57 | + req.remove(id); | ||
58 | + } else if (local.compareTo(theirs) < 0) { | ||
59 | + // they got older one, suggest | ||
60 | + sug.put(id, e); | ||
61 | + // don't need theirs | ||
62 | + req.remove(id); | ||
63 | + } else if (local.equals(theirs)) { | ||
64 | + // same, don't need theirs | ||
65 | + req.remove(id); | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + return new DeviceAntiEntropyReply(self, sug.build(), req); | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * Creates a reply to request for values held locally. | ||
74 | + * | ||
75 | + * @param requests message containing the request | ||
76 | + * @param self node identifier representing local node | ||
77 | + * @param localValues local valeds held on this node | ||
78 | + * @return reply message | ||
79 | + */ | ||
80 | + public static DeviceAntiEntropyReply reply( | ||
81 | + DeviceAntiEntropyReply requests, | ||
82 | + NodeId self, | ||
83 | + Map<DeviceId, VersionedValue<Device>> localValues | ||
84 | + ) { | ||
85 | + | ||
86 | + Set<DeviceId> reqs = requests.request(); | ||
87 | + | ||
88 | + Map<DeviceId, VersionedValue<Device>> requested = new HashMap<>(reqs.size()); | ||
89 | + for (DeviceId id : reqs) { | ||
90 | + final VersionedValue<Device> value = localValues.get(id); | ||
91 | + if (value != null) { | ||
92 | + requested.put(id, value); | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + Set<DeviceId> empty = ImmutableSet.of(); | ||
97 | + return new DeviceAntiEntropyReply(self, requested, empty); | ||
98 | + } | ||
99 | + | ||
100 | + // For serializer | ||
101 | + protected DeviceAntiEntropyReply() {} | ||
102 | +} |
... | @@ -40,6 +40,7 @@ import java.util.Map; | ... | @@ -40,6 +40,7 @@ import java.util.Map; |
40 | import java.util.Objects; | 40 | import java.util.Objects; |
41 | import java.util.Set; | 41 | import java.util.Set; |
42 | import java.util.concurrent.ConcurrentHashMap; | 42 | import java.util.concurrent.ConcurrentHashMap; |
43 | +import java.util.concurrent.ConcurrentMap; | ||
43 | 44 | ||
44 | import static com.google.common.base.Preconditions.checkArgument; | 45 | import static com.google.common.base.Preconditions.checkArgument; |
45 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; | 46 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
... | @@ -59,8 +60,8 @@ public class OnosDistributedDeviceStore | ... | @@ -59,8 +60,8 @@ public class OnosDistributedDeviceStore |
59 | 60 | ||
60 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | 61 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; |
61 | 62 | ||
62 | - private ConcurrentHashMap<DeviceId, VersionedValue<Device>> devices; | 63 | + private ConcurrentMap<DeviceId, VersionedValue<Device>> devices; |
63 | - private ConcurrentHashMap<DeviceId, Map<PortNumber, VersionedValue<Port>>> devicePorts; | 64 | + private ConcurrentMap<DeviceId, Map<PortNumber, VersionedValue<Port>>> devicePorts; |
64 | 65 | ||
65 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 66 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
66 | protected ClockService clockService; | 67 | protected ClockService clockService; |
... | @@ -191,7 +192,7 @@ public class OnosDistributedDeviceStore | ... | @@ -191,7 +192,7 @@ public class OnosDistributedDeviceStore |
191 | } | 192 | } |
192 | 193 | ||
193 | @Override | 194 | @Override |
194 | - public List<DeviceEvent> updatePorts(DeviceId deviceId, | 195 | + public List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
195 | List<PortDescription> portDescriptions) { | 196 | List<PortDescription> portDescriptions) { |
196 | List<DeviceEvent> events = new ArrayList<>(); | 197 | List<DeviceEvent> events = new ArrayList<>(); |
197 | synchronized (this) { | 198 | synchronized (this) { |
... | @@ -295,7 +296,7 @@ public class OnosDistributedDeviceStore | ... | @@ -295,7 +296,7 @@ public class OnosDistributedDeviceStore |
295 | } | 296 | } |
296 | 297 | ||
297 | @Override | 298 | @Override |
298 | - public DeviceEvent updatePortStatus(DeviceId deviceId, | 299 | + public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
299 | PortDescription portDescription) { | 300 | PortDescription portDescription) { |
300 | VersionedValue<Device> device = devices.get(deviceId); | 301 | VersionedValue<Device> device = devices.get(deviceId); |
301 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | 302 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ... | ... |
1 | package org.onlab.onos.store.device.impl; | 1 | package org.onlab.onos.store.device.impl; |
2 | 2 | ||
3 | +import java.util.Objects; | ||
4 | + | ||
3 | import org.onlab.onos.store.Timestamp; | 5 | import org.onlab.onos.store.Timestamp; |
4 | 6 | ||
5 | /** | 7 | /** |
... | @@ -42,4 +44,35 @@ public class VersionedValue<T> { | ... | @@ -42,4 +44,35 @@ public class VersionedValue<T> { |
42 | public Timestamp timestamp() { | 44 | public Timestamp timestamp() { |
43 | return timestamp; | 45 | return timestamp; |
44 | } | 46 | } |
47 | + | ||
48 | + | ||
49 | + @Override | ||
50 | + public int hashCode() { | ||
51 | + return Objects.hash(entity, timestamp, isUp); | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
55 | + public boolean equals(Object obj) { | ||
56 | + if (this == obj) { | ||
57 | + return true; | ||
58 | + } | ||
59 | + if (obj == null) { | ||
60 | + return false; | ||
61 | + } | ||
62 | + if (getClass() != obj.getClass()) { | ||
63 | + return false; | ||
64 | + } | ||
65 | + @SuppressWarnings("unchecked") | ||
66 | + VersionedValue<T> that = (VersionedValue<T>) obj; | ||
67 | + return Objects.equals(this.entity, that.entity) && | ||
68 | + Objects.equals(this.timestamp, that.timestamp) && | ||
69 | + Objects.equals(this.isUp, that.isUp); | ||
70 | + } | ||
71 | + | ||
72 | + // Default constructor for serializer | ||
73 | + protected VersionedValue() { | ||
74 | + this.entity = null; | ||
75 | + this.isUp = false; | ||
76 | + this.timestamp = null; | ||
77 | + } | ||
45 | } | 78 | } | ... | ... |
... | @@ -123,6 +123,12 @@ implements MastershipStore { | ... | @@ -123,6 +123,12 @@ implements MastershipStore { |
123 | return null; | 123 | return null; |
124 | } | 124 | } |
125 | 125 | ||
126 | + @Override | ||
127 | + public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { | ||
128 | + // TODO Auto-generated method stub | ||
129 | + return null; | ||
130 | + } | ||
131 | + | ||
126 | private class RemoteMasterShipEventHandler extends RemoteCacheEventHandler<DeviceId, NodeId> { | 132 | private class RemoteMasterShipEventHandler extends RemoteCacheEventHandler<DeviceId, NodeId> { |
127 | public RemoteMasterShipEventHandler(LoadingCache<DeviceId, Optional<NodeId>> cache) { | 133 | public RemoteMasterShipEventHandler(LoadingCache<DeviceId, Optional<NodeId>> cache) { |
128 | super(cache); | 134 | super(cache); | ... | ... |
... | @@ -221,7 +221,7 @@ public class DistributedDeviceStore | ... | @@ -221,7 +221,7 @@ public class DistributedDeviceStore |
221 | } | 221 | } |
222 | 222 | ||
223 | @Override | 223 | @Override |
224 | - public List<DeviceEvent> updatePorts(DeviceId deviceId, | 224 | + public List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
225 | List<PortDescription> portDescriptions) { | 225 | List<PortDescription> portDescriptions) { |
226 | List<DeviceEvent> events = new ArrayList<>(); | 226 | List<DeviceEvent> events = new ArrayList<>(); |
227 | synchronized (this) { | 227 | synchronized (this) { |
... | @@ -319,7 +319,7 @@ public class DistributedDeviceStore | ... | @@ -319,7 +319,7 @@ public class DistributedDeviceStore |
319 | } | 319 | } |
320 | 320 | ||
321 | @Override | 321 | @Override |
322 | - public DeviceEvent updatePortStatus(DeviceId deviceId, | 322 | + public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
323 | PortDescription portDescription) { | 323 | PortDescription portDescription) { |
324 | synchronized (this) { | 324 | synchronized (this) { |
325 | Device device = devices.getUnchecked(deviceId).orNull(); | 325 | Device device = devices.getUnchecked(deviceId).orNull(); | ... | ... |
... | @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableSet; | ... | @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableSet; |
28 | import com.google.common.collect.Multimap; | 28 | import com.google.common.collect.Multimap; |
29 | 29 | ||
30 | /** | 30 | /** |
31 | - * Manages inventory of flow rules using trivial in-memory implementation. | 31 | + * TEMPORARY: Manages inventory of flow rules using distributed store implementation. |
32 | */ | 32 | */ |
33 | //FIXME: I LIE I AM NOT DISTRIBUTED | 33 | //FIXME: I LIE I AM NOT DISTRIBUTED |
34 | @Component(immediate = true) | 34 | @Component(immediate = true) | ... | ... |
... | @@ -39,8 +39,8 @@ import com.google.common.collect.Multimap; | ... | @@ -39,8 +39,8 @@ import com.google.common.collect.Multimap; |
39 | import com.google.common.collect.Sets; | 39 | import com.google.common.collect.Sets; |
40 | 40 | ||
41 | /** | 41 | /** |
42 | - * Manages inventory of end-station hosts using trivial in-memory | 42 | + * TEMPORARY: Manages inventory of end-station hosts using distributed |
43 | - * implementation. | 43 | + * structures implementation. |
44 | */ | 44 | */ |
45 | //FIXME: I LIE I AM NOT DISTRIBUTED | 45 | //FIXME: I LIE I AM NOT DISTRIBUTED |
46 | @Component(immediate = true) | 46 | @Component(immediate = true) | ... | ... |
... | @@ -28,7 +28,7 @@ import org.onlab.onos.store.AbstractStore; | ... | @@ -28,7 +28,7 @@ import org.onlab.onos.store.AbstractStore; |
28 | import org.slf4j.Logger; | 28 | import org.slf4j.Logger; |
29 | 29 | ||
30 | /** | 30 | /** |
31 | - * Manages inventory of topology snapshots using trivial in-memory | 31 | + * TEMPORARY: Manages inventory of topology snapshots using distributed |
32 | * structures implementation. | 32 | * structures implementation. |
33 | */ | 33 | */ |
34 | //FIXME: I LIE I AM NOT DISTRIBUTED | 34 | //FIXME: I LIE I AM NOT DISTRIBUTED | ... | ... |
... | @@ -201,7 +201,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -201,7 +201,7 @@ public class DistributedDeviceStoreTest { |
201 | new DefaultPortDescription(P2, true) | 201 | new DefaultPortDescription(P2, true) |
202 | ); | 202 | ); |
203 | 203 | ||
204 | - List<DeviceEvent> events = deviceStore.updatePorts(DID1, pds); | 204 | + List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); |
205 | 205 | ||
206 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 206 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
207 | for (DeviceEvent event : events) { | 207 | for (DeviceEvent event : events) { |
... | @@ -220,7 +220,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -220,7 +220,7 @@ public class DistributedDeviceStoreTest { |
220 | new DefaultPortDescription(P3, true) | 220 | new DefaultPortDescription(P3, true) |
221 | ); | 221 | ); |
222 | 222 | ||
223 | - events = deviceStore.updatePorts(DID1, pds2); | 223 | + events = deviceStore.updatePorts(PID, DID1, pds2); |
224 | assertFalse("event should be triggered", events.isEmpty()); | 224 | assertFalse("event should be triggered", events.isEmpty()); |
225 | for (DeviceEvent event : events) { | 225 | for (DeviceEvent event : events) { |
226 | PortNumber num = event.port().number(); | 226 | PortNumber num = event.port().number(); |
... | @@ -243,7 +243,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -243,7 +243,7 @@ public class DistributedDeviceStoreTest { |
243 | new DefaultPortDescription(P1, false), | 243 | new DefaultPortDescription(P1, false), |
244 | new DefaultPortDescription(P2, true) | 244 | new DefaultPortDescription(P2, true) |
245 | ); | 245 | ); |
246 | - events = deviceStore.updatePorts(DID1, pds3); | 246 | + events = deviceStore.updatePorts(PID, DID1, pds3); |
247 | assertFalse("event should be triggered", events.isEmpty()); | 247 | assertFalse("event should be triggered", events.isEmpty()); |
248 | for (DeviceEvent event : events) { | 248 | for (DeviceEvent event : events) { |
249 | PortNumber num = event.port().number(); | 249 | PortNumber num = event.port().number(); |
... | @@ -268,9 +268,9 @@ public class DistributedDeviceStoreTest { | ... | @@ -268,9 +268,9 @@ public class DistributedDeviceStoreTest { |
268 | List<PortDescription> pds = Arrays.<PortDescription>asList( | 268 | List<PortDescription> pds = Arrays.<PortDescription>asList( |
269 | new DefaultPortDescription(P1, true) | 269 | new DefaultPortDescription(P1, true) |
270 | ); | 270 | ); |
271 | - deviceStore.updatePorts(DID1, pds); | 271 | + deviceStore.updatePorts(PID, DID1, pds); |
272 | 272 | ||
273 | - DeviceEvent event = deviceStore.updatePortStatus(DID1, | 273 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, |
274 | new DefaultPortDescription(P1, false)); | 274 | new DefaultPortDescription(P1, false)); |
275 | assertEquals(PORT_UPDATED, event.type()); | 275 | assertEquals(PORT_UPDATED, event.type()); |
276 | assertDevice(DID1, SW1, event.subject()); | 276 | assertDevice(DID1, SW1, event.subject()); |
... | @@ -286,7 +286,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -286,7 +286,7 @@ public class DistributedDeviceStoreTest { |
286 | new DefaultPortDescription(P1, true), | 286 | new DefaultPortDescription(P1, true), |
287 | new DefaultPortDescription(P2, true) | 287 | new DefaultPortDescription(P2, true) |
288 | ); | 288 | ); |
289 | - deviceStore.updatePorts(DID1, pds); | 289 | + deviceStore.updatePorts(PID, DID1, pds); |
290 | 290 | ||
291 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 291 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
292 | List<Port> ports = deviceStore.getPorts(DID1); | 292 | List<Port> ports = deviceStore.getPorts(DID1); |
... | @@ -309,7 +309,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -309,7 +309,7 @@ public class DistributedDeviceStoreTest { |
309 | new DefaultPortDescription(P1, true), | 309 | new DefaultPortDescription(P1, true), |
310 | new DefaultPortDescription(P2, false) | 310 | new DefaultPortDescription(P2, false) |
311 | ); | 311 | ); |
312 | - deviceStore.updatePorts(DID1, pds); | 312 | + deviceStore.updatePorts(PID, DID1, pds); |
313 | 313 | ||
314 | Port port1 = deviceStore.getPort(DID1, P1); | 314 | Port port1 = deviceStore.getPort(DID1, P1); |
315 | assertEquals(P1, port1.number()); | 315 | assertEquals(P1, port1.number()); | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/ImmutableMapSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import java.util.Collections; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.Map; | ||
6 | + | ||
7 | +import org.onlab.util.KryoPool.FamilySerializer; | ||
8 | + | ||
9 | +import com.esotericsoftware.kryo.Kryo; | ||
10 | +import com.esotericsoftware.kryo.io.Input; | ||
11 | +import com.esotericsoftware.kryo.io.Output; | ||
12 | +import com.esotericsoftware.kryo.serializers.MapSerializer; | ||
13 | +import com.google.common.collect.ImmutableMap; | ||
14 | + | ||
15 | +/** | ||
16 | +* Kryo Serializer for {@link ImmutableMap}. | ||
17 | +*/ | ||
18 | +public class ImmutableMapSerializer extends FamilySerializer<ImmutableMap<?, ?>> { | ||
19 | + | ||
20 | + private final MapSerializer mapSerializer = new MapSerializer(); | ||
21 | + | ||
22 | + public ImmutableMapSerializer() { | ||
23 | + // non-null, immutable | ||
24 | + super(false, true); | ||
25 | + } | ||
26 | + | ||
27 | + @Override | ||
28 | + public void write(Kryo kryo, Output output, ImmutableMap<?, ?> object) { | ||
29 | + // wrapping with unmodifiableMap proxy | ||
30 | + // to avoid Kryo from writing only the reference marker of this instance, | ||
31 | + // which will be embedded right before this method call. | ||
32 | + kryo.writeObject(output, Collections.unmodifiableMap(object), mapSerializer); | ||
33 | + } | ||
34 | + | ||
35 | + @Override | ||
36 | + public ImmutableMap<?, ?> read(Kryo kryo, Input input, | ||
37 | + Class<ImmutableMap<?, ?>> type) { | ||
38 | + Map<?, ?> map = kryo.readObject(input, HashMap.class, mapSerializer); | ||
39 | + return ImmutableMap.copyOf(map); | ||
40 | + } | ||
41 | + | ||
42 | + @Override | ||
43 | + public void registerFamilies(Kryo kryo) { | ||
44 | + kryo.register(ImmutableMap.of().getClass(), this); | ||
45 | + kryo.register(ImmutableMap.of(1, 2).getClass(), this); | ||
46 | + kryo.register(ImmutableMap.of(1, 2, 3, 4).getClass(), this); | ||
47 | + // TODO register required ImmutableMap variants | ||
48 | + } | ||
49 | +} |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/ImmutableSetSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.List; | ||
5 | + | ||
6 | +import org.onlab.util.KryoPool.FamilySerializer; | ||
7 | + | ||
8 | +import com.esotericsoftware.kryo.Kryo; | ||
9 | +import com.esotericsoftware.kryo.io.Input; | ||
10 | +import com.esotericsoftware.kryo.io.Output; | ||
11 | +import com.esotericsoftware.kryo.serializers.CollectionSerializer; | ||
12 | +import com.google.common.collect.ImmutableSet; | ||
13 | + | ||
14 | +/** | ||
15 | +* Kryo Serializer for {@link ImmutableSet}. | ||
16 | +*/ | ||
17 | +public class ImmutableSetSerializer extends FamilySerializer<ImmutableSet<?>> { | ||
18 | + | ||
19 | + private final CollectionSerializer serializer = new CollectionSerializer(); | ||
20 | + | ||
21 | + public ImmutableSetSerializer() { | ||
22 | + // non-null, immutable | ||
23 | + super(false, true); | ||
24 | + } | ||
25 | + | ||
26 | + @Override | ||
27 | + public void write(Kryo kryo, Output output, ImmutableSet<?> object) { | ||
28 | + kryo.writeObject(output, object.asList(), serializer); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public ImmutableSet<?> read(Kryo kryo, Input input, | ||
33 | + Class<ImmutableSet<?>> type) { | ||
34 | + List<?> elms = kryo.readObject(input, ArrayList.class, serializer); | ||
35 | + return ImmutableSet.copyOf(elms); | ||
36 | + } | ||
37 | + | ||
38 | + @Override | ||
39 | + public void registerFamilies(Kryo kryo) { | ||
40 | + kryo.register(ImmutableSet.of().getClass(), this); | ||
41 | + kryo.register(ImmutableSet.of(1).getClass(), this); | ||
42 | + kryo.register(ImmutableSet.of(1, 2).getClass(), this); | ||
43 | + // TODO register required ImmutableSet variants | ||
44 | + } | ||
45 | +} |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | import java.net.URI; | 3 | import java.net.URI; |
4 | +import java.nio.ByteBuffer; | ||
4 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
5 | import java.util.HashMap; | 6 | import java.util.HashMap; |
6 | 7 | ||
... | @@ -100,4 +101,14 @@ public class KryoSerializationManager implements KryoSerializationService { | ... | @@ -100,4 +101,14 @@ public class KryoSerializationManager implements KryoSerializationService { |
100 | return serializerPool.deserialize(bytes); | 101 | return serializerPool.deserialize(bytes); |
101 | } | 102 | } |
102 | 103 | ||
104 | + @Override | ||
105 | + public void serialize(Object obj, ByteBuffer buffer) { | ||
106 | + serializerPool.serialize(obj, buffer); | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public <T> T deserialize(ByteBuffer buffer) { | ||
111 | + return serializerPool.deserialize(buffer); | ||
112 | + } | ||
113 | + | ||
103 | } | 114 | } | ... | ... |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | +import java.nio.ByteBuffer; | ||
4 | + | ||
3 | // TODO: To be replaced with SerializationService from IOLoop activity | 5 | // TODO: To be replaced with SerializationService from IOLoop activity |
4 | /** | 6 | /** |
5 | * Service to serialize Objects into byte array. | 7 | * Service to serialize Objects into byte array. |
... | @@ -16,6 +18,15 @@ public interface KryoSerializationService { | ... | @@ -16,6 +18,15 @@ public interface KryoSerializationService { |
16 | public byte[] serialize(final Object obj); | 18 | public byte[] serialize(final Object obj); |
17 | 19 | ||
18 | /** | 20 | /** |
21 | + * Serializes the specified object into bytes using one of the | ||
22 | + * pre-registered serializers. | ||
23 | + * | ||
24 | + * @param obj object to be serialized | ||
25 | + * @param buffer to write serialized bytes | ||
26 | + */ | ||
27 | + public void serialize(final Object obj, ByteBuffer buffer); | ||
28 | + | ||
29 | + /** | ||
19 | * Deserializes the specified bytes into an object using one of the | 30 | * Deserializes the specified bytes into an object using one of the |
20 | * pre-registered serializers. | 31 | * pre-registered serializers. |
21 | * | 32 | * |
... | @@ -24,4 +35,12 @@ public interface KryoSerializationService { | ... | @@ -24,4 +35,12 @@ public interface KryoSerializationService { |
24 | */ | 35 | */ |
25 | public <T> T deserialize(final byte[] bytes); | 36 | public <T> T deserialize(final byte[] bytes); |
26 | 37 | ||
38 | + /** | ||
39 | + * Deserializes the specified bytes into an object using one of the | ||
40 | + * pre-registered serializers. | ||
41 | + * | ||
42 | + * @param buffer bytes to be deserialized | ||
43 | + * @return deserialized object | ||
44 | + */ | ||
45 | + public <T> T deserialize(final ByteBuffer buffer); | ||
27 | } | 46 | } | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipRoleSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import org.onlab.onos.net.MastershipRole; | ||
4 | + | ||
5 | +import com.esotericsoftware.kryo.Kryo; | ||
6 | +import com.esotericsoftware.kryo.Serializer; | ||
7 | +import com.esotericsoftware.kryo.io.Input; | ||
8 | +import com.esotericsoftware.kryo.io.Output; | ||
9 | + | ||
10 | +/** | ||
11 | + * Kryo Serializer for {@link org.onlab.onos.net.MastershipRole}. | ||
12 | + */ | ||
13 | +public class MastershipRoleSerializer extends Serializer<MastershipRole> { | ||
14 | + | ||
15 | + @Override | ||
16 | + public MastershipRole read(Kryo kryo, Input input, Class<MastershipRole> type) { | ||
17 | + final String role = kryo.readObject(input, String.class); | ||
18 | + return MastershipRole.valueOf(role); | ||
19 | + } | ||
20 | + | ||
21 | + @Override | ||
22 | + public void write(Kryo kryo, Output output, MastershipRole object) { | ||
23 | + kryo.writeObject(output, object.toString()); | ||
24 | + } | ||
25 | + | ||
26 | +} |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipTermSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import org.onlab.onos.cluster.MastershipTerm; | ||
4 | +import org.onlab.onos.cluster.NodeId; | ||
5 | + | ||
6 | +import com.esotericsoftware.kryo.Kryo; | ||
7 | +import com.esotericsoftware.kryo.Serializer; | ||
8 | +import com.esotericsoftware.kryo.io.Input; | ||
9 | +import com.esotericsoftware.kryo.io.Output; | ||
10 | + | ||
11 | +/** | ||
12 | + * Kryo Serializer for {@link org.onlab.onos.cluster.MastershipTerm}. | ||
13 | + */ | ||
14 | +public class MastershipTermSerializer extends Serializer<MastershipTerm> { | ||
15 | + | ||
16 | + @Override | ||
17 | + public MastershipTerm read(Kryo kryo, Input input, Class<MastershipTerm> type) { | ||
18 | + final NodeId node = new NodeId(kryo.readObject(input, String.class)); | ||
19 | + final int term = input.readInt(); | ||
20 | + return MastershipTerm.of(node, term); | ||
21 | + } | ||
22 | + | ||
23 | + @Override | ||
24 | + public void write(Kryo kryo, Output output, MastershipTerm object) { | ||
25 | + output.writeString(object.master().toString()); | ||
26 | + output.writeInt(object.termNumber()); | ||
27 | + } | ||
28 | + | ||
29 | +} |
core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTests.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
4 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
5 | + | ||
6 | +import java.net.URI; | ||
7 | +import java.nio.ByteBuffer; | ||
8 | +import java.util.ArrayList; | ||
9 | +import java.util.HashMap; | ||
10 | + | ||
11 | +import org.junit.After; | ||
12 | +import org.junit.Before; | ||
13 | +import org.junit.BeforeClass; | ||
14 | +import org.junit.Test; | ||
15 | +import org.onlab.onos.cluster.MastershipTerm; | ||
16 | +import org.onlab.onos.cluster.NodeId; | ||
17 | +import org.onlab.onos.net.ConnectPoint; | ||
18 | +import org.onlab.onos.net.DefaultDevice; | ||
19 | +import org.onlab.onos.net.DefaultLink; | ||
20 | +import org.onlab.onos.net.DefaultPort; | ||
21 | +import org.onlab.onos.net.Device; | ||
22 | +import org.onlab.onos.net.DeviceId; | ||
23 | +import org.onlab.onos.net.Link; | ||
24 | +import org.onlab.onos.net.LinkKey; | ||
25 | +import org.onlab.onos.net.MastershipRole; | ||
26 | +import org.onlab.onos.net.PortNumber; | ||
27 | +import org.onlab.onos.net.provider.ProviderId; | ||
28 | +import org.onlab.packet.IpPrefix; | ||
29 | +import org.onlab.util.KryoPool; | ||
30 | + | ||
31 | +import com.google.common.collect.ImmutableMap; | ||
32 | +import com.google.common.collect.ImmutableSet; | ||
33 | +import com.google.common.testing.EqualsTester; | ||
34 | + | ||
35 | +import de.javakaffee.kryoserializers.URISerializer; | ||
36 | + | ||
37 | +public class KryoSerializerTests { | ||
38 | + private static final ProviderId PID = new ProviderId("of", "foo"); | ||
39 | + private static final DeviceId DID1 = deviceId("of:foo"); | ||
40 | + private static final DeviceId DID2 = deviceId("of:bar"); | ||
41 | + private static final PortNumber P1 = portNumber(1); | ||
42 | + private static final PortNumber P2 = portNumber(2); | ||
43 | + private static final ConnectPoint CP1 = new ConnectPoint(DID1, P1); | ||
44 | + private static final ConnectPoint CP2 = new ConnectPoint(DID2, P2); | ||
45 | + private static final String MFR = "whitebox"; | ||
46 | + private static final String HW = "1.1.x"; | ||
47 | + private static final String SW1 = "3.8.1"; | ||
48 | + private static final String SW2 = "3.9.5"; | ||
49 | + private static final String SN = "43311-12345"; | ||
50 | + private static final Device DEV1 = new DefaultDevice(PID, DID1, Device.Type.SWITCH, MFR, HW, SW1, SN); | ||
51 | + | ||
52 | + private static KryoPool kryos; | ||
53 | + | ||
54 | + @BeforeClass | ||
55 | + public static void setUpBeforeClass() throws Exception { | ||
56 | + kryos = KryoPool.newBuilder() | ||
57 | + .register( | ||
58 | + ArrayList.class, | ||
59 | + HashMap.class | ||
60 | + ) | ||
61 | + .register( | ||
62 | + Device.Type.class, | ||
63 | + Link.Type.class | ||
64 | + | ||
65 | +// ControllerNode.State.class, | ||
66 | +// DefaultControllerNode.class, | ||
67 | +// MastershipRole.class, | ||
68 | +// Port.class, | ||
69 | +// Element.class, | ||
70 | + ) | ||
71 | + .register(ConnectPoint.class, new ConnectPointSerializer()) | ||
72 | + .register(DefaultLink.class, new DefaultLinkSerializer()) | ||
73 | + .register(DefaultPort.class, new DefaultPortSerializer()) | ||
74 | + .register(DeviceId.class, new DeviceIdSerializer()) | ||
75 | + .register(ImmutableMap.class, new ImmutableMapSerializer()) | ||
76 | + .register(ImmutableSet.class, new ImmutableSetSerializer()) | ||
77 | + .register(IpPrefix.class, new IpPrefixSerializer()) | ||
78 | + .register(LinkKey.class, new LinkKeySerializer()) | ||
79 | + .register(NodeId.class, new NodeIdSerializer()) | ||
80 | + .register(PortNumber.class, new PortNumberSerializer()) | ||
81 | + .register(ProviderId.class, new ProviderIdSerializer()) | ||
82 | + | ||
83 | + .register(DefaultDevice.class) | ||
84 | + | ||
85 | + .register(URI.class, new URISerializer()) | ||
86 | + | ||
87 | + .register(MastershipRole.class, new MastershipRoleSerializer()) | ||
88 | + .register(MastershipTerm.class, new MastershipTermSerializer()) | ||
89 | + .build(); | ||
90 | + } | ||
91 | + | ||
92 | + @Before | ||
93 | + public void setUp() throws Exception { | ||
94 | + } | ||
95 | + | ||
96 | + @After | ||
97 | + public void tearDown() throws Exception { | ||
98 | + // removing Kryo instance to use fresh Kryo on each tests | ||
99 | + kryos.getKryo(); | ||
100 | + } | ||
101 | + | ||
102 | + private static <T> void testSerialized(T original) { | ||
103 | + ByteBuffer buffer = ByteBuffer.allocate(1 * 1024 * 1024); | ||
104 | + kryos.serialize(original, buffer); | ||
105 | + buffer.flip(); | ||
106 | + T copy = kryos.deserialize(buffer); | ||
107 | + | ||
108 | + new EqualsTester() | ||
109 | + .addEqualityGroup(original, copy) | ||
110 | + .testEquals(); | ||
111 | + } | ||
112 | + | ||
113 | + | ||
114 | + @Test | ||
115 | + public final void test() { | ||
116 | + testSerialized(new ConnectPoint(DID1, P1)); | ||
117 | + testSerialized(new DefaultLink(PID, CP1, CP2, Link.Type.DIRECT)); | ||
118 | + testSerialized(new DefaultPort(DEV1, P1, true)); | ||
119 | + testSerialized(DID1); | ||
120 | + testSerialized(ImmutableMap.of(DID1, DEV1, DID2, DEV1)); | ||
121 | + testSerialized(ImmutableMap.of(DID1, DEV1)); | ||
122 | + testSerialized(ImmutableMap.of()); | ||
123 | + testSerialized(ImmutableSet.of(DID1, DID2)); | ||
124 | + testSerialized(ImmutableSet.of(DID1)); | ||
125 | + testSerialized(ImmutableSet.of()); | ||
126 | + testSerialized(IpPrefix.valueOf("192.168.0.1/24")); | ||
127 | + testSerialized(new LinkKey(CP1, CP2)); | ||
128 | + testSerialized(new NodeId("SomeNodeIdentifier")); | ||
129 | + testSerialized(P1); | ||
130 | + testSerialized(PID); | ||
131 | + } | ||
132 | + | ||
133 | +} |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import org.apache.felix.scr.annotations.Component; | 3 | import org.apache.felix.scr.annotations.Component; |
4 | import org.apache.felix.scr.annotations.Service; | 4 | import org.apache.felix.scr.annotations.Service; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableSet; | 3 | import com.google.common.collect.ImmutableSet; |
4 | import org.apache.felix.scr.annotations.Activate; | 4 | import org.apache.felix.scr.annotations.Activate; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import com.google.common.collect.FluentIterable; | 3 | import com.google.common.collect.FluentIterable; |
4 | import com.google.common.collect.ImmutableList; | 4 | import com.google.common.collect.ImmutableList; |
... | @@ -143,7 +143,7 @@ public class SimpleDeviceStore | ... | @@ -143,7 +143,7 @@ public class SimpleDeviceStore |
143 | } | 143 | } |
144 | 144 | ||
145 | @Override | 145 | @Override |
146 | - public List<DeviceEvent> updatePorts(DeviceId deviceId, | 146 | + public List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
147 | List<PortDescription> portDescriptions) { | 147 | List<PortDescription> portDescriptions) { |
148 | List<DeviceEvent> events = new ArrayList<>(); | 148 | List<DeviceEvent> events = new ArrayList<>(); |
149 | synchronized (this) { | 149 | synchronized (this) { |
... | @@ -221,7 +221,7 @@ public class SimpleDeviceStore | ... | @@ -221,7 +221,7 @@ public class SimpleDeviceStore |
221 | } | 221 | } |
222 | 222 | ||
223 | @Override | 223 | @Override |
224 | - public DeviceEvent updatePortStatus(DeviceId deviceId, | 224 | + public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
225 | PortDescription portDescription) { | 225 | PortDescription portDescription) { |
226 | synchronized (this) { | 226 | synchronized (this) { |
227 | Device device = devices.get(deviceId); | 227 | Device device = devices.get(deviceId); | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; | 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; |
4 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 4 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; | 3 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; |
4 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; | 4 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import static org.slf4j.LoggerFactory.getLogger; | 3 | import static org.slf4j.LoggerFactory.getLogger; |
4 | 4 | ||
... | @@ -7,8 +7,6 @@ import java.util.HashMap; | ... | @@ -7,8 +7,6 @@ import java.util.HashMap; |
7 | import java.util.HashSet; | 7 | import java.util.HashSet; |
8 | import java.util.Map; | 8 | import java.util.Map; |
9 | import java.util.Set; | 9 | import java.util.Set; |
10 | -import java.util.concurrent.ConcurrentHashMap; | ||
11 | -import java.util.concurrent.ConcurrentMap; | ||
12 | import java.util.concurrent.atomic.AtomicInteger; | 10 | import java.util.concurrent.atomic.AtomicInteger; |
13 | 11 | ||
14 | import org.apache.felix.scr.annotations.Activate; | 12 | import org.apache.felix.scr.annotations.Activate; |
... | @@ -48,8 +46,10 @@ public class SimpleMastershipStore | ... | @@ -48,8 +46,10 @@ public class SimpleMastershipStore |
48 | new DefaultControllerNode(new NodeId("local"), LOCALHOST); | 46 | new DefaultControllerNode(new NodeId("local"), LOCALHOST); |
49 | 47 | ||
50 | //devices mapped to their masters, to emulate multiple nodes | 48 | //devices mapped to their masters, to emulate multiple nodes |
51 | - protected final ConcurrentMap<DeviceId, NodeId> masterMap = | 49 | + protected final Map<DeviceId, NodeId> masterMap = new HashMap<>(); |
52 | - new ConcurrentHashMap<>(); | 50 | + //emulate backups with pile of nodes |
51 | + protected final Set<NodeId> backups = new HashSet<>(); | ||
52 | + //terms | ||
53 | protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>(); | 53 | protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>(); |
54 | 54 | ||
55 | @Activate | 55 | @Activate |
... | @@ -64,26 +64,30 @@ public class SimpleMastershipStore | ... | @@ -64,26 +64,30 @@ public class SimpleMastershipStore |
64 | 64 | ||
65 | @Override | 65 | @Override |
66 | public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { | 66 | public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { |
67 | + MastershipRole role = getRole(nodeId, deviceId); | ||
67 | 68 | ||
68 | - NodeId node = masterMap.get(deviceId); | ||
69 | - if (node == null) { | ||
70 | synchronized (this) { | 69 | synchronized (this) { |
70 | + switch (role) { | ||
71 | + case MASTER: | ||
72 | + return null; | ||
73 | + case STANDBY: | ||
74 | + masterMap.put(deviceId, nodeId); | ||
75 | + termMap.get(deviceId).incrementAndGet(); | ||
76 | + backups.add(nodeId); | ||
77 | + break; | ||
78 | + case NONE: | ||
71 | masterMap.put(deviceId, nodeId); | 79 | masterMap.put(deviceId, nodeId); |
72 | termMap.put(deviceId, new AtomicInteger()); | 80 | termMap.put(deviceId, new AtomicInteger()); |
81 | + backups.add(nodeId); | ||
82 | + break; | ||
83 | + default: | ||
84 | + log.warn("unknown Mastership Role {}", role); | ||
85 | + return null; | ||
73 | } | 86 | } |
74 | - return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | ||
75 | } | 87 | } |
76 | 88 | ||
77 | - if (node.equals(nodeId)) { | ||
78 | - return null; | ||
79 | - } else { | ||
80 | - synchronized (this) { | ||
81 | - masterMap.put(deviceId, nodeId); | ||
82 | - termMap.get(deviceId).incrementAndGet(); | ||
83 | return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | 89 | return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); |
84 | } | 90 | } |
85 | - } | ||
86 | - } | ||
87 | 91 | ||
88 | @Override | 92 | @Override |
89 | public NodeId getMaster(DeviceId deviceId) { | 93 | public NodeId getMaster(DeviceId deviceId) { |
... | @@ -103,34 +107,111 @@ public class SimpleMastershipStore | ... | @@ -103,34 +107,111 @@ public class SimpleMastershipStore |
103 | 107 | ||
104 | @Override | 108 | @Override |
105 | public MastershipRole requestRole(DeviceId deviceId) { | 109 | public MastershipRole requestRole(DeviceId deviceId) { |
106 | - return getRole(instance.id(), deviceId); | 110 | + //query+possible reelection |
111 | + NodeId node = instance.id(); | ||
112 | + MastershipRole role = getRole(node, deviceId); | ||
113 | + | ||
114 | + switch (role) { | ||
115 | + case MASTER: | ||
116 | + break; | ||
117 | + case STANDBY: | ||
118 | + synchronized (this) { | ||
119 | + //try to "re-elect", since we're really not distributed | ||
120 | + NodeId rel = reelect(node); | ||
121 | + if (rel == null) { | ||
122 | + masterMap.put(deviceId, node); | ||
123 | + termMap.put(deviceId, new AtomicInteger()); | ||
124 | + role = MastershipRole.MASTER; | ||
125 | + } | ||
126 | + backups.add(node); | ||
127 | + } | ||
128 | + break; | ||
129 | + case NONE: | ||
130 | + //first to get to it, say we are master | ||
131 | + synchronized (this) { | ||
132 | + masterMap.put(deviceId, node); | ||
133 | + termMap.put(deviceId, new AtomicInteger()); | ||
134 | + backups.add(node); | ||
135 | + role = MastershipRole.MASTER; | ||
136 | + } | ||
137 | + break; | ||
138 | + default: | ||
139 | + log.warn("unknown Mastership Role {}", role); | ||
140 | + } | ||
141 | + return role; | ||
107 | } | 142 | } |
108 | 143 | ||
109 | @Override | 144 | @Override |
110 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 145 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
111 | - NodeId node = masterMap.get(deviceId); | 146 | + //just query |
147 | + NodeId current = masterMap.get(deviceId); | ||
112 | MastershipRole role; | 148 | MastershipRole role; |
113 | - if (node != null) { | 149 | + |
114 | - if (node.equals(nodeId)) { | 150 | + if (current == null) { |
115 | - role = MastershipRole.MASTER; | 151 | + if (backups.contains(nodeId)) { |
116 | - } else { | ||
117 | role = MastershipRole.STANDBY; | 152 | role = MastershipRole.STANDBY; |
153 | + } else { | ||
154 | + role = MastershipRole.NONE; | ||
118 | } | 155 | } |
119 | } else { | 156 | } else { |
120 | - //masterMap doesn't contain it. | 157 | + if (current.equals(nodeId)) { |
121 | role = MastershipRole.MASTER; | 158 | role = MastershipRole.MASTER; |
122 | - masterMap.put(deviceId, nodeId); | 159 | + } else { |
160 | + role = MastershipRole.STANDBY; | ||
161 | + } | ||
123 | } | 162 | } |
124 | return role; | 163 | return role; |
125 | } | 164 | } |
126 | 165 | ||
127 | @Override | 166 | @Override |
128 | public MastershipTerm getTermFor(DeviceId deviceId) { | 167 | public MastershipTerm getTermFor(DeviceId deviceId) { |
129 | - if (masterMap.get(deviceId) == null) { | 168 | + if ((masterMap.get(deviceId) == null) || |
169 | + (termMap.get(deviceId) == null)) { | ||
130 | return null; | 170 | return null; |
131 | } | 171 | } |
132 | return MastershipTerm.of( | 172 | return MastershipTerm.of( |
133 | masterMap.get(deviceId), termMap.get(deviceId).get()); | 173 | masterMap.get(deviceId), termMap.get(deviceId).get()); |
134 | } | 174 | } |
135 | 175 | ||
176 | + @Override | ||
177 | + public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { | ||
178 | + MastershipRole role = getRole(nodeId, deviceId); | ||
179 | + synchronized (this) { | ||
180 | + switch (role) { | ||
181 | + case MASTER: | ||
182 | + NodeId backup = reelect(nodeId); | ||
183 | + if (backup == null) { | ||
184 | + masterMap.remove(deviceId); | ||
185 | + } else { | ||
186 | + masterMap.put(deviceId, backup); | ||
187 | + termMap.get(deviceId).incrementAndGet(); | ||
188 | + return new MastershipEvent(MASTER_CHANGED, deviceId, backup); | ||
189 | + } | ||
190 | + case STANDBY: | ||
191 | + case NONE: | ||
192 | + if (!termMap.containsKey(deviceId)) { | ||
193 | + termMap.put(deviceId, new AtomicInteger()); | ||
194 | + } | ||
195 | + backups.add(nodeId); | ||
196 | + break; | ||
197 | + default: | ||
198 | + log.warn("unknown Mastership Role {}", role); | ||
199 | + } | ||
200 | + } | ||
201 | + return null; | ||
202 | + } | ||
203 | + | ||
204 | + //dumbly selects next-available node that's not the current one | ||
205 | + //emulate leader election | ||
206 | + private NodeId reelect(NodeId nodeId) { | ||
207 | + NodeId backup = null; | ||
208 | + for (NodeId n : backups) { | ||
209 | + if (!n.equals(nodeId)) { | ||
210 | + backup = n; | ||
211 | + break; | ||
212 | + } | ||
213 | + } | ||
214 | + return backup; | ||
215 | + } | ||
216 | + | ||
136 | } | 217 | } | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import org.apache.felix.scr.annotations.Activate; | 3 | import org.apache.felix.scr.annotations.Activate; |
4 | import org.apache.felix.scr.annotations.Component; | 4 | import org.apache.felix.scr.annotations.Component; | ... | ... |
... | @@ -2,4 +2,4 @@ | ... | @@ -2,4 +2,4 @@ |
2 | * Implementations of in-memory stores suitable for unit testing and | 2 | * Implementations of in-memory stores suitable for unit testing and |
3 | * experimentation; not for production use. | 3 | * experimentation; not for production use. |
4 | */ | 4 | */ |
5 | -package org.onlab.onos.net.trivial.impl; | 5 | +package org.onlab.onos.store.trivial.impl; | ... | ... |
1 | /** | 1 | /** |
2 | * | 2 | * |
3 | */ | 3 | */ |
4 | -package org.onlab.onos.net.trivial.impl; | 4 | +package org.onlab.onos.store.trivial.impl; |
5 | 5 | ||
6 | import static org.junit.Assert.*; | 6 | import static org.junit.Assert.*; |
7 | import static org.onlab.onos.net.Device.Type.SWITCH; | 7 | import static org.onlab.onos.net.Device.Type.SWITCH; |
... | @@ -182,7 +182,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -182,7 +182,7 @@ public class SimpleDeviceStoreTest { |
182 | new DefaultPortDescription(P2, true) | 182 | new DefaultPortDescription(P2, true) |
183 | ); | 183 | ); |
184 | 184 | ||
185 | - List<DeviceEvent> events = deviceStore.updatePorts(DID1, pds); | 185 | + List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); |
186 | 186 | ||
187 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 187 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
188 | for (DeviceEvent event : events) { | 188 | for (DeviceEvent event : events) { |
... | @@ -201,7 +201,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -201,7 +201,7 @@ public class SimpleDeviceStoreTest { |
201 | new DefaultPortDescription(P3, true) | 201 | new DefaultPortDescription(P3, true) |
202 | ); | 202 | ); |
203 | 203 | ||
204 | - events = deviceStore.updatePorts(DID1, pds2); | 204 | + events = deviceStore.updatePorts(PID, DID1, pds2); |
205 | assertFalse("event should be triggered", events.isEmpty()); | 205 | assertFalse("event should be triggered", events.isEmpty()); |
206 | for (DeviceEvent event : events) { | 206 | for (DeviceEvent event : events) { |
207 | PortNumber num = event.port().number(); | 207 | PortNumber num = event.port().number(); |
... | @@ -224,7 +224,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -224,7 +224,7 @@ public class SimpleDeviceStoreTest { |
224 | new DefaultPortDescription(P1, false), | 224 | new DefaultPortDescription(P1, false), |
225 | new DefaultPortDescription(P2, true) | 225 | new DefaultPortDescription(P2, true) |
226 | ); | 226 | ); |
227 | - events = deviceStore.updatePorts(DID1, pds3); | 227 | + events = deviceStore.updatePorts(PID, DID1, pds3); |
228 | assertFalse("event should be triggered", events.isEmpty()); | 228 | assertFalse("event should be triggered", events.isEmpty()); |
229 | for (DeviceEvent event : events) { | 229 | for (DeviceEvent event : events) { |
230 | PortNumber num = event.port().number(); | 230 | PortNumber num = event.port().number(); |
... | @@ -249,9 +249,9 @@ public class SimpleDeviceStoreTest { | ... | @@ -249,9 +249,9 @@ public class SimpleDeviceStoreTest { |
249 | List<PortDescription> pds = Arrays.<PortDescription>asList( | 249 | List<PortDescription> pds = Arrays.<PortDescription>asList( |
250 | new DefaultPortDescription(P1, true) | 250 | new DefaultPortDescription(P1, true) |
251 | ); | 251 | ); |
252 | - deviceStore.updatePorts(DID1, pds); | 252 | + deviceStore.updatePorts(PID, DID1, pds); |
253 | 253 | ||
254 | - DeviceEvent event = deviceStore.updatePortStatus(DID1, | 254 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, |
255 | new DefaultPortDescription(P1, false)); | 255 | new DefaultPortDescription(P1, false)); |
256 | assertEquals(PORT_UPDATED, event.type()); | 256 | assertEquals(PORT_UPDATED, event.type()); |
257 | assertDevice(DID1, SW1, event.subject()); | 257 | assertDevice(DID1, SW1, event.subject()); |
... | @@ -267,7 +267,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -267,7 +267,7 @@ public class SimpleDeviceStoreTest { |
267 | new DefaultPortDescription(P1, true), | 267 | new DefaultPortDescription(P1, true), |
268 | new DefaultPortDescription(P2, true) | 268 | new DefaultPortDescription(P2, true) |
269 | ); | 269 | ); |
270 | - deviceStore.updatePorts(DID1, pds); | 270 | + deviceStore.updatePorts(PID, DID1, pds); |
271 | 271 | ||
272 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 272 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
273 | List<Port> ports = deviceStore.getPorts(DID1); | 273 | List<Port> ports = deviceStore.getPorts(DID1); |
... | @@ -290,7 +290,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -290,7 +290,7 @@ public class SimpleDeviceStoreTest { |
290 | new DefaultPortDescription(P1, true), | 290 | new DefaultPortDescription(P1, true), |
291 | new DefaultPortDescription(P2, false) | 291 | new DefaultPortDescription(P2, false) |
292 | ); | 292 | ); |
293 | - deviceStore.updatePorts(DID1, pds); | 293 | + deviceStore.updatePorts(PID, DID1, pds); |
294 | 294 | ||
295 | Port port1 = deviceStore.getPort(DID1, P1); | 295 | Port port1 = deviceStore.getPort(DID1, P1); |
296 | assertEquals(P1, port1.number()); | 296 | assertEquals(P1, port1.number()); | ... | ... |
core/store/trivial/src/test/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStoreTest.java
0 → 100644
1 | +package org.onlab.onos.store.trivial.impl; | ||
2 | + | ||
3 | +import java.util.Set; | ||
4 | +import java.util.concurrent.atomic.AtomicInteger; | ||
5 | + | ||
6 | +import org.junit.After; | ||
7 | +import org.junit.Before; | ||
8 | +import org.junit.Test; | ||
9 | +import org.onlab.onos.cluster.MastershipTerm; | ||
10 | +import org.onlab.onos.cluster.NodeId; | ||
11 | +import org.onlab.onos.net.DeviceId; | ||
12 | + | ||
13 | +import com.google.common.collect.Sets; | ||
14 | + | ||
15 | +import static org.junit.Assert.assertEquals; | ||
16 | +import static org.junit.Assert.assertNull; | ||
17 | +import static org.junit.Assert.assertTrue; | ||
18 | +import static org.onlab.onos.net.MastershipRole.*; | ||
19 | +import static org.onlab.onos.cluster.MastershipEvent.Type.*; | ||
20 | + | ||
21 | +/** | ||
22 | + * Test for the simple MastershipStore implementation. | ||
23 | + */ | ||
24 | +public class SimpleMastershipStoreTest { | ||
25 | + | ||
26 | + private static final DeviceId DID1 = DeviceId.deviceId("of:01"); | ||
27 | + private static final DeviceId DID2 = DeviceId.deviceId("of:02"); | ||
28 | + private static final DeviceId DID3 = DeviceId.deviceId("of:03"); | ||
29 | + private static final DeviceId DID4 = DeviceId.deviceId("of:04"); | ||
30 | + | ||
31 | + private static final NodeId N1 = new NodeId("local"); | ||
32 | + private static final NodeId N2 = new NodeId("other"); | ||
33 | + | ||
34 | + private SimpleMastershipStore sms; | ||
35 | + | ||
36 | + @Before | ||
37 | + public void setUp() throws Exception { | ||
38 | + sms = new SimpleMastershipStore(); | ||
39 | + sms.activate(); | ||
40 | + } | ||
41 | + | ||
42 | + @After | ||
43 | + public void tearDown() throws Exception { | ||
44 | + sms.deactivate(); | ||
45 | + } | ||
46 | + | ||
47 | + @Test | ||
48 | + public void getRole() { | ||
49 | + //special case, no backup or master | ||
50 | + put(DID1, N1, false, false); | ||
51 | + assertEquals("wrong role", NONE, sms.getRole(N1, DID1)); | ||
52 | + | ||
53 | + //backup exists but we aren't mapped | ||
54 | + put(DID2, N1, false, true); | ||
55 | + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID2)); | ||
56 | + | ||
57 | + //N2 is master | ||
58 | + put(DID3, N2, true, true); | ||
59 | + assertEquals("wrong role", MASTER, sms.getRole(N2, DID3)); | ||
60 | + | ||
61 | + //N2 is master but N1 is only in backups set | ||
62 | + put(DID4, N2, true, false); | ||
63 | + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID4)); | ||
64 | + } | ||
65 | + | ||
66 | + @Test | ||
67 | + public void getMaster() { | ||
68 | + put(DID3, N2, true, true); | ||
69 | + assertEquals("wrong role", MASTER, sms.getRole(N2, DID3)); | ||
70 | + assertEquals("wrong device", N2, sms.getMaster(DID3)); | ||
71 | + } | ||
72 | + | ||
73 | + @Test | ||
74 | + public void setMaster() { | ||
75 | + put(DID1, N1, false, false); | ||
76 | + assertEquals("wrong event", MASTER_CHANGED, sms.setMaster(N1, DID1).type()); | ||
77 | + assertEquals("wrong role", MASTER, sms.getRole(N1, DID1)); | ||
78 | + //set node that's already master - should be ignored | ||
79 | + assertNull("wrong event", sms.setMaster(N1, DID1)); | ||
80 | + | ||
81 | + //set STANDBY to MASTER | ||
82 | + put(DID2, N1, false, true); | ||
83 | + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID2)); | ||
84 | + assertEquals("wrong event", MASTER_CHANGED, sms.setMaster(N1, DID2).type()); | ||
85 | + assertEquals("wrong role", MASTER, sms.getRole(N1, DID2)); | ||
86 | + } | ||
87 | + | ||
88 | + @Test | ||
89 | + public void getDevices() { | ||
90 | + Set<DeviceId> d = Sets.newHashSet(DID1, DID2); | ||
91 | + | ||
92 | + put(DID1, N2, true, true); | ||
93 | + put(DID2, N2, true, true); | ||
94 | + put(DID3, N1, true, true); | ||
95 | + assertTrue("wrong devices", d.equals(sms.getDevices(N2))); | ||
96 | + } | ||
97 | + | ||
98 | + @Test | ||
99 | + public void getTermFor() { | ||
100 | + put(DID1, N1, true, true); | ||
101 | + assertEquals("wrong term", MastershipTerm.of(N1, 0), sms.getTermFor(DID1)); | ||
102 | + | ||
103 | + //switch to N2 and back - 2 term switches | ||
104 | + sms.setMaster(N2, DID1); | ||
105 | + sms.setMaster(N1, DID1); | ||
106 | + assertEquals("wrong term", MastershipTerm.of(N1, 2), sms.getTermFor(DID1)); | ||
107 | + } | ||
108 | + | ||
109 | + @Test | ||
110 | + public void requestRole() { | ||
111 | + //NONE - become MASTER | ||
112 | + put(DID1, N1, false, false); | ||
113 | + assertEquals("wrong role", MASTER, sms.requestRole(DID1)); | ||
114 | + | ||
115 | + //STANDBY without backup - become MASTER | ||
116 | + put(DID2, N1, false, true); | ||
117 | + assertEquals("wrong role", MASTER, sms.requestRole(DID2)); | ||
118 | + | ||
119 | + //STANDBY with backup - stay STANDBY | ||
120 | + put(DID3, N2, false, true); | ||
121 | + assertEquals("wrong role", STANDBY, sms.requestRole(DID3)); | ||
122 | + | ||
123 | + //local (N1) is MASTER - stay MASTER | ||
124 | + put(DID4, N1, true, true); | ||
125 | + assertEquals("wrong role", MASTER, sms.requestRole(DID4)); | ||
126 | + } | ||
127 | + | ||
128 | + @Test | ||
129 | + public void unsetMaster() { | ||
130 | + //NONE - record backup but take no other action | ||
131 | + put(DID1, N1, false, false); | ||
132 | + sms.unsetMaster(N1, DID1); | ||
133 | + assertTrue("not backed up", sms.backups.contains(N1)); | ||
134 | + sms.termMap.clear(); | ||
135 | + sms.unsetMaster(N1, DID1); | ||
136 | + assertTrue("term not set", sms.termMap.containsKey(DID1)); | ||
137 | + | ||
138 | + //no backup, MASTER | ||
139 | + put(DID1, N1, true, true); | ||
140 | + assertNull("wrong event", sms.unsetMaster(N1, DID1)); | ||
141 | + assertNull("wrong node", sms.masterMap.get(DID1)); | ||
142 | + | ||
143 | + //backup, switch | ||
144 | + sms.masterMap.clear(); | ||
145 | + put(DID1, N1, true, true); | ||
146 | + put(DID2, N2, true, true); | ||
147 | + assertEquals("wrong event", MASTER_CHANGED, sms.unsetMaster(N1, DID1).type()); | ||
148 | + } | ||
149 | + | ||
150 | + //helper to populate master/backup structures | ||
151 | + private void put(DeviceId dev, NodeId node, boolean store, boolean backup) { | ||
152 | + if (store) { | ||
153 | + sms.masterMap.put(dev, node); | ||
154 | + } | ||
155 | + if (backup) { | ||
156 | + sms.backups.add(node); | ||
157 | + } | ||
158 | + sms.termMap.put(dev, new AtomicInteger()); | ||
159 | + } | ||
160 | +} |
... | @@ -419,7 +419,7 @@ | ... | @@ -419,7 +419,7 @@ |
419 | <group> | 419 | <group> |
420 | <title>Core Subsystems</title> | 420 | <title>Core Subsystems</title> |
421 | <packages> | 421 | <packages> |
422 | - org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.net.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.* | 422 | + org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.* |
423 | </packages> | 423 | </packages> |
424 | </group> | 424 | </group> |
425 | <group> | 425 | <group> | ... | ... |
... | @@ -6,22 +6,21 @@ | ... | @@ -6,22 +6,21 @@ |
6 | export ONOS_ROOT=${ONOS_ROOT:-~/onos-next} | 6 | export ONOS_ROOT=${ONOS_ROOT:-~/onos-next} |
7 | 7 | ||
8 | # Setup some environmental context for developers | 8 | # Setup some environmental context for developers |
9 | -export JAVA_HOME=$(/usr/libexec/java_home) | 9 | +export JAVA_HOME=$(/usr/libexec/java_home -v 1.7) |
10 | export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2} | 10 | export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2} |
11 | export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1} | 11 | export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1} |
12 | export KARAF_LOG=$KARAF/data/log/karaf.log | 12 | export KARAF_LOG=$KARAF/data/log/karaf.log |
13 | 13 | ||
14 | # Setup a path | 14 | # Setup a path |
15 | -export PS=":" | 15 | +export PATH="$PATH:$ONOS_ROOT/tools/dev/bin:$ONOS_ROOT/tools/test/bin" |
16 | -export PATH="$PATH:$ONOS_ROOT/tools/dev:$ONOS_ROOT/tools/build" | 16 | +export PATH="$PATH:$ONOS_ROOT/tools/build" |
17 | -export PATH="$PATH:$ONOS_ROOT/tools/test/bin" | ||
18 | export PATH="$PATH:$MAVEN/bin:$KARAF/bin" | 17 | export PATH="$PATH:$MAVEN/bin:$KARAF/bin" |
19 | export PATH="$PATH:." | 18 | export PATH="$PATH:." |
20 | 19 | ||
21 | # Convenience utility to warp to various ONOS source projects | 20 | # Convenience utility to warp to various ONOS source projects |
22 | # e.g. 'o api', 'o dev', 'o' | 21 | # e.g. 'o api', 'o dev', 'o' |
23 | function o { | 22 | function o { |
24 | - cd $(find $ONOS_ROOT/ -type d | egrep -v '\.git|target|src' | \ | 23 | + cd $(find $ONOS_ROOT/ -type d | egrep -v '\.git|target' | \ |
25 | egrep "${1:-$ONOS_ROOT}" | head -n 1) | 24 | egrep "${1:-$ONOS_ROOT}" | head -n 1) |
26 | } | 25 | } |
27 | 26 | ||
... | @@ -30,11 +29,12 @@ alias mci='mvn clean install' | ... | @@ -30,11 +29,12 @@ alias mci='mvn clean install' |
30 | 29 | ||
31 | # Short-hand for ONOS build, package and test. | 30 | # Short-hand for ONOS build, package and test. |
32 | alias ob='onos-build' | 31 | alias ob='onos-build' |
32 | +alias obs='onos-build-selective' | ||
33 | alias op='onos-package' | 33 | alias op='onos-package' |
34 | alias ot='onos-test' | 34 | alias ot='onos-test' |
35 | 35 | ||
36 | # Short-hand for tailing the ONOS (karaf) log | 36 | # Short-hand for tailing the ONOS (karaf) log |
37 | -alias tl='$ONOS_ROOT/tools/dev/watchLog' | 37 | +alias tl='$ONOS_ROOT/tools/dev/bin/onos-local-log' |
38 | alias tlo='tl | grep --colour=always org.onlab' | 38 | alias tlo='tl | grep --colour=always org.onlab' |
39 | 39 | ||
40 | # Pretty-print JSON output | 40 | # Pretty-print JSON output | ... | ... |
tools/dev/bin/onos-build-selective
0 → 100755
1 | +#!/bin/bash | ||
2 | +#------------------------------------------------------------------------------ | ||
3 | +# Selectively builds only those projects that contained modified Java files. | ||
4 | +#------------------------------------------------------------------------------ | ||
5 | + | ||
6 | +projects=$(find $ONOS_ROOT -name '*.java' \ | ||
7 | + -not -path '*/openflowj/*' -and -not -path '.git/*' \ | ||
8 | + -exec $ONOS_ROOT/tools/dev/bin/onos-build-selective-hook {} \; | \ | ||
9 | + sort -u | sed "s:$ONOS_ROOT::g" | tr '\n' ',' | \ | ||
10 | + sed 's:/,:,:g;s:,/:,:g;s:^/::g;s:,$::g') | ||
11 | + | ||
12 | +[ -n "$projects" ] && cd $ONOS_ROOT && mvn --projects $projects ${@:-clean install} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
tools/dev/bin/onos-build-selective-hook
0 → 100755
1 | +#------------------------------------------------------------------------------ | ||
2 | +# Echoes project-level directory if a Java file within is newer than its | ||
3 | +# class file counterpart | ||
4 | +#------------------------------------------------------------------------------ | ||
5 | + | ||
6 | +javaFile=${1#*\/src\/*\/java/} | ||
7 | +basename=${1/*\//} | ||
8 | + | ||
9 | +[ $basename = "package-info.java" ] && exit 0 | ||
10 | + | ||
11 | +src=${1/$javaFile/} | ||
12 | +project=${src/src*/} | ||
13 | +classFile=${javaFile/.java/.class} | ||
14 | + | ||
15 | +[ ${project}target/classes/$classFile -nt ${src}$javaFile -o \ | ||
16 | + ${project}target/test-classes/$classFile -nt ${src}$javaFile ] \ | ||
17 | + || echo ${src/src*/} | ||
18 | + |
... | @@ -239,12 +239,41 @@ public final class KryoPool { | ... | @@ -239,12 +239,41 @@ public final class KryoPool { |
239 | Kryo kryo = new Kryo(); | 239 | Kryo kryo = new Kryo(); |
240 | kryo.setRegistrationRequired(registrationRequired); | 240 | kryo.setRegistrationRequired(registrationRequired); |
241 | for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) { | 241 | for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) { |
242 | - if (registry.getRight() == null) { | 242 | + final Serializer<?> serializer = registry.getRight(); |
243 | + if (serializer == null) { | ||
243 | kryo.register(registry.getLeft()); | 244 | kryo.register(registry.getLeft()); |
244 | } else { | 245 | } else { |
245 | - kryo.register(registry.getLeft(), registry.getRight()); | 246 | + kryo.register(registry.getLeft(), serializer); |
247 | + if (serializer instanceof FamilySerializer) { | ||
248 | + FamilySerializer<?> fser = (FamilySerializer<?>) serializer; | ||
249 | + fser.registerFamilies(kryo); | ||
250 | + } | ||
246 | } | 251 | } |
247 | } | 252 | } |
248 | return kryo; | 253 | return kryo; |
249 | } | 254 | } |
255 | + | ||
256 | + /** | ||
257 | + * Serializer implementation, which required registration of family of Classes. | ||
258 | + * @param <T> base type of this serializer. | ||
259 | + */ | ||
260 | + public abstract static class FamilySerializer<T> extends Serializer<T> { | ||
261 | + | ||
262 | + | ||
263 | + public FamilySerializer(boolean acceptsNull) { | ||
264 | + super(acceptsNull); | ||
265 | + } | ||
266 | + | ||
267 | + public FamilySerializer(boolean acceptsNull, boolean immutable) { | ||
268 | + super(acceptsNull, immutable); | ||
269 | + } | ||
270 | + | ||
271 | + /** | ||
272 | + * Registers other classes this Serializer supports. | ||
273 | + * | ||
274 | + * @param kryo instance to register classes to | ||
275 | + */ | ||
276 | + public void registerFamilies(Kryo kryo) { | ||
277 | + } | ||
278 | + } | ||
250 | } | 279 | } | ... | ... |
-
Please register or login to post a comment