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