/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.deephacks.confit.internal.cached;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.deephacks.cached.CacheValueSerializer;
import org.deephacks.cached.buffer.ByteBuf;
import org.deephacks.cached.buffer.ByteBufOutputStream;
import org.deephacks.cached.buffer.Unpooled;
import org.deephacks.cached.buffer.util.internal.chmv8.ConcurrentHashMapV8;
import org.deephacks.confit.internal.cached.KryoSerializers.URISerializer;
import org.deephacks.confit.internal.cached.KryoSerializers.URLSerializer;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A Kryo based serializer that read and write object proxies to a binary
* off-heap cache. Note that DefaultCacheValueSerializer is roughly twice
* as fast Kryo.
*
* Each class is given an integer id which is used to correlate how to read objects
* from a byte buffer without actually writing the whole class into the buffer.
*/
public class KryoCacheValueSerializer extends CacheValueSerializer<Object> {
/** able to write and read object without no-arg constructors */
private static final KryoReflectionFactorySupport kryo = new KryoReflectionFactorySupport();
/** keeps track of class -> id */
private static final ConcurrentHashMapV8<Class<?>, Integer> classToId = new ConcurrentHashMapV8<>();
/** keeps track of id -> class */
private static final ConcurrentHashMapV8<Integer, Class<?>> idToClass = new ConcurrentHashMapV8<>();
/** maintain unique ids to classes */
private static final AtomicInteger clsCount = new AtomicInteger(0);
static {
// kryo cannot serialize URL and URI classes with a little help
kryo.addDefaultSerializer(URL.class, new URLSerializer());
kryo.addDefaultSerializer(URI.class, new URISerializer());
}
@Override
public ByteBuf write(Object value) {
Class<?> cls = value.getClass();
Integer id = classToId.get(cls);
if(id == null) {
synchronized (kryo) {
id = clsCount.incrementAndGet();
classToId.put(cls, id);
idToClass.put(id, cls);
}
}
ByteBuf buf = Unpooled.directBuffer();
buf.writeInt(id);
ByteBufOutputStream byteBufOutput = new ByteBufOutputStream(buf);
Output output = new Output(byteBufOutput);
kryo.writeObject(output, value);
output.flush();
return buf;
}
@Override
public Object read(ByteBuf buf) {
buf.resetReaderIndex();
int id = buf.readInt();
int readable = buf.readableBytes();
byte[] bytes = new byte[readable];
buf.readBytes(bytes);
Input input = new Input(bytes);
return kryo.readObject(input, idToClass.get(id));
}
}