Add byte array backed cells

Patch by Blake Eggleston; reviewed by Caleb Rackliffe and Marcus Eriksson for CASSANDRA-15393
This commit is contained in:
Blake Eggleston 2019-10-15 13:04:26 -07:00
parent 8ba163f25a
commit ccab496d2d
303 changed files with 5720 additions and 2820 deletions

View File

@ -1,4 +1,5 @@
4.0-beta3
* Add byte array backed cells (CASSANDRA-15393)
* Correctly handle pending ranges with adjacent range movements (CASSANDRA-14801)
* Avoid adding locahost when streaming trivial ranges (CASSANDRA-16099)
* Add nodetool getfullquerylog (CASSANDRA-15988)

View File

@ -27,6 +27,7 @@ import org.apache.cassandra.db.*;
import org.apache.cassandra.db.filter.ClusteringIndexFilter;
import org.apache.cassandra.db.filter.ClusteringIndexNamesFilter;
import org.apache.cassandra.db.filter.ColumnFilter;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.db.rows.CellPath;
@ -61,22 +62,22 @@ public final class CounterCacheKey extends CacheKey
this(tableMetadata, ByteBufferUtil.getArray(partitionKey), ByteBufferUtil.getArray(cellName));
}
public static CounterCacheKey create(TableMetadata tableMetadata, ByteBuffer partitionKey, Clustering clustering, ColumnMetadata c, CellPath path)
public static CounterCacheKey create(TableMetadata tableMetadata, ByteBuffer partitionKey, Clustering<?> clustering, ColumnMetadata c, CellPath path)
{
return new CounterCacheKey(tableMetadata, partitionKey, makeCellName(clustering, c, path));
}
private static ByteBuffer makeCellName(Clustering clustering, ColumnMetadata c, CellPath path)
private static ByteBuffer makeCellName(Clustering<?> clustering, ColumnMetadata c, CellPath path)
{
int cs = clustering.size();
ByteBuffer[] values = new ByteBuffer[cs + 1 + (path == null ? 0 : path.size())];
for (int i = 0; i < cs; i++)
values[i] = clustering.get(i);
values[i] = clustering.bufferAt(i);
values[cs] = c.name.bytes;
if (path != null)
for (int i = 0; i < path.size(); i++)
values[cs + 1 + i] = path.get(i);
return CompositeType.build(values);
return CompositeType.build(ByteBufferAccessor.instance, values);
}
public ByteBuffer partitionKey()
@ -99,10 +100,10 @@ public final class CounterCacheKey extends CacheKey
DecoratedKey key = cfs.decorateKey(partitionKey());
int clusteringSize = metadata.comparator.size();
List<ByteBuffer> buffers = CompositeType.splitName(ByteBuffer.wrap(cellName));
List<ByteBuffer> buffers = CompositeType.splitName(ByteBuffer.wrap(cellName), ByteBufferAccessor.instance);
assert buffers.size() >= clusteringSize + 1; // See makeCellName above
Clustering clustering = Clustering.make(buffers.subList(0, clusteringSize).toArray(new ByteBuffer[clusteringSize]));
Clustering<?> clustering = Clustering.make(buffers.subList(0, clusteringSize).toArray(new ByteBuffer[clusteringSize]));
ColumnMetadata column = metadata.getColumn(buffers.get(clusteringSize));
// This can theoretically happen if a column is dropped after the cache is saved and we
// try to load it. Not point if failing in any case, just skip the value.
@ -125,9 +126,9 @@ public final class CounterCacheKey extends CacheKey
{
ByteBuffer value = null;
if (column.isStatic())
value = iter.staticRow().getCell(column).value();
value = iter.staticRow().getCell(column).buffer();
else if (iter.hasNext())
value = iter.next().getCell(column).value();
value = iter.next().getCell(column).buffer();
return value;
}
@ -136,8 +137,8 @@ public final class CounterCacheKey extends CacheKey
public void write(DataOutputPlus out)
throws IOException
{
ByteBufferUtil.writeWithLength(partitionKey, out);
ByteBufferUtil.writeWithLength(cellName, out);
ByteArrayUtil.writeWithLength(partitionKey, out);
ByteArrayUtil.writeWithLength(cellName, out);
}
public static CounterCacheKey read(TableMetadata tableMetadata, DataInputPlus in)

View File

@ -24,6 +24,7 @@ import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.db.marshal.CollectionType.Kind;
@ -57,11 +58,11 @@ public interface CQL3Type
/**
* Generates CQL literal from a binary value of this type.
* @param buffer the value to convert to a CQL literal. This value must be
* @param bytes the value to convert to a CQL literal. This value must be
* serialized with {@code version} of the native protocol.
* @param version the native protocol version in which {@code buffer} is encoded.
*/
public String toCQLLiteral(ByteBuffer buffer, ProtocolVersion version);
String toCQLLiteral(ByteBuffer bytes, ProtocolVersion version);
public enum Native implements CQL3Type
{
@ -196,6 +197,7 @@ public interface CQL3Type
StringBuilder target = new StringBuilder();
buffer = buffer.duplicate();
int size = CollectionSerializer.readCollectionSize(buffer, version);
buffer.position(buffer.position() + CollectionSerializer.sizeOfCollectionSize(size, version));
switch (type.kind)
{
@ -224,25 +226,30 @@ public interface CQL3Type
{
CQL3Type keys = ((MapType) type).getKeysType().asCQL3Type();
CQL3Type values = ((MapType) type).getValuesType().asCQL3Type();
int offset = 0;
for (int i = 0; i < size; i++)
{
if (i > 0)
target.append(", ");
ByteBuffer element = CollectionSerializer.readValue(buffer, version);
ByteBuffer element = CollectionSerializer.readValue(buffer, ByteBufferAccessor.instance, offset, version);
offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, version);
target.append(keys.toCQLLiteral(element, version));
target.append(": ");
element = CollectionSerializer.readValue(buffer, version);
element = CollectionSerializer.readValue(buffer, ByteBufferAccessor.instance, offset, version);
offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, version);
target.append(values.toCQLLiteral(element, version));
}
}
private static void generateSetOrListCQLLiteral(ByteBuffer buffer, ProtocolVersion version, StringBuilder target, int size, CQL3Type elements)
{
int offset = 0;
for (int i = 0; i < size; i++)
{
if (i > 0)
target.append(", ");
ByteBuffer element = CollectionSerializer.readValue(buffer, version);
ByteBuffer element = CollectionSerializer.readValue(buffer, ByteBufferAccessor.instance, offset, version);
offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, version);
target.append(elements.toCQLLiteral(element, version));
}
}

View File

@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.schema.ColumnMetadata;
import com.google.common.annotations.VisibleForTesting;
import org.apache.cassandra.cql3.functions.Function;
@ -210,7 +211,7 @@ public abstract class Lists
{
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
List<?> l = type.getSerializer().deserializeForNativeProtocol(value, version);
List<?> l = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version);
List<ByteBuffer> elements = new ArrayList<>(l.size());
for (Object element : l)
// elements can be null in lists that represent a set of IN values
@ -576,9 +577,9 @@ public abstract class Lists
// the read-before-write this operation requires limits its usefulness on big lists, so in practice
// toDiscard will be small and keeping a list will be more efficient.
List<ByteBuffer> toDiscard = ((Value)value).elements;
for (Cell cell : complexData)
for (Cell<?> cell : complexData)
{
if (toDiscard.contains(cell.value()))
if (toDiscard.contains(cell.buffer()))
params.addTombstone(column, cell.path());
}
}

View File

@ -228,7 +228,7 @@ public abstract class Maps
{
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
Map<?, ?> m = type.getSerializer().deserializeForNativeProtocol(value, version);
Map<?, ?> m = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version);
Map<ByteBuffer, ByteBuffer> map = new LinkedHashMap<>(m.size());
for (Map.Entry<?, ?> entry : m.entrySet())
map.put(type.getKeysType().decompose(entry.getKey()), type.getValuesType().decompose(entry.getValue()));

View File

@ -214,7 +214,7 @@ public abstract class Sets
{
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
Set<?> s = type.getSerializer().deserializeForNativeProtocol(value, version);
Set<?> s = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version);
SortedSet<ByteBuffer> elements = new TreeSet<>(type.getElementsType());
for (Object element : s)
elements.add(type.getElementsType().decompose(element));

View File

@ -264,7 +264,7 @@ public class Tuples
{
// Collections have this small hack that validate cannot be called on a serialized object,
// but the deserialization does the validation (so we're fine).
List<?> l = type.getSerializer().deserializeForNativeProtocol(value, options.getProtocolVersion());
List<?> l = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, options.getProtocolVersion());
assert type.getElementsType() instanceof TupleType;
TupleType tupleType = Tuples.getTupleType(type.getElementsType());

View File

@ -310,17 +310,17 @@ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row>
for (ColumnMetadata def : metadata.partitionKeyColumns())
data.put(def.name.toString(), keyComponents[def.position()]);
Clustering clustering = row.clustering();
Clustering<?> clustering = row.clustering();
for (ColumnMetadata def : metadata.clusteringColumns())
data.put(def.name.toString(), clustering.get(def.position()));
data.put(def.name.toString(), clustering.bufferAt(def.position()));
for (ColumnMetadata def : metadata.regularAndStaticColumns())
{
if (def.isSimple())
{
Cell cell = row.getCell(def);
Cell<?> cell = row.getCell(def);
if (cell != null)
data.put(def.name.toString(), cell.value());
data.put(def.name.toString(), cell.buffer());
}
else
{

View File

@ -80,7 +80,7 @@ public class UpdateParameters
throw new InvalidRequestException(String.format("Out of bound timestamp, must be in [%d, %d]", Long.MIN_VALUE + 1, Long.MAX_VALUE));
}
public void newRow(Clustering clustering) throws InvalidRequestException
public <V> void newRow(Clustering<V> clustering) throws InvalidRequestException
{
if (clustering == Clustering.STATIC_CLUSTERING)
{
@ -98,7 +98,7 @@ public class UpdateParameters
builder.newRow(clustering);
}
public Clustering currentClustering()
public Clustering<?> currentClustering()
{
return builder.clustering();
}
@ -130,9 +130,9 @@ public class UpdateParameters
public void addCell(ColumnMetadata column, CellPath path, ByteBuffer value) throws InvalidRequestException
{
Cell cell = ttl == LivenessInfo.NO_TTL
? BufferCell.live(column, timestamp, value, path)
: BufferCell.expiring(column, timestamp, ttl, nowInSec, value, path);
Cell<?> cell = ttl == LivenessInfo.NO_TTL
? BufferCell.live(column, timestamp, value, path)
: BufferCell.expiring(column, timestamp, ttl, nowInSec, value, path);
builder.addCell(cell);
}
@ -177,7 +177,7 @@ public class UpdateParameters
return deletionTime;
}
public RangeTombstone makeRangeTombstone(ClusteringComparator comparator, Clustering clustering)
public RangeTombstone makeRangeTombstone(ClusteringComparator comparator, Clustering<?> clustering)
{
return makeRangeTombstone(Slice.make(comparator, clustering));
}
@ -197,7 +197,7 @@ public class UpdateParameters
* @param clustering the row clustering
* @return the prefetched row with the already performed modifications
*/
public Row getPrefetchedRow(DecoratedKey key, Clustering clustering)
public Row getPrefetchedRow(DecoratedKey key, Clustering<?> clustering)
{
if (prefetchedRows == null)
return null;

View File

@ -259,29 +259,29 @@ public abstract class ColumnCondition
}
}
protected static final Cell getCell(Row row, ColumnMetadata column)
protected static final Cell<?> getCell(Row row, ColumnMetadata column)
{
// If we're asking for a given cell, and we didn't got any row from our read, it's
// the same as not having said cell.
return row == null ? null : row.getCell(column);
}
protected static final Cell getCell(Row row, ColumnMetadata column, CellPath path)
protected static final Cell<?> getCell(Row row, ColumnMetadata column, CellPath path)
{
// If we're asking for a given cell, and we didn't got any row from our read, it's
// the same as not having said cell.
return row == null ? null : row.getCell(column, path);
}
protected static final Iterator<Cell> getCells(Row row, ColumnMetadata column)
protected static final Iterator<Cell<?>> getCells(Row row, ColumnMetadata column)
{
// If we're asking for a complex cells, and we didn't got any row from our read, it's
// the same as not having any cells for that column.
if (row == null)
return Collections.<Cell>emptyIterator();
return Collections.emptyIterator();
ComplexColumnData complexData = row.getComplexColumnData(column);
return complexData == null ? Collections.<Cell>emptyIterator() : complexData.iterator();
return complexData == null ? Collections.<Cell<?>>emptyIterator() : complexData.iterator();
}
protected static final boolean evaluateComparisonWithOperator(int comparison, Operator operator)
@ -328,8 +328,8 @@ public abstract class ColumnCondition
private ByteBuffer rowValue(Row row)
{
Cell c = getCell(row, column);
return c == null ? null : c.value();
Cell<?> c = getCell(row, column);
return c == null ? null : c.buffer();
}
private boolean isSatisfiedBy(ByteBuffer rowValue)
@ -393,14 +393,14 @@ public abstract class ColumnCondition
{
if (column.type.isMultiCell())
{
Cell cell = getCell(row, column, CellPath.create(collectionElement));
return cell == null ? null : cell.value();
Cell<?> cell = getCell(row, column, CellPath.create(collectionElement));
return cell == null ? null : cell.buffer();
}
Cell cell = getCell(row, column);
Cell<?> cell = getCell(row, column);
return cell == null
? null
: type.getSerializer().getSerializedValue(cell.value(), collectionElement, type.getKeysType());
: type.getSerializer().getSerializedValue(cell.buffer(), collectionElement, type.getKeysType());
}
private ByteBuffer rowListValue(ListType<?> type, Row row)
@ -408,17 +408,17 @@ public abstract class ColumnCondition
if (column.type.isMultiCell())
return cellValueAtIndex(getCells(row, column), getListIndex(collectionElement));
Cell cell = getCell(row, column);
Cell<?> cell = getCell(row, column);
return cell == null
? null
: type.getSerializer().getElement(cell.value(), getListIndex(collectionElement));
: type.getSerializer().getElement(cell.buffer(), getListIndex(collectionElement));
}
private static ByteBuffer cellValueAtIndex(Iterator<Cell> iter, int index)
private static ByteBuffer cellValueAtIndex(Iterator<Cell<?>> iter, int index)
{
int adv = Iterators.advance(iter, index);
if (adv == index && iter.hasNext())
return iter.next().value();
return iter.next().buffer();
return null;
}
@ -468,7 +468,7 @@ public abstract class ColumnCondition
// copy iterator contents so that we can properly reuse them for each comparison with an IN value
for (Term.Terminal value : values)
{
Iterator<Cell> iter = getCells(row, column);
Iterator<Cell<?>> iter = getCells(row, column);
if (value == null)
{
if (comparisonOperator == Operator.EQ)
@ -490,7 +490,7 @@ public abstract class ColumnCondition
return false;
}
private static boolean valueAppliesTo(CollectionType<?> type, Iterator<Cell> iter, Term.Terminal value, Operator operator)
private static boolean valueAppliesTo(CollectionType<?> type, Iterator<Cell<?>> iter, Term.Terminal value, Operator operator)
{
if (value == null)
return !iter.hasNext();
@ -510,7 +510,7 @@ public abstract class ColumnCondition
throw new AssertionError();
}
private static boolean setOrListAppliesTo(AbstractType<?> type, Iterator<Cell> iter, Iterator<ByteBuffer> conditionIter, Operator operator, boolean isSet)
private static boolean setOrListAppliesTo(AbstractType<?> type, Iterator<Cell<?>> iter, Iterator<ByteBuffer> conditionIter, Operator operator, boolean isSet)
{
while(iter.hasNext())
{
@ -518,7 +518,7 @@ public abstract class ColumnCondition
return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ);
// for lists we use the cell value; for sets we use the cell name
ByteBuffer cellValue = isSet ? iter.next().path().get(0) : iter.next().value();
ByteBuffer cellValue = isSet ? iter.next().path().get(0) : iter.next().buffer();
int comparison = type.compare(cellValue, conditionIter.next());
if (comparison != 0)
return evaluateComparisonWithOperator(comparison, operator);
@ -531,19 +531,19 @@ public abstract class ColumnCondition
return operator == Operator.EQ || operator == Operator.LTE || operator == Operator.GTE;
}
private static boolean listAppliesTo(ListType<?> type, Iterator<Cell> iter, List<ByteBuffer> elements, Operator operator)
private static boolean listAppliesTo(ListType<?> type, Iterator<Cell<?>> iter, List<ByteBuffer> elements, Operator operator)
{
return setOrListAppliesTo(type.getElementsType(), iter, elements.iterator(), operator, false);
}
private static boolean setAppliesTo(SetType<?> type, Iterator<Cell> iter, Set<ByteBuffer> elements, Operator operator)
private static boolean setAppliesTo(SetType<?> type, Iterator<Cell<?>> iter, Set<ByteBuffer> elements, Operator operator)
{
ArrayList<ByteBuffer> sortedElements = new ArrayList<>(elements);
Collections.sort(sortedElements, type.getElementsType());
return setOrListAppliesTo(type.getElementsType(), iter, sortedElements.iterator(), operator, true);
}
private static boolean mapAppliesTo(MapType<?, ?> type, Iterator<Cell> iter, Map<ByteBuffer, ByteBuffer> elements, Operator operator)
private static boolean mapAppliesTo(MapType<?, ?> type, Iterator<Cell<?>> iter, Map<ByteBuffer, ByteBuffer> elements, Operator operator)
{
Iterator<Map.Entry<ByteBuffer, ByteBuffer>> conditionIter = elements.entrySet().iterator();
while(iter.hasNext())
@ -552,7 +552,7 @@ public abstract class ColumnCondition
return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ);
Map.Entry<ByteBuffer, ByteBuffer> conditionEntry = conditionIter.next();
Cell c = iter.next();
Cell<?> c = iter.next();
// compare the keys
int comparison = type.getKeysType().compare(c.path().get(0), conditionEntry.getKey());
@ -560,7 +560,7 @@ public abstract class ColumnCondition
return evaluateComparisonWithOperator(comparison, operator);
// compare the values
comparison = type.getValuesType().compare(c.value(), conditionEntry.getValue());
comparison = type.getValuesType().compare(c.buffer(), conditionEntry.getValue());
if (comparison != 0)
return evaluateComparisonWithOperator(comparison, operator);
}
@ -608,14 +608,14 @@ public abstract class ColumnCondition
if (column.type.isMultiCell())
{
Cell cell = getCell(row, column, userType.cellPathForField(field));
return cell == null ? null : cell.value();
Cell<?> cell = getCell(row, column, userType.cellPathForField(field));
return cell == null ? null : cell.buffer();
}
Cell cell = getCell(row, column);
Cell<?> cell = getCell(row, column);
return cell == null
? null
: userType.split(cell.value())[userType.fieldPosition(field)];
: userType.split(cell.buffer())[userType.fieldPosition(field)];
}
private boolean isSatisfiedBy(ByteBuffer rowValue)
@ -670,7 +670,7 @@ public abstract class ColumnCondition
private final ByteBuffer rowValue(Row row)
{
UserType userType = (UserType) column.type;
Iterator<Cell> iter = getCells(row, column);
Iterator<Cell<?>> iter = getCells(row, column);
return iter.hasNext() ? userType.serializeForNativeProtocol(iter, protocolVersion) : null;
}

View File

@ -91,7 +91,7 @@ public final class ColumnConditions extends AbstractConditions
* @param options the query options
*/
public void addConditionsTo(CQL3CasRequest request,
Clustering clustering,
Clustering<?> clustering,
QueryOptions options)
{
if (!columnConditions.isEmpty())

View File

@ -98,6 +98,6 @@ public interface Conditions
* @param options the query options
*/
public void addConditionsTo(CQL3CasRequest request,
Clustering clustering,
Clustering<?> clustering,
QueryOptions options);
}

View File

@ -24,7 +24,7 @@ import org.apache.cassandra.db.Clustering;
final class IfExistsCondition extends AbstractConditions
{
@Override
public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options)
public void addConditionsTo(CQL3CasRequest request, Clustering<?> clustering, QueryOptions options)
{
request.addExist(clustering);
}

View File

@ -24,7 +24,7 @@ import org.apache.cassandra.db.Clustering;
final class IfNotExistsCondition extends AbstractConditions
{
@Override
public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options)
public void addConditionsTo(CQL3CasRequest request, Clustering<?> clustering, QueryOptions options)
{
request.addNotExist(clustering);
}

View File

@ -101,7 +101,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper
return false;
}
public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) throws InvalidRequestException
public NavigableSet<Clustering<?>> valuesAsClustering(QueryOptions options) throws InvalidRequestException
{
MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN());
for (SingleRestriction r : restrictions)
@ -113,7 +113,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper
return builder.build();
}
public NavigableSet<ClusteringBound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException
public NavigableSet<ClusteringBound<?>> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException
{
MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || hasMultiColumnSlice());
int keyPosition = 0;

View File

@ -743,7 +743,7 @@ public final class StatementRestrictions
* @param options the query options
* @return the requested clustering columns
*/
public NavigableSet<Clustering> getClusteringColumns(QueryOptions options)
public NavigableSet<Clustering<?>> getClusteringColumns(QueryOptions options)
{
return clusteringColumnsRestrictions.valuesAsClustering(options);
}
@ -755,7 +755,7 @@ public final class StatementRestrictions
* @param options the query options
* @return the bounds (start or end) of the clustering columns
*/
public NavigableSet<ClusteringBound> getClusteringColumnsBounds(Bound b, QueryOptions options)
public NavigableSet<ClusteringBound<?>> getClusteringColumnsBounds(Bound b, QueryOptions options)
{
return clusteringColumnsRestrictions.boundsAsClustering(b, options);
}

View File

