Kryo related changes.
Change-Id: I5b4fab63d6ece084b65aa712971a22d953d0caf0
Showing
10 changed files
with
383 additions
and
0 deletions
... | @@ -7,6 +7,9 @@ import java.net.URI; | ... | @@ -7,6 +7,9 @@ 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 | + | ||
10 | // Public construction is prohibited | 13 | // Public construction is prohibited |
11 | private DeviceId(URI uri) { | 14 | private DeviceId(URI uri) { |
12 | super(uri); | 15 | super(uri); | ... | ... |
... | @@ -10,6 +10,11 @@ public abstract class ElementId { | ... | @@ -10,6 +10,11 @@ public abstract class ElementId { |
10 | 10 | ||
11 | private final URI uri; | 11 | private final URI uri; |
12 | 12 | ||
13 | + // Default constructor for serialization | ||
14 | + protected ElementId() { | ||
15 | + this.uri = null; | ||
16 | + } | ||
17 | + | ||
13 | /** | 18 | /** |
14 | * Creates an element identifier using the supplied URI. | 19 | * Creates an element identifier using the supplied URI. |
15 | * | 20 | * | ... | ... |
... | @@ -12,6 +12,12 @@ public class ProviderId { | ... | @@ -12,6 +12,12 @@ 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 | + | ||
15 | /** | 21 | /** |
16 | * Creates a new provider identifier from the specified string. | 22 | * Creates a new provider identifier from the specified string. |
17 | * The providers are expected to follow the reverse DNS convention, e.g. | 23 | * The providers are expected to follow the reverse DNS convention, e.g. | ... | ... |
... | @@ -25,6 +25,14 @@ | ... | @@ -25,6 +25,14 @@ |
25 | <groupId>org.apache.felix</groupId> | 25 | <groupId>org.apache.felix</groupId> |
26 | <artifactId>org.apache.felix.scr.annotations</artifactId> | 26 | <artifactId>org.apache.felix.scr.annotations</artifactId> |
27 | </dependency> | 27 | </dependency> |
28 | + <dependency> | ||
29 | + <groupId>com.hazelcast</groupId> | ||
30 | + <artifactId>hazelcast</artifactId> | ||
31 | + </dependency> | ||
32 | + <dependency> | ||
33 | + <groupId>de.javakaffee</groupId> | ||
34 | + <artifactId>kryo-serializers</artifactId> | ||
35 | + </dependency> | ||
28 | </dependencies> | 36 | </dependencies> |
29 | 37 | ||
30 | <build> | 38 | <build> | ... | ... |
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.Collection; | ||
5 | + | ||
6 | +import org.onlab.onos.net.DefaultPort; | ||
7 | +import org.onlab.onos.net.Element; | ||
8 | +import org.onlab.onos.net.PortNumber; | ||
9 | +import org.onlab.packet.IpPrefix; | ||
10 | + | ||
11 | +import com.esotericsoftware.kryo.Kryo; | ||
12 | +import com.esotericsoftware.kryo.Serializer; | ||
13 | +import com.esotericsoftware.kryo.io.Input; | ||
14 | +import com.esotericsoftware.kryo.io.Output; | ||
15 | +import com.esotericsoftware.kryo.serializers.CollectionSerializer; | ||
16 | +import com.google.common.collect.ImmutableSet; | ||
17 | + | ||
18 | +// TODO move to util, etc. | ||
19 | +public final class DefaultPortSerializer extends | ||
20 | + Serializer<DefaultPort> { | ||
21 | + | ||
22 | + private final CollectionSerializer ipAddrSerializer | ||
23 | + = new CollectionSerializer(IpPrefix.class, | ||
24 | + new IpPrefixSerializer(), false); | ||
25 | + | ||
26 | + public DefaultPortSerializer() { | ||
27 | + // non-null, immutable | ||
28 | + super(false, true); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public void write(Kryo kryo, Output output, DefaultPort object) { | ||
33 | + kryo.writeClassAndObject(output, object.element()); | ||
34 | + kryo.writeObject(output, object.number()); | ||
35 | + output.writeBoolean(object.isEnabled()); | ||
36 | + kryo.writeObject(output, object.ipAddresses(), | ||
37 | + ipAddrSerializer); | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
41 | + public DefaultPort read(Kryo kryo, Input input, | ||
42 | + Class<DefaultPort> type) { | ||
43 | + Element element = (Element) kryo.readClassAndObject(input); | ||
44 | + PortNumber number = kryo.readObject(input, PortNumber.class); | ||
45 | + boolean isEnabled = input.readBoolean(); | ||
46 | + @SuppressWarnings("unchecked") | ||
47 | + Collection<IpPrefix> ipAddresses = kryo.readObject( | ||
48 | + input, ArrayList.class, ipAddrSerializer); | ||
49 | + | ||
50 | + return new DefaultPort(element, number, isEnabled, | ||
51 | + ImmutableSet.copyOf(ipAddresses)); | ||
52 | + } | ||
53 | +} |
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import org.onlab.packet.IpPrefix; | ||
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 | +public final class IpPrefixSerializer extends Serializer<IpPrefix> { | ||
12 | + | ||
13 | + public IpPrefixSerializer() { | ||
14 | + // non-null, immutable | ||
15 | + super(false, true); | ||
16 | + } | ||
17 | + | ||
18 | + @Override | ||
19 | + public void write(Kryo kryo, Output output, | ||
20 | + IpPrefix object) { | ||
21 | + byte[] octs = object.toOctets(); | ||
22 | + output.writeInt(octs.length); | ||
23 | + output.writeBytes(octs); | ||
24 | + output.writeInt(object.prefixLength()); | ||
25 | + } | ||
26 | + | ||
27 | + @Override | ||
28 | + public IpPrefix read(Kryo kryo, Input input, | ||
29 | + Class<IpPrefix> type) { | ||
30 | + int octLen = input.readInt(); | ||
31 | + byte[] octs = new byte[octLen]; | ||
32 | + input.read(octs); | ||
33 | + int prefLen = input.readInt(); | ||
34 | + return IpPrefix.valueOf(octs, prefLen); | ||
35 | + } | ||
36 | +} |
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.PortNumber; | ||
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 | +public final class PortNumberSerializer extends | ||
12 | + Serializer<PortNumber> { | ||
13 | + | ||
14 | + public PortNumberSerializer() { | ||
15 | + // non-null, immutable | ||
16 | + super(false, true); | ||
17 | + } | ||
18 | + | ||
19 | + @Override | ||
20 | + public void write(Kryo kryo, Output output, PortNumber object) { | ||
21 | + output.writeLong(object.toLong()); | ||
22 | + } | ||
23 | + | ||
24 | + @Override | ||
25 | + public PortNumber read(Kryo kryo, Input input, | ||
26 | + Class<PortNumber> type) { | ||
27 | + return PortNumber.portNumber(input.readLong()); | ||
28 | + } | ||
29 | +} |
... | @@ -128,6 +128,28 @@ | ... | @@ -128,6 +128,28 @@ |
128 | <scope>provided</scope> | 128 | <scope>provided</scope> |
129 | </dependency> | 129 | </dependency> |
130 | 130 | ||
131 | + <dependency> | ||
132 | + <groupId>com.hazelcast</groupId> | ||
133 | + <artifactId>hazelcast</artifactId> | ||
134 | + <version>3.3</version> | ||
135 | + </dependency> | ||
136 | + <dependency> | ||
137 | + <groupId>com.esotericsoftware.kryo</groupId> | ||
138 | + <artifactId>kryo</artifactId> | ||
139 | + <version>2.24.0</version> | ||
140 | + </dependency> | ||
141 | + <dependency> | ||
142 | + <groupId>de.javakaffee</groupId> | ||
143 | + <artifactId>kryo-serializers</artifactId> | ||
144 | + <version>0.27</version> | ||
145 | + </dependency> | ||
146 | + | ||
147 | + <dependency> | ||
148 | + <groupId>org.apache.commons</groupId> | ||
149 | + <artifactId>commons-lang3</artifactId> | ||
150 | + <version>3.3.2</version> | ||
151 | + </dependency> | ||
152 | + | ||
131 | <!-- ONOS related --> | 153 | <!-- ONOS related --> |
132 | <dependency> | 154 | <dependency> |
133 | <groupId>org.onlab.onos</groupId> | 155 | <groupId>org.onlab.onos</groupId> | ... | ... |
... | @@ -30,6 +30,14 @@ | ... | @@ -30,6 +30,14 @@ |
30 | <groupId>commons-lang</groupId> | 30 | <groupId>commons-lang</groupId> |
31 | <artifactId>commons-lang</artifactId> | 31 | <artifactId>commons-lang</artifactId> |
32 | </dependency> | 32 | </dependency> |
33 | + <dependency> | ||
34 | + <groupId>com.esotericsoftware.kryo</groupId> | ||
35 | + <artifactId>kryo</artifactId> | ||
36 | + </dependency> | ||
37 | + <dependency> | ||
38 | + <groupId>org.apache.commons</groupId> | ||
39 | + <artifactId>commons-lang3</artifactId> | ||
40 | + </dependency> | ||
33 | </dependencies> | 41 | </dependencies> |
34 | 42 | ||
35 | </project> | 43 | </project> | ... | ... |
1 | +package org.onlab.util; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.List; | ||
5 | +import java.util.concurrent.ConcurrentLinkedQueue; | ||
6 | + | ||
7 | +import org.apache.commons.lang3.tuple.Pair; | ||
8 | + | ||
9 | +import com.esotericsoftware.kryo.Kryo; | ||
10 | +import com.esotericsoftware.kryo.Serializer; | ||
11 | +import com.esotericsoftware.kryo.io.Input; | ||
12 | +import com.esotericsoftware.kryo.io.Output; | ||
13 | +import com.google.common.collect.ImmutableList; | ||
14 | + | ||
15 | +// TODO Add tests for this class. | ||
16 | +/** | ||
17 | + * Pool of Kryo instances, with classes pre-registered. | ||
18 | + */ | ||
19 | +//@ThreadSafe | ||
20 | +public final class KryoPool { | ||
21 | + | ||
22 | + /** | ||
23 | + * Default buffer size used for serialization. | ||
24 | + * | ||
25 | + * @see #serialize(Object) | ||
26 | + */ | ||
27 | + public static final int DEFAULT_BUFFER_SIZE = 1 * 1000 * 1000; | ||
28 | + | ||
29 | + private final ConcurrentLinkedQueue<Kryo> pool = new ConcurrentLinkedQueue<>(); | ||
30 | + private final ImmutableList<Pair<Class<?>, Serializer<?>>> registeredTypes; | ||
31 | + private final boolean registrationRequired; | ||
32 | + | ||
33 | + /** | ||
34 | + * KryoPool builder. | ||
35 | + */ | ||
36 | + //@NotThreadSafe | ||
37 | + public static final class Builder { | ||
38 | + | ||
39 | + private final List<Pair<Class<?>, Serializer<?>>> types = new ArrayList<>(); | ||
40 | + | ||
41 | + /** | ||
42 | + * Builds a {@link KryoPool} instance. | ||
43 | + * | ||
44 | + * @return KryoPool | ||
45 | + */ | ||
46 | + public KryoPool build() { | ||
47 | + return new KryoPool(types); | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * Registers classes to be serialized using Kryo default serializer. | ||
52 | + * | ||
53 | + * @param expectedTypes list of classes | ||
54 | + * @return this | ||
55 | + */ | ||
56 | + public Builder register(final Class<?>... expectedTypes) { | ||
57 | + for (Class<?> clazz : expectedTypes) { | ||
58 | + types.add(Pair.<Class<?>, Serializer<?>>of(clazz, null)); | ||
59 | + } | ||
60 | + return this; | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Registers a class and it's serializer. | ||
65 | + * | ||
66 | + * @param clazz the class to register | ||
67 | + * @param serializer serializer to use for the class | ||
68 | + * @return this | ||
69 | + */ | ||
70 | + public Builder register(final Class<?> clazz, Serializer<?> serializer) { | ||
71 | + types.add(Pair.<Class<?>, Serializer<?>>of(clazz, serializer)); | ||
72 | + return this; | ||
73 | + } | ||
74 | + | ||
75 | + /** | ||
76 | + * Registers all the class registered to given KryoPool. | ||
77 | + * | ||
78 | + * @param pool KryoPool | ||
79 | + * @return this | ||
80 | + */ | ||
81 | + public Builder register(final KryoPool pool) { | ||
82 | + types.addAll(pool.registeredTypes); | ||
83 | + return this; | ||
84 | + } | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * Creates a new {@link KryoPool} builder. | ||
89 | + * | ||
90 | + * @return builder | ||
91 | + */ | ||
92 | + public static Builder newBuilder() { | ||
93 | + return new Builder(); | ||
94 | + } | ||
95 | + | ||
96 | + /** | ||
97 | + * Creates a Kryo instance pool. | ||
98 | + * | ||
99 | + * @param registerdTypes types to register | ||
100 | + */ | ||
101 | + private KryoPool(final List<Pair<Class<?>, Serializer<?>>> registerdTypes) { | ||
102 | + this.registeredTypes = ImmutableList.copyOf(registerdTypes); | ||
103 | + // always true for now | ||
104 | + this.registrationRequired = true; | ||
105 | + } | ||
106 | + | ||
107 | + /** | ||
108 | + * Populates the Kryo pool. | ||
109 | + * | ||
110 | + * @param instances to add to the pool | ||
111 | + * @return this | ||
112 | + */ | ||
113 | + public KryoPool populate(int instances) { | ||
114 | + List<Kryo> kryos = new ArrayList<>(instances); | ||
115 | + for (int i = 0; i < instances; ++i) { | ||
116 | + kryos.add(newKryoInstance()); | ||
117 | + } | ||
118 | + pool.addAll(kryos); | ||
119 | + return this; | ||
120 | + } | ||
121 | + | ||
122 | + /** | ||
123 | + * Gets a Kryo instance from the pool. | ||
124 | + * | ||
125 | + * @return Kryo instance | ||
126 | + */ | ||
127 | + public Kryo getKryo() { | ||
128 | + Kryo kryo = pool.poll(); | ||
129 | + if (kryo == null) { | ||
130 | + return newKryoInstance(); | ||
131 | + } | ||
132 | + return kryo; | ||
133 | + } | ||
134 | + | ||
135 | + /** | ||
136 | + * Returns a Kryo instance to the pool. | ||
137 | + * | ||
138 | + * @param kryo instance obtained from this pool. | ||
139 | + */ | ||
140 | + public void putKryo(Kryo kryo) { | ||
141 | + if (kryo != null) { | ||
142 | + pool.add(kryo); | ||
143 | + } | ||
144 | + } | ||
145 | + | ||
146 | + /** | ||
147 | + * Serializes given object to byte array using Kryo instance in pool. | ||
148 | + * <p> | ||
149 | + * Note: Serialized bytes must be smaller than {@link #DEFAULT_BUFFER_SIZE}. | ||
150 | + * | ||
151 | + * @param obj Object to serialize | ||
152 | + * @return serialized bytes | ||
153 | + */ | ||
154 | + public byte[] serialize(final Object obj) { | ||
155 | + return serialize(obj, DEFAULT_BUFFER_SIZE); | ||
156 | + } | ||
157 | + | ||
158 | + /** | ||
159 | + * Serializes given object to byte array using Kryo instance in pool. | ||
160 | + * | ||
161 | + * @param obj Object to serialize | ||
162 | + * @param bufferSize maximum size of serialized bytes | ||
163 | + * @return serialized bytes | ||
164 | + */ | ||
165 | + public byte[] serialize(final Object obj, final int bufferSize) { | ||
166 | + Output out = new Output(bufferSize); | ||
167 | + Kryo kryo = getKryo(); | ||
168 | + try { | ||
169 | + kryo.writeClassAndObject(out, obj); | ||
170 | + return out.toBytes(); | ||
171 | + } finally { | ||
172 | + putKryo(kryo); | ||
173 | + } | ||
174 | + } | ||
175 | + | ||
176 | + /** | ||
177 | + * Deserializes given byte array to Object using Kryo instance in pool. | ||
178 | + * | ||
179 | + * @param bytes serialized bytes | ||
180 | + * @param <T> deserialized Object type | ||
181 | + * @return deserialized Object | ||
182 | + */ | ||
183 | + public <T> T deserialize(final byte[] bytes) { | ||
184 | + Input in = new Input(bytes); | ||
185 | + Kryo kryo = getKryo(); | ||
186 | + try { | ||
187 | + @SuppressWarnings("unchecked") | ||
188 | + T obj = (T) kryo.readClassAndObject(in); | ||
189 | + return obj; | ||
190 | + } finally { | ||
191 | + putKryo(kryo); | ||
192 | + } | ||
193 | + } | ||
194 | + | ||
195 | + | ||
196 | + /** | ||
197 | + * Creates a Kryo instance with {@link #registeredTypes} pre-registered. | ||
198 | + * | ||
199 | + * @return Kryo instance | ||
200 | + */ | ||
201 | + private Kryo newKryoInstance() { | ||
202 | + Kryo kryo = new Kryo(); | ||
203 | + kryo.setRegistrationRequired(registrationRequired); | ||
204 | + for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) { | ||
205 | + if (registry.getRight() == null) { | ||
206 | + kryo.register(registry.getLeft()); | ||
207 | + } else { | ||
208 | + kryo.register(registry.getLeft(), registry.getRight()); | ||
209 | + } | ||
210 | + } | ||
211 | + return kryo; | ||
212 | + } | ||
213 | +} |
-
Please register or login to post a comment