/*
* 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.
/** * 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.
/** 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.

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.

/** * 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); } } } }