@ -84,7 +84,7 @@ public final class ResultSetBuilder
current.add(v);
}
public void add(Cell c, int nowInSec)
public void add(Cell<?> c, int nowInSec)
{
if (c == null)
{
@ -101,7 +101,7 @@ public final class ResultSetBuilder
ttls[current.size() - 1] = remainingTTL(c, nowInSec);
}
private int remainingTTL(Cell c, int nowInSec)
private int remainingTTL(Cell<?> c, int nowInSec)
{
if (!c.isExpiring())
return -1;
@ -110,11 +110,11 @@ public final class ResultSetBuilder
return remaining >= 0 ? remaining : -1;
}
private ByteBuffer value(Cell c)
private <V> ByteBuffer value(Cell<V> c)
{
return c.isCounterCell()
? ByteBufferUtil.bytes(CounterContext.instance().total(c.value()))
: c.value();
? ByteBufferUtil.bytes(CounterContext.instance().total(c.value(), c.accessor()))
: c.buffer();
}
/**
@ -123,7 +123,7 @@ public final class ResultSetBuilder
* @param partitionKey the partition key of the new row
* @param clustering the clustering of the new row
*/
public void newRow(DecoratedKey partitionKey, Clustering clustering)
public void newRow(DecoratedKey partitionKey, Clustering<?> clustering)
{
// The groupMaker needs to be called for each row
boolean isNewAggregate = groupMaker == null || groupMaker.isNewGroup(partitionKey, clustering);

View File

@ -503,7 +503,7 @@ public class BatchStatement implements CQLStatement
}
else
{
Clustering clustering = Iterables.getOnlyElement(statement.createClustering(statementOptions));
Clustering<?> clustering = Iterables.getOnlyElement(statement.createClustering(statementOptions));
if (statement.hasConditions())
{
statement.addConditions(clustering, casRequest, statementOptions);

View File

@ -56,7 +56,7 @@ public class CQL3CasRequest implements CASRequest
// We index RowCondition by the clustering of the row they applied to for 2 reasons:
// 1) this allows to keep things sorted to build the read command below
// 2) this allows to detect when contradictory conditions are set (not exists with some other conditions on the same row)
private final TreeMap<Clustering, RowCondition> conditions;
private final TreeMap<Clustering<?>, RowCondition> conditions;
private final List<RowUpdate> updates = new ArrayList<>();
private final List<RangeDeletion> rangeDeletions = new ArrayList<>();
@ -75,7 +75,7 @@ public class CQL3CasRequest implements CASRequest
this.updatesStaticRow = updatesStaticRow;
}
void addRowUpdate(Clustering clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds)
void addRowUpdate(Clustering<?> clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds)
{
updates.add(new RowUpdate(clustering, stmt, options, timestamp, nowInSeconds));
}
@ -85,17 +85,17 @@ public class CQL3CasRequest implements CASRequest
rangeDeletions.add(new RangeDeletion(slice, stmt, options, timestamp, nowInSeconds));
}
public void addNotExist(Clustering clustering) throws InvalidRequestException
public void addNotExist(Clustering<?> clustering) throws InvalidRequestException
{
addExistsCondition(clustering, new NotExistCondition(clustering), true);
}
public void addExist(Clustering clustering) throws InvalidRequestException
public void addExist(Clustering<?> clustering) throws InvalidRequestException
{
addExistsCondition(clustering, new ExistCondition(clustering), false);
}
private void addExistsCondition(Clustering clustering, RowCondition condition, boolean isNotExist)
private void addExistsCondition(Clustering<?> clustering, RowCondition condition, boolean isNotExist)
{
assert condition instanceof ExistCondition || condition instanceof NotExistCondition;
RowCondition previous = getConditionsForRow(clustering);
@ -128,7 +128,7 @@ public class CQL3CasRequest implements CASRequest
hasExists = true;
}
public void addConditions(Clustering clustering, Collection<ColumnCondition> conds, QueryOptions options) throws InvalidRequestException
public void addConditions(Clustering<?> clustering, Collection<ColumnCondition> conds, QueryOptions options) throws InvalidRequestException
{
RowCondition condition = getConditionsForRow(clustering);
if (condition == null)
@ -143,12 +143,12 @@ public class CQL3CasRequest implements CASRequest
((ColumnsConditions)condition).addConditions(conds, options);
}
private RowCondition getConditionsForRow(Clustering clustering)
private RowCondition getConditionsForRow(Clustering<?> clustering)
{
return clustering == Clustering.STATIC_CLUSTERING ? staticConditions : conditions.get(clustering);
}
private void setConditionsForRow(Clustering clustering, RowCondition condition)
private void setConditionsForRow(Clustering<?> clustering, RowCondition condition)
{
if (clustering == Clustering.STATIC_CLUSTERING)
{
@ -255,13 +255,13 @@ public class CQL3CasRequest implements CASRequest
*/
private class RowUpdate
{
private final Clustering clustering;
private final Clustering<?> clustering;
private final ModificationStatement stmt;
private final QueryOptions options;
private final long timestamp;
private final int nowInSeconds;
private RowUpdate(Clustering clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds)
private RowUpdate(Clustering<?> clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds)
{
this.clustering = clustering;
this.stmt = stmt;
@ -320,9 +320,9 @@ public class CQL3CasRequest implements CASRequest
private static abstract class RowCondition
{
public final Clustering clustering;
public final Clustering<?> clustering;
protected RowCondition(Clustering clustering)
protected RowCondition(Clustering<?> clustering)
{
this.clustering = clustering;
}
@ -332,7 +332,7 @@ public class CQL3CasRequest implements CASRequest
private static class NotExistCondition extends RowCondition
{
private NotExistCondition(Clustering clustering)
private NotExistCondition(Clustering<?> clustering)
{
super(clustering);
}
@ -345,7 +345,7 @@ public class CQL3CasRequest implements CASRequest
private static class ExistCondition extends RowCondition
{
private ExistCondition(Clustering clustering)
private ExistCondition(Clustering<?> clustering)
{
super(clustering);
}
@ -360,7 +360,7 @@ public class CQL3CasRequest implements CASRequest
{
private final Multimap<Pair<ColumnIdentifier, ByteBuffer>, ColumnCondition.Bound> conditions = HashMultimap.create();
private ColumnsConditions(Clustering clustering)
private ColumnsConditions(Clustering<?> clustering)
{
super(clustering);
}

View File

@ -54,7 +54,7 @@ public class DeleteStatement extends ModificationStatement
}
@Override
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params)
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params)
throws InvalidRequestException
{
TableMetadata metadata = metadata();

View File

@ -26,6 +26,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.schema.TableMetadata;
@ -180,7 +181,7 @@ public abstract class ModificationStatement implements CQLStatement
return restrictions;
}
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params);
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params);
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Slice slice, UpdateParameters params);
@ -323,7 +324,7 @@ public abstract class ModificationStatement implements CQLStatement
return partitionKeys;
}
public NavigableSet<Clustering> createClustering(QueryOptions options)
public NavigableSet<Clustering<?>> createClustering(QueryOptions options)
throws InvalidRequestException
{
if (appliesOnlyToStaticColumns() && !restrictions.hasClusteringColumnsRestrictions())
@ -503,7 +504,7 @@ public abstract class ModificationStatement implements CQLStatement
"IN on the clustering key columns is not supported with conditional %s",
type.isUpdate()? "updates" : "deletions");
Clustering clustering = Iterables.getOnlyElement(createClustering(options));
Clustering<?> clustering = Iterables.getOnlyElement(createClustering(options));
CQL3CasRequest request = new CQL3CasRequest(metadata(), key, conditionColumns(), updatesRegularRows(), updatesStaticRow());
addConditions(clustering, request, options);
@ -512,7 +513,7 @@ public abstract class ModificationStatement implements CQLStatement
return request;
}
public void addConditions(Clustering clustering, CQL3CasRequest request, QueryOptions options) throws InvalidRequestException
public void addConditions(Clustering<?> clustering, CQL3CasRequest request, QueryOptions options) throws InvalidRequestException
{
conditions.addConditionsTo(request, clustering, options);
}
@ -717,7 +718,7 @@ public abstract class ModificationStatement implements CQLStatement
}
else
{
NavigableSet<Clustering> clusterings = createClustering(options);
NavigableSet<Clustering<?>> clusterings = createClustering(options);
// If some of the restrictions were unspecified (e.g. empty IN restrictions) we do not need to do anything.
if (restrictions.hasClusteringColumnsRestrictions() && clusterings.isEmpty())
@ -738,15 +739,9 @@ public abstract class ModificationStatement implements CQLStatement
}
else
{
for (Clustering clustering : clusterings)
for (Clustering<?> clustering : clusterings)
{
for (ByteBuffer c : clustering.getRawValues())
{
if (c != null && c.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
throw new InvalidRequestException(String.format("Key length of %d is longer than maximum of %d",
clustering.dataSize(),
FBUtilities.MAX_UNSIGNED_SHORT));
}
validateClustering(clustering);
addUpdateForKey(updateBuilder, clustering, params);
}
}
@ -754,16 +749,28 @@ public abstract class ModificationStatement implements CQLStatement
}
}
private <V> void validateClustering(Clustering<V> clustering)
{
ValueAccessor<V> accessor = clustering.accessor();
for (V v : clustering.getRawValues())
{
if (v != null && accessor.size(v) > FBUtilities.MAX_UNSIGNED_SHORT)
throw new InvalidRequestException(String.format("Key length of %d is longer than maximum of %d",
clustering.dataSize(),
FBUtilities.MAX_UNSIGNED_SHORT));
}
}
Slices createSlices(QueryOptions options)
{
SortedSet<ClusteringBound> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options);
SortedSet<ClusteringBound> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options);
SortedSet<ClusteringBound<?>> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options);
SortedSet<ClusteringBound<?>> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options);
return toSlices(startBounds, endBounds);
}
private UpdateParameters makeUpdateParameters(Collection<ByteBuffer> keys,
NavigableSet<Clustering> clusterings,
NavigableSet<Clustering<?>> clusterings,
QueryOptions options,
boolean local,
long timestamp,
@ -818,14 +825,14 @@ public abstract class ModificationStatement implements CQLStatement
lists);
}
private Slices toSlices(SortedSet<ClusteringBound> startBounds, SortedSet<ClusteringBound> endBounds)
private Slices toSlices(SortedSet<ClusteringBound<?>> startBounds, SortedSet<ClusteringBound<?>> endBounds)
{
assert startBounds.size() == endBounds.size();
Slices.Builder builder = new Slices.Builder(metadata().comparator);
Iterator<ClusteringBound> starts = startBounds.iterator();
Iterator<ClusteringBound> ends = endBounds.iterator();
Iterator<ClusteringBound<?>> starts = startBounds.iterator();
Iterator<ClusteringBound<?>> ends = endBounds.iterator();
while (starts.hasNext())
{

View File

@ -544,7 +544,7 @@ public class SelectStatement implements CQLStatement
return ((ClusteringIndexSliceFilter)filter).requestedSlices();
Slices.Builder builder = new Slices.Builder(table.comparator);
for (Clustering clustering: ((ClusteringIndexNamesFilter)filter).requestedRows())
for (Clustering<?> clustering: ((ClusteringIndexNamesFilter)filter).requestedRows())
builder.add(Slice.make(clustering));
return builder.build();
}
@ -616,7 +616,7 @@ public class SelectStatement implements CQLStatement
return new ClusteringIndexSliceFilter(slices, isReversed);
}
NavigableSet<Clustering> clusterings = getRequestedRows(options);
NavigableSet<Clustering<?>> clusterings = getRequestedRows(options);
// We can have no clusterings if either we're only selecting the static columns, or if we have
// a 'IN ()' for clusterings. In that case, we still want to query if some static columns are
// queried. But we're fine otherwise.
@ -630,27 +630,27 @@ public class SelectStatement implements CQLStatement
public Slices makeSlices(QueryOptions options)
throws InvalidRequestException
{
SortedSet<ClusteringBound> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options);
SortedSet<ClusteringBound> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options);
SortedSet<ClusteringBound<?>> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options);
SortedSet<ClusteringBound<?>> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options);
assert startBounds.size() == endBounds.size();
// The case where startBounds == 1 is common enough that it's worth optimizing
if (startBounds.size() == 1)
{
ClusteringBound start = startBounds.first();
ClusteringBound end = endBounds.first();
ClusteringBound<?> start = startBounds.first();
ClusteringBound<?> end = endBounds.first();
return Slice.isEmpty(table.comparator, start, end)
? Slices.NONE
: Slices.with(table.comparator, Slice.make(start, end));
}
Slices.Builder builder = new Slices.Builder(table.comparator, startBounds.size());
Iterator<ClusteringBound> startIter = startBounds.iterator();
Iterator<ClusteringBound> endIter = endBounds.iterator();
Iterator<ClusteringBound<?>> startIter = startBounds.iterator();
Iterator<ClusteringBound<?>> endIter = endBounds.iterator();
while (startIter.hasNext() && endIter.hasNext())
{
ClusteringBound start = startIter.next();
ClusteringBound end = endIter.next();
ClusteringBound<?> start = startIter.next();
ClusteringBound<?> end = endIter.next();
// Ignore slices that are nonsensical
if (Slice.isEmpty(table.comparator, start, end))
@ -748,7 +748,7 @@ public class SelectStatement implements CQLStatement
return userLimit;
}
private NavigableSet<Clustering> getRequestedRows(QueryOptions options) throws InvalidRequestException
private NavigableSet<Clustering<?>> getRequestedRows(QueryOptions options) throws InvalidRequestException
{
// Note: getRequestedColumns don't handle static columns, but due to CASSANDRA-5762
// we always do a slice for CQL3 tables, so it's ok to ignore them here
@ -860,7 +860,7 @@ public class SelectStatement implements CQLStatement
result.add(keyComponents[def.position()]);
break;
case CLUSTERING:
result.add(row.clustering().get(def.position()));
result.add(row.clustering().bufferAt(def.position()));
break;
case REGULAR:
addValue(result, def, row, nowInSec, protocolVersion);

View File

@ -57,7 +57,7 @@ public class UpdateStatement extends ModificationStatement
}
@Override
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params)
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params)
{
if (updatesRegularRows())
{

View File

@ -0,0 +1,53 @@
/*
* 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.nio.ByteBuffer;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.db.marshal.ValueAccessor;
public abstract class AbstractArrayClusteringPrefix extends AbstractOnHeapClusteringPrefix<byte[]>
{
public static final byte[][] EMPTY_VALUES_ARRAY = new byte[0][];
public AbstractArrayClusteringPrefix(Kind kind, byte[][] values)
{
super(kind, values);
}
public ValueAccessor<byte[]> accessor()
{
return ByteArrayAccessor.instance;
}
public ByteBuffer[] getBufferArray()
{
ByteBuffer[] out = new ByteBuffer[values.length];
for (int i=0; i<values.length; i++)
out[i] = ByteBuffer.wrap(values[i]);
return out;
}
public ClusteringPrefix<byte[]> minimize()
{
return this;
}
}

View File

@ -19,53 +19,33 @@ package org.apache.cassandra.db;
import java.nio.ByteBuffer;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.utils.ByteBufferUtil;
public abstract class AbstractBufferClusteringPrefix extends AbstractClusteringPrefix
public abstract class AbstractBufferClusteringPrefix extends AbstractOnHeapClusteringPrefix<ByteBuffer>
{
public static final ByteBuffer[] EMPTY_VALUES_ARRAY = new ByteBuffer[0];
protected final Kind kind;
protected final ByteBuffer[] values;
protected AbstractBufferClusteringPrefix(Kind kind, ByteBuffer[] values)
{
this.kind = kind;
this.values = values;
super(kind, values);
}
public Kind kind()
public ValueAccessor<ByteBuffer> accessor()
{
return kind;
return ByteBufferAccessor.instance;
}
public ClusteringPrefix clustering()
public ByteBuffer[] getBufferArray()
{
return this;
return getRawValues();
}
public int size()
public ClusteringPrefix<ByteBuffer> minimize()
{
return values.length;
}
public ByteBuffer get(int i)
{
return values[i];
}
public ByteBuffer[] getRawValues()
{
return values;
}
public long unsharedHeapSize()
{
return Clustering.EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values);
}
public long unsharedHeapSizeExcludingData()
{
return Clustering.EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(values);
if (!ByteBufferUtil.canMinimize(values))
return this;
return new BufferClustering(ByteBufferUtil.minimizeBuffers(values));
}
}

View File

@ -1,77 +0,0 @@
/*
* 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.nio.ByteBuffer;
import java.util.Objects;
public abstract class AbstractClusteringPrefix implements ClusteringPrefix
{
public ClusteringPrefix clustering()
{
return this;
}
public int dataSize()
{
int size = 0;
for (int i = 0; i < size(); i++)
{
ByteBuffer bb = get(i);
size += bb == null ? 0 : bb.remaining();
}
return size;
}
public void digest(Digest digest)
{
for (int i = 0; i < size(); i++)
{
ByteBuffer bb = get(i);
if (bb != null)
digest.update(bb);
}
digest.updateWithByte(kind().ordinal());
}
@Override
public final int hashCode()
{
int result = 31;
for (int i = 0; i < size(); i++)
result += 31 * Objects.hashCode(get(i));
return 31 * result + Objects.hashCode(kind());
}
@Override
public final boolean equals(Object o)
{
if(!(o instanceof ClusteringPrefix))
return false;
ClusteringPrefix that = (ClusteringPrefix)o;
if (this.kind() != that.kind() || this.size() != that.size())
return false;
for (int i = 0; i < size(); i++)
if (!Objects.equals(this.get(i), that.get(i)))
return false;
return true;
}
}

View File

@ -0,0 +1,67 @@
/*
* 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;
public abstract class AbstractOnHeapClusteringPrefix<V> implements ClusteringPrefix<V>
{
protected final Kind kind;
protected final V[] values;
public AbstractOnHeapClusteringPrefix(Kind kind, V[] values)
{
this.kind = kind;
this.values = values;
}
public Kind kind()
{
return kind;
}
public ClusteringPrefix<V> clustering()
{
return this;
}
public int size()
{
return values.length;
}
public V get(int i)
{
return values[i];
}
public V[] getRawValues()
{
return values;
}
@Override
public int hashCode()
{
return ClusteringPrefix.hashCode(this);
}
@Override
public boolean equals(Object o)
{
return ClusteringPrefix.equals(this, o);
}
}

View File

@ -45,10 +45,10 @@ public abstract class AbstractReadCommandBuilder
protected Set<ColumnIdentifier> columns;
protected final RowFilter filter = RowFilter.create();
private ClusteringBound lowerClusteringBound;
private ClusteringBound upperClusteringBound;
private ClusteringBound<?> lowerClusteringBound;
private ClusteringBound<?> upperClusteringBound;
private NavigableSet<Clustering> clusterings;
private NavigableSet<Clustering<?>> clusterings;
// Use Util.cmd() instead of this ctor directly
AbstractReadCommandBuilder(ColumnFamilyStore cfs)
@ -197,8 +197,8 @@ public abstract class AbstractReadCommandBuilder
}
else
{
Slice slice = Slice.make(lowerClusteringBound == null ? ClusteringBound.BOTTOM : lowerClusteringBound,
upperClusteringBound == null ? ClusteringBound.TOP : upperClusteringBound);
Slice slice = Slice.make(lowerClusteringBound == null ? BufferClusteringBound.BOTTOM : lowerClusteringBound,
upperClusteringBound == null ? BufferClusteringBound.TOP : upperClusteringBound);
return new ClusteringIndexSliceFilter(Slices.with(cfs.metadata().comparator, slice), reversed);
}
}
@ -230,37 +230,6 @@ public abstract class AbstractReadCommandBuilder
}
}
public static class SinglePartitionSliceBuilder extends AbstractReadCommandBuilder
{
private final DecoratedKey partitionKey;
private Slices.Builder sliceBuilder;
public SinglePartitionSliceBuilder(ColumnFamilyStore cfs, DecoratedKey key)
{
super(cfs);
this.partitionKey = key;
sliceBuilder = new Slices.Builder(cfs.getComparator());
}
public SinglePartitionSliceBuilder addSlice(Slice slice)
{
sliceBuilder.add(slice);
return this;
}
@Override
protected ClusteringIndexFilter makeFilter()
{
return new ClusteringIndexSliceFilter(sliceBuilder.build(), reversed);
}
@Override
public ReadCommand build()
{
return SinglePartitionReadCommand.create(cfs.metadata(), nowInSeconds, makeColumnFilter(), filter, makeLimits(), partitionKey, makeFilter());
}
}
public static class PartitionRangeBuilder extends AbstractReadCommandBuilder
{
private DecoratedKey startKey;

View File

@ -0,0 +1,46 @@
/*
* 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 org.apache.cassandra.utils.ObjectSizes;
public class ArrayClustering extends AbstractArrayClusteringPrefix implements Clustering<byte[]>
{
private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayClustering(EMPTY_VALUES_ARRAY));
public ArrayClustering(byte[]... values)
{
super(Kind.CLUSTERING, values);
}
public long unsharedHeapSize()
{
return EMPTY_SIZE + ObjectSizes.sizeOfArray(values) + values.length;
}
public long unsharedHeapSizeExcludingData()
{
return EMPTY_SIZE + ObjectSizes.sizeOfArray(values);
}
public static ArrayClustering make(byte[]... values)
{
return new ArrayClustering(values);
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.nio.ByteBuffer;
import com.google.common.base.Preconditions;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.memory.AbstractAllocator;
public class ArrayClusteringBound extends ArrayClusteringBoundOrBoundary implements ClusteringBound<byte[]>
{
private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY));
public ArrayClusteringBound(Kind kind, byte[][] values)
{
super(kind, values);
}
public long unsharedHeapSize()
{
return EMPTY_SIZE + ObjectSizes.sizeOfArray(values) + values.length;
}
@Override
public ClusteringBound<byte[]> invert()
{
return create(kind().invert(), values);
}
public ClusteringBound<ByteBuffer> copy(AbstractAllocator allocator)
{
return (ClusteringBound<ByteBuffer>) super.copy(allocator);
}
public static ArrayClusteringBound create(ClusteringPrefix.Kind kind, byte[][] values)
{
Preconditions.checkArgument(!kind.isBoundary(), "Expected bound clustering kind, got %s", kind);
return new ArrayClusteringBound(kind, values);
}
}

View File

@ -0,0 +1,37 @@
/*
* 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 com.google.common.base.Preconditions;
public abstract class ArrayClusteringBoundOrBoundary extends AbstractArrayClusteringPrefix implements ClusteringBoundOrBoundary<byte[]>
{
public ArrayClusteringBoundOrBoundary(Kind kind, byte[][] values)
{
super(kind, values);
Preconditions.checkArgument(values.length > 0 || !kind.isBoundary(),
"Cannot create bounds/boundary objects without clustering values");
}
public static ClusteringBoundOrBoundary<byte[]> create(Kind kind, byte[][] values)
{
return kind.isBoundary()
? new ArrayClusteringBoundary(kind, values)
: new ArrayClusteringBound(kind, values);
}
}

View File

@ -0,0 +1,60 @@
/*
* 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 com.google.common.base.Preconditions;
import org.apache.cassandra.utils.ObjectSizes;
public class ArrayClusteringBoundary extends ArrayClusteringBoundOrBoundary implements ClusteringBoundary<byte[]>
{
private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayClusteringBoundary(ClusteringPrefix.Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY));
public ArrayClusteringBoundary(Kind kind, byte[][] values)
{
super(kind, values);
}
public long unsharedHeapSize()
{
return EMPTY_SIZE + ObjectSizes.sizeOfArray(values) + values.length;
}
public static ClusteringBoundary<byte[]> create(Kind kind, byte[][] values)
{
Preconditions.checkArgument(kind.isBoundary(), "Expected boundary clustering kind, got %s", kind);
return new ArrayClusteringBoundary(kind, values);
}
@Override
public ClusteringBoundary<byte[]> invert()
{
return create(kind().invert(), values);
}
public ClusteringBound<byte[]> openBound(boolean reversed)
{
return ArrayClusteringBound.create(kind.openBoundOfBoundary(reversed), values);
}
public ClusteringBound<byte[]> closeBound(boolean reversed)
{
return ArrayClusteringBound.create(kind.closeBoundOfBoundary(reversed), values);
}
}

View File

@ -20,6 +20,7 @@ package org.apache.cassandra.db;
import java.nio.ByteBuffer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.ObjectSizes;
/**
* The clustering column values for a row.
@ -32,17 +33,27 @@ import org.apache.cassandra.utils.ByteBufferUtil;
* {@code null} values (this is currently only allowed in COMPACT table for historical reasons, but we
* could imagine lifting that limitation if we decide it make sense from a CQL point of view).
*/
public class BufferClustering extends AbstractBufferClusteringPrefix implements Clustering
public class BufferClustering extends AbstractBufferClusteringPrefix implements Clustering<ByteBuffer>
{
BufferClustering(ByteBuffer... values)
private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClustering(EMPTY_VALUES_ARRAY));
public BufferClustering(ByteBuffer... values)
{
super(Kind.CLUSTERING, values);
}
public ClusteringPrefix minimize()
public long unsharedHeapSize()
{
if (!ByteBufferUtil.canMinimize(values))
return this;
return new BufferClustering(ByteBufferUtil.minimizeBuffers(values));
return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values);
}
public long unsharedHeapSizeExcludingData()
{
return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(values);
}
public static BufferClustering make(ByteBuffer... values)
{
return new BufferClustering(values);
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.nio.ByteBuffer;
import com.google.common.base.Preconditions;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.memory.AbstractAllocator;
public class BufferClusteringBound extends BufferClusteringBoundOrBoundary implements ClusteringBound<ByteBuffer>
{
private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClusteringBound(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY));
public BufferClusteringBound(ClusteringPrefix.Kind kind, ByteBuffer[] values)
{
super(kind, values);
}
public long unsharedHeapSize()
{
return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values);
}
@Override
public ClusteringBound<ByteBuffer> invert()
{
return create(kind().invert(), values);
}
public ClusteringBound<ByteBuffer> copy(AbstractAllocator allocator)
{
return (ClusteringBound<ByteBuffer>) super.copy(allocator);
}
public static BufferClusteringBound create(ClusteringPrefix.Kind kind, ByteBuffer[] values)
{
Preconditions.checkArgument(!kind.isBoundary(), "Expected bound clustering kind, got %s", kind);
return new BufferClusteringBound(kind, values);
}
public static BufferClusteringBound inclusiveStartOf(ByteBuffer... values)
{
return create(ClusteringPrefix.Kind.INCL_START_BOUND, values);
}
public static BufferClusteringBound inclusiveEndOf(ByteBuffer... values)
{
return create(ClusteringPrefix.Kind.INCL_END_BOUND, values);
}
public static BufferClusteringBound exclusiveStartOf(ByteBuffer... values)
{
return create(ClusteringPrefix.Kind.EXCL_START_BOUND, values);
}
public static BufferClusteringBound exclusiveEndOf(ByteBuffer... values)
{
return create(ClusteringPrefix.Kind.EXCL_END_BOUND, values);
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.nio.ByteBuffer;
import com.google.common.base.Preconditions;
public abstract class BufferClusteringBoundOrBoundary extends AbstractBufferClusteringPrefix implements ClusteringBoundOrBoundary<ByteBuffer>
{
BufferClusteringBoundOrBoundary(Kind kind, ByteBuffer[] values)
{
super(kind, values);
Preconditions.checkArgument(values.length > 0 || !kind.isBoundary(),
"Cannot create bounds/boundary objects without clustering values");
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.nio.ByteBuffer;
import com.google.common.base.Preconditions;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.memory.AbstractAllocator;
public class BufferClusteringBoundary extends BufferClusteringBoundOrBoundary implements ClusteringBoundary<ByteBuffer>
{
private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClusteringBoundary(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY));
public BufferClusteringBoundary(Kind kind, ByteBuffer[] values)
{
super(kind, values);
}
public long unsharedHeapSize()
{
return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values);
}
public static ClusteringBoundary<ByteBuffer> create(Kind kind, ByteBuffer[] values)
{
Preconditions.checkArgument(kind.isBoundary(), "Expected boundary clustering kind, got %s", kind);
return new BufferClusteringBoundary(kind, values);
}
@Override
public ClusteringBoundary<ByteBuffer> invert()
{
return create(kind().invert(), values);
}
@Override
public ClusteringBoundary<ByteBuffer> copy(AbstractAllocator allocator)
{
return (ClusteringBoundary<ByteBuffer>) super.copy(allocator);
}
public ClusteringBound<ByteBuffer> openBound(boolean reversed)
{
return BufferClusteringBound.create(kind.openBoundOfBoundary(reversed), values);
}
public ClusteringBound<ByteBuffer> closeBound(boolean reversed)
{
return BufferClusteringBound.create(kind.closeBoundOfBoundary(reversed), values);
}
}

View File

@ -22,6 +22,8 @@ import java.util.Arrays;
import java.util.List;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.marshal.ValueAccessor;
/**
* Allows to build ClusteringPrefixes, either Clustering or ClusteringBound.
@ -45,7 +47,7 @@ public abstract class CBuilder
throw new UnsupportedOperationException();
}
public CBuilder add(ByteBuffer value)
public <T> CBuilder add(T value, ValueAccessor<T> accessor)
{
throw new UnsupportedOperationException();
}
@ -55,37 +57,22 @@ public abstract class CBuilder
throw new UnsupportedOperationException();
}
public Clustering build()
public Clustering<?> build()
{
return Clustering.STATIC_CLUSTERING;
}
public ClusteringBound buildBound(boolean isStart, boolean isInclusive)
public ClusteringBound<?> buildBound(boolean isStart, boolean isInclusive)
{
throw new UnsupportedOperationException();
}
public Slice buildSlice()
public Clustering<?> buildWith(List<ByteBuffer> newValues)
{
throw new UnsupportedOperationException();
}
public Clustering buildWith(ByteBuffer value)
{
throw new UnsupportedOperationException();
}
public Clustering buildWith(List<ByteBuffer> newValues)
{
throw new UnsupportedOperationException();
}
public ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive)
{
throw new UnsupportedOperationException();
}
public ClusteringBound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive)
public ClusteringBound<?> buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive)
{
throw new UnsupportedOperationException();
}
@ -99,15 +86,20 @@ public abstract class CBuilder
public abstract int count();
public abstract int remainingCount();
public abstract ClusteringComparator comparator();
public abstract CBuilder add(ByteBuffer value);
public final CBuilder add(ByteBuffer value)
{
return add(value, ByteBufferAccessor.instance);
}
public final <V> CBuilder add(ClusteringPrefix<V> prefix, int i)
{
return add(prefix.get(i), prefix.accessor());
}
public abstract <V> CBuilder add(V value, ValueAccessor<V> accessor);
public abstract CBuilder add(Object value);
public abstract Clustering build();
public abstract ClusteringBound buildBound(boolean isStart, boolean isInclusive);
public abstract Slice buildSlice();
public abstract Clustering buildWith(ByteBuffer value);
public abstract Clustering buildWith(List<ByteBuffer> newValues);
public abstract ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive);
public abstract ClusteringBound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive);
public abstract Clustering<?> build();
public abstract ClusteringBound<?> buildBound(boolean isStart, boolean isInclusive);
public abstract Clustering<?> buildWith(List<ByteBuffer> newValues);
public abstract ClusteringBound<?> buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive);
private static class ArrayBackedBuilder extends CBuilder
{
@ -137,11 +129,11 @@ public abstract class CBuilder
return type;
}
public CBuilder add(ByteBuffer value)
public <V> CBuilder add(V value, ValueAccessor<V> accessor)
{
if (isDone())
throw new IllegalStateException();
values[size++] = value;
values[size++] = accessor.toBuffer(value);
return this;
}
@ -155,7 +147,7 @@ public abstract class CBuilder
return remainingCount() == 0 || built;
}
public Clustering build()
public Clustering<?> build()
{
// We don't allow to add more element to a builder that has been built so
// that we don't have to copy values.
@ -165,41 +157,20 @@ public abstract class CBuilder
return size == 0 ? Clustering.EMPTY : Clustering.make(values);
}
public ClusteringBound buildBound(boolean isStart, boolean isInclusive)
public ClusteringBound<?> buildBound(boolean isStart, boolean isInclusive)
{
// We don't allow to add more element to a builder that has been built so
// that we don't have to copy values (even though we have to do it in most cases).
built = true;
if (size == 0)
return isStart ? ClusteringBound.BOTTOM : ClusteringBound.TOP;
return isStart ? BufferClusteringBound.BOTTOM : BufferClusteringBound.TOP;
return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive),
return BufferClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive),
size == values.length ? values : Arrays.copyOfRange(values, 0, size));
}
public Slice buildSlice()
{
// We don't allow to add more element to a builder that has been built so
// that we don't have to copy values.
built = true;
if (size == 0)
return Slice.ALL;
return Slice.make(buildBound(true, true), buildBound(false, true));
}
public Clustering buildWith(ByteBuffer value)
{
assert size+1 <= type.size();
ByteBuffer[] newValues = Arrays.copyOf(values, type.size());
newValues[size] = value;
return Clustering.make(newValues);
}
public Clustering buildWith(List<ByteBuffer> newValues)
public Clustering<?> buildWith(List<ByteBuffer> newValues)
{
assert size + newValues.size() <= type.size();
ByteBuffer[] buffers = Arrays.copyOf(values, type.size());
@ -210,21 +181,14 @@ public abstract class CBuilder
return Clustering.make(buffers);
}
public ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive)
{
ByteBuffer[] newValues = Arrays.copyOf(values, size+1);
newValues[size] = value;
return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues);
}
public ClusteringBound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive)
public ClusteringBound<?> buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive)
{
ByteBuffer[] buffers = Arrays.copyOf(values, size + newValues.size());
int newSize = size;
for (ByteBuffer value : newValues)
buffers[newSize++] = value;
return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), buffers);
return BufferClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), buffers);
}
}
}

View File

@ -21,7 +21,7 @@ package org.apache.cassandra.db;
* Common class for objects that are identified by a clustering prefix, and can be thus sorted by a
* {@link ClusteringComparator}.
*/
public interface Clusterable
public interface Clusterable<T>
{
public ClusteringPrefix clustering();
public ClusteringPrefix<T> clustering();
}

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.db.marshal.AbstractType;
@ -29,20 +30,17 @@ 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.ObjectSizes;
import org.apache.cassandra.utils.memory.AbstractAllocator;
import static org.apache.cassandra.db.AbstractBufferClusteringPrefix.EMPTY_VALUES_ARRAY;
public interface Clustering extends ClusteringPrefix
public interface Clustering<V> extends ClusteringPrefix<V>
{
static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClustering(EMPTY_VALUES_ARRAY));
public static final Serializer serializer = new Serializer();
public long unsharedHeapSizeExcludingData();
public default Clustering copy(AbstractAllocator allocator)
public default Clustering<?> copy(AbstractAllocator allocator)
{
// Important for STATIC_CLUSTERING (but must copy empty native clustering types).
if (size() == 0)
@ -51,7 +49,7 @@ public interface Clustering extends ClusteringPrefix
ByteBuffer[] newValues = new ByteBuffer[size()];
for (int i = 0; i < size(); i++)
{
ByteBuffer val = get(i);
ByteBuffer val = accessor().toBuffer(get(i));
newValues[i] = val == null ? null : allocator.clone(val);
}
return new BufferClustering(newValues);
@ -63,7 +61,7 @@ public interface Clustering extends ClusteringPrefix
for (int i = 0; i < size(); i++)
{
ColumnMetadata c = metadata.clusteringColumns().get(i);
sb.append(i == 0 ? "" : ", ").append(c.name).append('=').append(get(i) == null ? "null" : c.type.getString(get(i)));
sb.append(i == 0 ? "" : ", ").append(c.name).append('=').append(get(i) == null ? "null" : c.type.getString(get(i), accessor()));
}
return sb.toString();
}
@ -74,12 +72,12 @@ public interface Clustering extends ClusteringPrefix
for (int i = 0; i < size(); i++)
{
ColumnMetadata c = metadata.clusteringColumns().get(i);
sb.append(i == 0 ? "" : ", ").append(c.type.getString(get(i)));
sb.append(i == 0 ? "" : ", ").append(c.type.getString(get(i), accessor()));
}
return sb.toString();
}
public static Clustering make(ByteBuffer... values)
public static Clustering<ByteBuffer> make(ByteBuffer... values)
{
return values.length == 0 ? EMPTY : new BufferClustering(values);
}
@ -88,7 +86,7 @@ public interface Clustering extends ClusteringPrefix
* 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)
public static final Clustering<ByteBuffer> STATIC_CLUSTERING = new BufferClustering(EMPTY_VALUES_ARRAY)
{
@Override
public Kind kind()
@ -110,7 +108,7 @@ public interface Clustering extends ClusteringPrefix
};
/** Empty clustering for tables having no clustering columns. */
public static final Clustering EMPTY = new BufferClustering(EMPTY_VALUES_ARRAY)
public static final Clustering<ByteBuffer> EMPTY = new BufferClustering(EMPTY_VALUES_ARRAY)
{
@Override
public String toString(TableMetadata metadata)
@ -127,14 +125,14 @@ public interface Clustering extends ClusteringPrefix
*/
public static class Serializer
{
public void serialize(Clustering clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
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)
public ByteBuffer serialize(Clustering<?> clustering, int version, List<AbstractType<?>> types)
{
try (DataOutputBuffer buffer = new DataOutputBuffer((int)serializedSize(clustering, version, types)))
{
@ -147,7 +145,7 @@ public interface Clustering extends ClusteringPrefix
}
}
public long serializedSize(Clustering clustering, int version, List<AbstractType<?>> types)
public long serializedSize(Clustering<?> clustering, int version, List<AbstractType<?>> types)
{
return ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(clustering, version, types);
}
@ -158,16 +156,16 @@ public interface Clustering extends ClusteringPrefix
ClusteringPrefix.serializer.skipValuesWithoutSize(in, types.size(), version, types);
}
public Clustering deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
public Clustering<byte[]> deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
{
if (types.isEmpty())
return EMPTY;
return ByteArrayAccessor.factory.clustering();
ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, types.size(), version, types);
return new BufferClustering(values);
byte[][] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, types.size(), version, types);
return ByteArrayAccessor.factory.clustering(values);
}
public Clustering deserialize(ByteBuffer in, int version, List<AbstractType<?>> types)
public Clustering<byte[]> deserialize(ByteBuffer in, int version, List<AbstractType<?>> types)
{
try (DataInputBuffer buffer = new DataInputBuffer(in, true))
{

View File

@ -23,135 +23,55 @@ package org.apache.cassandra.db;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.utils.memory.AbstractAllocator;
/**
* The start or end of a range of clusterings, either inclusive or exclusive.
*/
public class ClusteringBound extends ClusteringBoundOrBoundary
public interface ClusteringBound<V> extends ClusteringBoundOrBoundary<V>
{
/** The smallest start bound, i.e. the one that starts before any row. */
public static final ClusteringBound BOTTOM = new ClusteringBound(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY);
public static final ClusteringBound<?> BOTTOM = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, BufferClusteringBound.EMPTY_VALUES_ARRAY);
/** The biggest end bound, i.e. the one that ends after any row. */
public static final ClusteringBound TOP = new ClusteringBound(Kind.INCL_END_BOUND, EMPTY_VALUES_ARRAY);
public static final ClusteringBound<?> TOP = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_END_BOUND, BufferClusteringBound.EMPTY_VALUES_ARRAY);
protected ClusteringBound(Kind kind, ByteBuffer[] values)
{
super(kind, values);
}
public ClusteringPrefix minimize()
{
if (!ByteBufferUtil.canMinimize(values))
return this;
return new ClusteringBound(kind, ByteBufferUtil.minimizeBuffers(values));
}
public static ClusteringBound create(Kind kind, ByteBuffer[] values)
{
assert !kind.isBoundary();
return new ClusteringBound(kind, values);
}
public static Kind boundKind(boolean isStart, boolean isInclusive)
public static ClusteringPrefix.Kind boundKind(boolean isStart, boolean isInclusive)
{
return isStart
? (isInclusive ? Kind.INCL_START_BOUND : Kind.EXCL_START_BOUND)
: (isInclusive ? Kind.INCL_END_BOUND : Kind.EXCL_END_BOUND);
}
public static ClusteringBound inclusiveStartOf(ByteBuffer... values)
{
return create(Kind.INCL_START_BOUND, values);
}
public static ClusteringBound inclusiveEndOf(ByteBuffer... values)
{
return create(Kind.INCL_END_BOUND, values);
}
public static ClusteringBound exclusiveStartOf(ByteBuffer... values)
{
return create(Kind.EXCL_START_BOUND, values);
}
public static ClusteringBound exclusiveEndOf(ByteBuffer... values)
{
return create(Kind.EXCL_END_BOUND, values);
}
public static ClusteringBound inclusiveStartOf(ClusteringPrefix prefix)
{
ByteBuffer[] values = new ByteBuffer[prefix.size()];
for (int i = 0; i < prefix.size(); i++)
values[i] = prefix.get(i);
return inclusiveStartOf(values);
}
public static ClusteringBound exclusiveStartOf(ClusteringPrefix prefix)
{
ByteBuffer[] values = new ByteBuffer[prefix.size()];
for (int i = 0; i < prefix.size(); i++)
values[i] = prefix.get(i);
return exclusiveStartOf(values);
}
public static ClusteringBound inclusiveEndOf(ClusteringPrefix prefix)
{
ByteBuffer[] values = new ByteBuffer[prefix.size()];
for (int i = 0; i < prefix.size(); i++)
values[i] = prefix.get(i);
return inclusiveEndOf(values);
}
public static ClusteringBound create(ClusteringComparator comparator, boolean isStart, boolean isInclusive, Object... values)
{
CBuilder builder = CBuilder.create(comparator);
for (Object val : values)
{
if (val instanceof ByteBuffer)
builder.add((ByteBuffer) val);
else
builder.add(val);
}
return builder.buildBound(isStart, isInclusive);
? (isInclusive ? ClusteringPrefix.Kind.INCL_START_BOUND : ClusteringPrefix.Kind.EXCL_START_BOUND)
: (isInclusive ? ClusteringPrefix.Kind.INCL_END_BOUND : ClusteringPrefix.Kind.EXCL_END_BOUND);
}
@Override
public ClusteringBound invert()
{
return create(kind().invert(), values);
}
ClusteringBound<V> invert();
public ClusteringBound copy(AbstractAllocator allocator)
{
return (ClusteringBound) super.copy(allocator);
}
@Override
ClusteringBound<ByteBuffer> copy(AbstractAllocator allocator);
public boolean isStart()
default boolean isStart()
{
return kind().isStart();
}
public boolean isEnd()
default boolean isEnd()
{
return !isStart();
}
public boolean isInclusive()
default boolean isInclusive()
{
return kind == Kind.INCL_START_BOUND || kind == Kind.INCL_END_BOUND;
return kind() == Kind.INCL_START_BOUND || kind() == Kind.INCL_END_BOUND;
}
public boolean isExclusive()
default boolean isExclusive()
{
return kind == Kind.EXCL_START_BOUND || kind == Kind.EXCL_END_BOUND;
return kind() == Kind.EXCL_START_BOUND || kind() == Kind.EXCL_END_BOUND;
}
// For use by intersects, it's called with the sstable bound opposite to the slice bound
// (so if the slice bound is a start, it's call with the max sstable bound)
int compareTo(ClusteringComparator comparator, List<ByteBuffer> sstableBound)
default int compareTo(ClusteringComparator comparator, List<ByteBuffer> sstableBound)
{
for (int i = 0; i < sstableBound.size(); i++)
{
@ -162,7 +82,7 @@ public class ClusteringBound extends ClusteringBoundOrBoundary
if (i >= size())
return isStart() ? -1 : 1;
int cmp = comparator.compareComponent(i, get(i), sstableBound.get(i));
int cmp = comparator.compareComponent(i, get(i), accessor(), sstableBound.get(i), ByteBufferAccessor.instance);
if (cmp != 0)
return cmp;
}
@ -176,4 +96,42 @@ public class ClusteringBound extends ClusteringBoundOrBoundary
// The slice bound is equal to the sstable bound. Results depends on whether the slice is inclusive or not
return isInclusive() ? 0 : (isStart() ? 1 : -1);
}
static <V> ClusteringBound<V> create(ClusteringPrefix.Kind kind, ClusteringPrefix<V> from)
{
return from.accessor().factory().bound(kind, from.getRawValues());
}
public static ClusteringBound<?> inclusiveStartOf(ClusteringPrefix<?> from)
{
return create(ClusteringPrefix.Kind.INCL_START_BOUND, from);
}
public static ClusteringBound<?> inclusiveEndOf(ClusteringPrefix<?> from)
{
return create(ClusteringPrefix.Kind.INCL_END_BOUND, from);
}
public static ClusteringBound<?> exclusiveStartOf(ClusteringPrefix<?> from)
{
return create(ClusteringPrefix.Kind.EXCL_START_BOUND, from);
}
public static ClusteringBound<?> exclusiveEndOf(ClusteringPrefix<?> from)
{
return create(ClusteringPrefix.Kind.EXCL_END_BOUND, from);
}
public static ClusteringBound<?> create(ClusteringComparator comparator, boolean isStart, boolean isInclusive, Object... values)
{
CBuilder builder = CBuilder.create(comparator);
for (Object val : values)
{
if (val instanceof ByteBuffer)
builder.add((ByteBuffer) val);
else
builder.add(val);
}
return builder.buildBound(isStart, isInclusive);
}
}

