Yuta HIGUCHI

Kryo related changes.

Change-Id: I5b4fab63d6ece084b65aa712971a22d953d0caf0
...@@ -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 +}