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