View File

@ -24,6 +24,8 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.io.util.DataInputPlus;
@ -41,82 +43,39 @@ import org.apache.cassandra.utils.memory.AbstractAllocator;
* iterator. See this comment for more details: https://goo.gl/yyB5mR.
* 2) This saves some storage space.
*/
public abstract class ClusteringBoundOrBoundary extends AbstractBufferClusteringPrefix
public interface ClusteringBoundOrBoundary<V> extends ClusteringPrefix<V>
{
public static final ClusteringBoundOrBoundary.Serializer serializer = new Serializer();
protected ClusteringBoundOrBoundary(Kind kind, ByteBuffer[] values)
default boolean isBoundary()
{
super(kind, values);
assert values.length > 0 || !kind.isBoundary();
return kind().isBoundary();
}
public static ClusteringBoundOrBoundary create(Kind kind, ByteBuffer[] values)
default boolean isOpen(boolean reversed)
{
return kind.isBoundary()
? new ClusteringBoundary(kind, values)
: new ClusteringBound(kind, values);
return kind().isOpen(reversed);
}
public boolean isBoundary()
default boolean isClose(boolean reversed)
{
return kind.isBoundary();
return kind().isClose(reversed);
}
public boolean isOpen(boolean reversed)
{
return kind.isOpen(reversed);
}
public boolean isClose(boolean reversed)
{
return kind.isClose(reversed);
}
public static ClusteringBound inclusiveOpen(boolean reversed, ByteBuffer[] boundValues)
{
return new ClusteringBound(reversed ? Kind.INCL_END_BOUND : Kind.INCL_START_BOUND, boundValues);
}
public static ClusteringBound exclusiveOpen(boolean reversed, ByteBuffer[] boundValues)
{
return new ClusteringBound(reversed ? Kind.EXCL_END_BOUND : Kind.EXCL_START_BOUND, boundValues);
}
public static ClusteringBound inclusiveClose(boolean reversed, ByteBuffer[] boundValues)
{
return new ClusteringBound(reversed ? Kind.INCL_START_BOUND : Kind.INCL_END_BOUND, boundValues);
}
public static ClusteringBound exclusiveClose(boolean reversed, ByteBuffer[] boundValues)
{
return new ClusteringBound(reversed ? Kind.EXCL_START_BOUND : Kind.EXCL_END_BOUND, boundValues);
}
public static ClusteringBoundary inclusiveCloseExclusiveOpen(boolean reversed, ByteBuffer[] boundValues)
{
return new ClusteringBoundary(reversed ? Kind.EXCL_END_INCL_START_BOUNDARY : Kind.INCL_END_EXCL_START_BOUNDARY, boundValues);
}
public static ClusteringBoundary exclusiveCloseInclusiveOpen(boolean reversed, ByteBuffer[] boundValues)
{
return new ClusteringBoundary(reversed ? Kind.INCL_END_EXCL_START_BOUNDARY : Kind.EXCL_END_INCL_START_BOUNDARY, boundValues);
}
public ClusteringBoundOrBoundary copy(AbstractAllocator allocator)
default ClusteringBoundOrBoundary<ByteBuffer> copy(AbstractAllocator allocator)
{
ByteBuffer[] newValues = new ByteBuffer[size()];
for (int i = 0; i < size(); i++)
newValues[i] = allocator.clone(get(i));
return create(kind(), newValues);
newValues[i] = allocator.clone(get(i), accessor());
return ByteBufferAccessor.instance.factory().boundOrBoundary(kind(), newValues);
}
public String toString(TableMetadata metadata)
default String toString(TableMetadata metadata)
{
return toString(metadata.comparator);
}
public String toString(ClusteringComparator comparator)
default String toString(ClusteringComparator comparator)
{
StringBuilder sb = new StringBuilder();
sb.append(kind()).append('(');
@ -124,7 +83,7 @@ public abstract class ClusteringBoundOrBoundary extends AbstractBufferClustering
{
if (i > 0)
sb.append(", ");
sb.append(comparator.subtype(i).getString(get(i)));
sb.append(comparator.subtype(i).getString(get(i), accessor()));
}
return sb.append(')').toString();
}
@ -137,25 +96,25 @@ public abstract class ClusteringBoundOrBoundary extends AbstractBufferClustering
* @return the invert of this bound. For instance, if this bound is an exlusive start, this return
* an inclusive end with the same values.
*/
public abstract ClusteringBoundOrBoundary invert();
public abstract ClusteringBoundOrBoundary<V> invert();
public static class Serializer
{
public void serialize(ClusteringBoundOrBoundary bound, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
public <T> void serialize(ClusteringBoundOrBoundary<T> bound, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
{
out.writeByte(bound.kind().ordinal());
out.writeShort(bound.size());
ClusteringPrefix.serializer.serializeValuesWithoutSize(bound, out, version, types);
}
public long serializedSize(ClusteringBoundOrBoundary bound, int version, List<AbstractType<?>> types)
public <T> long serializedSize(ClusteringBoundOrBoundary<T> bound, int version, List<AbstractType<?>> types)
{
return 1 // kind ordinal
+ TypeSizes.sizeof((short)bound.size())
+ ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(bound, version, types);
}
public ClusteringBoundOrBoundary deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
public ClusteringBoundOrBoundary<byte[]> deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
{
Kind kind = Kind.values()[in.readByte()];
return deserializeValues(in, kind, version, types);
@ -170,14 +129,14 @@ public abstract class ClusteringBoundOrBoundary extends AbstractBufferClustering
ClusteringPrefix.serializer.skipValuesWithoutSize(in, size, version, types);
}
public ClusteringBoundOrBoundary deserializeValues(DataInputPlus in, Kind kind, int version, List<AbstractType<?>> types) throws IOException
public ClusteringBoundOrBoundary<byte[]> deserializeValues(DataInputPlus in, Kind kind, int version, List<AbstractType<?>> types) throws IOException
{
int size = in.readUnsignedShort();
if (size == 0)
return kind.isStart() ? ClusteringBound.BOTTOM : ClusteringBound.TOP;
return ByteArrayAccessor.factory.bound(kind);
ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types);
return create(kind, values);
byte[][] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types);
return ByteArrayAccessor.factory.boundOrBoundary(kind, values);
}
}
}

View File

@ -20,54 +20,21 @@
*/
package org.apache.cassandra.db;
import java.nio.ByteBuffer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.memory.AbstractAllocator;
/**
* The threshold between two different ranges, i.e. a shortcut for the combination of two ClusteringBounds -- one
* specifying the end of one of the ranges, and its (implicit) complement specifying the beginning of the other.
*/
public class ClusteringBoundary extends ClusteringBoundOrBoundary
public interface ClusteringBoundary<V> extends ClusteringBoundOrBoundary<V>
{
protected ClusteringBoundary(Kind kind, ByteBuffer[] values)
{
super(kind, values);
}
public ClusteringPrefix minimize()
{
if (!ByteBufferUtil.canMinimize(values))
return this;
return new ClusteringBoundary(kind, ByteBufferUtil.minimizeBuffers(values));
}
public static ClusteringBoundary create(Kind kind, ByteBuffer[] values)
{
assert kind.isBoundary();
return new ClusteringBoundary(kind, values);
}
@Override
public ClusteringBoundary invert()
{
return create(kind().invert(), values);
}
public ClusteringBoundary<V> invert();
@Override
public ClusteringBoundary copy(AbstractAllocator allocator)
{
return (ClusteringBoundary) super.copy(allocator);
}
public ClusteringBound<V> openBound(boolean reversed);
public ClusteringBound openBound(boolean reversed)
{
return ClusteringBound.create(kind.openBoundOfBoundary(reversed), values);
}
public ClusteringBound<V> closeBound(boolean reversed);
public ClusteringBound closeBound(boolean reversed)
public static <V> ClusteringBoundary<V> create(ClusteringBound.Kind kind, ClusteringPrefix<V> from)
{
return ClusteringBound.create(kind.closeBoundOfBoundary(reversed), values);
return from.accessor().factory().boundary(kind, from.getRawValues());
}
}

View File

