Fix for Kryo related issue crossing OSGi bundle boundaries.
Change-Id: I121dfe360de14a5b4760e5d2fd8cb2db93e0be63
Showing
8 changed files
with
171 additions
and
92 deletions
| ... | @@ -7,9 +7,6 @@ import java.net.URI; | ... | @@ -7,9 +7,6 @@ import java.net.URI; |
| 7 | */ | 7 | */ |
| 8 | public final class DeviceId extends ElementId { | 8 | public final class DeviceId extends ElementId { |
| 9 | 9 | ||
| 10 | - // Default constructor for serialization | ||
| 11 | - protected DeviceId() {} | ||
| 12 | - | ||
| 13 | // Public construction is prohibited | 10 | // Public construction is prohibited |
| 14 | private DeviceId(URI uri) { | 11 | private DeviceId(URI uri) { |
| 15 | super(uri); | 12 | super(uri); | ... | ... |
| ... | @@ -12,12 +12,6 @@ public class ProviderId { | ... | @@ -12,12 +12,6 @@ public class ProviderId { |
| 12 | private final String scheme; | 12 | private final String scheme; |
| 13 | private final String id; | 13 | private final String id; |
| 14 | 14 | ||
| 15 | - // Default constructor for serialization | ||
| 16 | - protected ProviderId() { | ||
| 17 | - scheme = null; | ||
| 18 | - id = null; | ||
| 19 | - } | ||
| 20 | - | ||
| 21 | /** | 15 | /** |
| 22 | * Creates a new provider identifier from the specified string. | 16 | * Creates a new provider identifier from the specified string. |
| 23 | * The providers are expected to follow the reverse DNS convention, e.g. | 17 | * The providers are expected to follow the reverse DNS convention, e.g. |
| ... | @@ -40,6 +34,15 @@ public class ProviderId { | ... | @@ -40,6 +34,15 @@ public class ProviderId { |
| 40 | return scheme; | 34 | return scheme; |
| 41 | } | 35 | } |
| 42 | 36 | ||
| 37 | + /** | ||
| 38 | + * Returns the device URI scheme specific id portion. | ||
| 39 | + * | ||
| 40 | + * @return id | ||
| 41 | + */ | ||
| 42 | + public String id() { | ||
| 43 | + return id; | ||
| 44 | + } | ||
| 45 | + | ||
| 43 | @Override | 46 | @Override |
| 44 | public int hashCode() { | 47 | public int hashCode() { |
| 45 | return Objects.hash(scheme, id); | 48 | return Objects.hash(scheme, id); | ... | ... |
| ... | @@ -112,7 +112,7 @@ public class DistributedDeviceManagerTest { | ... | @@ -112,7 +112,7 @@ public class DistributedDeviceManagerTest { |
| 112 | mgr.deactivate(); | 112 | mgr.deactivate(); |
| 113 | 113 | ||
| 114 | dstore.deactivate(); | 114 | dstore.deactivate(); |
| 115 | - dstore.theInstance.shutdown(); | 115 | + ((TestDistributedDeviceStore) dstore).shutdownHz(); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | private void connectDevice(DeviceId deviceId, String swVersion) { | 118 | private void connectDevice(DeviceId deviceId, String swVersion) { |
| ... | @@ -290,5 +290,12 @@ public class DistributedDeviceManagerTest { | ... | @@ -290,5 +290,12 @@ public class DistributedDeviceManagerTest { |
| 290 | } | 290 | } |
| 291 | }; | 291 | }; |
| 292 | } | 292 | } |
| 293 | + | ||
| 294 | + /** | ||
| 295 | + * Shutdowns the hazelcast instance. | ||
| 296 | + */ | ||
| 297 | + public void shutdownHz() { | ||
| 298 | + theInstance.shutdown(); | ||
| 299 | + } | ||
| 293 | } | 300 | } |
| 294 | } | 301 | } | ... | ... |
| ... | @@ -16,6 +16,9 @@ import com.esotericsoftware.kryo.serializers.CollectionSerializer; | ... | @@ -16,6 +16,9 @@ import com.esotericsoftware.kryo.serializers.CollectionSerializer; |
| 16 | import com.google.common.collect.ImmutableSet; | 16 | import com.google.common.collect.ImmutableSet; |
| 17 | 17 | ||
| 18 | // TODO move to util, etc. | 18 | // TODO move to util, etc. |
| 19 | +/** | ||
| 20 | + * Kryo Serializer for {@link DefaultPort}. | ||
| 21 | + */ | ||
| 19 | public final class DefaultPortSerializer extends | 22 | public final class DefaultPortSerializer extends |
| 20 | Serializer<DefaultPort> { | 23 | Serializer<DefaultPort> { |
| 21 | 24 | ||
| ... | @@ -23,6 +26,9 @@ public final class DefaultPortSerializer extends | ... | @@ -23,6 +26,9 @@ public final class DefaultPortSerializer extends |
| 23 | = new CollectionSerializer(IpPrefix.class, | 26 | = new CollectionSerializer(IpPrefix.class, |
| 24 | new IpPrefixSerializer(), false); | 27 | new IpPrefixSerializer(), false); |
| 25 | 28 | ||
| 29 | + /** | ||
| 30 | + * Default constructor. | ||
| 31 | + */ | ||
| 26 | public DefaultPortSerializer() { | 32 | public DefaultPortSerializer() { |
| 27 | // non-null, immutable | 33 | // non-null, immutable |
| 28 | super(false, true); | 34 | super(false, true); | ... | ... |
| ... | @@ -44,6 +44,10 @@ import org.onlab.onos.store.StoreService; | ... | @@ -44,6 +44,10 @@ import org.onlab.onos.store.StoreService; |
| 44 | import org.onlab.util.KryoPool; | 44 | import org.onlab.util.KryoPool; |
| 45 | import org.slf4j.Logger; | 45 | import org.slf4j.Logger; |
| 46 | 46 | ||
| 47 | +import com.esotericsoftware.kryo.Kryo; | ||
| 48 | +import com.esotericsoftware.kryo.Serializer; | ||
| 49 | +import com.esotericsoftware.kryo.io.Input; | ||
| 50 | +import com.esotericsoftware.kryo.io.Output; | ||
| 47 | import com.google.common.base.Optional; | 51 | import com.google.common.base.Optional; |
| 48 | import com.google.common.cache.CacheBuilder; | 52 | import com.google.common.cache.CacheBuilder; |
| 49 | import com.google.common.cache.CacheLoader; | 53 | import com.google.common.cache.CacheLoader; |
| ... | @@ -68,103 +72,26 @@ import de.javakaffee.kryoserializers.URISerializer; | ... | @@ -68,103 +72,26 @@ import de.javakaffee.kryoserializers.URISerializer; |
| 68 | @Service | 72 | @Service |
| 69 | public class DistributedDeviceStore implements DeviceStore { | 73 | public class DistributedDeviceStore implements DeviceStore { |
| 70 | 74 | ||
| 71 | - /** | ||
| 72 | - * An IMap EntryListener, which reflects each remote event to cache. | ||
| 73 | - * | ||
| 74 | - * @param <K> IMap key type after deserialization | ||
| 75 | - * @param <V> IMap value type after deserialization | ||
| 76 | - */ | ||
| 77 | - public static final class RemoteEventHandler<K, V> extends | ||
| 78 | - EntryAdapter<byte[], byte[]> { | ||
| 79 | - | ||
| 80 | - private LoadingCache<K, Optional<V>> cache; | ||
| 81 | - | ||
| 82 | - /** | ||
| 83 | - * Constructor. | ||
| 84 | - * | ||
| 85 | - * @param cache cache to update | ||
| 86 | - */ | ||
| 87 | - public RemoteEventHandler( | ||
| 88 | - LoadingCache<K, Optional<V>> cache) { | ||
| 89 | - this.cache = checkNotNull(cache); | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | - @Override | ||
| 93 | - public void mapCleared(MapEvent event) { | ||
| 94 | - cache.invalidateAll(); | ||
| 95 | - } | ||
| 96 | - | ||
| 97 | - @Override | ||
| 98 | - public void entryUpdated(EntryEvent<byte[], byte[]> event) { | ||
| 99 | - cache.put(POOL.<K>deserialize(event.getKey()), | ||
| 100 | - Optional.of(POOL.<V>deserialize( | ||
| 101 | - event.getValue()))); | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - @Override | ||
| 105 | - public void entryRemoved(EntryEvent<byte[], byte[]> event) { | ||
| 106 | - cache.invalidate(POOL.<DeviceId>deserialize(event.getKey())); | ||
| 107 | - } | ||
| 108 | - | ||
| 109 | - @Override | ||
| 110 | - public void entryAdded(EntryEvent<byte[], byte[]> event) { | ||
| 111 | - entryUpdated(event); | ||
| 112 | - } | ||
| 113 | - } | ||
| 114 | - | ||
| 115 | - /** | ||
| 116 | - * CacheLoader to wrap Map value with Optional, | ||
| 117 | - * to handle negative hit on underlying IMap. | ||
| 118 | - * | ||
| 119 | - * @param <K> IMap key type after deserialization | ||
| 120 | - * @param <V> IMap value type after deserialization | ||
| 121 | - */ | ||
| 122 | - public static final class OptionalCacheLoader<K, V> extends | ||
| 123 | - CacheLoader<K, Optional<V>> { | ||
| 124 | - | ||
| 125 | - private IMap<byte[], byte[]> rawMap; | ||
| 126 | - | ||
| 127 | - /** | ||
| 128 | - * Constructor. | ||
| 129 | - * | ||
| 130 | - * @param rawMap underlying IMap | ||
| 131 | - */ | ||
| 132 | - public OptionalCacheLoader(IMap<byte[], byte[]> rawMap) { | ||
| 133 | - this.rawMap = checkNotNull(rawMap); | ||
| 134 | - } | ||
| 135 | - | ||
| 136 | - @Override | ||
| 137 | - public Optional<V> load(K key) throws Exception { | ||
| 138 | - byte[] keyBytes = serialize(key); | ||
| 139 | - byte[] valBytes = rawMap.get(keyBytes); | ||
| 140 | - if (valBytes == null) { | ||
| 141 | - return Optional.absent(); | ||
| 142 | - } | ||
| 143 | - V dev = deserialize(valBytes); | ||
| 144 | - return Optional.of(dev); | ||
| 145 | - } | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | private final Logger log = getLogger(getClass()); | 75 | private final Logger log = getLogger(getClass()); |
| 149 | 76 | ||
| 150 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | 77 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; |
| 151 | 78 | ||
| 152 | // FIXME Slice out types used in common to separate pool/namespace. | 79 | // FIXME Slice out types used in common to separate pool/namespace. |
| 153 | private static final KryoPool POOL = KryoPool.newBuilder() | 80 | private static final KryoPool POOL = KryoPool.newBuilder() |
| 154 | - .register(URI.class, new URISerializer()) | ||
| 155 | .register( | 81 | .register( |
| 156 | ArrayList.class, | 82 | ArrayList.class, |
| 83 | + HashMap.class, | ||
| 157 | 84 | ||
| 158 | - ProviderId.class, | ||
| 159 | Device.Type.class, | 85 | Device.Type.class, |
| 160 | 86 | ||
| 161 | - DeviceId.class, | ||
| 162 | DefaultDevice.class, | 87 | DefaultDevice.class, |
| 163 | MastershipRole.class, | 88 | MastershipRole.class, |
| 164 | - HashMap.class, | ||
| 165 | Port.class, | 89 | Port.class, |
| 166 | Element.class | 90 | Element.class |
| 167 | ) | 91 | ) |
| 92 | + .register(URI.class, new URISerializer()) | ||
| 93 | + .register(ProviderId.class, new ProviderIdSerializer()) | ||
| 94 | + .register(DeviceId.class, new DeviceIdSerializer()) | ||
| 168 | .register(PortNumber.class, new PortNumberSerializer()) | 95 | .register(PortNumber.class, new PortNumberSerializer()) |
| 169 | .register(DefaultPort.class, new DefaultPortSerializer()) | 96 | .register(DefaultPort.class, new DefaultPortSerializer()) |
| 170 | .build() | 97 | .build() |
| ... | @@ -190,7 +117,7 @@ public class DistributedDeviceStore implements DeviceStore { | ... | @@ -190,7 +117,7 @@ public class DistributedDeviceStore implements DeviceStore { |
| 190 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 117 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 191 | protected StoreService storeService; | 118 | protected StoreService storeService; |
| 192 | 119 | ||
| 193 | - /*protected*/public HazelcastInstance theInstance; | 120 | + protected HazelcastInstance theInstance; |
| 194 | 121 | ||
| 195 | 122 | ||
| 196 | @Activate | 123 | @Activate |
| ... | @@ -517,4 +444,94 @@ public class DistributedDeviceStore implements DeviceStore { | ... | @@ -517,4 +444,94 @@ public class DistributedDeviceStore implements DeviceStore { |
| 517 | return POOL.deserialize(bytes); | 444 | return POOL.deserialize(bytes); |
| 518 | } | 445 | } |
| 519 | 446 | ||
| 447 | + public static final class DeviceIdSerializer extends Serializer<DeviceId> { | ||
| 448 | + | ||
| 449 | + @Override | ||
| 450 | + public void write(Kryo kryo, Output output, DeviceId object) { | ||
| 451 | + kryo.writeObject(output, object.uri()); | ||
| 452 | + } | ||
| 453 | + | ||
| 454 | + @Override | ||
| 455 | + public DeviceId read(Kryo kryo, Input input, Class<DeviceId> type) { | ||
| 456 | + final URI uri = kryo.readObject(input, URI.class); | ||
| 457 | + return DeviceId.deviceId(uri); | ||
| 458 | + } | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + /** | ||
| 462 | + * An IMap EntryListener, which reflects each remote event to cache. | ||
| 463 | + * | ||
| 464 | + * @param <K> IMap key type after deserialization | ||
| 465 | + * @param <V> IMap value type after deserialization | ||
| 466 | + */ | ||
| 467 | + public static final class RemoteEventHandler<K, V> extends | ||
| 468 | + EntryAdapter<byte[], byte[]> { | ||
| 469 | + | ||
| 470 | + private LoadingCache<K, Optional<V>> cache; | ||
| 471 | + | ||
| 472 | + /** | ||
| 473 | + * Constructor. | ||
| 474 | + * | ||
| 475 | + * @param cache cache to update | ||
| 476 | + */ | ||
| 477 | + public RemoteEventHandler( | ||
| 478 | + LoadingCache<K, Optional<V>> cache) { | ||
| 479 | + this.cache = checkNotNull(cache); | ||
| 480 | + } | ||
| 481 | + | ||
| 482 | + @Override | ||
| 483 | + public void mapCleared(MapEvent event) { | ||
| 484 | + cache.invalidateAll(); | ||
| 485 | + } | ||
| 486 | + | ||
| 487 | + @Override | ||
| 488 | + public void entryUpdated(EntryEvent<byte[], byte[]> event) { | ||
| 489 | + cache.put(POOL.<K>deserialize(event.getKey()), | ||
| 490 | + Optional.of(POOL.<V>deserialize( | ||
| 491 | + event.getValue()))); | ||
| 492 | + } | ||
| 493 | + | ||
| 494 | + @Override | ||
| 495 | + public void entryRemoved(EntryEvent<byte[], byte[]> event) { | ||
| 496 | + cache.invalidate(POOL.<DeviceId>deserialize(event.getKey())); | ||
| 497 | + } | ||
| 498 | + | ||
| 499 | + @Override | ||
| 500 | + public void entryAdded(EntryEvent<byte[], byte[]> event) { | ||
| 501 | + entryUpdated(event); | ||
| 502 | + } | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + /** | ||
| 506 | + * CacheLoader to wrap Map value with Optional, | ||
| 507 | + * to handle negative hit on underlying IMap. | ||
| 508 | + * | ||
| 509 | + * @param <K> IMap key type after deserialization | ||
| 510 | + * @param <V> IMap value type after deserialization | ||
| 511 | + */ | ||
| 512 | + public static final class OptionalCacheLoader<K, V> extends | ||
| 513 | + CacheLoader<K, Optional<V>> { | ||
| 514 | + | ||
| 515 | + private IMap<byte[], byte[]> rawMap; | ||
| 516 | + | ||
| 517 | + /** | ||
| 518 | + * Constructor. | ||
| 519 | + * | ||
| 520 | + * @param rawMap underlying IMap | ||
| 521 | + */ | ||
| 522 | + public OptionalCacheLoader(IMap<byte[], byte[]> rawMap) { | ||
| 523 | + this.rawMap = checkNotNull(rawMap); | ||
| 524 | + } | ||
| 525 | + | ||
| 526 | + @Override | ||
| 527 | + public Optional<V> load(K key) throws Exception { | ||
| 528 | + byte[] keyBytes = serialize(key); | ||
| 529 | + byte[] valBytes = rawMap.get(keyBytes); | ||
| 530 | + if (valBytes == null) { | ||
| 531 | + return Optional.absent(); | ||
| 532 | + } | ||
| 533 | + V dev = deserialize(valBytes); | ||
| 534 | + return Optional.of(dev); | ||
| 535 | + } | ||
| 536 | + } | ||
| 520 | } | 537 | } | ... | ... |
| ... | @@ -8,8 +8,14 @@ import com.esotericsoftware.kryo.io.Input; | ... | @@ -8,8 +8,14 @@ import com.esotericsoftware.kryo.io.Input; |
| 8 | import com.esotericsoftware.kryo.io.Output; | 8 | import com.esotericsoftware.kryo.io.Output; |
| 9 | 9 | ||
| 10 | // TODO move to util, etc. | 10 | // TODO move to util, etc. |
| 11 | +/** | ||
| 12 | + * Kryo Serializer for {@link IpPrefix}. | ||
| 13 | + */ | ||
| 11 | public final class IpPrefixSerializer extends Serializer<IpPrefix> { | 14 | public final class IpPrefixSerializer extends Serializer<IpPrefix> { |
| 12 | 15 | ||
| 16 | + /** | ||
| 17 | + * Default constructor. | ||
| 18 | + */ | ||
| 13 | public IpPrefixSerializer() { | 19 | public IpPrefixSerializer() { |
| 14 | // non-null, immutable | 20 | // non-null, immutable |
| 15 | super(false, true); | 21 | super(false, true); | ... | ... |
| ... | @@ -8,9 +8,15 @@ import com.esotericsoftware.kryo.io.Input; | ... | @@ -8,9 +8,15 @@ import com.esotericsoftware.kryo.io.Input; |
| 8 | import com.esotericsoftware.kryo.io.Output; | 8 | import com.esotericsoftware.kryo.io.Output; |
| 9 | 9 | ||
| 10 | // TODO move to util, etc. | 10 | // TODO move to util, etc. |
| 11 | +/** | ||
| 12 | + * Serializer for {@link PortNumber}. | ||
| 13 | + */ | ||
| 11 | public final class PortNumberSerializer extends | 14 | public final class PortNumberSerializer extends |
| 12 | Serializer<PortNumber> { | 15 | Serializer<PortNumber> { |
| 13 | 16 | ||
| 17 | + /** | ||
| 18 | + * Default constructor. | ||
| 19 | + */ | ||
| 14 | public PortNumberSerializer() { | 20 | public PortNumberSerializer() { |
| 15 | // non-null, immutable | 21 | // non-null, immutable |
| 16 | super(false, true); | 22 | super(false, true); | ... | ... |
| 1 | +package org.onlab.onos.store.device.impl; | ||
| 2 | + | ||
| 3 | +import org.onlab.onos.net.provider.ProviderId; | ||
| 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 | +//TODO move to util, etc. | ||
| 11 | +/** | ||
| 12 | + * Serializer for {@link ProviderId}. | ||
| 13 | + */ | ||
| 14 | +public class ProviderIdSerializer extends Serializer<ProviderId> { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * Default constructor. | ||
| 18 | + */ | ||
| 19 | + public ProviderIdSerializer() { | ||
| 20 | + // non-null, immutable | ||
| 21 | + super(false, true); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + @Override | ||
| 25 | + public void write(Kryo kryo, Output output, ProviderId object) { | ||
| 26 | + output.writeString(object.scheme()); | ||
| 27 | + output.writeString(object.id()); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + @Override | ||
| 31 | + public ProviderId read(Kryo kryo, Input input, Class<ProviderId> type) { | ||
| 32 | + String scheme = input.readString(); | ||
| 33 | + String id = input.readString(); | ||
| 34 | + return new ProviderId(scheme, id); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | +} |
-
Please register or login to post a comment