package org.apache.cassandra.db;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.io.ISerializer;
import org.apache.cassandra.io.sstable.IndexInfo;
import org.apache.cassandra.io.sstable.format.big.BigFormat;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.io.sstable.format.Version;
import org.apache.cassandra.utils.ByteBufferUtil;
public class Serializers
{
private final CFMetaData metadata;
private Map<Version, IndexInfo.Serializer> otherVersionClusteringSerializers;
private final IndexInfo.Serializer latestVersionIndexSerializer;
public Serializers(CFMetaData metadata)
{
this.metadata = metadata;
this.latestVersionIndexSerializer = new IndexInfo.Serializer(BigFormat.latestVersion,
indexEntryClusteringPrefixSerializer(BigFormat.latestVersion, SerializationHeader.makeWithoutStats(metadata)));
}
IndexInfo.Serializer indexInfoSerializer(Version version, SerializationHeader header)
{
if (version.equals(BigFormat.latestVersion) && header != null)
return latestVersionIndexSerializer;
if (otherVersionClusteringSerializers == null)
otherVersionClusteringSerializers = new ConcurrentHashMap<>();
IndexInfo.Serializer serializer = otherVersionClusteringSerializers.get(version);
if (serializer == null)
{
serializer = new IndexInfo.Serializer(version,
indexEntryClusteringPrefixSerializer(version, header));
otherVersionClusteringSerializers.put(version, serializer);
}
return serializer;
}
private ISerializer<ClusteringPrefix> indexEntryClusteringPrefixSerializer(Version version, SerializationHeader header)
{
if (!version.storeRows() || header == null)
{
return oldFormatSerializer(version);
}
return new NewFormatSerializer(version, header.clusteringTypes());
}
private ISerializer<ClusteringPrefix> oldFormatSerializer(Version version)
{
return new ISerializer<ClusteringPrefix>()
{
List<AbstractType<?>> clusteringTypes = SerializationHeader.makeWithoutStats(metadata).clusteringTypes();
public void serialize(ClusteringPrefix clustering, DataOutputPlus out) throws IOException
{
ClusteringPrefix.serializer.serialize(clustering, out,
version.correspondingMessagingVersion(),
clusteringTypes);
}
@Override
public void skip(DataInputPlus in) throws IOException
{
ByteBufferUtil.skipShortLength(in);
}
public ClusteringPrefix deserialize(DataInputPlus in) throws IOException
{
ByteBuffer bb = ByteBufferUtil.readWithShortLength(in);
assert bb.hasRemaining();
int clusteringSize = metadata.clusteringColumns().size();
if (clusteringSize == 0)
return Clustering.EMPTY;
if (metadata.isCompound() && CompositeType.isStaticName(bb))
return Clustering.STATIC_CLUSTERING;
if (!metadata.isCompound())
return Clustering.make(bb);
List<ByteBuffer> components = CompositeType.splitName(bb);
byte eoc = CompositeType.lastEOC(bb);
if (eoc == 0 || components.size() >= clusteringSize)
{
if (components.size() > clusteringSize)
components = components.subList(0, clusteringSize);
return Clustering.make(components.toArray(new ByteBuffer[clusteringSize]));
}
else
{
ClusteringPrefix.Kind boundKind = eoc > 0
? ClusteringPrefix.Kind.EXCL_START_BOUND
: ClusteringPrefix.Kind.INCL_START_BOUND;
return ClusteringBound.create(boundKind, components.toArray(new ByteBuffer[components.size()]));
}
}
public long serializedSize(ClusteringPrefix clustering)
{
return ClusteringPrefix.serializer.serializedSize(clustering, version.correspondingMessagingVersion(),
clusteringTypes);
}
};
}
private static class NewFormatSerializer implements ISerializer<ClusteringPrefix>
{
private final Version version;
private final List<AbstractType<?>> clusteringTypes;
NewFormatSerializer(Version version, List<AbstractType<?>> clusteringTypes)
{
this.version = version;
this.clusteringTypes = clusteringTypes;
}
public void serialize(ClusteringPrefix clustering, DataOutputPlus out) throws IOException
{
ClusteringPrefix.serializer.serialize(clustering, out, version.correspondingMessagingVersion(), clusteringTypes);
}
@Override
public void skip(DataInputPlus in) throws IOException
{
ClusteringPrefix.serializer.skip(in, version.correspondingMessagingVersion(), clusteringTypes);
}
public ClusteringPrefix deserialize(DataInputPlus in) throws IOException
{
return ClusteringPrefix.serializer.deserialize(in, version.correspondingMessagingVersion(), clusteringTypes);
}
public long serializedSize(ClusteringPrefix clustering)
{
return ClusteringPrefix.serializer.serializedSize(clustering, version.correspondingMessagingVersion(), clusteringTypes);
}
}
}