blob: fa38ce15b835273a6dd3e6f2b9395677792bb05b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cassandra.db;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.io.util.DataInputBuffer;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputBuffer;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.memory.AbstractAllocator;
import static org.apache.cassandra.db.AbstractBufferClusteringPrefix.EMPTY_VALUES_ARRAY;
public interface Clustering extends ClusteringPrefix
{
public static final Serializer serializer = new Serializer();
public long unsharedHeapSizeExcludingData();
public default Clustering copy(AbstractAllocator allocator)
{
// Important for STATIC_CLUSTERING (but must copy empty native clustering types).
if (size() == 0)
return kind() == Kind.STATIC_CLUSTERING ? this : new BufferClustering(EMPTY_VALUES_ARRAY);
ByteBuffer[] newValues = new ByteBuffer[size()];
for (int i = 0; i < size(); i++)
{
ByteBuffer val = get(i);
newValues[i] = val == null ? null : allocator.clone(val);
}
return new BufferClustering(newValues);
}
public default String toString(CFMetaData metadata)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size(); i++)
{
ColumnDefinition c = metadata.clusteringColumns().get(i);
sb.append(i == 0 ? "" : ", ").append(c.name).append('=').append(get(i) == null ? "null" : c.type.getString(get(i)));
}
return sb.toString();
}
public default String toCQLString(CFMetaData metadata)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size(); i++)
{
ColumnDefinition c = metadata.clusteringColumns().get(i);
sb.append(i == 0 ? "" : ", ").append(c.type.getString(get(i)));
}
return sb.toString();
}
public static Clustering make(ByteBuffer... values)
{
return new BufferClustering(values);
}
/**
* The special cased clustering used by all static rows. It is a special case in the
* sense that it's always empty, no matter how many clustering columns the table has.
*/
public static final Clustering STATIC_CLUSTERING = new BufferClustering(EMPTY_VALUES_ARRAY)
{
@Override
public Kind kind()
{
return Kind.STATIC_CLUSTERING;
}
@Override
public String toString()
{
return "STATIC";
}
@Override
public String toString(CFMetaData metadata)
{
return toString();
}
};
/** Empty clustering for tables having no clustering columns. */
public static final Clustering EMPTY = new BufferClustering(EMPTY_VALUES_ARRAY)
{
@Override
public String toString(CFMetaData metadata)
{
return "EMPTY";
}
};
/**
* Serializer for Clustering object.
* <p>
* Because every clustering in a given table must have the same size (ant that size cannot actually change once the table
* has been defined), we don't record that size.
*/
public static class Serializer
{
public void serialize(Clustering clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
{
assert clustering != STATIC_CLUSTERING : "We should never serialize a static clustering";
assert clustering.size() == types.size() : "Invalid clustering for the table: " + clustering;
ClusteringPrefix.serializer.serializeValuesWithoutSize(clustering, out, version, types);
}
public ByteBuffer serialize(Clustering clustering, int version, List<AbstractType<?>> types)
{
try (DataOutputBuffer buffer = new DataOutputBuffer((int)serializedSize(clustering, version, types)))
{
serialize(clustering, buffer, version, types);
return buffer.buffer();
}
catch (IOException e)
{
throw new RuntimeException("Writting to an in-memory buffer shouldn't trigger an IOException", e);
}
}
public long serializedSize(Clustering clustering, int version, List<AbstractType<?>> types)
{
return ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(clustering, version, types);
}
public void skip(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
{
if (!types.isEmpty())
ClusteringPrefix.serializer.skipValuesWithoutSize(in, types.size(), version, types);
}
public Clustering deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
{
if (types.isEmpty())
return EMPTY;
ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, types.size(), version, types);
return new BufferClustering(values);
}
public Clustering deserialize(ByteBuffer in, int version, List<AbstractType<?>> types)
{
try (DataInputBuffer buffer = new DataInputBuffer(in, true))
{
return deserialize(buffer, version, types);
}
catch (IOException e)
{
throw new RuntimeException("Reading from an in-memory buffer shouldn't trigger an IOException", e);
}
}
}
}