@ -25,6 +25,7 @@ import java.util.Objects;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.db.rows.Row;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.serializers.MarshalException;
@ -46,7 +47,8 @@ public class ClusteringComparator implements Comparator<Clusterable>
private final Comparator<IndexInfo> indexReverseComparator;
private final Comparator<Clusterable> reverseComparator;
private final Comparator<Row> rowComparator = (r1, r2) -> compare(r1.clustering(), r2.clustering());
private final Comparator<Row> rowComparator = (r1, r2) -> compare((ClusteringPrefix<?>) r1.clustering(),
(ClusteringPrefix<?>) r2.clustering());
public ClusteringComparator(AbstractType<?>... clusteringTypes)
{
@ -58,8 +60,10 @@ public class ClusteringComparator implements Comparator<Clusterable>
// copy the list to ensure despatch is monomorphic
this.clusteringTypes = ImmutableList.copyOf(clusteringTypes);
this.indexComparator = (o1, o2) -> ClusteringComparator.this.compare(o1.lastName, o2.lastName);
this.indexReverseComparator = (o1, o2) -> ClusteringComparator.this.compare(o1.firstName, o2.firstName);
this.indexComparator = (o1, o2) -> ClusteringComparator.this.compare((ClusteringPrefix<?>) o1.lastName,
(ClusteringPrefix<?>) o2.lastName);
this.indexReverseComparator = (o1, o2) -> ClusteringComparator.this.compare((ClusteringPrefix<?>) o1.firstName,
(ClusteringPrefix<?>) o2.firstName);
this.reverseComparator = (c1, c2) -> ClusteringComparator.this.compare(c2, c1);
for (AbstractType<?> type : clusteringTypes)
type.checkComparable(); // this should already be enforced by TableMetadata.Builder.addColumn, but we check again for other constructors
@ -102,7 +106,7 @@ public class ClusteringComparator implements Comparator<Clusterable>
*
* @return the newly created clustering.
*/
public Clustering make(Object... values)
public Clustering<?> make(Object... values)
{
if (values.length != size())
throw new IllegalArgumentException(String.format("Invalid number of components, expecting %d but got %d", size(), values.length));
@ -120,10 +124,10 @@ public class ClusteringComparator implements Comparator<Clusterable>
public int compare(Clusterable c1, Clusterable c2)
{
return compare(c1.clustering(), c2.clustering());
return compare((ClusteringPrefix<?>) c1.clustering(), (ClusteringPrefix<?>) c2.clustering());
}
public int compare(ClusteringPrefix c1, ClusteringPrefix c2)
public <V1, V2> int compare(ClusteringPrefix<V1> c1, ClusteringPrefix<V2> c2)
{
int s1 = c1.size();
int s2 = c2.size();
@ -131,7 +135,7 @@ public class ClusteringComparator implements Comparator<Clusterable>
for (int i = 0; i < minSize; i++)
{
int cmp = compareComponent(i, c1.get(i), c2.get(i));
int cmp = compareComponent(i, c1.get(i), c1.accessor(), c2.get(i), c2.accessor());
if (cmp != 0)
return cmp;
}
@ -142,7 +146,7 @@ public class ClusteringComparator implements Comparator<Clusterable>
return s1 < s2 ? c1.kind().comparedToClustering : -c2.kind().comparedToClustering;
}
public int compare(Clustering c1, Clustering c2)
public <V1, V2> int compare(Clustering<V1> c1, Clustering<V2> c2)
{
return compare(c1, c2, size());
}
@ -156,25 +160,30 @@ public class ClusteringComparator implements Comparator<Clusterable>
* @return a negative integer, zero, or a positive integer as the first argument is less than,
* equal to, or greater than the second.
*/
public int compare(Clustering c1, Clustering c2, int size)
public <V1, V2> int compare(Clustering<V1> c1, Clustering<V2> c2, int size)
{
for (int i = 0; i < size; i++)
{
int cmp = compareComponent(i, c1.get(i), c2.get(i));
int cmp = compareComponent(i, c1.get(i), c1.accessor(), c2.get(i), c2.accessor());
if (cmp != 0)
return cmp;
}
return 0;
}
public int compareComponent(int i, ByteBuffer v1, ByteBuffer v2)
public <V1, V2> int compareComponent(int i, V1 v1, ValueAccessor<V1> accessor1, V2 v2, ValueAccessor<V2> accessor2)
{
if (v1 == null)
return v2 == null ? 0 : -1;
if (v2 == null)
return 1;
return clusteringTypes.get(i).compare(v1, v2);
return clusteringTypes.get(i).compare(v1, accessor1, v2, accessor2);
}
public <V1, V2> int compareComponent(int i, ClusteringPrefix<V1> v1, ClusteringPrefix<V2> v2)
{
return compareComponent(i, v1.get(i), v1.accessor(), v2.get(i), v2.accessor());
}
/**
@ -212,13 +221,14 @@ public class ClusteringComparator implements Comparator<Clusterable>
*
* @throws MarshalException if {@code clustering} contains some invalid data.
*/
public void validate(ClusteringPrefix clustering)
public <T> void validate(ClusteringPrefix<T> clustering)
{
ValueAccessor<T> accessor = clustering.accessor();
for (int i = 0; i < clustering.size(); i++)
{
ByteBuffer value = clustering.get(i);
T value = clustering.get(i);
if (value != null)
subtype(i).validate(value);
subtype(i).validate(value, accessor);
}
}

View File

@ -23,12 +23,16 @@ import java.util.*;
import org.apache.cassandra.cache.IMeasurableMemory;
import org.apache.cassandra.config.*;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.db.rows.*;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.utils.ByteArrayUtil;
import org.apache.cassandra.utils.ByteBufferUtil;
/**
@ -44,7 +48,7 @@ import org.apache.cassandra.utils.ByteBufferUtil;
* 3) {@code ClusteringBoundary} represents the threshold between two adjacent range tombstones.
* See those classes for more details.
*/
public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
public interface ClusteringPrefix<V> extends IMeasurableMemory, Clusterable<V>
{
public static final Serializer serializer = new Serializer();
@ -195,6 +199,16 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
}
}
default boolean isBottom()
{
return kind() == Kind.INCL_START_BOUND && size() == 0;
}
default boolean isTop()
{
return kind() == Kind.INCL_END_BOUND && size() == 0;
}
public Kind kind();
/**
@ -206,6 +220,11 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
*/
public int size();
default boolean isEmpty()
{
return size() == 0;
}
/**
* Retrieves the ith value of this prefix.
*
@ -213,14 +232,40 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
*
* @return the ith value of this prefix. Note that a value can be {@code null}.
*/
public ByteBuffer get(int i);
public V get(int i);
public ValueAccessor<V> accessor();
default ByteBuffer bufferAt(int i)
{
return accessor().toBuffer(get(i));
}
default String stringAt(int i, ClusteringComparator comparator)
{
return comparator.subtype(i).getString(get(i), accessor());
}
default void validate(int i, ClusteringComparator comparator)
{
comparator.subtype(i).validate(get(i), accessor());
}
/**
* Adds the data of this clustering prefix to the provided Digest instance.
*
* @param digest the Digest instance to which to add this prefix.
*/
public void digest(Digest digest);
default void digest(Digest digest)
{
for (int i = 0; i < size(); i++)
{
V value = get(i);
if (value != null)
digest.update(value, accessor());
}
digest.updateWithByte(kind().ordinal());
}
/**
* The size of the data hold by this prefix.
@ -228,7 +273,16 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
* @return the size of the data hold by this prefix (this is not the size of the object in memory, just
* the size of the data it stores).
*/
public int dataSize();
default int dataSize()
{
int size = 0;
for (int i = 0; i < size(); i++)
{
V v = get(i);
size += v == null ? 0 : accessor().size(v);
}
return size;
}
/**
* Generates a proper string representation of the prefix.
@ -247,12 +301,12 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
default ByteBuffer serializeAsPartitionKey()
{
if (size() == 1)
return get(0);
return accessor().toBuffer(get(0));
ByteBuffer[] values = new ByteBuffer[size()];
for (int i = 0; i < size(); i++)
values[i] = get(i);
return CompositeType.build(values);
values[i] = accessor().toBuffer(get(i));
return CompositeType.build(ByteBufferAccessor.instance, values);
}
/**
* The values of this prefix as an array.
@ -263,28 +317,30 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
*
* @return the values for this prefix as an array.
*/
public ByteBuffer[] getRawValues();
public V[] getRawValues();
public ByteBuffer[] getBufferArray();
/**
* If the prefix contains byte buffers that can be minimized (see {@link ByteBufferUtil#minimalBufferFor(ByteBuffer)}),
* this will return a copy of the prefix with minimized values, otherwise it returns itself.
*/
public ClusteringPrefix minimize();
public ClusteringPrefix<V> minimize();
public static class Serializer
{
public void serialize(ClusteringPrefix clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
public void serialize(ClusteringPrefix<?> clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
{
// We shouldn't serialize static clusterings
assert clustering.kind() != Kind.STATIC_CLUSTERING;
if (clustering.kind() == Kind.CLUSTERING)
{
out.writeByte(clustering.kind().ordinal());
Clustering.serializer.serialize((Clustering)clustering, out, version, types);
Clustering.serializer.serialize((Clustering<?>)clustering, out, version, types);
}
else
{
ClusteringBoundOrBoundary.serializer.serialize((ClusteringBoundOrBoundary)clustering, out, version, types);
ClusteringBoundOrBoundary.serializer.serialize((ClusteringBoundOrBoundary<?>)clustering, out, version, types);
}
}
@ -299,7 +355,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
ClusteringBoundOrBoundary.serializer.skipValues(in, kind, version, types);
}
public ClusteringPrefix deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
public ClusteringPrefix<byte[]> deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
{
Kind kind = Kind.values()[in.readByte()];
// We shouldn't serialize static clusterings
@ -310,20 +366,21 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
return ClusteringBoundOrBoundary.serializer.deserializeValues(in, kind, version, types);
}
public long serializedSize(ClusteringPrefix clustering, int version, List<AbstractType<?>> types)
public long serializedSize(ClusteringPrefix<?> clustering, int version, List<AbstractType<?>> types)
{
// We shouldn't serialize static clusterings
assert clustering.kind() != Kind.STATIC_CLUSTERING;
if (clustering.kind() == Kind.CLUSTERING)
return 1 + Clustering.serializer.serializedSize((Clustering)clustering, version, types);
return 1 + Clustering.serializer.serializedSize((Clustering<?>)clustering, version, types);
else
return ClusteringBoundOrBoundary.serializer.serializedSize((ClusteringBoundOrBoundary)clustering, version, types);
return ClusteringBoundOrBoundary.serializer.serializedSize((ClusteringBoundOrBoundary<?>)clustering, version, types);
}
void serializeValuesWithoutSize(ClusteringPrefix clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
<V> void serializeValuesWithoutSize(ClusteringPrefix<V> clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException
{
int offset = 0;
int clusteringSize = clustering.size();
ValueAccessor<V> accessor = clustering.accessor();
// serialize in batches of 32, to avoid garbage when deserializing headers
while (offset < clusteringSize)
{
@ -335,15 +392,15 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
out.writeUnsignedVInt(makeHeader(clustering, offset, limit));
while (offset < limit)
{
ByteBuffer v = clustering.get(offset);
if (v != null && v.hasRemaining())
types.get(offset).writeValue(v, out);
V v = clustering.get(offset);
if (v != null && !accessor.isEmpty(v))
types.get(offset).writeValue(v, accessor, out);
offset++;
}
}
}
long valuesWithoutSizeSerializedSize(ClusteringPrefix clustering, int version, List<AbstractType<?>> types)
<V> long valuesWithoutSizeSerializedSize(ClusteringPrefix<V> clustering, int version, List<AbstractType<?>> types)
{
long result = 0;
int offset = 0;
@ -354,22 +411,23 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
result += TypeSizes.sizeofUnsignedVInt(makeHeader(clustering, offset, limit));
offset = limit;
}
ValueAccessor<V> accessor = clustering.accessor();
for (int i = 0; i < clusteringSize; i++)
{
ByteBuffer v = clustering.get(i);
if (v == null || !v.hasRemaining())
V v = clustering.get(i);
if (v == null || accessor.isEmpty(v))
continue; // handled in the header
result += types.get(i).writtenLength(v);
result += types.get(i).writtenLength(v, accessor);
}
return result;
}
ByteBuffer[] deserializeValuesWithoutSize(DataInputPlus in, int size, int version, List<AbstractType<?>> types) throws IOException
byte[][] deserializeValuesWithoutSize(DataInputPlus in, int size, int version, List<AbstractType<?>> types) throws IOException
{
// Callers of this method should handle the case where size = 0 (in all case we want to return a special value anyway).
assert size > 0;
ByteBuffer[] values = new ByteBuffer[size];
byte[][] values = new byte[size][];
int offset = 0;
while (offset < size)
{
@ -378,8 +436,9 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
while (offset < limit)
{
values[offset] = isNull(header, offset)
? null
: (isEmpty(header, offset) ? ByteBufferUtil.EMPTY_BYTE_BUFFER : types.get(offset).readValue(in, DatabaseDescriptor.getMaxValueSize()));
? null
: (isEmpty(header, offset) ? ByteArrayUtil.EMPTY_BYTE_ARRAY
: types.get(offset).readArray(in, DatabaseDescriptor.getMaxValueSize()));
offset++;
}
}
@ -410,16 +469,17 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
* empty values too. So for that, every clustering prefix includes a "header" that contains 2 bits per element in the prefix. For each element,
* those 2 bits encode whether the element is null, empty, or none of those.
*/
private static long makeHeader(ClusteringPrefix clustering, int offset, int limit)
private static <V> long makeHeader(ClusteringPrefix<V> clustering, int offset, int limit)
{
long header = 0;
ValueAccessor<V> accessor = clustering.accessor();
for (int i = offset ; i < limit ; i++)
{
ByteBuffer v = clustering.get(i);
V v = clustering.get(i);
// no need to do modulo arithmetic for i, since the left-shift execute on the modulus of RH operand by definition
if (v == null)
header |= (1L << (i * 2) + 1);
else if (!v.hasRemaining())
else if (accessor.isEmpty(v))
header |= (1L << (i * 2));
}
return header;
@ -461,7 +521,8 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
private int nextSize;
private ClusteringPrefix.Kind nextKind;
private int deserializedSize;
private ByteBuffer[] nextValues;
private byte[][] nextValues;
private final ValueAccessor<byte[]> accessor = ByteArrayAccessor.instance;
public Deserializer(ClusteringComparator comparator, DataInputPlus in, SerializationHeader header)
{
@ -486,12 +547,12 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
// nextValues is of the proper size. Note that the 2nd condition may not hold for range tombstone bounds, but all
// rows have a fixed size clustering, so we'll still save in the common case.
if (nextValues == null || nextValues.length != nextSize)
this.nextValues = new ByteBuffer[nextSize];
this.nextValues = new byte[nextSize][];
}
public int compareNextTo(ClusteringBoundOrBoundary bound) throws IOException
public <T> int compareNextTo(ClusteringBoundOrBoundary<T> bound) throws IOException
{
if (bound == ClusteringBound.TOP)
if (bound.isTop())
return -1;
for (int i = 0; i < bound.size(); i++)
@ -499,7 +560,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
if (!hasComponent(i))
return nextKind.comparedToClustering;
int cmp = comparator.compareComponent(i, nextValues[i], bound.get(i));
int cmp = comparator.compareComponent(i, nextValues[i], accessor, bound.get(i), bound.accessor());
if (cmp != 0)
return cmp;
}
@ -533,7 +594,8 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
int i = deserializedSize++;
nextValues[i] = Serializer.isNull(nextHeader, i)
? null
: (Serializer.isEmpty(nextHeader, i) ? ByteBufferUtil.EMPTY_BYTE_BUFFER : serializationHeader.clusteringTypes().get(i).readValue(in, DatabaseDescriptor.getMaxValueSize()));
: (Serializer.isEmpty(nextHeader, i) ? ByteArrayUtil.EMPTY_BYTE_ARRAY
: serializationHeader.clusteringTypes().get(i).readArray(in, DatabaseDescriptor.getMaxValueSize()));
return true;
}
@ -543,20 +605,20 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
continue;
}
public ClusteringBoundOrBoundary deserializeNextBound() throws IOException
public ClusteringBoundOrBoundary<byte[]> deserializeNextBound() throws IOException
{
assert !nextIsRow;
deserializeAll();
ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.create(nextKind, nextValues);
ClusteringBoundOrBoundary<byte[]> bound = accessor.factory().boundOrBoundary(nextKind, nextValues);
nextValues = null;
return bound;
}
public Clustering deserializeNextClustering() throws IOException
public Clustering<byte[]> deserializeNextClustering() throws IOException
{
assert nextIsRow;
deserializeAll();
Clustering clustering = Clustering.make(nextValues);
Clustering<byte[]> clustering = accessor.factory().clustering(nextValues);
nextValues = null;
return clustering;
}
@ -574,4 +636,44 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable
return nextKind;
}
}
public static <V> int hashCode(ClusteringPrefix<V> prefix)
{
int result = 31;
for (int i = 0; i < prefix.size(); i++)
result += 31 * prefix.accessor().hashCode(prefix.get(i));
return 31 * result + Objects.hashCode(prefix.kind());
}
static <V1, V2> boolean equals(ClusteringPrefix<V1> left, ClusteringPrefix<V2> right)
{
if (left.kind() != right.kind() || left.size() != right.size())
return false;
for (int i = 0; i < left.size(); i++)
{
V1 lVal = left.get(i);
V2 rVal = right.get(i);
if (lVal == null && rVal == null)
continue;
if (lVal == null || rVal == null)
return false;
if (!ValueAccessor.equals(lVal, left.accessor(), rVal, right.accessor()))
return false;
}
return true;
}
public static boolean equals(ClusteringPrefix<?> prefix, Object o)
{
if(!(o instanceof ClusteringPrefix))
return false;
return equals(prefix, (ClusteringPrefix<?>) o);
}
}

View File

@ -2057,14 +2057,14 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
invalidateCachedPartition(new RowCacheKey(metadata(), key));
}
public ClockAndCount getCachedCounter(ByteBuffer partitionKey, Clustering clustering, ColumnMetadata column, CellPath path)
public ClockAndCount getCachedCounter(ByteBuffer partitionKey, Clustering<?> clustering, ColumnMetadata column, CellPath path)
{
if (CacheService.instance.counterCache.getCapacity() == 0L) // counter cache disabled.
return null;
return CacheService.instance.counterCache.get(CounterCacheKey.create(metadata(), partitionKey, clustering, column, path));
}
public void putCachedCounter(ByteBuffer partitionKey, Clustering clustering, ColumnMetadata column, CellPath path, ClockAndCount clockAndCount)
public void putCachedCounter(ByteBuffer partitionKey, Clustering<?> clustering, ColumnMetadata column, CellPath path, ClockAndCount clockAndCount)
{
if (CacheService.instance.counterCache.getCapacity() == 0L) // counter cache disabled.
return;

View File

@ -65,8 +65,8 @@ public class ColumnIndex
private int written;
private long previousRowStart;
private ClusteringPrefix firstClustering;
private ClusteringPrefix lastClustering;
private ClusteringPrefix<?> firstClustering;
private ClusteringPrefix<?> lastClustering;
private DeletionTime openMarker;

View File

@ -30,6 +30,7 @@ import com.google.common.collect.PeekingIterator;
import com.google.common.util.concurrent.Striped;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.rows.*;
import org.apache.cassandra.db.filter.*;
import org.apache.cassandra.db.partitions.*;
@ -221,7 +222,7 @@ public class CounterMutation implements IMutation
private void updateWithCurrentValue(PartitionUpdate.CounterMark mark, ClockAndCount currentValue, ColumnFamilyStore cfs)
{
long clock = Math.max(FBUtilities.timestampMicros(), currentValue.clock + 1L);
long count = currentValue.count + CounterContext.instance().total(mark.value());
long count = currentValue.count + CounterContext.instance().total(mark.value(), ByteBufferAccessor.instance);
mark.setValue(CounterContext.instance().createGlobal(CounterId.getLocalId(), clock, count));
@ -249,7 +250,7 @@ public class CounterMutation implements IMutation
private void updateWithCurrentValuesFromCFS(List<PartitionUpdate.CounterMark> marks, ColumnFamilyStore cfs)
{
ColumnFilter.Builder builder = ColumnFilter.selectionBuilder();
BTreeSet.Builder<Clustering> names = BTreeSet.builder(cfs.metadata().comparator);
BTreeSet.Builder<Clustering<?>> names = BTreeSet.builder(cfs.metadata().comparator);
for (PartitionUpdate.CounterMark mark : marks)
{
if (mark.clustering() != Clustering.STATIC_CLUSTERING)
@ -279,7 +280,7 @@ public class CounterMutation implements IMutation
}
}
private int compare(Clustering c1, Clustering c2, ColumnFamilyStore cfs)
private int compare(Clustering<?> c1, Clustering<?> c2, ColumnFamilyStore cfs)
{
if (c1 == Clustering.STATIC_CLUSTERING)
return c2 == Clustering.STATIC_CLUSTERING ? 0 : -1;
@ -302,10 +303,10 @@ public class CounterMutation implements IMutation
while (cmp == 0)
{
PartitionUpdate.CounterMark mark = markIter.next();
Cell cell = mark.path() == null ? row.getCell(mark.column()) : row.getCell(mark.column(), mark.path());
Cell<?> cell = mark.path() == null ? row.getCell(mark.column()) : row.getCell(mark.column(), mark.path());
if (cell != null)
{
updateWithCurrentValue(mark, CounterContext.instance().getLocalClockAndCount(cell.value()), cfs);
updateWithCurrentValue(mark, CounterContext.instance().getLocalClockAndCount(cell.buffer()), cfs);
markIter.remove();
}
if (!markIter.hasNext())

View File

@ -19,6 +19,7 @@ package org.apache.cassandra.db;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.db.filter.*;
@ -232,7 +233,7 @@ public class DataRange
*
* @return a new {@code DataRange} suitable for paging {@code this} range given the {@code lastRetuned} result of the previous page.
*/
public DataRange forPaging(AbstractBounds<PartitionPosition> range, ClusteringComparator comparator, Clustering lastReturned, boolean inclusive)
public DataRange forPaging(AbstractBounds<PartitionPosition> range, ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive)
{
return new Paging(range, clusteringIndexFilter, comparator, lastReturned, inclusive);
}
@ -338,13 +339,13 @@ public class DataRange
public static class Paging extends DataRange
{
private final ClusteringComparator comparator;
private final Clustering lastReturned;
private final Clustering<?> lastReturned;
private final boolean inclusive;
private Paging(AbstractBounds<PartitionPosition> range,
ClusteringIndexFilter filter,
ClusteringComparator comparator,
Clustering lastReturned,
Clustering<?> lastReturned,
boolean inclusive)
{
super(range, filter);
@ -380,7 +381,7 @@ public class DataRange
/**
* @return the last Clustering that was returned (in the previous page)
*/
public Clustering getLastReturned()
public Clustering<?> getLastReturned()
{
return lastReturned;
}
@ -430,7 +431,7 @@ public class DataRange
if (in.readBoolean())
{
ClusteringComparator comparator = metadata.comparator;
Clustering lastReturned = Clustering.serializer.deserialize(in, version, comparator.subtypes());
Clustering<byte[]> lastReturned = Clustering.serializer.deserialize(in, version, comparator.subtypes());
boolean inclusive = in.readBoolean();
return new Paging(range, filter, comparator, lastReturned, inclusive);
}

View File

@ -52,7 +52,7 @@ public interface DeletionInfo extends IMeasurableMemory
public Iterator<RangeTombstone> rangeIterator(Slice slice, boolean reversed);
public RangeTombstone rangeCovering(Clustering name);
public RangeTombstone rangeCovering(Clustering<?> name);
public void collectStats(EncodingStats.Collector collector);

View File

@ -140,7 +140,7 @@ public class DeletionTime implements Comparable<DeletionTime>, IMeasurableMemory
return deletes(info.timestamp());
}
public boolean deletes(Cell cell)
public boolean deletes(Cell<?> cell)
{
return deletes(cell.timestamp());
}

View File

@ -24,6 +24,7 @@ import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import org.apache.cassandra.db.context.CounterContext;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.utils.FastByteOperations;
public class Digest
@ -63,15 +64,15 @@ public class Digest
return new Digest(Hashing.crc32c().newHasher())
{
@Override
public Digest updateWithCounterContext(ByteBuffer context)
public <V> Digest updateWithCounterContext(V context, ValueAccessor<V> accessor)
{
// for the purposes of repaired data tracking on the read path, exclude
// contexts with legacy shards as these may be irrevocably different on
// different replicas
if (CounterContext.instance().hasLegacyShards(context))
if (CounterContext.instance().hasLegacyShards(context, accessor))
return this;
return super.updateWithCounterContext(context);
return super.updateWithCounterContext(context, accessor);
}
};
}
@ -88,6 +89,12 @@ public class Digest
return this;
}
public <V> Digest update(V input, ValueAccessor<V> accessor)
{
accessor.digest(input, this);
return this;
}
/**
* Update the digest with the bytes from the supplied buffer. This does
* not modify the position of the supplied buffer, so callers are not
@ -103,7 +110,7 @@ public class Digest
* not modify the position of the supplied buffer, so callers are not
* required to duplicate() the source buffer before calling
*/
private Digest update(ByteBuffer input, int pos, int len)
public Digest update(ByteBuffer input, int pos, int len)
{
if (len <= 0)
return this;
@ -138,15 +145,15 @@ public class Digest
* nodes. This means in particular that we always have:
* updateDigest(ctx) == updateDigest(clearAllLocal(ctx))
*/
public Digest updateWithCounterContext(ByteBuffer context)
public <V> Digest updateWithCounterContext(V context, ValueAccessor<V> accessor)
{
// context can be empty due to the optimization from CASSANDRA-10657
if (!context.hasRemaining())
if (accessor.isEmpty(context))
return this;
int pos = context.position() + CounterContext.headerLength(context);
int len = context.limit() - pos;
update(context, pos, len);
int pos = CounterContext.headerLength(context, accessor);
int len = accessor.size(context) - pos;
accessor.digest(context, pos, len, this);
return this;
}

View File

@ -163,7 +163,7 @@ public abstract class MultiCBuilder
*
* @return the clusterings
*/
public abstract NavigableSet<Clustering> build();
public abstract NavigableSet<Clustering<?>> build();
/**
* Builds the <code>ClusteringBound</code>s for slice restrictions.
@ -174,10 +174,10 @@ public abstract class MultiCBuilder
* @param columnDefs the columns of the slice restriction
* @return the <code>ClusteringBound</code>s
*/
public abstract NavigableSet<ClusteringBound> buildBoundForSlice(boolean isStart,
boolean isInclusive,
boolean isOtherBoundInclusive,
List<ColumnMetadata> columnDefs);
public abstract NavigableSet<ClusteringBound<?>> buildBoundForSlice(boolean isStart,
boolean isInclusive,
boolean isOtherBoundInclusive,
List<ColumnMetadata> columnDefs);
/**
* Builds the <code>ClusteringBound</code>s
@ -186,7 +186,7 @@ public abstract class MultiCBuilder
* @param isInclusive specify if the bound is inclusive or not
* @return the <code>ClusteringBound</code>s
*/
public abstract NavigableSet<ClusteringBound> buildBound(boolean isStart, boolean isInclusive);
public abstract NavigableSet<ClusteringBound<?>> buildBound(boolean isStart, boolean isInclusive);
/**
* Checks if some elements can still be added to the clusterings.
@ -252,7 +252,7 @@ public abstract class MultiCBuilder
return addEachElementToAll(values.get(0));
}
public NavigableSet<Clustering> build()
public NavigableSet<Clustering<?>> build()
{
built = true;
@ -263,15 +263,15 @@ public abstract class MultiCBuilder
}
@Override
public NavigableSet<ClusteringBound> buildBoundForSlice(boolean isStart,
boolean isInclusive,
boolean isOtherBoundInclusive,
List<ColumnMetadata> columnDefs)
public NavigableSet<ClusteringBound<?>> buildBoundForSlice(boolean isStart,
boolean isInclusive,
boolean isOtherBoundInclusive,
List<ColumnMetadata> columnDefs)
{
return buildBound(isStart, columnDefs.get(0).isReversedType() ? isOtherBoundInclusive : isInclusive);
}
public NavigableSet<ClusteringBound> buildBound(boolean isStart, boolean isInclusive)
public NavigableSet<ClusteringBound<?>> buildBound(boolean isStart, boolean isInclusive)
{
built = true;
@ -279,13 +279,13 @@ public abstract class MultiCBuilder
return BTreeSet.empty(comparator);
if (size == 0)
return BTreeSet.of(comparator, isStart ? ClusteringBound.BOTTOM : ClusteringBound.TOP);
return BTreeSet.of(comparator, isStart ? BufferClusteringBound.BOTTOM : BufferClusteringBound.TOP);
ByteBuffer[] newValues = size == elements.length
? elements
: Arrays.copyOf(elements, size);
return BTreeSet.of(comparator, ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues));
return BTreeSet.of(comparator, BufferClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues));
}
}
@ -397,7 +397,7 @@ public abstract class MultiCBuilder
return this;
}
public NavigableSet<Clustering> build()
public NavigableSet<Clustering<?>> build()
{
built = true;
@ -409,7 +409,7 @@ public abstract class MultiCBuilder
if (elementsList.isEmpty())
return BTreeSet.of(builder.comparator(), builder.build());
BTreeSet.Builder<Clustering> set = BTreeSet.builder(builder.comparator());
BTreeSet.Builder<Clustering<?>> set = BTreeSet.builder(builder.comparator());
for (int i = 0, m = elementsList.size(); i < m; i++)
{
List<ByteBuffer> elements = elementsList.get(i);
@ -418,10 +418,10 @@ public abstract class MultiCBuilder
return set.build();
}
public NavigableSet<ClusteringBound> buildBoundForSlice(boolean isStart,
boolean isInclusive,
boolean isOtherBoundInclusive,
List<ColumnMetadata> columnDefs)
public NavigableSet<ClusteringBound<?>> buildBoundForSlice(boolean isStart,
boolean isInclusive,
boolean isOtherBoundInclusive,
List<ColumnMetadata> columnDefs)
{
built = true;
@ -434,7 +434,7 @@ public abstract class MultiCBuilder
return BTreeSet.of(comparator, builder.buildBound(isStart, isInclusive));
// Use a TreeSet to sort and eliminate duplicates
BTreeSet.Builder<ClusteringBound> set = BTreeSet.builder(comparator);
BTreeSet.Builder<ClusteringBound<?>> set = BTreeSet.builder(comparator);
// The first column of the slice might not be the first clustering column (e.g. clustering_0 = ? AND (clustering_1, clustering_2) >= (?, ?)
int offset = columnDefs.get(0).position();
@ -469,7 +469,7 @@ public abstract class MultiCBuilder
return set.build();
}
public NavigableSet<ClusteringBound> buildBound(boolean isStart, boolean isInclusive)
public NavigableSet<ClusteringBound<?>> buildBound(boolean isStart, boolean isInclusive)
{
built = true;
@ -482,7 +482,7 @@ public abstract class MultiCBuilder
return BTreeSet.of(comparator, builder.buildBound(isStart, isInclusive));
// Use a TreeSet to sort and eliminate duplicates
BTreeSet.Builder<ClusteringBound> set = BTreeSet.builder(comparator);
BTreeSet.Builder<ClusteringBound<?>> set = BTreeSet.builder(comparator);
for (int i = 0, m = elementsList.size(); i < m; i++)
{

View File

@ -160,7 +160,7 @@ public class MutableDeletionInfo implements DeletionInfo
return ranges == null ? Collections.emptyIterator() : ranges.iterator(slice, reversed);
}
public RangeTombstone rangeCovering(Clustering name)
public RangeTombstone rangeCovering(Clustering<?> name)
{
return ranges == null ? null : ranges.search(name);
}
@ -291,8 +291,8 @@ public class MutableDeletionInfo implements DeletionInfo
DeletionTime openDeletion = openMarker.openDeletionTime(reversed);
assert marker.closeDeletionTime(reversed).equals(openDeletion);
ClusteringBound open = openMarker.openBound(reversed);
ClusteringBound close = marker.closeBound(reversed);
ClusteringBound<?> open = openMarker.openBound(reversed);
ClusteringBound<?> close = marker.closeBound(reversed);
Slice slice = reversed ? Slice.make(close, open) : Slice.make(open, close);
deletion.add(new RangeTombstone(slice, openDeletion), comparator);

View File

@ -21,12 +21,14 @@ package org.apache.cassandra.db;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.concurrent.OpOrder;
import org.apache.cassandra.utils.memory.MemoryUtil;
import org.apache.cassandra.utils.memory.NativeAllocator;
public class NativeClustering extends AbstractClusteringPrefix implements Clustering
public class NativeClustering implements Clustering<ByteBuffer>
{
private static final long EMPTY_SIZE = ObjectSizes.measure(new NativeClustering());
@ -34,12 +36,12 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste
private NativeClustering() { peer = 0; }
public ClusteringPrefix minimize()
public ClusteringPrefix<ByteBuffer> minimize()
{
return this;
}
public NativeClustering(NativeAllocator allocator, OpOrder.Group writeOp, Clustering clustering)
public NativeClustering(NativeAllocator allocator, OpOrder.Group writeOp, Clustering<?> clustering)
{
int count = clustering.size();
int metadataSize = (count * 2) + 4;
@ -61,7 +63,7 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste
{
MemoryUtil.setShort(peer + 2 + i * 2, (short) dataOffset);
ByteBuffer value = clustering.get(i);
ByteBuffer value = clustering.bufferAt(i);
if (value == null)
{
long boffset = bitmapStart + (i >>> 3);
@ -84,6 +86,11 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste
return Kind.CLUSTERING;
}
public ClusteringPrefix<ByteBuffer> clustering()
{
return this;
}
public int size()
{
return MemoryUtil.getShort(peer);
@ -118,6 +125,17 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste
return values;
}
public ByteBuffer[] getBufferArray()
{
return getRawValues();
}
public ValueAccessor<ByteBuffer> accessor()
{
// TODO: add a native accessor
return ByteBufferAccessor.instance;
}
public long unsharedHeapSize()
{
return EMPTY_SIZE;
@ -127,4 +145,16 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste
{
return EMPTY_SIZE;
}
@Override
public final int hashCode()
{
return ClusteringPrefix.hashCode(this);
}
@Override
public final boolean equals(Object o)
{
return ClusteringPrefix.equals(this, o);
}
}

View File

@ -75,7 +75,7 @@ public interface PartitionRangeReadQuery extends ReadQuery
return rowFilter().partitionKeyRestrictionsAreSatisfiedBy(key, metadata().partitionKeyType);
}
default boolean selectsClustering(DecoratedKey key, Clustering clustering)
default boolean selectsClustering(DecoratedKey key, Clustering<?> clustering)
{
if (clustering == Clustering.STATIC_CLUSTERING)
return !columnFilter().fetchedColumns().statics.isEmpty();

View File

@ -55,15 +55,15 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
// Note: we don't want to use a List for the markedAts and delTimes to avoid boxing. We could
// use a List for starts and ends, but having arrays everywhere is almost simpler.
private ClusteringBound[] starts;
private ClusteringBound[] ends;
private ClusteringBound<?>[] starts;
private ClusteringBound<?>[] ends;
private long[] markedAts;
private int[] delTimes;
private long boundaryHeapSize;
private int size;
private RangeTombstoneList(ClusteringComparator comparator, ClusteringBound[] starts, ClusteringBound[] ends, long[] markedAts, int[] delTimes, long boundaryHeapSize, int size)
private RangeTombstoneList(ClusteringComparator comparator, ClusteringBound<?>[] starts, ClusteringBound<?>[] ends, long[] markedAts, int[] delTimes, long boundaryHeapSize, int size)
{
assert starts.length == ends.length && starts.length == markedAts.length && starts.length == delTimes.length;
this.comparator = comparator;
@ -77,7 +77,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
public RangeTombstoneList(ClusteringComparator comparator, int capacity)
{
this(comparator, new ClusteringBound[capacity], new ClusteringBound[capacity], new long[capacity], new int[capacity], 0, 0);
this(comparator, new ClusteringBound<?>[capacity], new ClusteringBound<?>[capacity], new long[capacity], new int[capacity], 0, 0);
}
public boolean isEmpty()
@ -108,8 +108,8 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
public RangeTombstoneList copy(AbstractAllocator allocator)
{
RangeTombstoneList copy = new RangeTombstoneList(comparator,
new ClusteringBound[size],
new ClusteringBound[size],
new ClusteringBound<?>[size],
new ClusteringBound<?>[size],
Arrays.copyOf(markedAts, size),
Arrays.copyOf(delTimes, size),
boundaryHeapSize, size);
@ -124,12 +124,12 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
return copy;
}
private static ClusteringBound clone(ClusteringBound bound, AbstractAllocator allocator)
private static <T> ClusteringBound<ByteBuffer> clone(ClusteringBound<T> bound, AbstractAllocator allocator)
{
ByteBuffer[] values = new ByteBuffer[bound.size()];
for (int i = 0; i < values.length; i++)
values[i] = allocator.clone(bound.get(i));
return new ClusteringBound(bound.kind(), values);
values[i] = allocator.clone(bound.get(i), bound.accessor());
return new BufferClusteringBound(bound.kind(), values);
}
public void add(RangeTombstone tombstone)
@ -146,7 +146,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
* This method will be faster if the new tombstone sort after all the currently existing ones (this is a common use case),
* but it doesn't assume it.
*/
public void add(ClusteringBound start, ClusteringBound end, long markedAt, int delTime)
public void add(ClusteringBound<?> start, ClusteringBound<?> end, long markedAt, int delTime)
{
if (isEmpty())
{
@ -233,7 +233,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
* Returns whether the given name/timestamp pair is deleted by one of the tombstone
* of this RangeTombstoneList.
*/
public boolean isDeleted(Clustering clustering, Cell cell)
public boolean isDeleted(Clustering<?> clustering, Cell<?> cell)
{
int idx = searchInternal(clustering, 0, size);
// No matter what the counter cell's timestamp is, a tombstone always takes precedence. See CASSANDRA-7346.
@ -244,13 +244,13 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
* Returns the DeletionTime for the tombstone overlapping {@code name} (there can't be more than one),
* or null if {@code name} is not covered by any tombstone.
*/
public DeletionTime searchDeletionTime(Clustering name)
public DeletionTime searchDeletionTime(Clustering<?> name)
{
int idx = searchInternal(name, 0, size);
return idx < 0 ? null : new DeletionTime(markedAts[idx], delTimes[idx]);
}
public RangeTombstone search(Clustering name)
public RangeTombstone search(Clustering<?> name)
{
int idx = searchInternal(name, 0, size);
return idx < 0 ? null : rangeTombstone(idx);
@ -262,7 +262,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
*
* Note that bounds are not in the range if they fall on its boundary.
*/
private int searchInternal(ClusteringPrefix name, int startIdx, int endIdx)
private int searchInternal(ClusteringPrefix<?> name, int startIdx, int endIdx)
{
if (isEmpty())
return -1;
@ -325,17 +325,17 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
return new RangeTombstone(Slice.make(starts[idx], ends[idx]), new DeletionTime(markedAts[idx], delTimes[idx]));
}
private RangeTombstone rangeTombstoneWithNewStart(int idx, ClusteringBound newStart)
private RangeTombstone rangeTombstoneWithNewStart(int idx, ClusteringBound<?> newStart)
{
return new RangeTombstone(Slice.make(newStart, ends[idx]), new DeletionTime(markedAts[idx], delTimes[idx]));
}
private RangeTombstone rangeTombstoneWithNewEnd(int idx, ClusteringBound newEnd)
private RangeTombstone rangeTombstoneWithNewEnd(int idx, ClusteringBound<?> newEnd)
{
return new RangeTombstone(Slice.make(starts[idx], newEnd), new DeletionTime(markedAts[idx], delTimes[idx]));
}
private RangeTombstone rangeTombstoneWithNewBounds(int idx, ClusteringBound newStart, ClusteringBound newEnd)
private RangeTombstone rangeTombstoneWithNewBounds(int idx, ClusteringBound<?> newStart, ClusteringBound<?> newEnd)
{
return new RangeTombstone(Slice.make(newStart, newEnd), new DeletionTime(markedAts[idx], delTimes[idx]));
}
@ -382,13 +382,13 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
private Iterator<RangeTombstone> forwardIterator(final Slice slice)
{
int startIdx = slice.start() == ClusteringBound.BOTTOM ? 0 : searchInternal(slice.start(), 0, size);
int startIdx = slice.start().isBottom() ? 0 : searchInternal(slice.start(), 0, size);
final int start = startIdx < 0 ? -startIdx-1 : startIdx;
if (start >= size)
return Collections.emptyIterator();
int finishIdx = slice.end() == ClusteringBound.TOP ? size - 1 : searchInternal(slice.end(), start, size);
int finishIdx = slice.end().isTop() ? size - 1 : searchInternal(slice.end(), start, size);
// if stopIdx is the first range after 'slice.end()' we care only until the previous range
final int finish = finishIdx < 0 ? -finishIdx-2 : finishIdx;
@ -399,8 +399,8 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
{
// We want to make sure the range are stricly included within the queried slice as this
// make it easier to combine things when iterating over successive slices.
ClusteringBound s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start];
ClusteringBound e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start];
ClusteringBound<?> s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start];
ClusteringBound<?> e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start];
if (Slice.isEmpty(comparator, s, e))
return Collections.emptyIterator();
return Iterators.<RangeTombstone>singletonIterator(rangeTombstoneWithNewBounds(start, s, e));
@ -429,14 +429,14 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
private Iterator<RangeTombstone> reverseIterator(final Slice slice)
{
int startIdx = slice.end() == ClusteringBound.TOP ? size - 1 : searchInternal(slice.end(), 0, size);
int startIdx = slice.end().isTop() ? size - 1 : searchInternal(slice.end(), 0, size);
// if startIdx is the first range after 'slice.end()' we care only until the previous range
final int start = startIdx < 0 ? -startIdx-2 : startIdx;
if (start < 0)
return Collections.emptyIterator();
int finishIdx = slice.start() == ClusteringBound.BOTTOM ? 0 : searchInternal(slice.start(), 0, start + 1); // include same as finish
int finishIdx = slice.start().isBottom() ? 0 : searchInternal(slice.start(), 0, start + 1); // include same as finish
// if stopIdx is the first range after 'slice.end()' we care only until the previous range
final int finish = finishIdx < 0 ? -finishIdx-1 : finishIdx;
@ -447,8 +447,8 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
{
// We want to make sure the range are stricly included within the queried slice as this
// make it easier to combine things when iterator over successive slices.
ClusteringBound s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start];
ClusteringBound e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start];
ClusteringBound<?> s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start];
ClusteringBound<?> e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start];
if (Slice.isEmpty(comparator, s, e))
return Collections.emptyIterator();
return Iterators.<RangeTombstone>singletonIterator(rangeTombstoneWithNewBounds(start, s, e));
@ -533,7 +533,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
* - e_i <= s_i+1
* Basically, range are non overlapping and in order.
*/
private void insertFrom(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime)
private void insertFrom(int i, ClusteringBound<?> start, ClusteringBound<?> end, long markedAt, int delTime)
{
while (i < size)
{
@ -552,7 +552,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
// First deal with what might come before the newly added one.
if (comparator.compare(starts[i], start) < 0)
{
ClusteringBound newEnd = start.invert();
ClusteringBound<?> newEnd = start.invert();
if (!Slice.isEmpty(comparator, starts[i], newEnd))
{
addInternal(i, starts[i], newEnd, markedAts[i], delTimes[i]);
@ -600,7 +600,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
// one to reflect the not overwritten parts. We're then done.
addInternal(i, start, end, markedAt, delTime);
i++;
ClusteringBound newStart = end.invert();
ClusteringBound<?> newStart = end.invert();
if (!Slice.isEmpty(comparator, newStart, ends[i]))
{
setInternal(i, newStart, ends[i], markedAts[i], delTimes[i]);
@ -622,7 +622,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
addInternal(i, start, end, markedAt, delTime);
return;
}
ClusteringBound newEnd = starts[i].invert();
ClusteringBound<?> newEnd = starts[i].invert();
if (!Slice.isEmpty(comparator, start, newEnd))
{
addInternal(i, start, newEnd, markedAt, delTime);
@ -654,7 +654,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
/*
* Adds the new tombstone at index i, growing and/or moving elements to make room for it.
*/
private void addInternal(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime)
private void addInternal(int i, ClusteringBound<?> start, ClusteringBound<?> end, long markedAt, int delTime)
{
assert i >= 0;
@ -698,12 +698,12 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
delTimes = grow(delTimes, size, newLength, i);
}
private static ClusteringBound[] grow(ClusteringBound[] a, int size, int newLength, int i)
private static ClusteringBound<?>[] grow(ClusteringBound<?>[] a, int size, int newLength, int i)
{
if (i < 0 || i >= size)
return Arrays.copyOf(a, newLength);
ClusteringBound[] newA = new ClusteringBound[newLength];
ClusteringBound<?>[] newA = new ClusteringBound<?>[newLength];
System.arraycopy(a, 0, newA, 0, i);
System.arraycopy(a, i, newA, i+1, size - i);
return newA;
@ -748,7 +748,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable
starts[i] = null;
}
private void setInternal(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime)
private void setInternal(int i, ClusteringBound<?> start, ClusteringBound<?> end, long markedAt, int delTime)
{
if (starts[i] != null)
boundaryHeapSize -= starts[i].unsharedHeapSize() + ends[i].unsharedHeapSize();

View File

@ -550,7 +550,7 @@ public abstract class ReadCommand extends AbstractReadQuery
public Row applyToRow(Row row)
{
boolean hasTombstones = false;
for (Cell cell : row.cells())
for (Cell<?> cell : row.cells())
{
if (!cell.isLive(ReadCommand.this.nowInSec()))
{
@ -579,7 +579,7 @@ public abstract class ReadCommand extends AbstractReadQuery
return marker;
}
private void countTombstone(ClusteringPrefix clustering)
private void countTombstone(ClusteringPrefix<?> clustering)
{
++tombstones;
if (tombstones > failureThreshold && respectTombstoneThresholds)

View File

@ -81,7 +81,7 @@ public interface ReadQuery
return false;
}
public boolean selectsClustering(DecoratedKey key, Clustering clustering)
public boolean selectsClustering(DecoratedKey key, Clustering<?> clustering)
{
return false;
}
@ -192,7 +192,7 @@ public interface ReadQuery
* @return true if the read query would select the given clustering, including checks against the row filter, if
* checkRowFilter is true
*/
public boolean selectsClustering(DecoratedKey key, Clustering clustering);
public boolean selectsClustering(DecoratedKey key, Clustering<?> clustering);
/**
* The time in seconds to use as "now" for this query.

View File

@ -629,7 +629,7 @@ public class RowIndexEntry<T> implements IMeasurableMemory
this.idxInfoSerializer = idxInfoSerializer;
this.fieldsSerializedSize = serializedSize(deletionTime, headerLength, columnIndexCount);
this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.sizeof(0);
this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.INT_SIZE;
}
/**
@ -650,7 +650,7 @@ public class RowIndexEntry<T> implements IMeasurableMemory
this.idxInfoSerializer = idxInfoSerializer;
this.fieldsSerializedSize = serializedSize(deletionTime, headerLength, columnsIndexCount);
this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.sizeof(0);
this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.INT_SIZE;
}
@Override
@ -739,7 +739,7 @@ public class RowIndexEntry<T> implements IMeasurableMemory
IndexInfo fetchIndex(int index) throws IOException
{
// seek to position in "offsets to IndexInfo" table
indexReader.seek(indexInfoFilePosition + offsetsOffset + index * TypeSizes.sizeof(0));
indexReader.seek(indexInfoFilePosition + offsetsOffset + index * TypeSizes.INT_SIZE);
// read offset of IndexInfo
int indexInfoPos = indexReader.readInt();

View File

@ -53,10 +53,10 @@ public abstract class SimpleBuilders
return metadata.partitioner.decorateKey(key);
}
private static Clustering makeClustering(TableMetadata metadata, Object... clusteringColumns)
private static Clustering<?> makeClustering(TableMetadata metadata, Object... clusteringColumns)
{
if (clusteringColumns.length == 1 && clusteringColumns[0] instanceof Clustering)
return (Clustering)clusteringColumns[0];
return (Clustering<?>)clusteringColumns[0];
if (clusteringColumns.length == 0)
{
@ -157,7 +157,7 @@ public abstract class SimpleBuilders
{
private final TableMetadata metadata;
private final DecoratedKey key;
private final Map<Clustering, RowBuilder> rowBuilders = new HashMap<>();
private final Map<Clustering<?>, RowBuilder> rowBuilders = new HashMap<>();
private List<RTBuilder> rangeBuilders = null; // We use that rarely, so create lazily
private List<RangeTombstone> rangeTombstones = null;
@ -176,7 +176,7 @@ public abstract class SimpleBuilders
public Row.SimpleBuilder row(Object... clusteringValues)
{
Clustering clustering = makeClustering(metadata, clusteringValues);
Clustering<?> clustering = makeClustering(metadata, clusteringValues);
RowBuilder builder = rowBuilders.get(clustering);
if (builder == null)
{
@ -303,8 +303,8 @@ public abstract class SimpleBuilders
private RangeTombstone build()
{
ClusteringBound startBound = ClusteringBound.create(comparator, true, startInclusive, start);
ClusteringBound endBound = ClusteringBound.create(comparator, false, endInclusive, end);
ClusteringBound<?> startBound = ClusteringBound.create(comparator, true, startInclusive, start);
ClusteringBound<?> endBound = ClusteringBound.create(comparator, false, endInclusive, end);
return new RangeTombstone(Slice.make(startBound, endBound), deletionTime);
}
}
@ -446,7 +446,7 @@ public abstract class SimpleBuilders
return column;
}
private Cell cell(ColumnMetadata column, ByteBuffer value, CellPath path)
private Cell<?> cell(ColumnMetadata column, ByteBuffer value, CellPath path)
{
if (value == null)
return BufferCell.tombstone(column, timestamp, nowInSec, path);

View File

@ -255,7 +255,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
* @return a newly created read command that queries the {@code names} in {@code key}. The returned query will
* query every columns (without limit or row filtering) and be in forward order.
*/
public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, NavigableSet<Clustering> names)
public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, NavigableSet<Clustering<?>> names)
{
ClusteringIndexNamesFilter filter = new ClusteringIndexNamesFilter(names, false);
return create(metadata, nowInSec, ColumnFilter.all(metadata), RowFilter.NONE, DataLimits.NONE, key, filter);
@ -272,7 +272,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
* @return a newly created read command that queries {@code name} in {@code key}. The returned query will
* query every columns (without limit or row filtering).
*/
public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, Clustering name)
public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, Clustering<?> name)
{
return create(metadata, nowInSec, key, FBUtilities.singleton(name, metadata.comparator));
}
@ -368,7 +368,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
}
@Override
public SinglePartitionReadCommand forPaging(Clustering lastReturned, DataLimits limits)
public SinglePartitionReadCommand forPaging(Clustering<?> lastReturned, DataLimits limits)
{
// We shouldn't have set digest yet when reaching that point
assert !isDigestQuery();
@ -928,10 +928,10 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
if (result == null)
return filter;
SearchIterator<Clustering, Row> searchIter = result.searchIterator(columnFilter(), false);
SearchIterator<Clustering<?>, Row> searchIter = result.searchIterator(columnFilter(), false);
RegularAndStaticColumns columns = columnFilter().fetchedColumns();
NavigableSet<Clustering> clusterings = filter.requestedRows();
NavigableSet<Clustering<?>> clusterings = filter.requestedRows();
// We want to remove rows for which we have values for all requested columns. We have to deal with both static and regular rows.
// TODO: we could also remove a selected column if we've found values for every requested row but we'll leave
@ -944,8 +944,8 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
removeStatic = staticRow != null && canRemoveRow(staticRow, columns.statics, sstableTimestamp);
}
NavigableSet<Clustering> toRemove = null;
for (Clustering clustering : clusterings)
NavigableSet<Clustering<?>> toRemove = null;
for (Clustering<?> clustering : clusterings)
{
Row row = searchIter.next(clustering);
if (row == null || !canRemoveRow(row, columns.regulars, sstableTimestamp))
@ -967,7 +967,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
if (toRemove != null)
{
BTreeSet.Builder<Clustering> newClusterings = BTreeSet.builder(result.metadata().comparator);
BTreeSet.Builder<Clustering<?>> newClusterings = BTreeSet.builder(result.metadata().comparator);
newClusterings.addAll(Sets.difference(clusterings, toRemove));
clusterings = newClusterings.build();
}
@ -984,7 +984,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
for (ColumnMetadata column : requestedColumns)
{
Cell cell = row.getCell(column);
Cell<?> cell = row.getCell(column);
if (cell == null || cell.timestamp() <= sstableTimestamp)
return false;
}
@ -1113,7 +1113,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar
IndexMetadata index)
throws IOException
{
DecoratedKey key = metadata.partitioner.decorateKey(metadata.partitionKeyType.readValue(in, DatabaseDescriptor.getMaxValueSize()));
DecoratedKey key = metadata.partitioner.decorateKey(metadata.partitionKeyType.readBuffer(in, DatabaseDescriptor.getMaxValueSize()));
ClusteringIndexFilter filter = ClusteringIndexFilter.serializer.deserialize(in, version, metadata);
return new SinglePartitionReadCommand(isDigest, digestVersion, acceptsTransient, metadata, nowInSec, columnFilter, rowFilter, limits, key, filter, index);
}

View File

@ -129,7 +129,7 @@ public interface SinglePartitionReadQuery extends ReadQuery
*
* @return the newly create query.
*/
SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits);
SinglePartitionReadQuery forPaging(Clustering<?> lastReturned, DataLimits limits);
@Override
default SinglePartitionPager getPager(PagingState pagingState, ProtocolVersion protocolVersion)
@ -147,7 +147,7 @@ public interface SinglePartitionReadQuery extends ReadQuery
return rowFilter().partitionKeyRestrictionsAreSatisfiedBy(key, metadata().partitionKeyType);
}
default boolean selectsClustering(DecoratedKey key, Clustering clustering)
default boolean selectsClustering(DecoratedKey key, Clustering<?> clustering)
{
if (clustering == Clustering.STATIC_CLUSTERING)
return !columnFilter().fetchedColumns().statics.isEmpty();
@ -260,7 +260,7 @@ public interface SinglePartitionReadQuery extends ReadQuery
return Iterables.any(queries, c -> c.selectsKey(key));
}
public boolean selectsClustering(DecoratedKey key, Clustering clustering)
public boolean selectsClustering(DecoratedKey key, Clustering<?> clustering)
{
return Iterables.any(queries, c -> c.selectsClustering(key, clustering));
}

View File

@ -22,9 +22,9 @@ import java.nio.ByteBuffer;
import java.util.*;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.ByteBufferUtil;
/**
* A slice represents the selection of a range of rows.
@ -38,10 +38,10 @@ public class Slice
public static final Serializer serializer = new Serializer();
/** The slice selecting all rows (of a given partition) */
public static final Slice ALL = new Slice(ClusteringBound.BOTTOM, ClusteringBound.TOP)
public static final Slice ALL = new Slice(BufferClusteringBound.BOTTOM, BufferClusteringBound.TOP)
{
@Override
public boolean includes(ClusteringComparator comparator, ClusteringPrefix clustering)
public boolean includes(ClusteringComparator comparator, ClusteringPrefix<?> clustering)
{
return true;
}
@ -59,19 +59,19 @@ public class Slice
}
};
private final ClusteringBound start;
private final ClusteringBound end;
private final ClusteringBound<?> start;
private final ClusteringBound<?> end;
private Slice(ClusteringBound start, ClusteringBound end)
private Slice(ClusteringBound<?> start, ClusteringBound<?> end)
{
assert start.isStart() && end.isEnd();
this.start = start;
this.end = end;
}
public static Slice make(ClusteringBound start, ClusteringBound end)
public static Slice make(ClusteringBound<?> start, ClusteringBound<?> end)
{
if (start == ClusteringBound.BOTTOM && end == ClusteringBound.TOP)
if (start.isBottom() && end.isTop())
return ALL;
return new Slice(start, end);
@ -90,49 +90,37 @@ public class Slice
return new Slice(builder.buildBound(true, true), builder.buildBound(false, true));
}
public static Slice make(Clustering clustering)
public static Slice make(Clustering<?> clustering)
{
// This doesn't give us what we want with the clustering prefix
assert clustering != Clustering.STATIC_CLUSTERING;
ByteBuffer[] values = extractValues(clustering);
return new Slice(ClusteringBound.inclusiveStartOf(values), ClusteringBound.inclusiveEndOf(values));
return new Slice(ClusteringBound.inclusiveStartOf(clustering), ClusteringBound.inclusiveEndOf(clustering));
}
public static Slice make(Clustering start, Clustering end)
public static Slice make(Clustering<?> start, Clustering<?> end)
{
// This doesn't give us what we want with the clustering prefix
assert start != Clustering.STATIC_CLUSTERING && end != Clustering.STATIC_CLUSTERING;
ByteBuffer[] startValues = extractValues(start);
ByteBuffer[] endValues = extractValues(end);
return new Slice(ClusteringBound.inclusiveStartOf(startValues), ClusteringBound.inclusiveEndOf(endValues));
return new Slice(ClusteringBound.inclusiveStartOf(start), ClusteringBound.inclusiveEndOf(end));
}
private static ByteBuffer[] extractValues(ClusteringPrefix clustering)
{
ByteBuffer[] values = new ByteBuffer[clustering.size()];
for (int i = 0; i < clustering.size(); i++)
values[i] = clustering.get(i);
return values;
}
public ClusteringBound start()
public ClusteringBound<?> start()
{
return start;
}
public ClusteringBound end()
public ClusteringBound<?> end()
{
return end;
}
public ClusteringBound open(boolean reversed)
public ClusteringBound<?> open(boolean reversed)
{
return reversed ? end : start;
}
public ClusteringBound close(boolean reversed)
public ClusteringBound<?> close(boolean reversed)
{
return reversed ? start : end;
}
@ -157,7 +145,7 @@ public class Slice
* @return whether the slice formed by {@code start} and {@code end} is
* empty or not.
*/
public static boolean isEmpty(ClusteringComparator comparator, ClusteringBound start, ClusteringBound end)
public static boolean isEmpty(ClusteringComparator comparator, ClusteringBound<?> start, ClusteringBound<?> end)
{
assert start.isStart() && end.isEnd();
@ -179,7 +167,7 @@ public class Slice
*
* @return whether {@code bound} is within the bounds of this slice.
*/
public boolean includes(ClusteringComparator comparator, ClusteringPrefix bound)
public boolean includes(ClusteringComparator comparator, ClusteringPrefix<?> bound)
{
return comparator.compare(start, bound) <= 0 && comparator.compare(bound, end) <= 0;
}
@ -197,7 +185,7 @@ public class Slice
* @return a new slice that selects results coming after {@code lastReturned}, or {@code null} if paging
* the resulting slice selects nothing (i.e. if it originally selects nothing coming after {@code lastReturned}).
*/
public Slice forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed)
public Slice forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive, boolean reversed)
{
if (lastReturned == null)
return this;
@ -212,8 +200,7 @@ public class Slice
if (cmp < 0 || (inclusive && cmp == 0))
return this;
ByteBuffer[] values = extractValues(lastReturned);
return new Slice(start, inclusive ? ClusteringBound.inclusiveEndOf(values) : ClusteringBound.exclusiveEndOf(values));
return new Slice(start, inclusive ? ClusteringBound.inclusiveEndOf(lastReturned) : ClusteringBound.exclusiveEndOf(lastReturned));
}
else
{
@ -225,8 +212,7 @@ public class Slice
if (cmp < 0 || (inclusive && cmp == 0))
return this;
ByteBuffer[] values = extractValues(lastReturned);
return new Slice(inclusive ? ClusteringBound.inclusiveStartOf(values) : ClusteringBound.exclusiveStartOf(values), end);
return new Slice(inclusive ? ClusteringBound.inclusiveStartOf(lastReturned) : ClusteringBound.exclusiveStartOf(lastReturned), end);
}
}
@ -255,14 +241,14 @@ public class Slice
{
if (i > 0)
sb.append(':');
sb.append(comparator.subtype(i).getString(start.get(i)));
sb.append(start.stringAt(i, comparator));
}
sb.append(", ");
for (int i = 0; i < end.size(); i++)
{
if (i > 0)
sb.append(':');
sb.append(comparator.subtype(i).getString(end.get(i)));
sb.append(end.stringAt(i, comparator));
}
sb.append(end.isInclusive() ? "]" : ")");
return sb.toString();
@ -301,8 +287,8 @@ public class Slice
public Slice deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException
{
ClusteringBound start = (ClusteringBound) ClusteringBound.serializer.deserialize(in, version, types);
ClusteringBound end = (ClusteringBound) ClusteringBound.serializer.deserialize(in, version, types);
ClusteringBound<byte[]> start = (ClusteringBound<byte[]>) ClusteringBound.serializer.deserialize(in, version, types);
ClusteringBound<byte[]> end = (ClusteringBound<byte[]>) ClusteringBound.serializer.deserialize(in, version, types);
return new Slice(start, end);
}
}

View File

@ -59,7 +59,7 @@ public abstract class Slices implements Iterable<Slice>
*/
public static Slices with(ClusteringComparator comparator, Slice slice)
{
if (slice.start() == ClusteringBound.BOTTOM && slice.end() == ClusteringBound.TOP)
if (slice.start().isBottom() && slice.end().isTop())
return Slices.ALL;
Preconditions.checkArgument(!slice.isEmpty(comparator));
@ -106,7 +106,7 @@ public abstract class Slices implements Iterable<Slice>
*
* @return new slices that select results coming after {@code lastReturned}.
*/
public abstract Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed);
public abstract Slices forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive, boolean reversed);
/**
* An object that allows to test whether rows are selected by this {@code Slices} objects assuming those rows
@ -126,7 +126,7 @@ public abstract class Slices implements Iterable<Slice>
*
* @return whether a given clustering (row) is selected by this {@code Slices} object.
*/
public abstract boolean selects(Clustering clustering);
public abstract boolean selects(Clustering<?> clustering);
/**
@ -159,7 +159,7 @@ public abstract class Slices implements Iterable<Slice>
*/
public interface InOrderTester
{
public boolean includes(Clustering value);
public boolean includes(Clustering<?> value);
public boolean isDone();
}
@ -186,7 +186,7 @@ public abstract class Slices implements Iterable<Slice>
this.slices = new ArrayList<>(initialSize);
}
public Builder add(ClusteringBound start, ClusteringBound end)
public Builder add(ClusteringBound<?> start, ClusteringBound<?> end)
{
return add(Slice.make(start, end));
}
@ -335,7 +335,7 @@ public abstract class Slices implements Iterable<Slice>
for (int i = 0; i < size; i++)
slices[i] = Slice.serializer.deserialize(in, version, metadata.comparator.subtypes());
if (size == 1 && slices[0].start() == ClusteringBound.BOTTOM && slices[0].end() == ClusteringBound.TOP)
if (size == 1 && slices[0].start().isBottom() && slices[0].end().isTop())
return ALL;
return new ArrayBackedSlices(metadata.comparator, slices);
@ -377,7 +377,7 @@ public abstract class Slices implements Iterable<Slice>
return slices[i];
}
public boolean selects(Clustering clustering)
public boolean selects(Clustering<?> clustering)
{
for (int i = 0; i < slices.length; i++)
{
@ -396,12 +396,12 @@ public abstract class Slices implements Iterable<Slice>
return reversed ? new InReverseOrderTester() : new InForwardOrderTester();
}
public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed)
public Slices forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive, boolean reversed)
{
return reversed ? forReversePaging(comparator, lastReturned, inclusive) : forForwardPaging(comparator, lastReturned, inclusive);
}
private Slices forForwardPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive)
private Slices forForwardPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive)
{
for (int i = 0; i < slices.length; i++)
{
@ -420,7 +420,7 @@ public abstract class Slices implements Iterable<Slice>
return Slices.NONE;
}
private Slices forReversePaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive)
private Slices forReversePaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive)
{
for (int i = slices.length - 1; i >= 0; i--)
{
@ -459,7 +459,7 @@ public abstract class Slices implements Iterable<Slice>
private int idx;
private boolean inSlice;
public boolean includes(Clustering value)
public boolean includes(Clustering<?> value)
{
while (idx < slices.length)
{
@ -502,7 +502,7 @@ public abstract class Slices implements Iterable<Slice>
this.idx = slices.length - 1;
}
public boolean includes(Clustering value)
public boolean includes(Clustering<?> value)
{
while (idx >= 0)
{
@ -665,8 +665,8 @@ public abstract class Slices implements Iterable<Slice>
public static ComponentOfSlice fromSlice(int component, Slice slice)
{
ClusteringBound start = slice.start();
ClusteringBound end = slice.end();
ClusteringBound<?> start = slice.start();
ClusteringBound<?> end = slice.end();
if (component >= start.size() && component >= end.size())
return null;
@ -676,12 +676,12 @@ public abstract class Slices implements Iterable<Slice>
if (component < start.size())
{
startInclusive = start.isInclusive();
startValue = start.get(component);
startValue = start.bufferAt(component);
}
if (component < end.size())
{
endInclusive = end.isInclusive();
endValue = end.get(component);
endValue = end.bufferAt(component);
}
return new ComponentOfSlice(startInclusive, startValue, endInclusive, endValue);
}
@ -702,7 +702,7 @@ public abstract class Slices implements Iterable<Slice>
{
private static final InOrderTester trivialTester = new InOrderTester()
{
public boolean includes(Clustering value)
public boolean includes(Clustering<?> value)
{
return true;
}
@ -733,12 +733,12 @@ public abstract class Slices implements Iterable<Slice>
return false;
}
public boolean selects(Clustering clustering)
public boolean selects(Clustering<?> clustering)
{
return true;
}
public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed)
public Slices forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive, boolean reversed)
{
return new ArrayBackedSlices(comparator, new Slice[]{ Slice.ALL.forPaging(comparator, lastReturned, inclusive, reversed) });
}
@ -777,7 +777,7 @@ public abstract class Slices implements Iterable<Slice>
{
private static final InOrderTester trivialTester = new InOrderTester()
{
public boolean includes(Clustering value)
public boolean includes(Clustering<?> value)
{
return false;
}
@ -808,12 +808,12 @@ public abstract class Slices implements Iterable<Slice>
return false;
}
public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed)
public Slices forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive, boolean reversed)
{
return this;
}
public boolean selects(Clustering clustering)
public boolean selects(Clustering<?> clustering)
{
return false;
}

View File

@ -27,12 +27,14 @@ public final class TypeSizes
private TypeSizes(){}
private static final int BOOL_SIZE = 1;
private static final int BYTE_SIZE = 1;
private static final int SHORT_SIZE = 2;
private static final int INT_SIZE = 4;
private static final int LONG_SIZE = 8;
private static final int UUID_SIZE = 16;
public static final int BOOL_SIZE = 1;
public static final int BYTE_SIZE = 1;
public static final int SHORT_SIZE = 2;
public static final int INT_SIZE = 4;
public static final int LONG_SIZE = 8;
public static final int FLOAT_SIZE = 4;
public static final int DOUBLE_SIZE = 8;
public static final int UUID_SIZE = 16;
/** assumes UTF8 */
public static int sizeof(String value)
@ -74,31 +76,49 @@ public final class TypeSizes
return sizeofUnsignedVInt(value.remaining()) + value.remaining();
}
@SuppressWarnings("unused")
public static int sizeof(boolean value)
{
return BOOL_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(byte value)
{
return BYTE_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(short value)
{
return SHORT_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(int value)
{
return INT_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(long value)
{
return LONG_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(float value)
{
return FLOAT_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(double value)
{
return DOUBLE_SIZE;
}
@SuppressWarnings("unused")
public static int sizeof(UUID value)
{
return UUID_SIZE;

View File

@ -19,6 +19,7 @@ package org.apache.cassandra.db;
import java.io.IOException;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.db.rows.*;
import org.apache.cassandra.io.util.DataInputPlus;
@ -105,7 +106,7 @@ public class UnfilteredDeserializer
* comparison. Whenever we know what to do with this atom (read it or skip it),
* readNext or skipNext should be called.
*/
public int compareNextTo(ClusteringBound bound) throws IOException
public int compareNextTo(ClusteringBound<?> bound) throws IOException
{
if (!isReady)
prepareNext();
@ -134,7 +135,7 @@ public class UnfilteredDeserializer
isReady = false;
if (UnfilteredSerializer.kind(nextFlags) == Unfiltered.Kind.RANGE_TOMBSTONE_MARKER)
{
ClusteringBoundOrBoundary bound = clusteringDeserializer.deserializeNextBound();
ClusteringBoundOrBoundary<byte[]> bound = clusteringDeserializer.deserializeNextBound();
return UnfilteredSerializer.serializer.deserializeMarkerBody(in, header, bound);
}
else

View File

@ -122,7 +122,7 @@ public class VirtualTableSinglePartitionReadQuery extends VirtualTableReadQuery
}
@Override
public SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits)
public SinglePartitionReadQuery forPaging(Clustering<?> lastReturned, DataLimits limits)
{
return new VirtualTableSinglePartitionReadQuery(metadata(),
nowInSec(),

View File

@ -33,7 +33,7 @@ public abstract class GroupMaker
*/
public static final GroupMaker GROUP_EVERYTHING = new GroupMaker()
{
public boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering)
public boolean isNewGroup(DecoratedKey partitionKey, Clustering<?> clustering)
{
return false;
}
@ -62,7 +62,7 @@ public abstract class GroupMaker
* @return <code>true</code> if the row belongs to the same group that the previous one, <code>false</code>
* otherwise.
*/
public abstract boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering);
public abstract boolean isNewGroup(DecoratedKey partitionKey, Clustering<?> clustering);
/**
* Specify if at least one row must be returned. If the selection is performing some aggregations on all the rows,
@ -95,7 +95,7 @@ public abstract class GroupMaker
/**
* The last clustering seen
*/
private Clustering lastClustering;
private Clustering<?> lastClustering;
public PkPrefixGroupMaker(ClusteringComparator comparator, int clusteringPrefixSize, GroupingState state)
{
@ -111,7 +111,7 @@ public abstract class GroupMaker
}
@Override
public boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering)
public boolean isNewGroup(DecoratedKey partitionKey, Clustering<?> clustering)
{
boolean isNew = false;

View File

@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.ClusteringComparator;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.db.marshal.ByteArrayAccessor;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.ByteBufferUtil;
@ -55,9 +56,9 @@ public final class GroupingState
/**
* The last row clustering
*/
final Clustering clustering;
final Clustering<?> clustering;
public GroupingState(ByteBuffer partitionKey, Clustering clustering)
public GroupingState(ByteBuffer partitionKey, Clustering<?> clustering)
{
this.partitionKey = partitionKey;
this.clustering = clustering;
@ -78,7 +79,7 @@ public final class GroupingState
* @return he last row clustering or <code>null</code> if either no rows has been processed yet or the last
* row was a static row
*/
public Clustering clustering()
public Clustering<?> clustering()
{
return clustering;
}
@ -115,7 +116,7 @@ public final class GroupingState
return GroupingState.EMPTY_STATE;
ByteBuffer partitionKey = ByteBufferUtil.readWithVIntLength(in);
Clustering clustering = null;
Clustering<byte[]> clustering = null;
if (in.readBoolean())
clustering = Clustering.serializer.deserialize(in, version, comparator.subtypes());

View File

@ -530,17 +530,17 @@ public abstract class AbstractSSTableIterator implements UnfilteredRowIterator
// Finds the index of the first block containing the provided bound, starting at the provided index.
// Will be -1 if the bound is before any block, and blocksCount() if it is after every block.
public int findBlockIndex(ClusteringBound bound, int fromIdx) throws IOException
public int findBlockIndex(ClusteringBound<?> bound, int fromIdx) throws IOException
{
if (bound == ClusteringBound.BOTTOM)
if (bound.isBottom())
return -1;
if (bound == ClusteringBound.TOP)
if (bound.isTop())
return blocksCount();
return indexFor(bound, fromIdx);
}
public int indexFor(ClusteringPrefix name, int lastIndex) throws IOException
public int indexFor(ClusteringPrefix<?> name, int lastIndex) throws IOException
{
IndexInfo target = new IndexInfo(name, name, 0, 0, null);
/*

View File

@ -75,9 +75,9 @@ public class SSTableIterator extends AbstractSSTableIterator
private class ForwardReader extends Reader
{
// The start of the current slice. This will be null as soon as we know we've passed that bound.
protected ClusteringBound start;
protected ClusteringBound<?> start;
// The end of the current slice. Will never be null.
protected ClusteringBound end = ClusteringBound.TOP;
protected ClusteringBound<?> end = BufferClusteringBound.TOP;
protected Unfiltered next; // the next element to return: this is computed by hasNextInternal().
@ -91,7 +91,7 @@ public class SSTableIterator extends AbstractSSTableIterator
public void setForSlice(Slice slice) throws IOException
{
start = slice.start() == ClusteringBound.BOTTOM ? null : slice.start();
start = slice.start().isBottom() ? null : slice.start();
end = slice.end();
sliceDone = false;
@ -119,7 +119,7 @@ public class SSTableIterator extends AbstractSSTableIterator
updateOpenMarker((RangeTombstoneMarker)deserializer.readNext());
}
ClusteringBound sliceStart = start;
ClusteringBound<?> sliceStart = start;
start = null;
// We've reached the beginning of our queried slice. If we have an open marker

View File

@ -172,8 +172,8 @@ public class SSTableReversedIterator extends AbstractSSTableIterator
// Reads the unfiltered from disk and load them into the reader buffer. It stops reading when either the partition
// is fully read, or when stopReadingDisk() returns true.
protected void loadFromDisk(ClusteringBound start,
ClusteringBound end,
protected void loadFromDisk(ClusteringBound<?> start,
ClusteringBound<?> end,
boolean hasPreviousBlock,
boolean hasNextBlock) throws IOException
{
@ -209,7 +209,7 @@ public class SSTableReversedIterator extends AbstractSSTableIterator
// want to "return" it just yet, we'll wait until we reach it in the next blocks. That's why we trigger
// skipLastIteratedItem in that case (this is first item of the block, but we're iterating in reverse order
// so it will be last returned by the iterator).
ClusteringBound markerStart = start == null ? ClusteringBound.BOTTOM : start;
ClusteringBound<?> markerStart = start == null ? BufferClusteringBound.BOTTOM : start;
buffer.add(new RangeTombstoneBoundMarker(markerStart, openMarker));
if (hasNextBlock)
skipLastIteratedItem = true;
@ -243,7 +243,7 @@ public class SSTableReversedIterator extends AbstractSSTableIterator
// not breaking ImmutableBTreePartition, we should skip it when returning from the iterator, hence the
// skipFirstIteratedItem (this is the last item of the block, but we're iterating in reverse order so it will
// be the first returned by the iterator).
ClusteringBound markerEnd = end == null ? ClusteringBound.TOP : end;
ClusteringBound<?> markerEnd = end == null ? BufferClusteringBound.TOP : end;
buffer.add(new RangeTombstoneBoundMarker(markerEnd, openMarker));
if (hasPreviousBlock)
skipFirstIteratedItem = true;

View File

@ -765,14 +765,14 @@ public class Scrubber implements Closeable
{
if (cd.column().isSimple())
{
Cell cell = (Cell)cd;
Cell<?> cell = (Cell<?>)cd;
if (cell.isExpiring() && cell.localDeletionTime() < 0)
return true;
}
else
{
ComplexColumnData complexData = (ComplexColumnData)cd;
for (Cell cell : complexData)
for (Cell<?> cell : complexData)
{
if (cell.isExpiring() && cell.localDeletionTime() < 0)
return true;
@ -795,14 +795,14 @@ public class Scrubber implements Closeable
{
if (cd.column().isSimple())
{
Cell cell = (Cell)cd;
Cell<?> cell = (Cell<?>)cd;
builder.addCell(cell.isExpiring() && cell.localDeletionTime() < 0 ? cell.withUpdatedTimestampAndLocalDeletionTime(cell.timestamp() + 1, AbstractCell.MAX_DELETION_TIME) : cell);
}
else
{
ComplexColumnData complexData = (ComplexColumnData)cd;
builder.addComplexDeletion(complexData.column(), complexData.complexDeletion());
for (Cell cell : complexData)
for (Cell<?> cell : complexData)
{
builder.addCell(cell.isExpiring() && cell.localDeletionTime() < 0 ? cell.withUpdatedTimestampAndLocalDeletionTime(cell.timestamp() + 1, AbstractCell.MAX_DELETION_TIME) : cell);
}

View File

@ -28,6 +28,9 @@ import org.slf4j.LoggerFactory;
import org.apache.cassandra.db.ClockAndCount;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.marshal.ByteBufferAccessor;
import org.apache.cassandra.db.marshal.ValueAccessor;
import org.apache.cassandra.db.rows.Cell;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.utils.*;
@ -90,7 +93,7 @@ public class CounterContext
private static final Logger logger = LoggerFactory.getLogger(CounterContext.class);
public static enum Relationship
public enum Relationship
{
EQUAL, GREATER_THAN, LESS_THAN, DISJOINT
}
@ -167,9 +170,9 @@ public class CounterContext
return state.context;
}
public static int headerLength(ByteBuffer context)
public static <V> int headerLength(V context, ValueAccessor<V> accessor)
{
return HEADER_SIZE_LENGTH + Math.abs(context.getShort(context.position())) * HEADER_ELT_LENGTH;
return HEADER_SIZE_LENGTH + Math.abs(accessor.getShort(context, 0)) * HEADER_ELT_LENGTH;
}
private static int compareId(ByteBuffer bb1, int pos1, ByteBuffer bb2, int pos2)
@ -566,34 +569,39 @@ public class CounterContext
* @param context a counter context
* @return the aggregated count represented by {@code context}
*/
public long total(ByteBuffer context)
public <V> long total(V context, ValueAccessor<V> accessor)
{
long total = 0L;
// we could use a ContextState but it is easy enough that we avoid the object creation
for (int offset = context.position() + headerLength(context); offset < context.limit(); offset += STEP_LENGTH)
total += context.getLong(offset + CounterId.LENGTH + CLOCK_LENGTH);
for (int offset = headerLength(context, accessor), size=accessor.size(context); offset < size; offset += STEP_LENGTH)
total += accessor.getLong(context, offset + CounterId.LENGTH + CLOCK_LENGTH);
return total;
}
public boolean shouldClearLocal(ByteBuffer context)
public <V> long total(Cell<V> cell)
{
return total(cell.value(), cell.accessor());
}
public <V> boolean shouldClearLocal(V context, ValueAccessor<V> accessor)
{
// #elt being negative means we have to clean local shards.
return context.getShort(context.position()) < 0;
return accessor.getShort(context, 0) < 0;
}
/**
* Detects whether or not the context has any legacy (local or remote) shards in it.
*/
public boolean hasLegacyShards(ByteBuffer context)
public <V> boolean hasLegacyShards(V context, ValueAccessor<V> accessor)
{
int totalCount = (context.remaining() - headerLength(context)) / STEP_LENGTH;
int localAndGlobalCount = Math.abs(context.getShort(context.position()));
int totalCount = (accessor.size(context) - headerLength(context, accessor)) / STEP_LENGTH;
int localAndGlobalCount = Math.abs(accessor.getShort(context, 0));
if (localAndGlobalCount < totalCount)
return true; // remote shard(s) present
for (int i = 0; i < localAndGlobalCount; i++)
if (context.getShort(context.position() + HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH) >= 0)
if (accessor.getShort(context, HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH) >= 0)
return true; // found a local shard
return false;
@ -636,22 +644,16 @@ public class CounterContext
return marked;
}
/**
* Remove all the local of a context (but keep global).
*
* @param context a counter context
* @return a version of {@code context} where no shards are local.
*/
public ByteBuffer clearAllLocal(ByteBuffer context)
public <V> V clearAllLocal(V context, ValueAccessor<V> accessor)
{
int count = Math.abs(context.getShort(context.position()));
int count = Math.abs(accessor.getShort(context, 0));
if (count == 0)
return context; // no local or global shards present.
List<Short> globalShardIndexes = new ArrayList<>(count);
for (int i = 0; i < count; i++)
{
short elt = context.getShort(context.position() + HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH);
short elt = accessor.getShort(context, HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH);
if (elt < 0)
globalShardIndexes.add(elt);
}
@ -660,25 +662,26 @@ public class CounterContext
return context; // no local shards detected.
// allocate a smaller BB for the cleared context - with no local header elts.
ByteBuffer cleared = ByteBuffer.allocate(context.remaining() - (count - globalShardIndexes.size()) * HEADER_ELT_LENGTH);
V cleared = accessor.allocate(accessor.size(context) - (count - globalShardIndexes.size()) * HEADER_ELT_LENGTH);
cleared.putShort(cleared.position(), (short) globalShardIndexes.size());
accessor.putShort(cleared, 0, (short) globalShardIndexes.size());
for (int i = 0; i < globalShardIndexes.size(); i++)
cleared.putShort(cleared.position() + HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH, globalShardIndexes.get(i));
accessor.putShort(cleared, HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH, globalShardIndexes.get(i));
int origHeaderLength = headerLength(context);
ByteBufferUtil.copyBytes(context,
context.position() + origHeaderLength,
cleared,
cleared.position() + headerLength(cleared),
context.remaining() - origHeaderLength);
int origHeaderLength = headerLength(context, accessor);
accessor.copyTo(context,
origHeaderLength,
cleared,
accessor,
headerLength(cleared, accessor),
accessor.size(context) - origHeaderLength);
return cleared;
}
public void validateContext(ByteBuffer context) throws MarshalException
public <V> void validateContext(V context, ValueAccessor<V> accessor) throws MarshalException
{
if ((context.remaining() - headerLength(context)) % STEP_LENGTH != 0)
if ((accessor.size(context) - headerLength(context, accessor)) % STEP_LENGTH != 0)
throw new MarshalException("Invalid size for a counter context");
}
@ -719,7 +722,7 @@ public class CounterContext
@VisibleForTesting
public int findPositionOf(ByteBuffer context, CounterId id)
{
int headerLength = headerLength(context);
int headerLength = headerLength(context, ByteBufferAccessor.instance);
int offset = context.position() + headerLength;
int left = 0;
@ -764,7 +767,7 @@ public class CounterContext
private ContextState(ByteBuffer context)
{
this.context = context;
this.headerLength = this.bodyOffset = headerLength(context);
this.headerLength = this.bodyOffset = headerLength(context, ByteBufferAccessor.instance);
this.headerOffset = HEADER_SIZE_LENGTH;
updateIsGlobalOrLocal();
}

View File

@ -77,7 +77,7 @@ public interface ClusteringIndexFilter
*
* @return a new filter that selects results coming after {@code lastReturned}.
*/
public ClusteringIndexFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive);
public ClusteringIndexFilter forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive);
/**
* Returns whether we can guarantee that a given cached partition contains all the data selected by this filter.
@ -109,7 +109,7 @@ public interface ClusteringIndexFilter
*
* @return whether the row with clustering {@code clustering} is selected by this filter.
*/
public boolean selects(Clustering clustering);
public boolean selects(Clustering<?> clustering);
/**
* Returns an iterator that only returns the rows of the provided iterator that this filter selects.

View File

@ -42,14 +42,14 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
// This could be empty if selectedColumns only has static columns (in which case the filter still
// selects the static row)
private final NavigableSet<Clustering> clusterings;
private final NavigableSet<Clustering<?>> clusterings;
// clusterings is always in clustering order (because we need it that way in some methods), but we also
// sometimes need those clustering in "query" order (i.e. in reverse clustering order if the query is
// reversed), so we keep that too for simplicity.
private final NavigableSet<Clustering> clusteringsInQueryOrder;
private final NavigableSet<Clustering<?>> clusteringsInQueryOrder;
public ClusteringIndexNamesFilter(NavigableSet<Clustering> clusterings, boolean reversed)
public ClusteringIndexNamesFilter(NavigableSet<Clustering<?>> clusterings, boolean reversed)
{
super(reversed);
assert !clusterings.contains(Clustering.STATIC_CLUSTERING);
@ -65,7 +65,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
* @return the set of requested clustering in clustering order (note that
* this is always in clustering order even if the query is reversed).
*/
public NavigableSet<Clustering> requestedRows()
public NavigableSet<Clustering<?>> requestedRows()
{
return clusterings;
}
@ -77,16 +77,16 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
return clusterings.isEmpty();
}
public boolean selects(Clustering clustering)
public boolean selects(Clustering<?> clustering)
{
return clusterings.contains(clustering);
}
public ClusteringIndexNamesFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive)
public ClusteringIndexNamesFilter forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive)
{
NavigableSet<Clustering> newClusterings = reversed ?
clusterings.headSet(lastReturned, inclusive) :
clusterings.tailSet(lastReturned, inclusive);
NavigableSet<Clustering<?>> newClusterings = reversed ?
clusterings.headSet(lastReturned, inclusive) :
clusterings.tailSet(lastReturned, inclusive);
return new ClusteringIndexNamesFilter(newClusterings, reversed);
}
@ -131,15 +131,15 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
public Slices getSlices(TableMetadata metadata)
{
Slices.Builder builder = new Slices.Builder(metadata.comparator, clusteringsInQueryOrder.size());
for (Clustering clustering : clusteringsInQueryOrder)
for (Clustering<?> clustering : clusteringsInQueryOrder)
builder.add(Slice.make(clustering));
return builder.build();
}
public UnfilteredRowIterator getUnfilteredRowIterator(final ColumnFilter columnFilter, final Partition partition)
{
final Iterator<Clustering> clusteringIter = clusteringsInQueryOrder.iterator();
final SearchIterator<Clustering, Row> searcher = partition.searchIterator(columnFilter, reversed);
final Iterator<Clustering<?>> clusteringIter = clusteringsInQueryOrder.iterator();
final SearchIterator<Clustering<?>, Row> searcher = partition.searchIterator(columnFilter, reversed);
return new AbstractUnfilteredRowIterator(partition.metadata(),
partition.partitionKey(),
@ -169,7 +169,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
List<ByteBuffer> maxClusteringValues = sstable.getSSTableMetadata().maxClusteringValues;
// If any of the requested clustering is within the bounds covered by the sstable, we need to include the sstable
for (Clustering clustering : clusterings)
for (Clustering<?> clustering : clusterings)
{
if (Slice.make(clustering).intersects(comparator, minClusteringValues, maxClusteringValues))
return true;
@ -182,7 +182,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
StringBuilder sb = new StringBuilder();
sb.append("names(");
int i = 0;
for (Clustering clustering : clusterings)
for (Clustering<?> clustering : clusterings)
sb.append(i++ == 0 ? "" : ", ").append(clustering.toString(metadata));
if (reversed)
sb.append(", reversed");
@ -198,7 +198,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
sb.append('(').append(ColumnMetadata.toCQLString(metadata.clusteringColumns())).append(')');
sb.append(clusterings.size() == 1 ? " = " : " IN (");
int i = 0;
for (Clustering clustering : clusterings)
for (Clustering<?> clustering : clusterings)
sb.append(i++ == 0 ? "" : ", ").append('(').append(clustering.toCQLString(metadata)).append(')');
sb.append(clusterings.size() == 1 ? "" : ")");
@ -229,7 +229,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
{
ClusteringComparator comparator = (ClusteringComparator)clusterings.comparator();
out.writeUnsignedVInt(clusterings.size());
for (Clustering clustering : clusterings)
for (Clustering<?> clustering : clusterings)
Clustering.serializer.serialize(clustering, out, version, comparator.subtypes());
}
@ -237,7 +237,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
{
ClusteringComparator comparator = (ClusteringComparator)clusterings.comparator();
long size = TypeSizes.sizeofUnsignedVInt(clusterings.size());
for (Clustering clustering : clusterings)
for (Clustering<?> clustering : clusterings)
size += Clustering.serializer.serializedSize(clustering, version, comparator.subtypes());
return size;
}
@ -247,7 +247,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter
public ClusteringIndexFilter deserialize(DataInputPlus in, int version, TableMetadata metadata, boolean reversed) throws IOException
{
ClusteringComparator comparator = metadata.comparator;
BTreeSet.Builder<Clustering> clusterings = BTreeSet.builder(comparator);
BTreeSet.Builder<Clustering<?>> clusterings = BTreeSet.builder(comparator);
int size = (int)in.readUnsignedVInt();
for (int i = 0; i < size; i++)
clusterings.add(Clustering.serializer.deserialize(in, version, comparator.subtypes()));

View File

@ -56,12 +56,12 @@ public class ClusteringIndexSliceFilter extends AbstractClusteringIndexFilter
return slices.size() == 1 && !slices.hasLowerBound() && !slices.hasUpperBound();
}
public boolean selects(Clustering clustering)
public boolean selects(Clustering<?> clustering)
{
return slices.selects(clustering);
}
public ClusteringIndexSliceFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive)
public ClusteringIndexSliceFilter forPaging(ClusteringComparator comparator, Clustering<?> lastReturned, boolean inclusive)
{
Slices newSlices = slices.forPaging(comparator, lastReturned, inclusive, reversed);
return slices == newSlices

View File

@ -276,7 +276,7 @@ public class ColumnFilter
* @param cells the cells to filter.
* @return a filtered iterator that only include the cells from {@code cells} that are included by this filter.
*/
public Iterator<Cell> filterComplexCells(ColumnMetadata column, Iterator<Cell> cells)
public Iterator<Cell<?>> filterComplexCells(ColumnMetadata column, Iterator<Cell<?>> cells)
{
Tester tester = newTester(column);
if (tester == null)

View File

@ -205,14 +205,14 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
* Returns true if all of the expressions within this filter that apply to the clustering key are satisfied by
* the given Clustering, false otherwise.
*/
public boolean clusteringKeyRestrictionsAreSatisfiedBy(Clustering clustering)
public boolean clusteringKeyRestrictionsAreSatisfiedBy(Clustering<?> clustering)
{
for (Expression e : expressions)
{
if (!e.column.isClusteringColumn())
continue;
if (!e.operator().isSatisfiedBy(e.column.type, clustering.get(e.column.position()), e.value))
if (!e.operator().isSatisfiedBy(e.column.type, clustering.bufferAt(e.column.position()), e.value))
{
return false;
}
@ -448,10 +448,10 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
? CompositeType.extractComponent(partitionKey.getKey(), column.position())
: partitionKey.getKey();
case CLUSTERING:
return row.clustering().get(column.position());
return row.clustering().bufferAt(column.position());
default:
Cell cell = row.getCell(column);
return cell == null ? null : cell.value();
Cell<?> cell = row.getCell(column);
return cell == null ? null : cell.buffer();
}
}
@ -616,7 +616,7 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
if (foundValue == null)
return false;
ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue));
ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue, ByteBufferAccessor.instance));
return operator.isSatisfiedBy(LongType.instance, counterValue, value);
}
else
@ -645,7 +645,7 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
ComplexColumnData complexData = row.getComplexColumnData(column);
if (complexData != null)
{
for (Cell cell : complexData)
for (Cell<?> cell : complexData)
{
if (type.kind == CollectionType.Kind.SET)
{
@ -654,7 +654,7 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
}
else
{
if (type.valueComparator().compare(cell.value(), value) == 0)
if (type.valueComparator().compare(cell.buffer(), value) == 0)
return true;
}
}
@ -760,7 +760,7 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
@Override
public ByteBuffer getIndexValue()
{
return CompositeType.build(key, value);
return CompositeType.build(ByteBufferAccessor.instance, key, value);
}
public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey partitionKey, Row row)
@ -776,8 +776,8 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
MapType<?, ?> mt = (MapType<?, ?>)column.type;
if (column.isComplex())
{
Cell cell = row.getCell(column, CellPath.create(key));
return cell != null && mt.valueComparator().compare(cell.value(), value) == 0;
Cell<?> cell = row.getCell(column, CellPath.create(key));
return cell != null && mt.valueComparator().compare(cell.buffer(), value) == 0;
}
else
{

View File

@ -26,13 +26,13 @@ import org.apache.cassandra.db.marshal.*;
public class TombstoneOverwhelmingException extends RuntimeException
{
public TombstoneOverwhelmingException(int numTombstones, String query, TableMetadata metadata, DecoratedKey lastPartitionKey, ClusteringPrefix lastClustering)
public TombstoneOverwhelmingException(int numTombstones, String query, TableMetadata metadata, DecoratedKey lastPartitionKey, ClusteringPrefix<?> lastClustering)
{
super(String.format("Scanned over %d tombstones during query '%s' (last scanned row token was %s and partion key was (%s)); query aborted",
numTombstones, query, lastPartitionKey.getToken(), makePKString(metadata, lastPartitionKey.getKey(), lastClustering)));
}
private static String makePKString(TableMetadata metadata, ByteBuffer partitionKey, ClusteringPrefix clustering)
private static String makePKString(TableMetadata metadata, ByteBuffer partitionKey, ClusteringPrefix<?> clustering)
{
StringBuilder sb = new StringBuilder();
@ -61,7 +61,7 @@ public class TombstoneOverwhelmingException extends RuntimeException
sb.append(")");
for (int i = 0; i < clustering.size(); i++)
sb.append(", ").append(metadata.comparator.subtype(i).getString(clustering.get(i)));
sb.append(", ").append(clustering.stringAt(i, metadata.comparator));
return sb.toString();
}

View File

@ -43,72 +43,81 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer>
super(ComparisonType.CUSTOM);
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left));
ByteBuffer bb1 = o1.duplicate();
ByteBuffer bb2 = o2.duplicate();
boolean isStatic1 = readIsStatic(bb1);
boolean isStatic2 = readIsStatic(bb2);
if (isStatic1 != isStatic2)
return isStatic1 ? -1 : 1;
boolean isStaticL = readIsStatic(left, accessorL);
boolean isStaticR = readIsStatic(right, accessorR);
if (isStaticL != isStaticR)
return isStaticL ? -1 : 1;
int i = 0;
ByteBuffer previous = null;
VL previous = null;
int offsetL = startingOffset(isStaticL);
int offsetR = startingOffset(isStaticR);
while (bb1.remaining() > 0 && bb2.remaining() > 0)
while (!accessorL.isEmptyFromOffset(left, offsetL) && !accessorR.isEmptyFromOffset(right, offsetL))
{
AbstractType<?> comparator = getComparator(i, bb1, bb2);
AbstractType<?> comparator = getComparator(i, left, accessorL, right, accessorR, offsetL, offsetR);
offsetL += getComparatorSize(i, left, accessorL, offsetL);
offsetR += getComparatorSize(i, right, accessorR, offsetR);
ByteBuffer value1 = ByteBufferUtil.readBytesWithShortLength(bb1);
ByteBuffer value2 = ByteBufferUtil.readBytesWithShortLength(bb2);
VL value1 = accessorL.sliceWithShortLength(left, offsetL);
offsetL += accessorL.sizeWithShortLength(value1);
VR value2 = accessorR.sliceWithShortLength(right, offsetR);
offsetR += accessorR.sizeWithShortLength(value2);
int cmp = comparator.compareCollectionMembers(value1, value2, previous);
int cmp = comparator.compareCollectionMembers(value1, accessorL, value2, accessorR, previous);
if (cmp != 0)
return cmp;
previous = value1;
byte b1 = bb1.get();
byte b2 = bb2.get();
if (b1 != b2)
return b1 - b2;
byte bL = accessorL.getByte(left, offsetL++);
byte bR = accessorR.getByte(right, offsetR++);
if (bL != bR)
return bL - bR;
++i;
}
if (bb1.remaining() == 0)
return bb2.remaining() == 0 ? 0 : -1;
if (accessorL.isEmptyFromOffset(left, offsetL))
return accessorR.sizeFromOffset(right, offsetR) == 0 ? 0 : -1;
// bb1.remaining() > 0 && bb2.remaining() == 0
// left.remaining() > 0 && right.remaining() == 0
return 1;
}
// Check if the provided BB represents a static name and advance the
// buffer to the real beginning if so.
protected abstract boolean readIsStatic(ByteBuffer bb);
protected abstract <V> boolean readIsStatic(V value, ValueAccessor<V> accessor);
protected abstract int startingOffset(boolean isStatic);
/**
* Split a composite column names into it's components.
*/
public ByteBuffer[] split(ByteBuffer name)
public ByteBuffer[] split(ByteBuffer bb)
{
List<ByteBuffer> l = new ArrayList<ByteBuffer>();
ByteBuffer bb = name.duplicate();
readIsStatic(bb);
boolean isStatic = readIsStatic(bb, ByteBufferAccessor.instance);
int offset = startingOffset(isStatic);
int i = 0;
while (bb.remaining() > 0)
while (!ByteBufferAccessor.instance.isEmptyFromOffset(bb, offset))
{
getComparator(i++, bb);
l.add(ByteBufferUtil.readBytesWithShortLength(bb));
bb.get(); // skip end-of-component
offset += getComparatorSize(i++, bb, ByteBufferAccessor.instance, offset);
ByteBuffer value = ByteBufferAccessor.instance.sliceWithShortLength(bb, offset);
offset += ByteBufferAccessor.instance.sizeWithShortLength(value);
l.add(value);
offset++; // skip end-of-component
}
return l.toArray(new ByteBuffer[l.size()]);
}
private static final String COLON = ":";
private static final Pattern COLON_PAT = Pattern.compile(COLON);
private static final String ESCAPED_COLON = "\\\\:";
@ -165,24 +174,27 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer>
return res;
}
public String getString(ByteBuffer bytes)
public <V> String getString(V input, ValueAccessor<V> accessor)
{
StringBuilder sb = new StringBuilder();
ByteBuffer bb = bytes.duplicate();
readIsStatic(bb);
boolean isStatic = readIsStatic(input, accessor);
int offset = startingOffset(isStatic);
int startOffset = offset;
int i = 0;
while (bb.remaining() > 0)
while (!accessor.isEmptyFromOffset(input, offset))
{
if (bb.remaining() != bytes.remaining())
if (offset != startOffset)
sb.append(":");
AbstractType<?> comparator = getAndAppendComparator(i, bb, sb);
ByteBuffer value = ByteBufferUtil.readBytesWithShortLength(bb);
AbstractType<?> comparator = getAndAppendComparator(i, input, accessor, sb, offset);
offset += getComparatorSize(i, input, accessor, offset);
V value = accessor.sliceWithShortLength(input, offset);
offset += accessor.sizeWithShortLength(value);
sb.append(escape(comparator.getString(value)));
sb.append(escape(comparator.getString(value, accessor)));
byte b = bb.get();
byte b = accessor.getByte(input, offset++);
if (b != 0)
{
sb.append(b < 0 ? ":_" : ":!");
@ -258,31 +270,39 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer>
}
@Override
public void validate(ByteBuffer bytes) throws MarshalException
public void validate(ByteBuffer bb) throws MarshalException
{
ByteBuffer bb = bytes.duplicate();
readIsStatic(bb);
validate(bb, ByteBufferAccessor.instance);
}
public <V> void validate(V input, ValueAccessor<V> accessor)
{
boolean isStatic = readIsStatic(input, accessor);
int offset = startingOffset(isStatic);
int i = 0;
ByteBuffer previous = null;
while (bb.remaining() > 0)
V previous = null;
while (!accessor.isEmptyFromOffset(input, offset))
{
AbstractType<?> comparator = validateComparator(i, bb);
AbstractType<?> comparator = validateComparator(i, input, accessor, offset);
offset += getComparatorSize(i, input, accessor, offset);
if (bb.remaining() < 2)
if (accessor.sizeFromOffset(input, offset) < 2)
throw new MarshalException("Not enough bytes to read value size of component " + i);
int length = ByteBufferUtil.readShortLength(bb);
int length = accessor.getShort(input, offset);
offset += 2;
if (bb.remaining() < length)
if (accessor.sizeFromOffset(input, offset) < length)
throw new MarshalException("Not enough bytes to read value of component " + i);
ByteBuffer value = ByteBufferUtil.readBytes(bb, length);
V value = accessor.slice(input, offset, length);
offset += length;
comparator.validateCollectionMember(value, previous);
comparator.validateCollectionMember(value, previous, accessor);
if (bb.remaining() == 0)
if (accessor.isEmptyFromOffset(input, offset))
throw new MarshalException("Not enough bytes to read the end-of-component byte of component" + i);
byte b = bb.get();
if (b != 0 && bb.remaining() != 0)
byte b = accessor.getByte(input, offset++);
if (b != 0 && !accessor.isEmptyFromOffset(input, offset))
throw new MarshalException("Invalid bytes remaining after an end-of-component at component" + i);
previous = value;
@ -297,28 +317,29 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer>
return BytesSerializer.instance;
}
abstract protected <V> int getComparatorSize(int i, V value, ValueAccessor<V> accessor, int offset);
/**
* @return the comparator for the given component. static CompositeType will consult
* @param i DynamicCompositeType will read the type information from @param bb
* @param bb name of type definition
* @param value name of type definition
*/
abstract protected AbstractType<?> getComparator(int i, ByteBuffer bb);
abstract protected <V> AbstractType<?> getComparator(int i, V value, ValueAccessor<V> accessor, int offset);
/**
* Adds DynamicCompositeType type information from @param bb1 to @param bb2.
* @param i is ignored.
*/
abstract protected AbstractType<?> getComparator(int i, ByteBuffer bb1, ByteBuffer bb2);
abstract protected <VL, VR> AbstractType<?> getComparator(int i, VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR, int offsetL, int offsetR);
/**
* Adds type information from @param bb to @param sb. @param i is ignored.
*/
abstract protected AbstractType<?> getAndAppendComparator(int i, ByteBuffer bb, StringBuilder sb);
abstract protected <V> AbstractType<?> getAndAppendComparator(int i, V value, ValueAccessor<V> accessor, StringBuilder sb, int offset);
/**
* Like getComparator, but validates that @param i does not exceed the defined range
*/
abstract protected AbstractType<?> validateComparator(int i, ByteBuffer bb) throws MarshalException;
abstract protected <V> AbstractType<?> validateComparator(int i, V value, ValueAccessor<V> accessor, int offset) throws MarshalException;
/**
* Used by fromString

View File

@ -28,14 +28,10 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.Term;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.exceptions.SyntaxException;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
@ -43,7 +39,6 @@ import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FastByteOperations;
import org.github.jamm.Unmetered;
import static org.apache.cassandra.db.marshal.AbstractType.ComparisonType.CUSTOM;
@ -59,8 +54,6 @@ import static org.apache.cassandra.db.marshal.AbstractType.ComparisonType.CUSTOM
@Unmetered
public abstract class AbstractType<T> implements Comparator<ByteBuffer>, AssignmentTestable
{
private static final Logger logger = LoggerFactory.getLogger(AbstractType.class);
public final Comparator<ByteBuffer> reverseComparator;
public enum ComparisonType
@ -83,6 +76,7 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
public final ComparisonType comparisonType;
public final boolean isByteOrderComparable;
public final ValueComparators comparatorSet;
protected AbstractType(ComparisonType comparisonType)
{
@ -91,7 +85,7 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
reverseComparator = (o1, o2) -> AbstractType.this.compare(o2, o1);
try
{
Method custom = getClass().getMethod("compareCustom", ByteBuffer.class, ByteBuffer.class);
Method custom = getClass().getMethod("compareCustom", Object.class, ValueAccessor.class, Object.class, ValueAccessor.class);
if ((custom.getDeclaringClass() == AbstractType.class) == (comparisonType == CUSTOM))
throw new IllegalStateException((comparisonType == CUSTOM ? "compareCustom must be overridden if ComparisonType is CUSTOM"
: "compareCustom should not be overridden if ComparisonType is not CUSTOM")
@ -101,6 +95,17 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
{
throw new IllegalStateException();
}
comparatorSet = new ValueComparators((l, r) -> compare(l, ByteArrayAccessor.instance, r, ByteArrayAccessor.instance),
(l, r) -> compare(l, ByteBufferAccessor.instance, r, ByteBufferAccessor.instance));
}
static <VL, VR, T extends Comparable<T>> int compareComposed(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR, AbstractType<T> type)
{
if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left));
return type.compose(left, accessorL).compareTo(type.compose(right, accessorR));
}
public static List<String> asCQLTypeStringList(List<AbstractType<?>> abstractTypes)
@ -111,26 +116,36 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
return r;
}
public T compose(ByteBuffer bytes)
public final T compose(ByteBuffer bytes)
{
return getSerializer().deserialize(bytes);
}
public <V> T compose(V value, ValueAccessor<V> accessor)
{
return getSerializer().deserialize(value, accessor);
}
public ByteBuffer decompose(T value)
{
return getSerializer().serialize(value);
}
/** get a string representation of the bytes used for various identifier (NOT just for log messages) */
public String getString(ByteBuffer bytes)
public <V> String getString(V value, ValueAccessor<V> accessor)
{
if (bytes == null)
if (value == null)
return "null";
TypeSerializer<T> serializer = getSerializer();
serializer.validate(bytes);
serializer.validate(value, accessor);
return serializer.toString(serializer.deserialize(bytes));
return serializer.toString(serializer.deserialize(value, accessor));
}
public final String getString(ByteBuffer bytes)
{
return getString(bytes, ByteBufferAccessor.instance);
}
/** get a byte representation of the given string. */
@ -156,29 +171,46 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
return '"' + Objects.toString(getSerializer().deserialize(buffer), "") + '"';
}
public <V> String toJSONString(V value, ValueAccessor<V> accessor, ProtocolVersion protocolVersion)
{
return toJSONString(accessor.toBuffer(value), protocolVersion); // FIXME
}
/* validate that the byte array is a valid sequence for the type we are supposed to be comparing */
public void validate(ByteBuffer bytes) throws MarshalException
{
getSerializer().validate(bytes);
validate(bytes, ByteBufferAccessor.instance);
}
public <V> void validate(V value, ValueAccessor<V> accessor) throws MarshalException
{
getSerializer().validate(value, accessor);
}
public final int compare(ByteBuffer left, ByteBuffer right)
{
return isByteOrderComparable
? FastByteOperations.compareUnsigned(left, right)
: compareCustom(left, right);
return compare(left, ByteBufferAccessor.instance, right, ByteBufferAccessor.instance);
}
public final <VL, VR> int compare(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
return isByteOrderComparable ? ValueAccessor.compare(left, accessorL, right, accessorR) : compareCustom(left, accessorL, right, accessorR);
}
/**
* Implement IFF ComparisonType is CUSTOM
*
* Compares the ByteBuffer representation of two instances of this class,
* Compares the byte representation of two instances of this class,
* for types where this cannot be done by simple in-order comparison of the
* unsigned bytes
*
* Standard Java compare semantics
* @param left
* @param accessorL
* @param right
* @param accessorR
*/
public int compareCustom(ByteBuffer left, ByteBuffer right)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
throw new UnsupportedOperationException();
}
@ -191,9 +223,9 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
* @param cellValue ByteBuffer representing cell value
* @throws MarshalException
*/
public void validateCellValue(ByteBuffer cellValue) throws MarshalException
public <V> void validateCellValue(V cellValue, ValueAccessor<V> accessor) throws MarshalException
{
validate(cellValue);
validate(cellValue, accessor);
}
/* Most of our internal type should override that. */
@ -303,19 +335,14 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
*
* Unless you're doing something very similar to CollectionsType, you shouldn't override this.
*/
public int compareCollectionMembers(ByteBuffer v1, ByteBuffer v2, ByteBuffer collectionName)
public <VL, VR> int compareCollectionMembers(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR, VL collectionName)
{
return compare(v1, v2);
return compare(left, accessorL, right, accessorR);
}
/**
* An alternative validation function used by CollectionsType in conjunction with CompositeType.
*
* This is similar to the compare function above.
*/
public void validateCollectionMember(ByteBuffer bytes, ByteBuffer collectionName) throws MarshalException
public <V> void validateCollectionMember(V value, V collectionName, ValueAccessor<V> accessor) throws MarshalException
{
validate(bytes);
getSerializer().validate(value, accessor);
}
public boolean isCollection()
@ -382,15 +409,6 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
return this.toString();
}
/**
* The number of subcomponents this type has.
* This is always 1, i.e. the type has only itself as "subcomponents", except for CompositeType.
*/
public int componentsCount()
{
return 1;
}
/**
* Return a list of the "subcomponents" this type has.
* This always return a singleton list with the type itself except for CompositeType.
@ -411,32 +429,53 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
// This assumes that no empty values are passed
public void writeValue(ByteBuffer value, DataOutputPlus out) throws IOException
{
assert value.hasRemaining();
writeValue(value, ByteBufferAccessor.instance, out);
}
// This assumes that no empty values are passed
public <V> void writeValue(V value, ValueAccessor<V> accessor, DataOutputPlus out) throws IOException
{
assert !accessor.isEmpty(value);
if (valueLengthIfFixed() >= 0)
out.write(value);
accessor.write(value, out);
else
ByteBufferUtil.writeWithVIntLength(value, out);
accessor.writeWithVIntLength(value, out);
}
public long writtenLength(ByteBuffer value)
{
assert value.hasRemaining() : "bytes should not be empty for type " + this;
return valueLengthIfFixed() >= 0
? value.remaining()
: TypeSizes.sizeofWithVIntLength(value);
return writtenLength(value, ByteBufferAccessor.instance);
}
public ByteBuffer readValue(DataInputPlus in) throws IOException
public <V> long writtenLength(V value, ValueAccessor<V> accessor)
{
return readValue(in, Integer.MAX_VALUE);
assert !accessor.isEmpty(value) : "bytes should not be empty for type " + this;
return valueLengthIfFixed() >= 0
? accessor.size(value)
: accessor.sizeWithVIntLength(value);
}
public ByteBuffer readValue(DataInputPlus in, int maxValueSize) throws IOException
public ByteBuffer readBuffer(DataInputPlus in) throws IOException
{
return readBuffer(in, Integer.MAX_VALUE);
}
public ByteBuffer readBuffer(DataInputPlus in, int maxValueSize) throws IOException
{
return read(ByteBufferAccessor.instance, in, maxValueSize);
}
public byte[] readArray(DataInputPlus in, int maxValueSize) throws IOException
{
return read(ByteArrayAccessor.instance, in, maxValueSize);
}
public <V> V read(ValueAccessor<V> accessor, DataInputPlus in, int maxValueSize) throws IOException
{
int length = valueLengthIfFixed();
if (length >= 0)
return ByteBufferUtil.read(in, length);
return accessor.read(in, length);
else
{
int l = (int)in.readUnsignedVInt();
@ -448,7 +487,7 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
"which is set via max_value_size_in_mb in cassandra.yaml",
l, maxValueSize));
return ByteBufferUtil.read(in, l);
return accessor.read(in, l);
}
}
@ -461,7 +500,12 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
ByteBufferUtil.skipWithVIntLength(in);
}
public boolean referencesUserType(ByteBuffer name)
public final boolean referencesUserType(ByteBuffer name)
{
return referencesUserType(name, ByteBufferAccessor.instance);
}
public <V> boolean referencesUserType(V name, ValueAccessor<V> accessor)
{
return false;
}

View File

@ -43,17 +43,15 @@ public class BooleanType extends AbstractType<Boolean>
return true;
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left));
// False is 0, True is anything else, makes False sort before True.
byte b1 = o1.get(o1.position());
byte b2 = o2.get(o2.position());
if (b1 == 0)
return b2 == 0 ? 0 : -1;
return b2 == 0 ? 1 : 0;
int v1 = accessorL.getByte(left, 0) == 0 ? 0 : 1;
int v2 = accessorR.getByte(right, 0) == 0 ? 0 : 1;
return v1 - v2;
}
public ByteBuffer fromString(String source) throws MarshalException

View File

@ -0,0 +1,294 @@
/*
* 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.marshal;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.UUID;
import org.apache.cassandra.db.Digest;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.ByteArrayUtil;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FastByteOperations;
import org.apache.cassandra.utils.Hex;
import org.apache.cassandra.utils.UUIDGen;
public class ByteArrayAccessor implements ValueAccessor<byte[]>
{
public static final ValueAccessor<byte[]> instance = new ByteArrayAccessor();
public static final ObjectFactory<byte[]> factory = ByteArrayObjectFactory.instance;
private static final byte[] EMPTY = new byte[0];
private ByteArrayAccessor() {}
public int size(byte[] value)
{
return value.length;
}
public byte[][] createArray(int length)
{
return new byte[length][];
}
public void write(byte[] value, DataOutputPlus out) throws IOException
{
out.write(value);
}
public void write(byte[] value, ByteBuffer out)
{
out.put(value);
}
public <V2> int copyTo(byte[] src, int srcOffset, V2 dst, ValueAccessor<V2> dstAccessor, int dstOffset, int size)
{
dstAccessor.copyByteArrayTo(src, srcOffset, dst, dstOffset, size);
return size;
}
public int copyByteArrayTo(byte[] src, int srcOffset, byte[] dst, int dstOffset, int size)
{
FastByteOperations.copy(src, srcOffset, dst, dstOffset, size);
return size;
}
public int copyByteBufferTo(ByteBuffer src, int srcOffset, byte[] dst, int dstOffset, int size)
{
FastByteOperations.copy(src, src.position() + srcOffset, dst, dstOffset, size);
return size;
}
public void digest(byte[] value, int offset, int size, Digest digest)
{
digest.update(value, offset, size);
}
public byte[] read(DataInputPlus in, int length) throws IOException
{
byte[] b = new byte[length];
in.readFully(b);
return b;
}
public byte[] slice(byte[] input, int offset, int length)
{
return Arrays.copyOfRange(input, offset, offset + length);
}
public <V2> int compare(byte[] left, V2 right, ValueAccessor<V2> accessorR)
{
return accessorR.compareByteArrayTo(left, right);
}
public int compareByteArrayTo(byte[] left, byte[] right)
{
return ByteArrayUtil.compareUnsigned(left, right);
}
public int compareByteBufferTo(ByteBuffer left, byte[] right)
{
return ByteBufferUtil.compare(left, right);
}
public ByteBuffer toBuffer(byte[] value)
{
if (value == null)
return null;
return ByteBuffer.wrap(value);
}
public byte[] toArray(byte[] value)
{
return value;
}
public byte[] toArray(byte[] value, int offset, int length)
{
if (value == null)
return null;
if (offset == 0 && length == value.length)
return value;
return slice(value, offset, length);
}
public String toString(byte[] value, Charset charset) throws CharacterCodingException
{
return new String(value, charset);
}
public String toHex(byte[] value)
{
return Hex.bytesToHex(value);
}
public byte toByte(byte[] value)
{
return value[0];
}
public byte getByte(byte[] value, int offset)
{
return value[offset];
}
public short toShort(byte[] value)
{
return getShort(value, 0);
}
public short getShort(byte[] value, int offset)
{
return ByteArrayUtil.getShort(value, offset);
}
public int toInt(byte[] value)
{
return getInt(value, 0);
}
public int getInt(byte[] value, int offset)
{
return ByteArrayUtil.getInt(value, offset);
}
public long toLong(byte[] value)
{
return getLong(value, 0);
}
public long getLong(byte[] value, int offset)
{
return ByteArrayUtil.getLong(value, offset);
}
public float toFloat(byte[] value)
{
return ByteArrayUtil.getFloat(value, 0);
}
public double toDouble(byte[] value)
{
return ByteArrayUtil.getDouble(value, 0);
}
public UUID toUUID(byte[] value)
{
return new UUID(getLong(value, 0), getLong(value, 8));
}
public int putShort(byte[] dst, int offset, short value)
{
ByteArrayUtil.putShort(dst, offset, value);
return TypeSizes.SHORT_SIZE;
}
public int putInt(byte[] dst, int offset, int value)
{
ByteArrayUtil.putInt(dst, offset, value);
return TypeSizes.INT_SIZE;
}
public int putLong(byte[] dst, int offset, long value)
{
ByteArrayUtil.putLong(dst, offset, value);
return TypeSizes.LONG_SIZE;
}
public byte[] empty()
{
return EMPTY;
}
public byte[] valueOf(byte[] bytes)
{
return bytes;
}
public byte[] valueOf(ByteBuffer bytes)
{
return ByteBufferUtil.getArray(bytes);
}
public byte[] valueOf(String s, Charset charset)
{
return ByteArrayUtil.bytes(s, charset);
}
public byte[] valueOf(UUID v)
{
return UUIDGen.decompose(v);
}
public byte[] valueOf(boolean v)
{
return v ? new byte[] {1} : new byte[] {0};
}
public byte[] valueOf(byte v)
{
return ByteArrayUtil.bytes(v);
}
public byte[] valueOf(short v)
{
return ByteArrayUtil.bytes(v);
}
public byte[] valueOf(int v)
{
return ByteArrayUtil.bytes(v);
}
public byte[] valueOf(long v)
{
return ByteArrayUtil.bytes(v);
}
public byte[] valueOf(float v)
{
return ByteArrayUtil.bytes(v);
}
public byte[] valueOf(double v)
{
return ByteArrayUtil.bytes(v);
}
public <V2> byte[] convert(V2 src, ValueAccessor<V2> accessor)
{
return accessor.toArray(src);
}
public byte[] allocate(int size)
{
return new byte[size];
}
public ObjectFactory<byte[]> factory()
{
return factory;
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.marshal;
import org.apache.cassandra.db.ArrayClustering;
import org.apache.cassandra.db.ArrayClusteringBound;
import org.apache.cassandra.db.ArrayClusteringBoundary;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.ClusteringBound;
import org.apache.cassandra.db.ClusteringBoundary;
import org.apache.cassandra.db.ClusteringPrefix;
import org.apache.cassandra.db.rows.ArrayCell;
import org.apache.cassandra.db.rows.Cell;
import org.apache.cassandra.db.rows.CellPath;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
class ByteArrayObjectFactory implements ValueAccessor.ObjectFactory<byte[]>
{
private static final Clustering<byte[]> EMPTY_CLUSTERING = new ArrayClustering()
{
public String toString(TableMetadata metadata)
{
return "EMPTY";
}
};
static final ValueAccessor.ObjectFactory<byte[]> instance = new ByteArrayObjectFactory();
private ByteArrayObjectFactory() {}
/** The smallest start bound, i.e. the one that starts before any row. */
private static final ArrayClusteringBound BOTTOM_BOUND = new ArrayClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, new byte[0][]);
/** The biggest end bound, i.e. the one that ends after any row. */
private static final ArrayClusteringBound TOP_BOUND = new ArrayClusteringBound(ClusteringPrefix.Kind.INCL_END_BOUND, new byte[0][]);
public Cell<byte[]> cell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, byte[] value, CellPath path)
{
return new ArrayCell(column, timestamp, ttl, localDeletionTime, value, path);
}
public Clustering<byte[]> clustering(byte[]... values)
{
return new ArrayClustering(values);
}
public Clustering<byte[]> clustering()
{
return EMPTY_CLUSTERING;
}
public ClusteringBound<byte[]> bound(ClusteringPrefix.Kind kind, byte[]... values)
{
return new ArrayClusteringBound(kind, values);
}
public ClusteringBound<byte[]> bound(ClusteringPrefix.Kind kind)
{
return kind.isStart() ? BOTTOM_BOUND : TOP_BOUND;
}
public ClusteringBoundary<byte[]> boundary(ClusteringPrefix.Kind kind, byte[]... values)
{
return new ArrayClusteringBoundary(kind, values);
}
}

View File

@ -0,0 +1,292 @@
/*
* 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.marshal;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.util.UUID;
import org.apache.cassandra.db.Digest;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FastByteOperations;
import org.apache.cassandra.utils.UUIDGen;
/**
* Accessor for ByteBuffer values. ByteBufferAccessor treates {@link ByteBuffer#position()} as index 0,
* and {@link ByteBuffer#remaining()} as the length.
*/
public class ByteBufferAccessor implements ValueAccessor<ByteBuffer>
{
public static final ValueAccessor<ByteBuffer> instance = new ByteBufferAccessor();
private ByteBufferAccessor() {}
public int size(ByteBuffer value)
{
return value.remaining();
}
public ByteBuffer[] createArray(int length)
{
return new ByteBuffer[length];
}
public void write(ByteBuffer value, DataOutputPlus out) throws IOException
{
out.write(value);
}
public void write(ByteBuffer value, ByteBuffer out)
{
out.put(value.duplicate());
}
public <V2> int copyTo(ByteBuffer src, int srcOffset, V2 dst, ValueAccessor<V2> dstAccessor, int dstOffset, int size)
{
dstAccessor.copyByteBufferTo(src, srcOffset, dst, dstOffset, size);
return size;
}
public int copyByteArrayTo(byte[] src, int srcOffset, ByteBuffer dst, int dstOffset, int size)
{
FastByteOperations.copy(src, srcOffset, dst, dst.position() + dstOffset, size);
return size;
}
public int copyByteBufferTo(ByteBuffer src, int srcOffset, ByteBuffer dst, int dstOffset, int size)
{
FastByteOperations.copy(src, src.position() + srcOffset, dst, dst.position() + dstOffset, size);
return size;
}
public void digest(ByteBuffer value, int offset, int size, Digest digest)
{
digest.update(value, value.position() + offset, size);
}
public ByteBuffer read(DataInputPlus in, int length) throws IOException
{
return ByteBufferUtil.read(in, length);
}
public ByteBuffer slice(ByteBuffer input, int offset, int length)
{
ByteBuffer copy = input.duplicate();
copy.position(copy.position() + offset);
copy.limit(copy.position() + length);
return copy;
}
public <V2> int compare(ByteBuffer left, V2 right, ValueAccessor<V2> accessorR)
{
return accessorR.compareByteBufferTo(left, right);
}
public int compareByteArrayTo(byte[] left, ByteBuffer right)
{
return ByteBufferUtil.compare(left, right);
}
public int compareByteBufferTo(ByteBuffer left, ByteBuffer right)
{
return ByteBufferUtil.compareUnsigned(left, right);
}
public ByteBuffer toBuffer(ByteBuffer value)
{
return value;
}
public byte[] toArray(ByteBuffer value)
{
if (value == null)
return null;
return ByteBufferUtil.getArray(value);
}
public byte[] toArray(ByteBuffer value, int offset, int length)
{
if (value == null)
return null;
return ByteBufferUtil.getArray(value, value.position() + offset, length);
}
public String toString(ByteBuffer value, Charset charset) throws CharacterCodingException
{
return ByteBufferUtil.string(value, charset);
}
public ByteBuffer valueOf(UUID v)
{
return UUIDGen.toByteBuffer(v);
}
public String toHex(ByteBuffer value)
{
return ByteBufferUtil.bytesToHex(value);
}
public byte toByte(ByteBuffer value)
{
return ByteBufferUtil.toByte(value);
}
public byte getByte(ByteBuffer value, int offset)
{
return value.get(value.position() + offset);
}
public short toShort(ByteBuffer value)
{
return ByteBufferUtil.toShort(value);
}
public short getShort(ByteBuffer value, int offset)
{
return value.getShort(value.position() + offset);
}
public int toInt(ByteBuffer value)
{
return ByteBufferUtil.toInt(value);
}
public int getInt(ByteBuffer value, int offset)
{
return value.getInt(value.position() + offset);
}
public long toLong(ByteBuffer value)
{
return ByteBufferUtil.toLong(value);
}
public long getLong(ByteBuffer value, int offset)
{
return value.getLong(value.position() + offset);
}
public float toFloat(ByteBuffer value)
{
return ByteBufferUtil.toFloat(value);
}
public double toDouble(ByteBuffer value)
{
return ByteBufferUtil.toDouble(value);
}
public UUID toUUID(ByteBuffer value)
{
return UUIDGen.getUUID(value);
}
public int putShort(ByteBuffer dst, int offset, short value)
{
dst.putShort(dst.position() + offset, value);
return TypeSizes.SHORT_SIZE;
}
public int putInt(ByteBuffer dst, int offset, int value)
{
dst.putInt(dst.position() + offset, value);
return TypeSizes.INT_SIZE;
}
public int putLong(ByteBuffer dst, int offset, long value)
{
dst.putLong(dst.position() + offset, value);
return TypeSizes.LONG_SIZE;
}
public ByteBuffer empty()
{
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
}
public ByteBuffer valueOf(byte[] bytes)
{
return ByteBuffer.wrap(bytes);
}
public ByteBuffer valueOf(ByteBuffer bytes)
{
return bytes;
}
public ByteBuffer valueOf(String v, Charset charset)
{
return ByteBufferUtil.bytes(v, charset);
}
public ByteBuffer valueOf(boolean v)
{
return v ? ByteBuffer.wrap(new byte[] {1}) : ByteBuffer.wrap(new byte[] {0});
}
public ByteBuffer valueOf(byte v)
{
return ByteBufferUtil.bytes(v);
}
public ByteBuffer valueOf(short v)
{
return ByteBufferUtil.bytes(v);
}
public ByteBuffer valueOf(int v)
{
return ByteBufferUtil.bytes(v);
}
public ByteBuffer valueOf(long v)
{
return ByteBufferUtil.bytes(v);
}
public ByteBuffer valueOf(float v)
{
return ByteBufferUtil.bytes(v);
}
public ByteBuffer valueOf(double v)
{
return ByteBufferUtil.bytes(v);
}
public <V2> ByteBuffer convert(V2 src, ValueAccessor<V2> accessor)
{
return accessor.toBuffer(src);
}
public ByteBuffer allocate(int size)
{
return ByteBuffer.allocate(size);
}
public ObjectFactory<ByteBuffer> factory()
{
return ByteBufferObjectFactory.instance;
}
}

View File

@ -0,0 +1,86 @@
/*
* 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.marshal;
import java.nio.ByteBuffer;
import org.apache.cassandra.db.BufferClustering;
import org.apache.cassandra.db.BufferClusteringBound;
import org.apache.cassandra.db.BufferClusteringBoundary;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.ClusteringBound;
import org.apache.cassandra.db.ClusteringBoundary;
import org.apache.cassandra.db.ClusteringPrefix;
import org.apache.cassandra.db.rows.BufferCell;
import org.apache.cassandra.db.rows.Cell;
import org.apache.cassandra.db.rows.CellPath;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
class ByteBufferObjectFactory implements ValueAccessor.ObjectFactory<ByteBuffer>
{
/** Empty clustering for tables having no clustering columns. */
private static final Clustering<ByteBuffer> EMPTY_CLUSTERING = new BufferClustering()
{
@Override
public String toString(TableMetadata metadata)
{
return "EMPTY";
}
};
/** The smallest start bound, i.e. the one that starts before any row. */
private static final BufferClusteringBound BOTTOM_BOUND = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, new ByteBuffer[0]);
/** The biggest end bound, i.e. the one that ends after any row. */
private static final BufferClusteringBound TOP_BOUND = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_END_BOUND, new ByteBuffer[0]);
static final ValueAccessor.ObjectFactory<ByteBuffer> instance = new ByteBufferObjectFactory();
private ByteBufferObjectFactory() {}
public Cell<ByteBuffer> cell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, ByteBuffer value, CellPath path)
{
return new BufferCell(column, timestamp, ttl, localDeletionTime, value, path);
}
public Clustering<ByteBuffer> clustering(ByteBuffer... values)
{
return new BufferClustering(values);
}
public Clustering<ByteBuffer> clustering()
{
return EMPTY_CLUSTERING;
}
public ClusteringBound<ByteBuffer> bound(ClusteringPrefix.Kind kind, ByteBuffer... values)
{
return new BufferClusteringBound(kind, values);
}
public ClusteringBound<ByteBuffer> bound(ClusteringPrefix.Kind kind)
{
return kind.isStart() ? BOTTOM_BOUND : TOP_BOUND;
}
public ClusteringBoundary<ByteBuffer> boundary(ClusteringPrefix.Kind kind, ByteBuffer... values)
{
return new BufferClusteringBoundary(kind, values);
}
}

