blob: d3dd7135a7f3675bf4de8b48d49cd9259f6c52f3 [file] [log] [blame]
// Copyright (C) 2020 The Android Open Source Project
//
// 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 com.googlesource.gerrit.modules.cache.chroniclemap;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.server.cache.serialize.CacheSerializer;
import java.nio.ByteBuffer;
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.core.util.ReadResolvable;
import net.openhft.chronicle.hash.serialization.BytesReader;
import net.openhft.chronicle.hash.serialization.BytesWriter;
public class TimedValueMarshaller<V> extends SerializationMetricsForCache
implements BytesWriter<TimedValue<V>>,
BytesReader<TimedValue<V>>,
ReadResolvable<TimedValueMarshaller<V>> {
private static final ThreadLocal<byte[]> staticBuffer =
new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[Long.BYTES + Integer.BYTES];
}
};
private final CacheSerializer<V> cacheSerializer;
TimedValueMarshaller(MetricMaker metricMaker, String name) {
super(metricMaker, name);
this.cacheSerializer = CacheSerializers.getValueSerializer(name);
}
private TimedValueMarshaller(Metrics metrics, String name) {
super(metrics, name);
this.cacheSerializer = CacheSerializers.getValueSerializer(name);
}
@Override
public TimedValueMarshaller<V> readResolve() {
return new TimedValueMarshaller<>(metrics, name);
}
@SuppressWarnings("rawtypes")
@Override
public TimedValue<V> read(Bytes in, TimedValue<V> using) {
try (Timer0.Context timer = metrics.deserializeLatency.start()) {
byte[] bytesBuffer = staticBuffer.get();
in.read(bytesBuffer);
ByteBuffer buffer = ByteBuffer.wrap(bytesBuffer);
long created = buffer.getLong();
int vLength = buffer.getInt();
// Deserialize object V (remaining bytes)
byte[] serializedV = new byte[vLength];
in.read(serializedV);
V v = cacheSerializer.deserialize(serializedV);
if (using == null) {
using = new TimedValue<>(v, created);
} else {
using.setCreated(created);
using.setValue(v);
}
return using;
}
}
@SuppressWarnings("rawtypes")
@Override
public void write(Bytes out, TimedValue<V> toWrite) {
try (Timer0.Context timer = metrics.serializeLatency.start()) {
byte[] serialized = cacheSerializer.serialize(toWrite.getValue());
// Serialize as follows:
// created | length of serialized V | serialized value V
// 8 bytes | 4 bytes | serialized_length bytes
byte[] bytesBuffer = staticBuffer.get();
ByteBuffer buffer = ByteBuffer.wrap(bytesBuffer);
buffer.putLong(toWrite.getCreated());
buffer.putInt(serialized.length);
out.write(bytesBuffer);
out.write(serialized);
}
}
}