blob: 2aca86dccbbb602f25bbd993495eabba0a84e297 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070016package org.onlab.util;
17
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070018import com.esotericsoftware.kryo.Kryo;
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -070019import com.esotericsoftware.kryo.Registration;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070020import com.esotericsoftware.kryo.Serializer;
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -070021import com.esotericsoftware.kryo.io.ByteBufferInput;
22import com.esotericsoftware.kryo.io.ByteBufferOutput;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070023import com.esotericsoftware.kryo.io.Input;
Yuta HIGUCHI86f142f2016-07-09 17:44:09 -070024import com.esotericsoftware.kryo.io.Output;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080025import com.esotericsoftware.kryo.pool.KryoCallback;
Yuta HIGUCHI633cf882014-10-20 09:10:28 -070026import com.esotericsoftware.kryo.pool.KryoFactory;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080027import com.esotericsoftware.kryo.pool.KryoPool;
Jordan Haltermanc10a5012017-06-12 10:34:42 -070028import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080029import com.google.common.base.MoreObjects;
Jordan Haltermane1558e82017-06-13 14:38:20 -070030import com.google.common.base.Strings;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070031import com.google.common.collect.ImmutableList;
Jonathan Hartbe093f72016-03-25 11:14:29 -070032import org.apache.commons.lang3.tuple.Pair;
33import org.objenesis.strategy.StdInstantiatorStrategy;
34import org.slf4j.Logger;
35
Jordan Haltermanecfca4f2017-08-03 21:38:02 -070036import java.io.ByteArrayInputStream;
37import java.io.ByteArrayOutputStream;
Jonathan Hartbe093f72016-03-25 11:14:29 -070038import java.io.InputStream;
39import java.io.OutputStream;
40import java.nio.ByteBuffer;
41import java.util.ArrayList;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -070042import java.util.Arrays;
Jonathan Hartbe093f72016-03-25 11:14:29 -070043import java.util.List;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070044import java.util.Objects;
Jonathan Hartbe093f72016-03-25 11:14:29 -070045
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070046import static com.google.common.base.Preconditions.checkNotNull;
Jonathan Hartbe093f72016-03-25 11:14:29 -070047import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070048
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070049/**
50 * Pool of Kryo instances, with classes pre-registered.
51 */
52//@ThreadSafe
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080053public final class KryoNamespace implements KryoFactory, KryoPool {
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070054
55 /**
56 * Default buffer size used for serialization.
57 *
58 * @see #serialize(Object)
59 */
Yuta HIGUCHI38782052014-11-09 23:51:58 -080060 public static final int DEFAULT_BUFFER_SIZE = 4096;
Yuta HIGUCHId2a38822014-11-06 19:05:04 -080061 public static final int MAX_BUFFER_SIZE = 100 * 1000 * 1000;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070062
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080063 /**
64 * ID to use if this KryoNamespace does not define registration id.
65 */
66 public static final int FLOATING_ID = -1;
67
68 /**
69 * Smallest ID free to use for user defined registrations.
70 */
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -070071 public static final int INITIAL_ID = 16;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080072
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070073 private static final String NO_NAME = "(no name)";
74
HIGUCHI Yutab49b0072016-02-22 22:50:45 -080075 private static final Logger log = getLogger(KryoNamespace.class);
76
Yuta HIGUCHI91768e32014-11-22 05:06:35 -080077 private final KryoPool pool = new KryoPool.Builder(this)
78 .softReferences()
79 .build();
80
81 private final ImmutableList<RegistrationBlock> registeredBlocks;
82
Jordan Haltermane1558e82017-06-13 14:38:20 -070083 private final boolean compatible;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070084 private final boolean registrationRequired;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -070085 private final String friendlyName;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070086
87 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -070088 * KryoNamespace builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -070089 */
90 //@NotThreadSafe
91 public static final class Builder {
Jordan Haltermane1558e82017-06-13 14:38:20 -070092 private static final String ISSU_PROPERTY_NAME = "onos.cluster.issu.enabled";
93 private static final boolean DEFAULT_ISSU_ENABLED = false;
94
95 private static final boolean DEFAULT_COMPATIBLE_SERIALIZATION;
96
97 static {
98 String issuEnabled = System.getProperty(ISSU_PROPERTY_NAME);
99 DEFAULT_COMPATIBLE_SERIALIZATION = Strings.isNullOrEmpty(issuEnabled)
100 ? DEFAULT_ISSU_ENABLED : Boolean.parseBoolean(issuEnabled);
101 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700102
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800103 private int blockHeadId = INITIAL_ID;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700104 private List<Pair<Class<?>[], Serializer<?>>> types = new ArrayList<>();
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800105 private List<RegistrationBlock> blocks = new ArrayList<>();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700106 private boolean registrationRequired = true;
Jordan Haltermane1558e82017-06-13 14:38:20 -0700107 private boolean compatible = DEFAULT_COMPATIBLE_SERIALIZATION;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700108
109 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700110 * Builds a {@link KryoNamespace} instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700111 *
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700112 * @return KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700113 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700114 public KryoNamespace build() {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700115 return build(NO_NAME);
116 }
117
118 /**
119 * Builds a {@link KryoNamespace} instance.
120 *
121 * @param friendlyName friendly name for the namespace
122 * @return KryoNamespace
123 */
124 public KryoNamespace build(String friendlyName) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800125 if (!types.isEmpty()) {
126 blocks.add(new RegistrationBlock(this.blockHeadId, types));
127 }
Jordan Haltermane1558e82017-06-13 14:38:20 -0700128 return new KryoNamespace(blocks, registrationRequired, compatible, friendlyName).populate(1);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800129 }
130
131 /**
132 * Sets the next Kryo registration Id for following register entries.
133 *
134 * @param id Kryo registration Id
135 * @return this
136 *
137 * @see Kryo#register(Class, Serializer, int)
138 */
139 public Builder nextId(final int id) {
140 if (!types.isEmpty()) {
HIGUCHI Yutab49b0072016-02-22 22:50:45 -0800141 if (id != FLOATING_ID && id < blockHeadId + types.size()) {
142
HIGUCHI Yuta163efb52016-05-18 19:24:19 -0700143 if (log.isWarnEnabled()) {
144 log.warn("requested nextId {} could potentially overlap " +
145 "with existing registrations {}+{} ",
146 id, blockHeadId, types.size(), new RuntimeException());
147 }
HIGUCHI Yutab49b0072016-02-22 22:50:45 -0800148 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800149 blocks.add(new RegistrationBlock(this.blockHeadId, types));
150 types = new ArrayList<>();
151 }
152 this.blockHeadId = id;
153 return this;
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700154 }
155
156 /**
157 * Registers classes to be serialized using Kryo default serializer.
158 *
159 * @param expectedTypes list of classes
160 * @return this
161 */
162 public Builder register(final Class<?>... expectedTypes) {
163 for (Class<?> clazz : expectedTypes) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700164 types.add(Pair.of(new Class<?>[]{clazz}, null));
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700165 }
166 return this;
167 }
168
169 /**
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700170 * Registers serializer for the given set of classes.
171 * <p>
172 * When multiple classes are registered with an explicitly provided serializer, the namespace guarantees
173 * all instances will be serialized with the same type ID.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700174 *
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800175 * @param classes list of classes to register
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700176 * @param serializer serializer to use for the class
177 * @return this
178 */
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800179 public Builder register(Serializer<?> serializer, final Class<?>... classes) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700180 types.add(Pair.of(classes, checkNotNull(serializer)));
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800181 return this;
182 }
183
184 private Builder register(RegistrationBlock block) {
185 if (block.begin() != FLOATING_ID) {
186 // flush pending types
187 nextId(block.begin());
188 blocks.add(block);
189 nextId(block.begin() + block.types().size());
190 } else {
191 // flush pending types
192 final int addedBlockBegin = blockHeadId + types.size();
193 nextId(addedBlockBegin);
194 blocks.add(new RegistrationBlock(addedBlockBegin, block.types()));
195 nextId(addedBlockBegin + block.types().size());
196 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700197 return this;
198 }
199
200 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700201 * Registers all the class registered to given KryoNamespace.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700202 *
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800203 * @param ns KryoNamespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700204 * @return this
205 */
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800206 public Builder register(final KryoNamespace ns) {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700207
208 if (blocks.containsAll(ns.registeredBlocks)) {
209 // Everything was already registered.
210 log.debug("Ignoring {}, already registered.", ns);
211 return this;
212 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800213 for (RegistrationBlock block : ns.registeredBlocks) {
214 this.register(block);
215 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700216 return this;
217 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700218
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800219 /**
Jordan Haltermane1558e82017-06-13 14:38:20 -0700220 * Sets whether backwards/forwards compatible versioned serialization is enabled.
221 * <p>
222 * When compatible serialization is enabled, the {@link CompatibleFieldSerializer} will be set as the
223 * default serializer for types that do not otherwise explicitly specify a serializer.
224 *
225 * @param compatible whether versioned serialization is enabled
226 * @return this
227 */
228 public Builder setCompatible(boolean compatible) {
229 this.compatible = compatible;
230 return this;
231 }
232
233 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800234 * Sets the registrationRequired flag.
235 *
236 * @param registrationRequired Kryo's registrationRequired flag
237 * @return this
238 *
239 * @see Kryo#setRegistrationRequired(boolean)
240 */
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700241 public Builder setRegistrationRequired(boolean registrationRequired) {
242 this.registrationRequired = registrationRequired;
243 return this;
244 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700245 }
246
247 /**
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700248 * Creates a new {@link KryoNamespace} builder.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700249 *
250 * @return builder
251 */
252 public static Builder newBuilder() {
253 return new Builder();
254 }
255
256 /**
257 * Creates a Kryo instance pool.
258 *
Jonathan Hart4f60f982014-10-27 08:11:17 -0700259 * @param registeredTypes types to register
Jordan Haltermane1558e82017-06-13 14:38:20 -0700260 * @param registrationRequired whether registration is required
261 * @param compatible whether compatible serialization is enabled
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700262 * @param friendlyName friendly name for the namespace
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700263 */
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700264 private KryoNamespace(final List<RegistrationBlock> registeredTypes,
265 boolean registrationRequired,
Jordan Haltermane1558e82017-06-13 14:38:20 -0700266 boolean compatible,
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700267 String friendlyName) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800268 this.registeredBlocks = ImmutableList.copyOf(registeredTypes);
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700269 this.registrationRequired = registrationRequired;
Jordan Haltermane1558e82017-06-13 14:38:20 -0700270 this.compatible = compatible;
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700271 this.friendlyName = checkNotNull(friendlyName);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700272 }
273
274 /**
275 * Populates the Kryo pool.
276 *
277 * @param instances to add to the pool
278 * @return this
279 */
Yuta HIGUCHI8d143d22014-10-19 23:15:09 -0700280 public KryoNamespace populate(int instances) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800281
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700282 for (int i = 0; i < instances; ++i) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800283 release(create());
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700284 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700285 return this;
286 }
287
288 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700289 * Serializes given object to byte array using Kryo instance in pool.
290 * <p>
Yuta HIGUCHI38782052014-11-09 23:51:58 -0800291 * Note: Serialized bytes must be smaller than {@link #MAX_BUFFER_SIZE}.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700292 *
293 * @param obj Object to serialize
294 * @return serialized bytes
295 */
296 public byte[] serialize(final Object obj) {
297 return serialize(obj, DEFAULT_BUFFER_SIZE);
298 }
299
300 /**
301 * Serializes given object to byte array using Kryo instance in pool.
302 *
303 * @param obj Object to serialize
304 * @param bufferSize maximum size of serialized bytes
305 * @return serialized bytes
306 */
307 public byte[] serialize(final Object obj, final int bufferSize) {
Jordan Haltermanecfca4f2017-08-03 21:38:02 -0700308 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bufferSize);
309 Output out = new Output(outputStream);
Yuta HIGUCHI86f142f2016-07-09 17:44:09 -0700310 return pool.run(kryo -> {
311 kryo.writeClassAndObject(out, obj);
312 out.flush();
Jordan Haltermanecfca4f2017-08-03 21:38:02 -0700313 return outputStream.toByteArray();
Yuta HIGUCHI86f142f2016-07-09 17:44:09 -0700314 });
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700315 }
316
317 /**
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700318 * Serializes given object to byte buffer using Kryo instance in pool.
319 *
320 * @param obj Object to serialize
321 * @param buffer to write to
322 */
323 public void serialize(final Object obj, final ByteBuffer buffer) {
324 ByteBufferOutput out = new ByteBufferOutput(buffer);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800325 Kryo kryo = borrow();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700326 try {
327 kryo.writeClassAndObject(out, obj);
Yuta HIGUCHIcac919c2014-10-20 22:17:20 -0700328 out.flush();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700329 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800330 release(kryo);
331 }
332 }
333
334 /**
335 * Serializes given object to OutputStream using Kryo instance in pool.
336 *
337 * @param obj Object to serialize
338 * @param stream to write to
339 */
340 public void serialize(final Object obj, final OutputStream stream) {
341 serialize(obj, stream, DEFAULT_BUFFER_SIZE);
342 }
343
344 /**
345 * Serializes given object to OutputStream using Kryo instance in pool.
346 *
347 * @param obj Object to serialize
348 * @param stream to write to
349 * @param bufferSize size of the buffer in front of the stream
350 */
351 public void serialize(final Object obj, final OutputStream stream, final int bufferSize) {
352 ByteBufferOutput out = new ByteBufferOutput(stream, bufferSize);
353 Kryo kryo = borrow();
354 try {
355 kryo.writeClassAndObject(out, obj);
356 out.flush();
357 } finally {
358 release(kryo);
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700359 }
360 }
361
362 /**
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700363 * Deserializes given byte array to Object using Kryo instance in pool.
364 *
365 * @param bytes serialized bytes
366 * @param <T> deserialized Object type
367 * @return deserialized Object
368 */
369 public <T> T deserialize(final byte[] bytes) {
Jordan Haltermanecfca4f2017-08-03 21:38:02 -0700370 Input in = new Input(new ByteArrayInputStream(bytes));
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800371 Kryo kryo = borrow();
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700372 try {
373 @SuppressWarnings("unchecked")
374 T obj = (T) kryo.readClassAndObject(in);
375 return obj;
376 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800377 release(kryo);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700378 }
379 }
380
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700381 /**
382 * Deserializes given byte buffer to Object using Kryo instance in pool.
383 *
384 * @param buffer input with serialized bytes
385 * @param <T> deserialized Object type
386 * @return deserialized Object
387 */
388 public <T> T deserialize(final ByteBuffer buffer) {
389 ByteBufferInput in = new ByteBufferInput(buffer);
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800390 Kryo kryo = borrow();
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700391 try {
392 @SuppressWarnings("unchecked")
393 T obj = (T) kryo.readClassAndObject(in);
394 return obj;
395 } finally {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800396 release(kryo);
Yuta HIGUCHIf4b107e2014-09-29 17:27:26 -0700397 }
398 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700399
400 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800401 * Deserializes given InputStream to an Object using Kryo instance in pool.
402 *
403 * @param stream input stream
404 * @param <T> deserialized Object type
405 * @return deserialized Object
406 */
407 public <T> T deserialize(final InputStream stream) {
408 return deserialize(stream, DEFAULT_BUFFER_SIZE);
409 }
410
411 /**
412 * Deserializes given InputStream to an Object using Kryo instance in pool.
413 *
414 * @param stream input stream
415 * @param <T> deserialized Object type
416 * @return deserialized Object
417 * @param bufferSize size of the buffer in front of the stream
418 */
419 public <T> T deserialize(final InputStream stream, final int bufferSize) {
420 ByteBufferInput in = new ByteBufferInput(stream, bufferSize);
421 Kryo kryo = borrow();
422 try {
423 @SuppressWarnings("unchecked")
424 T obj = (T) kryo.readClassAndObject(in);
425 return obj;
426 } finally {
427 release(kryo);
428 }
429 }
430
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700431 private String friendlyName() {
432 return friendlyName;
433 }
434
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800435 /**
Jonathan Hart679d24d2016-05-13 13:29:53 -0700436 * Gets the number of classes registered in this Kryo namespace.
437 *
438 * @return size of namespace
439 */
440 public int size() {
441 return (int) registeredBlocks.stream()
442 .flatMap(block -> block.types().stream())
443 .count();
444 }
445
446 /**
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800447 * Creates a Kryo instance.
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700448 *
449 * @return Kryo instance
450 */
Yuta HIGUCHI633cf882014-10-20 09:10:28 -0700451 @Override
452 public Kryo create() {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700453 log.trace("Creating Kryo instance for {}", this);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700454 Kryo kryo = new Kryo();
455 kryo.setRegistrationRequired(registrationRequired);
Jordan Haltermane1558e82017-06-13 14:38:20 -0700456
457 // If compatible serialization is enabled, override the default serializer.
458 if (compatible) {
459 kryo.setDefaultSerializer(CompatibleFieldSerializer::new);
460 }
Jonathan Hartbe093f72016-03-25 11:14:29 -0700461
462 // TODO rethink whether we want to use StdInstantiatorStrategy
463 kryo.setInstantiatorStrategy(
464 new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
465
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800466 for (RegistrationBlock block : registeredBlocks) {
467 int id = block.begin();
468 if (id == FLOATING_ID) {
469 id = kryo.getNextRegistrationId();
470 }
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700471 for (Pair<Class<?>[], Serializer<?>> entry : block.types()) {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700472 register(kryo, entry.getLeft(), entry.getRight(), id++);
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700473 }
474 }
475 return kryo;
476 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700477
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700478 /**
479 * Register {@code type} and {@code serializer} to {@code kryo} instance.
480 *
481 * @param kryo Kryo instance
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700482 * @param types types to register
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700483 * @param serializer Specific serializer to register or null to use default.
484 * @param id type registration id to use
485 */
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700486 private void register(Kryo kryo, Class<?>[] types, Serializer<?> serializer, int id) {
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700487 Registration existing = kryo.getRegistration(id);
488 if (existing != null) {
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700489 boolean matches = false;
490 for (Class<?> type : types) {
491 if (existing.getType() == type) {
492 matches = true;
493 break;
494 }
495 }
496
497 if (!matches) {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700498 log.error("{}: Failed to register {} as {}, {} was already registered.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700499 friendlyName(), types, id, existing.getType());
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700500
501 throw new IllegalStateException(String.format(
502 "Failed to register %s as %s, %s was already registered.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700503 Arrays.toString(types), id, existing.getType()));
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700504 }
505 // falling through to register call for now.
506 // Consider skipping, if there's reasonable
507 // way to compare serializer equivalence.
508 }
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700509
510 for (Class<?> type : types) {
511 Registration r;
512 if (serializer == null) {
513 r = kryo.register(type, id);
514 } else {
515 r = kryo.register(type, serializer, id);
516 }
517 if (r.getId() != id) {
Jordan Halterman05bdb602017-07-28 17:05:57 -0700518 log.debug("{}: {} already registered as {}. Skipping {}.",
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700519 friendlyName(), r.getType(), r.getId(), id);
520 }
521 log.trace("{} registered as {}", r.getType(), r.getId());
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700522 }
HIGUCHI Yuta0a1f29e2016-05-05 15:34:41 -0700523 }
524
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800525 @Override
526 public Kryo borrow() {
527 return pool.borrow();
528 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700529
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800530 @Override
531 public void release(Kryo kryo) {
532 pool.release(kryo);
533 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700534
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800535 @Override
536 public <T> T run(KryoCallback<T> callback) {
537 return pool.run(callback);
538 }
539
540 @Override
541 public String toString() {
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700542 if (friendlyName != NO_NAME) {
543 return MoreObjects.toStringHelper(getClass())
544 .omitNullValues()
545 .add("friendlyName", friendlyName)
546 // omit lengthy detail, when there's a name
547 .toString();
548 }
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800549 return MoreObjects.toStringHelper(getClass())
550 .add("registeredBlocks", registeredBlocks)
551 .toString();
552 }
553
554 static final class RegistrationBlock {
555 private final int begin;
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700556 private final ImmutableList<Pair<Class<?>[], Serializer<?>>> types;
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800557
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700558 public RegistrationBlock(int begin, List<Pair<Class<?>[], Serializer<?>>> types) {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800559 this.begin = begin;
560 this.types = ImmutableList.copyOf(types);
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700561 }
562
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800563 public int begin() {
564 return begin;
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700565 }
566
Jordan Halterman0d1f3fa2017-05-26 00:14:27 -0700567 public ImmutableList<Pair<Class<?>[], Serializer<?>>> types() {
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800568 return types;
569 }
570
571 @Override
572 public String toString() {
573 return MoreObjects.toStringHelper(getClass())
574 .add("begin", begin)
575 .add("types", types)
576 .toString();
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700577 }
HIGUCHI Yutab2d0fd82016-05-17 20:34:58 -0700578
579 @Override
580 public int hashCode() {
581 return types.hashCode();
582 }
583
584 // Only the registered types are used for equality.
585 @Override
586 public boolean equals(Object obj) {
587 if (this == obj) {
588 return true;
589 }
590
591 if (obj instanceof RegistrationBlock) {
592 RegistrationBlock that = (RegistrationBlock) obj;
593 return Objects.equals(this.types, that.types);
594 }
595 return false;
596 }
Yuta HIGUCHI533ec322014-09-30 13:29:52 -0700597 }
Yuta HIGUCHI24a086b2014-09-21 23:28:41 -0700598}