View File

@ -37,9 +37,9 @@ public class ByteType extends NumberType<Byte>
super(ComparisonType.CUSTOM);
} // singleton
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
return o1.get(o1.position()) - o2.get(o2.position());
return accessorL.getByte(left, 0) - accessorR.getByte(right, 0);
}
public ByteBuffer fromString(String source) throws MarshalException

View File

@ -84,7 +84,7 @@ public abstract class CollectionType<T> extends AbstractType<T>
public abstract AbstractType<?> nameComparator();
public abstract AbstractType<?> valueComparator();
protected abstract List<ByteBuffer> serializedValues(Iterator<Cell> cells);
protected abstract List<ByteBuffer> serializedValues(Iterator<Cell<?>> cells);
@Override
public abstract CollectionSerializer<T> getSerializer();
@ -94,9 +94,9 @@ public abstract class CollectionType<T> extends AbstractType<T>
return kind.makeCollectionReceiver(collection, isKey);
}
public String getString(ByteBuffer bytes)
public <V> String getString(V value, ValueAccessor<V> accessor)
{
return BytesType.instance.getString(bytes);
return BytesType.instance.getString(value, accessor);
}
public ByteBuffer fromString(String source)
@ -117,12 +117,12 @@ public abstract class CollectionType<T> extends AbstractType<T>
}
@Override
public void validateCellValue(ByteBuffer cellValue) throws MarshalException
public <V> void validateCellValue(V cellValue, ValueAccessor<V> accessor) throws MarshalException
{
if (isMultiCell())
valueComparator().validateCellValue(cellValue);
valueComparator().validateCellValue(cellValue, accessor);
else
super.validateCellValue(cellValue);
super.validateCellValue(cellValue, accessor);
}
/**
@ -146,12 +146,12 @@ public abstract class CollectionType<T> extends AbstractType<T>
return values.size();
}
public ByteBuffer serializeForNativeProtocol(Iterator<Cell> cells, ProtocolVersion version)
public ByteBuffer serializeForNativeProtocol(Iterator<Cell<?>> cells, ProtocolVersion version)
{
assert isMultiCell();
List<ByteBuffer> values = serializedValues(cells);
int size = collectionSize(values);
return CollectionSerializer.pack(values, size, version);
return CollectionSerializer.pack(values, ByteBufferAccessor.instance, size, version);
}
@Override

View File

@ -84,9 +84,31 @@ public class CompositeType extends AbstractCompositeType
return getInstance(Arrays.asList(types));
}
protected boolean readIsStatic(ByteBuffer bb)
protected static int startingOffsetInternal(boolean isStatic)
{
return readStatic(bb);
return isStatic ? 2 : 0;
}
protected int startingOffset(boolean isStatic)
{
return startingOffsetInternal(isStatic);
}
protected static <V> boolean readIsStaticInternal(V value, ValueAccessor<V> accessor)
{
if (accessor.size(value) < 2)
return false;
int header = accessor.getShort(value, 0);
if ((header & 0xFFFF) != STATIC_MARKER)
return false;
return true;
}
protected <V> boolean readIsStatic(V value, ValueAccessor<V> accessor)
{
return readIsStaticInternal(value, accessor);
}
private static boolean readStatic(ByteBuffer bb)
@ -116,7 +138,7 @@ public class CompositeType extends AbstractCompositeType
this.types = ImmutableList.copyOf(types);
}
protected AbstractType<?> getComparator(int i, ByteBuffer bb)
protected <V> AbstractType<?> getComparator(int i, V value, ValueAccessor<V> accessor, int offset)
{
try
{
@ -133,12 +155,12 @@ public class CompositeType extends AbstractCompositeType
}
}
protected AbstractType<?> getComparator(int i, ByteBuffer bb1, ByteBuffer bb2)
protected <VL, VR> AbstractType<?> getComparator(int i, VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR, int offsetL, int offsetR)
{
return getComparator(i, bb1);
return getComparator(i, left, accessorL, offsetL);
}
protected AbstractType<?> getAndAppendComparator(int i, ByteBuffer bb, StringBuilder sb)
protected <V> AbstractType<?> getAndAppendComparator(int i, V value, ValueAccessor<V> accessor, StringBuilder sb, int offset)
{
return types.get(i);
}
@ -148,13 +170,18 @@ public class CompositeType extends AbstractCompositeType
return new StaticParsedComparator(types.get(i), part);
}
protected AbstractType<?> validateComparator(int i, ByteBuffer bb) throws MarshalException
protected <V> AbstractType<?> validateComparator(int i, V value, ValueAccessor<V> accessor, int offset) throws MarshalException
{
if (i >= types.size())
throw new MarshalException("Too many bytes for comparator");
return types.get(i);
}
protected <V> int getComparatorSize(int i, V value, ValueAccessor<V> accessor, int offset)
{
return 0;
}
public ByteBuffer decompose(Object... objects)
{
assert objects.length == types.size();
@ -165,9 +192,8 @@ public class CompositeType extends AbstractCompositeType
ByteBuffer buffer = ((AbstractType) types.get(i)).decompose(objects[i]);
serialized[i] = buffer;
}
return build(serialized);
return build(ByteBufferAccessor.instance, serialized);
}
// Overriding the one of AbstractCompositeType because we can do a tad better
@Override
public ByteBuffer[] split(ByteBuffer name)
@ -186,15 +212,17 @@ public class CompositeType extends AbstractCompositeType
return i == l.length ? l : Arrays.copyOfRange(l, 0, i);
}
public static List<ByteBuffer> splitName(ByteBuffer name)
public static <V> List<V> splitName(V name, ValueAccessor<V> accessor)
{
List<ByteBuffer> l = new ArrayList<>();
ByteBuffer bb = name.duplicate();
readStatic(bb);
while (bb.remaining() > 0)
List<V> l = new ArrayList<>();
boolean isStatic = readIsStaticInternal(name, accessor);
int offset = startingOffsetInternal(isStatic);
while (!accessor.isEmptyFromOffset(name, offset))
{
l.add(ByteBufferUtil.readBytesWithShortLength(bb));
bb.get(); // skip end-of-component
V value = accessor.sliceWithShortLength(name, offset);
offset += accessor.sizeWithShortLength(value);
l.add(value);
offset++; // skip end-of-component
}
return l;
}
@ -217,15 +245,9 @@ public class CompositeType extends AbstractCompositeType
return null;
}
public static boolean isStaticName(ByteBuffer bb)
public static <V> boolean isStaticName(V value, ValueAccessor<V> accessor)
{
return bb.remaining() >= 2 && (ByteBufferUtil.getShortLength(bb, bb.position()) & 0xFFFF) == STATIC_MARKER;
}
@Override
public int componentsCount()
{
return types.size();
return accessor.size(value) >= 2 && (accessor.getShortLength(value, 0) & 0xFFFF) == STATIC_MARKER;
}
@Override
@ -283,9 +305,9 @@ public class CompositeType extends AbstractCompositeType
}
@Override
public boolean referencesUserType(ByteBuffer name)
public <V> boolean referencesUserType(V name, ValueAccessor<V> accessor)
{
return any(types, t -> t.referencesUserType(name));
return any(types, t -> t.referencesUserType(name, accessor));
}
@Override
@ -340,31 +362,31 @@ public class CompositeType extends AbstractCompositeType
return getClass().getName() + TypeParser.stringifyTypeParameters(types);
}
public static ByteBuffer build(ByteBuffer... buffers)
@SafeVarargs
public static <V> V build(ValueAccessor<V> accessor, V... values)
{
return build(false, buffers);
return build(accessor, false, values);
}
public static ByteBuffer build(boolean isStatic, ByteBuffer... buffers)
@SafeVarargs
public static <V> V build(ValueAccessor<V> accessor, boolean isStatic, V... values)
{
int totalLength = isStatic ? 2 : 0;
for (ByteBuffer bb : buffers)
totalLength += 2 + bb.remaining() + 1;
for (V v : values)
totalLength += 2 + accessor.size(v) + 1;
ByteBuffer out = ByteBuffer.allocate(totalLength);
if (isStatic)
out.putShort((short)STATIC_MARKER);
for (ByteBuffer bb : buffers)
for (V v : values)
{
ByteBufferUtil.writeShortLength(out, bb.remaining());
int toCopy = bb.remaining();
ByteBufferUtil.copyBytes(bb, bb.position(), out, out.position(), toCopy);
out.position(out.position() + toCopy);
ByteBufferUtil.writeShortLength(out, accessor.size(v));
accessor.write(v, out);
out.put((byte) 0);
}
out.flip();
return out;
return accessor.valueOf(out);
}
}

View File

@ -44,10 +44,9 @@ public class CounterColumnType extends NumberType<Long>
return true;
}
@Override
public Long compose(ByteBuffer bytes)
public <V> Long compose(V value, ValueAccessor<V> accessor)
{
return CounterContext.instance().total(bytes);
return CounterContext.instance().total(value, accessor);
}
@Override
@ -57,14 +56,14 @@ public class CounterColumnType extends NumberType<Long>
}
@Override
public void validateCellValue(ByteBuffer cellValue) throws MarshalException
public <V> void validateCellValue(V cellValue, ValueAccessor<V> accessor) throws MarshalException
{
CounterContext.instance().validateContext(cellValue);
CounterContext.instance().validateContext(cellValue, accessor);
}
public String getString(ByteBuffer bytes)
public <V> String getString(V value, ValueAccessor<V> accessor)
{
return ByteBufferUtil.bytesToHex(bytes);
return accessor.toHex(value);
}
public ByteBuffer fromString(String source)

View File

@ -54,12 +54,9 @@ public class DecimalType extends NumberType<BigDecimal>
return true;
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
return compose(o1).compareTo(compose(o2));
return compareComposed(left, accessorL, right, accessorR, this);
}
public ByteBuffer fromString(String source) throws MarshalException

View File

@ -45,12 +45,9 @@ public class DoubleType extends NumberType<Double>
return true;
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
return compose(o1).compareTo(compose(o2));
return compareComposed(left, accessorL, right, accessorR, this);
}
public ByteBuffer fromString(String source) throws MarshalException

View File

@ -27,6 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.cql3.Term;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.exceptions.SyntaxException;
import org.apache.cassandra.serializers.MarshalException;
@ -82,20 +83,39 @@ public class DynamicCompositeType extends AbstractCompositeType
this.aliases = aliases;
}
protected boolean readIsStatic(ByteBuffer bb)
protected <V> boolean readIsStatic(V value, ValueAccessor<V> accessor)
{
// We don't have the static nothing for DCT
return false;
}
private AbstractType<?> getComparator(ByteBuffer bb)
protected int startingOffset(boolean isStatic)
{
return 0;
}
protected <V> int getComparatorSize(int i, V value, ValueAccessor<V> accessor, int offset)
{
int header = accessor.getShort(value, offset);
if ((header & 0x8000) == 0)
{
return 2 + header;
}
else
{
return 2;
}
}
private <V> AbstractType<?> getComparator(V value, ValueAccessor<V> accessor, int offset)
{
try
{
int header = ByteBufferUtil.readShortLength(bb);
int header = accessor.getShort(value, offset);
if ((header & 0x8000) == 0)
{
String name = ByteBufferUtil.string(ByteBufferUtil.readBytes(bb, header));
String name = accessor.toString(accessor.slice(value, offset + 2, header));
return TypeParser.parse(name);
}
else
@ -109,15 +129,15 @@ public class DynamicCompositeType extends AbstractCompositeType
}
}
protected AbstractType<?> getComparator(int i, ByteBuffer bb)
protected <V> AbstractType<?> getComparator(int i, V value, ValueAccessor<V> accessor, int offset)
{
return getComparator(bb);
return getComparator(value, accessor, offset);
}
protected AbstractType<?> getComparator(int i, ByteBuffer bb1, ByteBuffer bb2)
protected <VL, VR> AbstractType<?> getComparator(int i, VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR, int offsetL, int offsetR)
{
AbstractType<?> comp1 = getComparator(bb1);
AbstractType<?> comp2 = getComparator(bb2);
AbstractType<?> comp1 = getComparator(left, accessorL, offsetL);
AbstractType<?> comp2 = getComparator(right, accessorR, offsetR);
AbstractType<?> rawComp = comp1;
/*
@ -154,14 +174,14 @@ public class DynamicCompositeType extends AbstractCompositeType
return rawComp;
}
protected AbstractType<?> getAndAppendComparator(int i, ByteBuffer bb, StringBuilder sb)
protected <V> AbstractType<?> getAndAppendComparator(int i, V value, ValueAccessor<V> accessor, StringBuilder sb, int offset)
{
try
{
int header = ByteBufferUtil.readShortLength(bb);
int header = accessor.getShort(value, offset);
if ((header & 0x8000) == 0)
{
String name = ByteBufferUtil.string(ByteBufferUtil.readBytes(bb, header));
String name = accessor.toString(accessor.slice(value, offset + 2, header));
sb.append(name).append("@");
return TypeParser.parse(name);
}
@ -182,22 +202,23 @@ public class DynamicCompositeType extends AbstractCompositeType
return new DynamicParsedComparator(part);
}
protected AbstractType<?> validateComparator(int i, ByteBuffer bb) throws MarshalException
protected <V> AbstractType<?> validateComparator(int i, V input, ValueAccessor<V> accessor, int offset) throws MarshalException
{
AbstractType<?> comparator = null;
if (bb.remaining() < 2)
if (accessor.sizeFromOffset(input, offset) < 2)
throw new MarshalException("Not enough bytes to header of the comparator part of component " + i);
int header = ByteBufferUtil.readShortLength(bb);
int header = accessor.getShort(input, offset);
offset += TypeSizes.SHORT_SIZE;
if ((header & 0x8000) == 0)
{
if (bb.remaining() < header)
if (accessor.sizeFromOffset(input, offset) < header)
throw new MarshalException("Not enough bytes to read comparator name of component " + i);
ByteBuffer value = ByteBufferUtil.readBytes(bb, header);
V value = accessor.slice(input, offset, header);
String valueStr = null;
try
{
valueStr = ByteBufferUtil.string(value);
valueStr = accessor.toString(value);
comparator = TypeParser.parse(valueStr);
}
catch (CharacterCodingException ce)
@ -257,9 +278,9 @@ public class DynamicCompositeType extends AbstractCompositeType
}
@Override
public boolean referencesUserType(ByteBuffer name)
public <V> boolean referencesUserType(V name, ValueAccessor<V> accessor)
{
return any(aliases.values(), t -> t.referencesUserType(name));
return any(aliases.values(), t -> t.referencesUserType(name, accessor));
}
@Override
@ -370,24 +391,23 @@ public class DynamicCompositeType extends AbstractCompositeType
this.cmp = cmp;
}
public int compareCustom(ByteBuffer v1, ByteBuffer v2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
return cmp;
}
@Override
public Void compose(ByteBuffer bytes)
public <V> Void compose(V value, ValueAccessor<V> accessor)
{
throw new UnsupportedOperationException();
}
@Override
public ByteBuffer decompose(Void value)
{
throw new UnsupportedOperationException();
}
public String getString(ByteBuffer bytes)
public <V> String getString(V value, ValueAccessor<V> accessor)
{
throw new UnsupportedOperationException();
}

View File

@ -68,12 +68,12 @@ public class EmptyType extends AbstractType<Void>
private EmptyType() {super(ComparisonType.CUSTOM);} // singleton
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
return 0;
}
public String getString(ByteBuffer bytes)
public <V> String getString(V value, ValueAccessor<V> accessor)
{
return "";
}
@ -121,21 +121,20 @@ public class EmptyType extends AbstractType<Void>
}
@Override
public long writtenLength(ByteBuffer value)
public <V> long writtenLength(V value, ValueAccessor<V> accessor)
{
// default implemenation requires non-empty bytes but this always requires empty bytes, so special case
validate(value);
validate(value, accessor);
return 0;
}
@Override
public ByteBuffer readValue(DataInputPlus in)
public ByteBuffer readBuffer(DataInputPlus in)
{
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
}
@Override
public ByteBuffer readValue(DataInputPlus in, int maxValueSize)
public ByteBuffer readBuffer(DataInputPlus in, int maxValueSize)
{
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
}

View File

@ -46,12 +46,9 @@ public class FloatType extends NumberType<Float>
return true;
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
return compose(o1).compareTo(compose(o2));
return compareComposed(left, accessorL, right, accessorR, this);
}
public ByteBuffer fromString(String source) throws MarshalException

View File

@ -47,7 +47,7 @@ public class FrozenType extends AbstractType<Void>
return innerType.freeze();
}
public String getString(ByteBuffer bytes)
public <V> String getString(V value, ValueAccessor<V> accessor)
{
throw new UnsupportedOperationException();
}

View File

@ -43,16 +43,16 @@ public class Int32Type extends NumberType<Integer>
return true;
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left));
int diff = o1.get(o1.position()) - o2.get(o2.position());
int diff = accessorL.getByte(left, 0) - accessorR.getByte(right, 0);
if (diff != 0)
return diff;
return ByteBufferUtil.compareUnsigned(o1, o2);
return ValueAccessor.compare(left, accessorL, right, accessorR);
}
public ByteBuffer fromString(String source) throws MarshalException

View File

@ -35,16 +35,16 @@ public final class IntegerType extends NumberType<BigInteger>
{
public static final IntegerType instance = new IntegerType();
private static int findMostSignificantByte(ByteBuffer bytes)
private static <V> int findMostSignificantByte(V value, ValueAccessor<V> accessor)
{
int len = bytes.remaining() - 1;
int len = accessor.size(value) - 1;
int i = 0;
for (; i < len; i++)
{
byte b0 = bytes.get(bytes.position() + i);
byte b0 = accessor.getByte(value, i);
if (b0 != 0 && b0 != -1)
break;
byte b1 = bytes.get(bytes.position() + i + 1);
byte b1 = accessor.getByte(value, i + 1);
if (b0 == 0 && b1 != 0)
{
if (b1 > 0)
@ -68,30 +68,30 @@ public final class IntegerType extends NumberType<BigInteger>
return true;
}
public int compareCustom(ByteBuffer lhs, ByteBuffer rhs)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
return IntegerType.compareIntegers(lhs, rhs);
return IntegerType.compareIntegers(left, accessorL, right, accessorR);
}
public static int compareIntegers(ByteBuffer lhs, ByteBuffer rhs)
public static <VL, VR> int compareIntegers(VL lhs, ValueAccessor<VL> accessorL, VR rhs, ValueAccessor<VR> accessorR)
{
int lhsLen = lhs.remaining();
int rhsLen = rhs.remaining();
int lhsLen = accessorL.size(lhs);
int rhsLen = accessorR.size(rhs);
if (lhsLen == 0)
return rhsLen == 0 ? 0 : -1;
if (rhsLen == 0)
return 1;
int lhsMsbIdx = findMostSignificantByte(lhs);
int rhsMsbIdx = findMostSignificantByte(rhs);
int lhsMsbIdx = findMostSignificantByte(lhs, accessorL);
int rhsMsbIdx = findMostSignificantByte(rhs, accessorR);
//diffs contain number of "meaningful" bytes (i.e. ignore padding)
int lhsLenDiff = lhsLen - lhsMsbIdx;
int rhsLenDiff = rhsLen - rhsMsbIdx;
byte lhsMsb = lhs.get(lhs.position() + lhsMsbIdx);
byte rhsMsb = rhs.get(rhs.position() + rhsMsbIdx);
byte lhsMsb = accessorL.getByte(lhs, lhsMsbIdx);
byte rhsMsb = accessorR.getByte(rhs, rhsMsbIdx);
/* + -
* -----------
@ -121,8 +121,8 @@ public final class IntegerType extends NumberType<BigInteger>
// remaining bytes are compared unsigned
while (lhsMsbIdx < lhsLen)
{
lhsMsb = lhs.get(lhs.position() + lhsMsbIdx++);
rhsMsb = rhs.get(rhs.position() + rhsMsbIdx++);
lhsMsb = accessorL.getByte(lhs, lhsMsbIdx++);
rhsMsb = accessorR.getByte(rhs, rhsMsbIdx++);
if (lhsMsb != rhsMsb)
return (lhsMsb & 0xFF) - (rhsMsb & 0xFF);

View File

@ -26,7 +26,6 @@ import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.serializers.UUIDSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.UUIDGen;
public class LexicalUUIDType extends AbstractType<UUID>
{
@ -42,12 +41,11 @@ public class LexicalUUIDType extends AbstractType<UUID>
return true;
}
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0;
return UUIDGen.getUUID(o1).compareTo(UUIDGen.getUUID(o2));
if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left));
return accessorL.toUUID(left).compareTo(accessorR.toUUID(right));
}
public ByteBuffer fromString(String source) throws MarshalException

Some files were not shown because too many files have changed in this diff Show More