mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.1' into trunk
Conflicts: src/java/org/apache/cassandra/cql/QueryProcessor.java
This commit is contained in:
commit
7d7610fdb3
|
|
@ -283,6 +283,7 @@ memtable_cleanup_threshold: 0.4
|
|||
# Options are:
|
||||
# heap_buffers: on heap nio buffers
|
||||
# offheap_buffers: off heap (direct) nio buffers
|
||||
# offheap_objects: native memory, eliminating nio buffer heap overhead
|
||||
memtable_allocation_type: heap_buffers
|
||||
|
||||
# Total space to use for commitlogs. Since commitlog segments are
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class RowCacheKey implements CacheKey, Comparable<RowCacheKey>
|
|||
|
||||
public RowCacheKey(UUID cfId, DecoratedKey key)
|
||||
{
|
||||
this(cfId, key.key);
|
||||
this(cfId, key.getKey());
|
||||
}
|
||||
|
||||
public RowCacheKey(UUID cfId, ByteBuffer key)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import org.apache.cassandra.cql3.QueryProcessor;
|
|||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.cql3.statements.CFStatement;
|
||||
import org.apache.cassandra.cql3.statements.CreateTableStatement;
|
||||
import org.apache.cassandra.db.AbstractCell;
|
||||
import org.apache.cassandra.db.AtomDeserializer;
|
||||
import org.apache.cassandra.db.CFRowAdder;
|
||||
import org.apache.cassandra.db.Cell;
|
||||
|
|
@ -1317,7 +1318,7 @@ public final class CFMetaData
|
|||
*/
|
||||
public ColumnDefinition getColumnDefinition(CellName cellName)
|
||||
{
|
||||
ColumnIdentifier id = cellName.cql3ColumnName();
|
||||
ColumnIdentifier id = cellName.cql3ColumnName(this);
|
||||
ColumnDefinition def = id == null
|
||||
? getColumnDefinition(cellName.toByteBuffer()) // Means a dense layout, try the full column name
|
||||
: getColumnDefinition(id);
|
||||
|
|
@ -1398,7 +1399,7 @@ public final class CFMetaData
|
|||
|
||||
public Iterator<OnDiskAtom> getOnDiskIterator(DataInput in, ColumnSerializer.Flag flag, int expireBefore, Descriptor.Version version)
|
||||
{
|
||||
return Cell.onDiskIterator(in, flag, expireBefore, version, comparator);
|
||||
return AbstractCell.onDiskIterator(in, flag, expireBefore, version, comparator);
|
||||
}
|
||||
|
||||
public AtomDeserializer getOnDiskDeserializer(DataInput in, Descriptor.Version version)
|
||||
|
|
|
|||
|
|
@ -290,7 +290,8 @@ public class Config
|
|||
{
|
||||
unslabbed_heap_buffers,
|
||||
heap_buffers,
|
||||
offheap_buffers
|
||||
offheap_buffers,
|
||||
offheap_objects
|
||||
}
|
||||
|
||||
public static enum DiskFailurePolicy
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ import org.apache.cassandra.service.CacheService;
|
|||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.memory.HeapPool;
|
||||
import org.apache.cassandra.utils.memory.Pool;
|
||||
import org.apache.cassandra.utils.memory.NativePool;
|
||||
import org.apache.cassandra.utils.memory.MemtablePool;
|
||||
import org.apache.cassandra.utils.memory.SlabPool;
|
||||
|
||||
public class DatabaseDescriptor
|
||||
|
|
@ -1487,7 +1488,7 @@ public class DatabaseDescriptor
|
|||
return conf.inter_dc_tcp_nodelay;
|
||||
}
|
||||
|
||||
public static Pool getMemtableAllocatorPool()
|
||||
public static MemtablePool getMemtableAllocatorPool()
|
||||
{
|
||||
long heapLimit = ((long) conf.memtable_heap_space_in_mb) << 20;
|
||||
long offHeapLimit = ((long) conf.memtable_offheap_space_in_mb) << 20;
|
||||
|
|
@ -1504,6 +1505,8 @@ public class DatabaseDescriptor
|
|||
System.exit(-1);
|
||||
}
|
||||
return new SlabPool(heapLimit, offHeapLimit, conf.memtable_cleanup_threshold, new ColumnFamilyStore.FlushLargestColumnFamily());
|
||||
case offheap_objects:
|
||||
return new NativePool(heapLimit, offHeapLimit, conf.memtable_cleanup_threshold, new ColumnFamilyStore.FlushLargestColumnFamily());
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ public class Schema
|
|||
{
|
||||
try
|
||||
{
|
||||
return systemKeyspaceNames.contains(ByteBufferUtil.string(row.key.key));
|
||||
return systemKeyspaceNames.contains(ByteBufferUtil.string(row.key.getKey()));
|
||||
}
|
||||
catch (CharacterCodingException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class ColumnIdentifier implements Selectable, IMeasurableMemory
|
|||
this.text = type.getString(bytes);
|
||||
}
|
||||
|
||||
private ColumnIdentifier(ByteBuffer bytes, String text)
|
||||
public ColumnIdentifier(ByteBuffer bytes, String text)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
this.text = text;
|
||||
|
|
|
|||
|
|
@ -55,13 +55,13 @@ public class UpdateParameters
|
|||
public Cell makeColumn(CellName name, ByteBuffer value) throws InvalidRequestException
|
||||
{
|
||||
QueryProcessor.validateCellName(name, metadata.comparator);
|
||||
return Cell.create(name, value, timestamp, ttl, metadata);
|
||||
return AbstractCell.create(name, value, timestamp, ttl, metadata);
|
||||
}
|
||||
|
||||
public Cell makeTombstone(CellName name) throws InvalidRequestException
|
||||
{
|
||||
QueryProcessor.validateCellName(name, metadata.comparator);
|
||||
return new DeletedCell(name, localDeletionTime, timestamp);
|
||||
return new BufferDeletedCell(name, localDeletionTime, timestamp);
|
||||
}
|
||||
|
||||
public RangeTombstone makeRangeTombstone(ColumnSlice slice) throws InvalidRequestException
|
||||
|
|
|
|||
|
|
@ -32,12 +32,9 @@ import org.apache.cassandra.db.*;
|
|||
import org.apache.cassandra.db.composites.CBuilder;
|
||||
import org.apache.cassandra.db.composites.Composite;
|
||||
import org.apache.cassandra.db.filter.ColumnSlice;
|
||||
import org.apache.cassandra.db.filter.IDiskAtomFilter;
|
||||
import org.apache.cassandra.db.filter.SliceQueryFilter;
|
||||
import org.apache.cassandra.db.marshal.ListType;
|
||||
import org.apache.cassandra.db.marshal.BooleanType;
|
||||
import org.apache.cassandra.exceptions.*;
|
||||
import org.apache.cassandra.service.CASConditions;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.service.QueryState;
|
||||
import org.apache.cassandra.service.StorageProxy;
|
||||
|
|
@ -449,10 +446,10 @@ public abstract class ModificationStatement implements CQLStatement, MeasurableF
|
|||
if (row.cf == null || row.cf.isEmpty())
|
||||
continue;
|
||||
|
||||
Iterator<CQL3Row> iter = cfm.comparator.CQL3RowBuilder(now).group(row.cf.getSortedColumns().iterator());
|
||||
Iterator<CQL3Row> iter = cfm.comparator.CQL3RowBuilder(cfm, now).group(row.cf.getSortedColumns().iterator());
|
||||
if (iter.hasNext())
|
||||
{
|
||||
map.put(row.key.key, iter.next());
|
||||
map.put(row.key.getKey(), iter.next());
|
||||
// We can only update one CQ3Row per partition key at a time (we don't allow IN for clustering key)
|
||||
assert !iter.hasNext();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,8 +400,8 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
|
|||
ByteBuffer startKeyBytes = getKeyBound(Bound.START, variables);
|
||||
ByteBuffer finishKeyBytes = getKeyBound(Bound.END, variables);
|
||||
|
||||
RowPosition startKey = RowPosition.forKey(startKeyBytes, p);
|
||||
RowPosition finishKey = RowPosition.forKey(finishKeyBytes, p);
|
||||
RowPosition startKey = RowPosition.ForKey.get(startKeyBytes, p);
|
||||
RowPosition finishKey = RowPosition.ForKey.get(finishKeyBytes, p);
|
||||
|
||||
if (startKey.compareTo(finishKey) > 0 && !finishKey.isMinimum(p))
|
||||
return null;
|
||||
|
|
@ -1007,7 +1007,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
|
|||
if (row.cf == null)
|
||||
continue;
|
||||
|
||||
processColumnFamily(row.key.key, row.cf, variables, now, result);
|
||||
processColumnFamily(row.key.getKey(), row.cf, variables, now, result);
|
||||
}
|
||||
|
||||
ResultSet cqlRows = result.build();
|
||||
|
|
@ -1042,7 +1042,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
|
|||
if (sliceRestriction != null)
|
||||
cells = applySliceRestriction(cells, variables);
|
||||
|
||||
CQL3Row.RowIterator iter = cfm.comparator.CQL3RowBuilder(now).group(cells);
|
||||
CQL3Row.RowIterator iter = cfm.comparator.CQL3RowBuilder(cfm, now).group(cells);
|
||||
|
||||
// If there is static columns but there is no non-static row, then provided the select was a full
|
||||
// partition selection (i.e. not a 2ndary index search and there was no condition on clustering columns)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,265 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.io.sstable.Descriptor;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public abstract class AbstractCell implements Cell
|
||||
{
|
||||
public static Iterator<OnDiskAtom> onDiskIterator(final DataInput in,
|
||||
final ColumnSerializer.Flag flag,
|
||||
final int expireBefore,
|
||||
final Descriptor.Version version,
|
||||
final CellNameType type)
|
||||
{
|
||||
return new AbstractIterator<OnDiskAtom>()
|
||||
{
|
||||
protected OnDiskAtom computeNext()
|
||||
{
|
||||
OnDiskAtom atom;
|
||||
try
|
||||
{
|
||||
atom = type.onDiskAtomSerializer().deserializeFromSSTable(in, flag, expireBefore, version);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IOError(e);
|
||||
}
|
||||
if (atom == null)
|
||||
return endOfData();
|
||||
|
||||
return atom;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLive(long now)
|
||||
{
|
||||
return !isMarkedForDelete(now);
|
||||
}
|
||||
|
||||
// Don't call unless the column is actually marked for delete.
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cellDataSize()
|
||||
{
|
||||
return name().dataSize() + value().remaining() + TypeSizes.NATIVE.sizeof(timestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
/*
|
||||
* Size of a column is =
|
||||
* size of a name (short + length of the string)
|
||||
* + 1 byte to indicate if the column has been deleted
|
||||
* + 8 bytes for timestamp
|
||||
* + 4 bytes which basically indicates the size of the byte array
|
||||
* + entire byte array.
|
||||
*/
|
||||
int valueSize = value().remaining();
|
||||
return ((int)type.cellSerializer().serializedSize(name(), typeSizes)) + 1 + typeSizes.sizeof(timestamp()) + typeSizes.sizeof(valueSize) + valueSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
if (timestamp() < cell.timestamp())
|
||||
return cell;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name().toByteBuffer().duplicate());
|
||||
digest.update(value().duplicate());
|
||||
|
||||
FBUtilities.updateWithLong(digest, timestamp());
|
||||
FBUtilities.updateWithByte(digest, serializationFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
// tombstones take precedence. (if both are tombstones, then it doesn't matter which one we use.)
|
||||
if (isMarkedForDelete(System.currentTimeMillis()))
|
||||
return timestamp() < cell.timestamp() ? cell : this;
|
||||
if (cell.isMarkedForDelete(System.currentTimeMillis()))
|
||||
return timestamp() > cell.timestamp() ? this : cell;
|
||||
// break ties by comparing values.
|
||||
if (timestamp() == cell.timestamp())
|
||||
return value().compareTo(cell.value()) < 0 ? cell : this;
|
||||
// neither is tombstoned and timestamps are different
|
||||
return timestamp() < cell.timestamp() ? cell : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
return this == o || (o instanceof Cell && equals((Cell) o));
|
||||
}
|
||||
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return timestamp() == cell.timestamp() && name().equals(cell.name()) && value().equals(cell.value());
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s:%b:%d@%d",
|
||||
comparator.getString(name()),
|
||||
isMarkedForDelete(System.currentTimeMillis()),
|
||||
value().remaining(),
|
||||
timestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateName(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
metadata.comparator.validate(name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
|
||||
AbstractType<?> valueValidator = metadata.getValueValidator(name());
|
||||
if (valueValidator != null)
|
||||
valueValidator.validate(value());
|
||||
}
|
||||
|
||||
public static Cell create(CellName name, ByteBuffer value, long timestamp, int ttl, CFMetaData metadata)
|
||||
{
|
||||
if (ttl <= 0)
|
||||
ttl = metadata.getDefaultTimeToLive();
|
||||
|
||||
return ttl > 0
|
||||
? new BufferExpiringCell(name, value, timestamp, ttl)
|
||||
: new BufferCell(name, value, timestamp);
|
||||
}
|
||||
|
||||
public static Cell diff(CounterCell a, Cell b)
|
||||
{
|
||||
if (a.timestamp() < b.timestamp())
|
||||
return b;
|
||||
|
||||
// Note that if at that point, cell can't be a tombstone. Indeed,
|
||||
// cell is the result of merging us with other nodes results, and
|
||||
// merging a CounterCell with a tombstone never return a tombstone
|
||||
// unless that tombstone timestamp is greater that the CounterCell
|
||||
// one.
|
||||
assert b instanceof CounterCell : "Wrong class type: " + b.getClass();
|
||||
|
||||
if (a.timestampOfLastDelete() < ((CounterCell) b).timestampOfLastDelete())
|
||||
return b;
|
||||
|
||||
CounterContext.Relationship rel = CounterCell.contextManager.diff(b.value(), a.value());
|
||||
return (rel == CounterContext.Relationship.GREATER_THAN || rel == CounterContext.Relationship.DISJOINT) ? b : null;
|
||||
}
|
||||
|
||||
/** This is temporary until we start creating Cells of the different type (buffer vs. native) */
|
||||
public static Cell reconcile(CounterCell a, Cell b)
|
||||
{
|
||||
assert (b instanceof CounterCell) || (b instanceof DeletedCell) : "Wrong class type: " + b.getClass();
|
||||
|
||||
// live + tombstone: track last tombstone
|
||||
if (b.isMarkedForDelete(Long.MIN_VALUE)) // cannot be an expired cell, so the current time is irrelevant
|
||||
{
|
||||
// live < tombstone
|
||||
if (a.timestamp() < b.timestamp())
|
||||
return b;
|
||||
|
||||
// live last delete >= tombstone
|
||||
if (a.timestampOfLastDelete() >= b.timestamp())
|
||||
return a;
|
||||
|
||||
// live last delete < tombstone
|
||||
return new BufferCounterCell(a.name(), a.value(), a.timestamp(), b.timestamp());
|
||||
}
|
||||
|
||||
assert b instanceof CounterCell : "Wrong class type: " + b.getClass();
|
||||
|
||||
// live < live last delete
|
||||
if (a.timestamp() < ((CounterCell) b).timestampOfLastDelete())
|
||||
return b;
|
||||
|
||||
// live last delete > live
|
||||
if (a.timestampOfLastDelete() > b.timestamp())
|
||||
return a;
|
||||
|
||||
// live + live. return one of the cells if its context is a superset of the other's, or merge them otherwise
|
||||
ByteBuffer context = CounterCell.contextManager.merge(a.value(), b.value());
|
||||
if (context == a.value() && a.timestamp() >= b.timestamp() && a.timestampOfLastDelete() >= ((CounterCell) b).timestampOfLastDelete())
|
||||
return a;
|
||||
else if (context == b.value() && b.timestamp() >= a.timestamp() && ((CounterCell) b).timestampOfLastDelete() >= a.timestampOfLastDelete())
|
||||
return b;
|
||||
else // merge clocks and timsestamps.
|
||||
return new BufferCounterCell(a.name(),
|
||||
context,
|
||||
Math.max(a.timestamp(), b.timestamp()),
|
||||
Math.max(a.timestampOfLastDelete(), ((CounterCell) b).timestampOfLastDelete()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,647 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.composites.*;
|
||||
import org.apache.cassandra.db.filter.ColumnSlice;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.CompositeType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.*;
|
||||
|
||||
|
||||
/**
|
||||
* Packs a CellName AND a Cell into one off-heap representation.
|
||||
* Layout is:
|
||||
*
|
||||
* Note we store the ColumnIdentifier in full as bytes. This seems an okay tradeoff for now, as we just
|
||||
* look it back up again when we need to, and in the near future we hope to switch to ints, longs or
|
||||
* UUIDs representing column identifiers on disk, at which point we can switch that here as well.
|
||||
*
|
||||
* [timestamp][value offset][name size]][name extra][name offset deltas][cell names][value][Descendants]
|
||||
* [ 8b ][ 4b ][ 2b ][ 1b ][ each 2b ][ arb < 64k][ arb ][ arbitrary ]
|
||||
*
|
||||
* descendants: any overriding classes will put their state here
|
||||
* name offsets are deltas from their base offset, and don't include the first offset, or the end position of the final entry,
|
||||
* i.e. there will be size - 1 entries, and each is a delta that is added to the offset of the position of the first name
|
||||
* (which is always CELL_NAME_OFFSETS_OFFSET + (2 * (size - 1))). The length of the final name fills up any remaining
|
||||
* space upto the value offset
|
||||
* name extra: lowest 2 bits indicate the clustering size delta (i.e. how many name items are NOT part of the clustering key)
|
||||
* the next 2 bits indicate the CellNameType
|
||||
* the next bit indicates if the column is a static or clustered/dynamic column
|
||||
*/
|
||||
public abstract class AbstractNativeCell extends AbstractCell implements CellName
|
||||
{
|
||||
static final int TIMESTAMP_OFFSET = 4;
|
||||
private static final int VALUE_OFFSET_OFFSET = 12;
|
||||
private static final int CELL_NAME_SIZE_OFFSET = 16;
|
||||
private static final int CELL_NAME_EXTRA_OFFSET = 18;
|
||||
private static final int CELL_NAME_OFFSETS_OFFSET = 19;
|
||||
private static final int CELL_NAME_SIZE_DELTA_MASK = 3;
|
||||
private static final int CELL_NAME_TYPE_SHIFT = 2;
|
||||
private static final int CELL_NAME_TYPE_MASK = 7;
|
||||
|
||||
private static enum NameType
|
||||
{
|
||||
COMPOUND_DENSE(0 << 2), COMPOUND_SPARSE(1 << 2), COMPOUND_SPARSE_STATIC(2 << 2), SIMPLE_DENSE(3 << 2), SIMPLE_SPARSE(4 << 2);
|
||||
static final NameType[] TYPES = NameType.values();
|
||||
final int bits;
|
||||
|
||||
NameType(int bits)
|
||||
{
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
static NameType typeOf(CellName name)
|
||||
{
|
||||
if (name instanceof CompoundDenseCellName)
|
||||
{
|
||||
assert !name.isStatic();
|
||||
return COMPOUND_DENSE;
|
||||
}
|
||||
|
||||
if (name instanceof CompoundSparseCellName)
|
||||
return name.isStatic() ? COMPOUND_SPARSE_STATIC : COMPOUND_SPARSE;
|
||||
|
||||
if (name instanceof SimpleDenseCellName)
|
||||
{
|
||||
assert !name.isStatic();
|
||||
return SIMPLE_DENSE;
|
||||
}
|
||||
|
||||
if (name instanceof SimpleSparseCellName)
|
||||
{
|
||||
assert !name.isStatic();
|
||||
return SIMPLE_SPARSE;
|
||||
}
|
||||
|
||||
if (name instanceof NativeCell)
|
||||
return ((NativeCell) name).nametype();
|
||||
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private final long peer; // peer is assigned by peer updater in setPeer method
|
||||
|
||||
AbstractNativeCell()
|
||||
{
|
||||
peer = -1;
|
||||
}
|
||||
|
||||
public AbstractNativeCell(NativeAllocator allocator, OpOrder.Group writeOp, Cell copyOf)
|
||||
{
|
||||
int size = sizeOf(copyOf);
|
||||
peer = allocator.allocate(size, writeOp);
|
||||
|
||||
MemoryUtil.setInt(peer, size);
|
||||
construct(copyOf);
|
||||
}
|
||||
|
||||
protected int sizeOf(Cell cell)
|
||||
{
|
||||
int size = CELL_NAME_OFFSETS_OFFSET + Math.max(0, cell.name().size() - 1) * 2 + cell.value().remaining();
|
||||
CellName name = cell.name();
|
||||
for (int i = 0; i < name.size(); i++)
|
||||
size += name.get(i).remaining();
|
||||
return size;
|
||||
}
|
||||
|
||||
protected void construct(Cell from)
|
||||
{
|
||||
setLong(TIMESTAMP_OFFSET, from.timestamp());
|
||||
CellName name = from.name();
|
||||
int nameSize = name.size();
|
||||
int offset = CELL_NAME_SIZE_OFFSET;
|
||||
setShort(offset, (short) nameSize);
|
||||
assert nameSize - name.clusteringSize() <= 2;
|
||||
byte cellNameExtraBits = (byte) ((nameSize - name.clusteringSize()) | NameType.typeOf(name).bits);
|
||||
setByte(offset += 2, cellNameExtraBits);
|
||||
offset += 1;
|
||||
short cellNameDelta = 0;
|
||||
for (int i = 1; i < nameSize; i++)
|
||||
{
|
||||
cellNameDelta += name.get(i - 1).remaining();
|
||||
setShort(offset, cellNameDelta);
|
||||
offset += 2;
|
||||
}
|
||||
for (int i = 0; i < nameSize; i++)
|
||||
{
|
||||
ByteBuffer bb = name.get(i);
|
||||
setBytes(offset, bb);
|
||||
offset += bb.remaining();
|
||||
}
|
||||
setInt(VALUE_OFFSET_OFFSET, offset);
|
||||
setBytes(offset, from.value());
|
||||
}
|
||||
|
||||
// the offset at which to read the short that gives the names
|
||||
private int nameDeltaOffset(int i)
|
||||
{
|
||||
return CELL_NAME_OFFSETS_OFFSET + ((i - 1) * 2);
|
||||
}
|
||||
|
||||
int valueStartOffset()
|
||||
{
|
||||
return getInt(VALUE_OFFSET_OFFSET);
|
||||
}
|
||||
|
||||
private int valueEndOffset()
|
||||
{
|
||||
return (int) (internalSize() - postfixSize());
|
||||
}
|
||||
|
||||
protected int postfixSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer value()
|
||||
{
|
||||
long offset = valueStartOffset();
|
||||
return getByteBuffer(offset, (int) (internalSize() - (postfixSize() + offset)));
|
||||
}
|
||||
|
||||
private int clusteringSizeDelta()
|
||||
{
|
||||
return getByte(CELL_NAME_EXTRA_OFFSET) & CELL_NAME_SIZE_DELTA_MASK;
|
||||
}
|
||||
|
||||
public boolean isStatic()
|
||||
{
|
||||
return nametype() == NameType.COMPOUND_SPARSE_STATIC;
|
||||
}
|
||||
|
||||
NameType nametype()
|
||||
{
|
||||
return NameType.TYPES[(((int) this.getByte(CELL_NAME_EXTRA_OFFSET)) >> CELL_NAME_TYPE_SHIFT) & CELL_NAME_TYPE_MASK];
|
||||
}
|
||||
|
||||
public long minTimestamp()
|
||||
{
|
||||
return timestamp();
|
||||
}
|
||||
|
||||
public long maxTimestamp()
|
||||
{
|
||||
return timestamp();
|
||||
}
|
||||
|
||||
public int clusteringSize()
|
||||
{
|
||||
return size() - clusteringSizeDelta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata)
|
||||
{
|
||||
switch (nametype())
|
||||
{
|
||||
case SIMPLE_SPARSE:
|
||||
return getIdentifier(metadata, get(clusteringSize()));
|
||||
case COMPOUND_SPARSE_STATIC:
|
||||
case COMPOUND_SPARSE:
|
||||
ByteBuffer buffer = get(clusteringSize());
|
||||
if (buffer.remaining() == 0)
|
||||
return CompoundSparseCellNameType.rowMarkerId;
|
||||
|
||||
return getIdentifier(metadata, buffer);
|
||||
case SIMPLE_DENSE:
|
||||
case COMPOUND_DENSE:
|
||||
return null;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer collectionElement()
|
||||
{
|
||||
return isCollectionCell() ? get(size() - 1) : null;
|
||||
}
|
||||
|
||||
// we always have a collection element if our clustering size is 2 less than our total size,
|
||||
// and we never have one otherwiss
|
||||
public boolean isCollectionCell()
|
||||
{
|
||||
return clusteringSizeDelta() == 2;
|
||||
}
|
||||
|
||||
public boolean isSameCQL3RowAs(CellNameType type, CellName other)
|
||||
{
|
||||
switch (nametype())
|
||||
{
|
||||
case SIMPLE_DENSE:
|
||||
case COMPOUND_DENSE:
|
||||
return type.compare(this, other) == 0;
|
||||
case COMPOUND_SPARSE_STATIC:
|
||||
case COMPOUND_SPARSE:
|
||||
int clusteringSize = clusteringSize();
|
||||
if (clusteringSize != other.clusteringSize() || other.isStatic() != isStatic())
|
||||
return false;
|
||||
for (int i = 0; i < clusteringSize; i++)
|
||||
if (type.subtype(i).compare(get(i), other.get(i)) != 0)
|
||||
return false;
|
||||
return true;
|
||||
case SIMPLE_SPARSE:
|
||||
return true;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return getShort(CELL_NAME_SIZE_OFFSET);
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
public ByteBuffer get(int i)
|
||||
{
|
||||
// remember to take dense/sparse into account, and only return EOC when not dense
|
||||
int size = size();
|
||||
assert i >= 0 && i < size();
|
||||
int cellNamesOffset = nameDeltaOffset(size);
|
||||
int startDelta = i == 0 ? 0 : getShort(nameDeltaOffset(i));
|
||||
int endDelta = i < size - 1 ? getShort(nameDeltaOffset(i + 1)) : valueStartOffset() - cellNamesOffset;
|
||||
return getByteBuffer(cellNamesOffset + startDelta, endDelta - startDelta);
|
||||
}
|
||||
|
||||
private static final ThreadLocal<byte[]> BUFFER = new ThreadLocal<byte[]>()
|
||||
{
|
||||
protected byte[] initialValue()
|
||||
{
|
||||
return new byte[256];
|
||||
}
|
||||
};
|
||||
|
||||
protected void writeComponentTo(MessageDigest digest, int i, boolean includeSize)
|
||||
{
|
||||
// remember to take dense/sparse into account, and only return EOC when not dense
|
||||
int size = size();
|
||||
assert i >= 0 && i < size();
|
||||
int cellNamesOffset = nameDeltaOffset(size);
|
||||
int startDelta = i == 0 ? 0 : getShort(nameDeltaOffset(i));
|
||||
int endDelta = i < size - 1 ? getShort(nameDeltaOffset(i + 1)) : valueStartOffset() - cellNamesOffset;
|
||||
|
||||
int componentStart = cellNamesOffset + startDelta;
|
||||
int count = endDelta - startDelta;
|
||||
|
||||
if (includeSize)
|
||||
FBUtilities.updateWithShort(digest, count);
|
||||
|
||||
writeMemoryTo(digest, componentStart, count);
|
||||
}
|
||||
|
||||
protected void writeMemoryTo(MessageDigest digest, int from, int count)
|
||||
{
|
||||
// only batch if we have more than 16 bytes remaining to transfer, otherwise fall-back to single-byte updates
|
||||
int i = 0, batchEnd = count - 16;
|
||||
if (i < batchEnd)
|
||||
{
|
||||
byte[] buffer = BUFFER.get();
|
||||
while (i < batchEnd)
|
||||
{
|
||||
int transfer = Math.min(count - i, 256);
|
||||
getBytes(from + i, buffer, 0, transfer);
|
||||
digest.update(buffer, 0, transfer);
|
||||
i += transfer;
|
||||
}
|
||||
}
|
||||
while (i < count)
|
||||
digest.update(getByte(from + i++));
|
||||
}
|
||||
|
||||
public EOC eoc()
|
||||
{
|
||||
return EOC.NONE;
|
||||
}
|
||||
|
||||
public Composite withEOC(EOC eoc)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Composite start()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Composite end()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ColumnSlice slice()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean isPrefixOf(CType type, Composite c)
|
||||
{
|
||||
if (size() > c.size() || isStatic() != c.isStatic())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < size(); i++)
|
||||
{
|
||||
if (type.subtype(i).compare(get(i), c.get(i)) != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public ByteBuffer toByteBuffer()
|
||||
{
|
||||
// for simple sparse we just return our one name buffer
|
||||
switch (nametype())
|
||||
{
|
||||
case SIMPLE_DENSE:
|
||||
case SIMPLE_SPARSE:
|
||||
return get(0);
|
||||
case COMPOUND_DENSE:
|
||||
case COMPOUND_SPARSE_STATIC:
|
||||
case COMPOUND_SPARSE:
|
||||
// This is the legacy format of composites.
|
||||
// See org.apache.cassandra.db.marshal.CompositeType for details.
|
||||
ByteBuffer result = ByteBuffer.allocate(cellDataSize());
|
||||
if (isStatic())
|
||||
ByteBufferUtil.writeShortLength(result, CompositeType.STATIC_MARKER);
|
||||
|
||||
for (int i = 0; i < size(); i++)
|
||||
{
|
||||
ByteBuffer bb = get(i);
|
||||
ByteBufferUtil.writeShortLength(result, bb.remaining());
|
||||
result.put(bb);
|
||||
result.put((byte) 0);
|
||||
}
|
||||
result.flip();
|
||||
return result;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateWithName(MessageDigest digest)
|
||||
{
|
||||
// for simple sparse we just return our one name buffer
|
||||
switch (nametype())
|
||||
{
|
||||
case SIMPLE_DENSE:
|
||||
case SIMPLE_SPARSE:
|
||||
writeComponentTo(digest, 0, false);
|
||||
break;
|
||||
|
||||
case COMPOUND_DENSE:
|
||||
case COMPOUND_SPARSE_STATIC:
|
||||
case COMPOUND_SPARSE:
|
||||
// This is the legacy format of composites.
|
||||
// See org.apache.cassandra.db.marshal.CompositeType for details.
|
||||
if (isStatic())
|
||||
FBUtilities.updateWithShort(digest, CompositeType.STATIC_MARKER);
|
||||
|
||||
for (int i = 0; i < size(); i++)
|
||||
{
|
||||
writeComponentTo(digest, i, true);
|
||||
digest.update((byte) 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateWithValue(MessageDigest digest)
|
||||
{
|
||||
int offset = valueStartOffset();
|
||||
int length = valueEndOffset() - offset;
|
||||
writeMemoryTo(digest, offset, length);
|
||||
}
|
||||
|
||||
@Override // this is the NAME dataSize, only!
|
||||
public int dataSize()
|
||||
{
|
||||
switch (nametype())
|
||||
{
|
||||
case SIMPLE_DENSE:
|
||||
case SIMPLE_SPARSE:
|
||||
return valueStartOffset() - nameDeltaOffset(size());
|
||||
case COMPOUND_DENSE:
|
||||
case COMPOUND_SPARSE_STATIC:
|
||||
case COMPOUND_SPARSE:
|
||||
int size = size();
|
||||
return valueStartOffset() - nameDeltaOffset(size) + 3 * size + (isStatic() ? 2 : 0);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj instanceof CellName)
|
||||
return equals((CellName) obj);
|
||||
if (obj instanceof Cell)
|
||||
return equals((Cell) obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(CellName that)
|
||||
{
|
||||
int size = this.size();
|
||||
if (size != that.size())
|
||||
return false;
|
||||
|
||||
for (int i = 0 ; i < size ; i++)
|
||||
if (!get(i).equals(that.get(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final ByteBuffer[] EMPTY = new ByteBuffer[0];
|
||||
|
||||
@Override
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
ByteBuffer[] r;
|
||||
switch (nametype())
|
||||
{
|
||||
case SIMPLE_DENSE:
|
||||
return CellNames.simpleDense(allocator.clone(get(0)));
|
||||
|
||||
case COMPOUND_DENSE:
|
||||
r = new ByteBuffer[size()];
|
||||
for (int i = 0; i < r.length; i++)
|
||||
r[i] = allocator.clone(get(i));
|
||||
return CellNames.compositeDense(r);
|
||||
|
||||
case COMPOUND_SPARSE_STATIC:
|
||||
case COMPOUND_SPARSE:
|
||||
int clusteringSize = clusteringSize();
|
||||
r = clusteringSize == 0 ? EMPTY : new ByteBuffer[clusteringSize()];
|
||||
for (int i = 0; i < clusteringSize; i++)
|
||||
r[i] = allocator.clone(get(i));
|
||||
|
||||
ByteBuffer nameBuffer = get(r.length);
|
||||
ColumnIdentifier name;
|
||||
|
||||
if (nameBuffer.remaining() == 0)
|
||||
{
|
||||
name = CompoundSparseCellNameType.rowMarkerId;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = getIdentifier(cfm, nameBuffer);
|
||||
}
|
||||
|
||||
if (clusteringSizeDelta() == 2)
|
||||
{
|
||||
ByteBuffer element = allocator.clone(get(size() - 1));
|
||||
return CellNames.compositeSparseWithCollection(r, element, name, isStatic());
|
||||
}
|
||||
return CellNames.compositeSparse(r, name, isStatic());
|
||||
|
||||
case SIMPLE_SPARSE:
|
||||
return CellNames.simpleSparse(getIdentifier(cfm, get(0)));
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
private static ColumnIdentifier getIdentifier(CFMetaData cfMetaData, ByteBuffer name)
|
||||
{
|
||||
ColumnDefinition def = cfMetaData.getColumnDefinition(name);
|
||||
if (def != null)
|
||||
{
|
||||
return def.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's safe to simply grab based on clusteringPrefixSize() as we are only called if not a dense type
|
||||
AbstractType<?> type = cfMetaData.comparator.subtype(cfMetaData.comparator.clusteringPrefixSize());
|
||||
return new ColumnIdentifier(HeapAllocator.instance.clone(name), type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected long internalSize()
|
||||
{
|
||||
return MemoryUtil.getInt(peer);
|
||||
}
|
||||
|
||||
private void checkPosition(long offset, long size)
|
||||
{
|
||||
assert size >= 0;
|
||||
assert peer > 0 : "Memory was freed";
|
||||
assert offset >= 0 && offset + size <= internalSize() : String.format("Illegal range: [%d..%d), size: %s", offset, offset + size, internalSize());
|
||||
}
|
||||
|
||||
protected final void setByte(long offset, byte b)
|
||||
{
|
||||
checkPosition(offset, 1);
|
||||
MemoryUtil.setByte(peer + offset, b);
|
||||
}
|
||||
|
||||
protected final void setShort(long offset, short s)
|
||||
{
|
||||
checkPosition(offset, 1);
|
||||
MemoryUtil.setShort(peer + offset, s);
|
||||
}
|
||||
|
||||
protected final void setInt(long offset, int l)
|
||||
{
|
||||
checkPosition(offset, 4);
|
||||
MemoryUtil.setInt(peer + offset, l);
|
||||
}
|
||||
|
||||
protected final void setLong(long offset, long l)
|
||||
{
|
||||
checkPosition(offset, 8);
|
||||
MemoryUtil.setLong(peer + offset, l);
|
||||
}
|
||||
|
||||
protected final void setBytes(long offset, ByteBuffer buffer)
|
||||
{
|
||||
int start = buffer.position();
|
||||
int count = buffer.limit() - start;
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
checkPosition(offset, count);
|
||||
MemoryUtil.setBytes(peer + offset, buffer);
|
||||
}
|
||||
|
||||
protected final byte getByte(long offset)
|
||||
{
|
||||
checkPosition(offset, 1);
|
||||
return MemoryUtil.getByte(peer + offset);
|
||||
}
|
||||
|
||||
protected final void getBytes(long offset, byte[] trg, int trgOffset, int count)
|
||||
{
|
||||
checkPosition(offset, count);
|
||||
MemoryUtil.getBytes(peer + offset, trg, trgOffset, count);
|
||||
}
|
||||
|
||||
protected final int getShort(long offset)
|
||||
{
|
||||
checkPosition(offset, 2);
|
||||
return MemoryUtil.getShort(peer + offset);
|
||||
}
|
||||
|
||||
protected final int getInt(long offset)
|
||||
{
|
||||
checkPosition(offset, 4);
|
||||
return MemoryUtil.getInt(peer + offset);
|
||||
}
|
||||
|
||||
protected final long getLong(long offset)
|
||||
{
|
||||
checkPosition(offset, 8);
|
||||
return MemoryUtil.getLong(peer + offset);
|
||||
}
|
||||
|
||||
protected final ByteBuffer getByteBuffer(long offset, int length)
|
||||
{
|
||||
checkPosition(offset, length);
|
||||
return MemoryUtil.getByteBuffer(peer + offset, length);
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ public class ArrayBackedSortedColumns extends ColumnFamily
|
|||
{
|
||||
ArrayBackedSortedColumns copy = new ArrayBackedSortedColumns(original.metadata, false, new Cell[original.getColumnCount()], 0, 0);
|
||||
for (Cell cell : original)
|
||||
copy.internalAdd(cell.localCopy(allocator));
|
||||
copy.internalAdd(cell.localCopy(original.metadata, allocator));
|
||||
copy.sortedSize = copy.size; // internalAdd doesn't update sortedSize.
|
||||
copy.delete(original);
|
||||
return copy;
|
||||
|
|
@ -139,7 +139,7 @@ public class ArrayBackedSortedColumns extends ColumnFamily
|
|||
Arrays.sort(cells, sortedSize, size, comparator);
|
||||
|
||||
// Determine the merge start position for that segment
|
||||
int pos = binarySearch(0, sortedSize, cells[sortedSize].name, internalComparator());
|
||||
int pos = binarySearch(0, sortedSize, cells[sortedSize].name(), internalComparator());
|
||||
if (pos < 0)
|
||||
pos = -pos - 1;
|
||||
|
||||
|
|
@ -421,7 +421,7 @@ public class ArrayBackedSortedColumns extends ColumnFamily
|
|||
{
|
||||
public CellName apply(Cell cell)
|
||||
{
|
||||
return cell.name;
|
||||
return cell.name();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.apache.cassandra.db;
|
|||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -28,19 +27,21 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.collect.*;
|
||||
import com.google.common.collect.Iterators;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.Composite;
|
||||
import org.apache.cassandra.db.index.SecondaryIndexManager;
|
||||
import org.apache.cassandra.db.filter.ColumnSlice;
|
||||
import org.apache.cassandra.db.index.SecondaryIndexManager;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.SearchIterator;
|
||||
import org.apache.cassandra.utils.btree.BTree;
|
||||
import org.apache.cassandra.utils.btree.BTreeSearchIterator;
|
||||
import org.apache.cassandra.utils.btree.BTreeSet;
|
||||
import org.apache.cassandra.utils.btree.UpdateFunction;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
import static org.apache.cassandra.db.index.SecondaryIndexManager.Updater;
|
||||
|
||||
|
|
@ -55,14 +56,14 @@ import static org.apache.cassandra.db.index.SecondaryIndexManager.Updater;
|
|||
*/
|
||||
public class AtomicBTreeColumns extends ColumnFamily
|
||||
{
|
||||
static final long HEAP_SIZE = ObjectSizes.measure(new AtomicBTreeColumns(CFMetaData.IndexCf, null))
|
||||
static final long EMPTY_SIZE = ObjectSizes.measure(new AtomicBTreeColumns(CFMetaData.IndexCf, null))
|
||||
+ ObjectSizes.measure(new Holder(null, null));
|
||||
|
||||
private static final Function<Cell, CellName> NAME = new Function<Cell, CellName>()
|
||||
{
|
||||
public CellName apply(Cell column)
|
||||
{
|
||||
return column.name;
|
||||
return column.name();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -162,110 +163,40 @@ public class AtomicBTreeColumns extends ColumnFamily
|
|||
}
|
||||
}
|
||||
|
||||
// the function we provide to the btree utilities to perform any column replacements
|
||||
private static final class ColumnUpdater implements UpdateFunction<Cell>
|
||||
{
|
||||
final AtomicBTreeColumns updating;
|
||||
final Holder ref;
|
||||
final Function<Cell, Cell> transform;
|
||||
final Updater indexer;
|
||||
final Delta delta;
|
||||
|
||||
private ColumnUpdater(AtomicBTreeColumns updating, Holder ref, Function<Cell, Cell> transform, Updater indexer, Delta delta)
|
||||
{
|
||||
this.updating = updating;
|
||||
this.ref = ref;
|
||||
this.transform = transform;
|
||||
this.indexer = indexer;
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
public Cell apply(Cell inserted)
|
||||
{
|
||||
indexer.insert(inserted);
|
||||
delta.insert(inserted);
|
||||
return transform.apply(inserted);
|
||||
}
|
||||
|
||||
public Cell apply(Cell existing, Cell update)
|
||||
{
|
||||
Cell reconciled = update.reconcile(existing);
|
||||
indexer.update(existing, reconciled);
|
||||
if (existing != reconciled)
|
||||
delta.swap(existing, reconciled);
|
||||
else
|
||||
delta.abort(update);
|
||||
return transform.apply(reconciled);
|
||||
}
|
||||
|
||||
public boolean abortEarly()
|
||||
{
|
||||
return updating.ref != ref;
|
||||
}
|
||||
|
||||
public void allocated(long heapSize)
|
||||
{
|
||||
delta.addHeapSize(heapSize);
|
||||
}
|
||||
}
|
||||
|
||||
private static Collection<Cell> transform(Comparator<Cell> cmp, ColumnFamily cf, Function<Cell, Cell> transformation, boolean sort)
|
||||
{
|
||||
Cell[] tmp = new Cell[cf.getColumnCount()];
|
||||
|
||||
int i = 0;
|
||||
for (Cell c : cf)
|
||||
tmp[i++] = transformation.apply(c);
|
||||
|
||||
if (sort)
|
||||
Arrays.sort(tmp, cmp);
|
||||
|
||||
return Arrays.asList(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is only called by Memtable.resolve, so only AtomicBTreeColumns needs to implement it.
|
||||
*
|
||||
* @return the difference in size seen after merging the given columns
|
||||
*/
|
||||
public Delta addAllWithSizeDelta(final ColumnFamily cm, Function<Cell, Cell> transformation, Updater indexer, Delta delta)
|
||||
public long addAllWithSizeDelta(final ColumnFamily cm, MemtableAllocator allocator, OpOrder.Group writeOp, Updater indexer)
|
||||
{
|
||||
boolean transformed = false;
|
||||
Collection<Cell> insert = cm.getSortedColumns();
|
||||
|
||||
ColumnUpdater updater = new ColumnUpdater(this, cm.metadata, allocator, writeOp, indexer);
|
||||
while (true)
|
||||
{
|
||||
Holder current = ref;
|
||||
updater.ref = current;
|
||||
updater.reset();
|
||||
|
||||
delta.reset();
|
||||
DeletionInfo deletionInfo;
|
||||
if (cm.deletionInfo().mayModify(current.deletionInfo))
|
||||
{
|
||||
deletionInfo = current.deletionInfo.copy().add(cm.deletionInfo());
|
||||
delta.addHeapSize(deletionInfo.unsharedHeapSize() - current.deletionInfo.unsharedHeapSize());
|
||||
updater.allocated(deletionInfo.unsharedHeapSize() - current.deletionInfo.unsharedHeapSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
deletionInfo = current.deletionInfo;
|
||||
}
|
||||
|
||||
ColumnUpdater updater = new ColumnUpdater(this, current, transformation, indexer, delta);
|
||||
Object[] tree = BTree.update(current.tree, metadata.comparator.columnComparator(), insert, true, updater);
|
||||
Object[] tree = BTree.update(current.tree, metadata.comparator.columnComparator(), cm, cm.getColumnCount(), true, updater);
|
||||
|
||||
if (tree != null && refUpdater.compareAndSet(this, current, new Holder(tree, deletionInfo)))
|
||||
{
|
||||
indexer.updateRowLevelIndexes();
|
||||
return updater.delta;
|
||||
}
|
||||
|
||||
if (!transformed)
|
||||
{
|
||||
// After failing once, transform Columns into a new collection to avoid repeatedly allocating Slab space
|
||||
insert = transform(metadata.comparator.columnComparator(), cm, transformation, false);
|
||||
transformed = true;
|
||||
updater.finish();
|
||||
return updater.dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// no particular reason not to implement these next methods, we just haven't needed them yet
|
||||
|
|
@ -297,7 +228,7 @@ public class AtomicBTreeColumns extends ColumnFamily
|
|||
{
|
||||
public int compare(Object o1, Object o2)
|
||||
{
|
||||
return cmp.compare((CellName) o1, ((Cell) o2).name);
|
||||
return cmp.compare((CellName) o1, ((Cell) o2).name());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -359,7 +290,7 @@ public class AtomicBTreeColumns extends ColumnFamily
|
|||
return false;
|
||||
}
|
||||
|
||||
private static class Holder
|
||||
private static final class Holder
|
||||
{
|
||||
final DeletionInfo deletionInfo;
|
||||
// the btree of columns
|
||||
|
|
@ -382,69 +313,96 @@ public class AtomicBTreeColumns extends ColumnFamily
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: create a stack-allocation-friendly list to help optimise garbage for updates to rows with few columns
|
||||
|
||||
/**
|
||||
* tracks the size changes made while merging a new group of cells in
|
||||
*/
|
||||
public static final class Delta
|
||||
// the function we provide to the btree utilities to perform any column replacements
|
||||
private static final class ColumnUpdater implements UpdateFunction<Cell>
|
||||
{
|
||||
private long dataSize;
|
||||
private long heapSize;
|
||||
final AtomicBTreeColumns updating;
|
||||
final CFMetaData metadata;
|
||||
final MemtableAllocator allocator;
|
||||
final OpOrder.Group writeOp;
|
||||
final Updater indexer;
|
||||
Holder ref;
|
||||
long dataSize;
|
||||
long heapSize;
|
||||
final MemtableAllocator.DataReclaimer reclaimer;
|
||||
List<Cell> inserted; // TODO: replace with walk of aborted BTree
|
||||
|
||||
// we track the discarded cells (cells that were in the btree, but replaced by new ones)
|
||||
// separately from aborted ones (were part of an update but older than existing cells)
|
||||
// since we need to reset the former when we race on the btree update, but not the latter
|
||||
private List<Cell> discarded = new ArrayList<>();
|
||||
private List<Cell> aborted;
|
||||
private ColumnUpdater(AtomicBTreeColumns updating, CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group writeOp, Updater indexer)
|
||||
{
|
||||
this.updating = updating;
|
||||
this.allocator = allocator;
|
||||
this.writeOp = writeOp;
|
||||
this.indexer = indexer;
|
||||
this.metadata = metadata;
|
||||
this.reclaimer = allocator.reclaimer();
|
||||
}
|
||||
|
||||
public Cell apply(Cell insert)
|
||||
{
|
||||
indexer.insert(insert);
|
||||
insert = insert.localCopy(metadata, allocator, writeOp);
|
||||
this.dataSize += insert.cellDataSize();
|
||||
this.heapSize += insert.excessHeapSizeExcludingData();
|
||||
if (inserted == null)
|
||||
inserted = new ArrayList<>();
|
||||
inserted.add(insert);
|
||||
return insert;
|
||||
}
|
||||
|
||||
public Cell apply(Cell existing, Cell update)
|
||||
{
|
||||
Cell reconciled = existing.reconcile(update);
|
||||
indexer.update(existing, reconciled);
|
||||
if (existing != reconciled)
|
||||
{
|
||||
reconciled = reconciled.localCopy(metadata, allocator, writeOp);
|
||||
dataSize += reconciled.cellDataSize() - existing.cellDataSize();
|
||||
heapSize += reconciled.excessHeapSizeExcludingData() - existing.excessHeapSizeExcludingData();
|
||||
if (inserted == null)
|
||||
inserted = new ArrayList<>();
|
||||
inserted.add(reconciled);
|
||||
discard(existing);
|
||||
}
|
||||
return reconciled;
|
||||
}
|
||||
|
||||
protected void reset()
|
||||
{
|
||||
this.dataSize = 0;
|
||||
this.heapSize = 0;
|
||||
discarded.clear();
|
||||
if (inserted != null)
|
||||
{
|
||||
for (Cell cell : inserted)
|
||||
abort(cell);
|
||||
inserted.clear();
|
||||
}
|
||||
reclaimer.cancel();
|
||||
}
|
||||
|
||||
protected void addHeapSize(long heapSize)
|
||||
protected void abort(Cell abort)
|
||||
{
|
||||
reclaimer.reclaimImmediately(abort);
|
||||
}
|
||||
|
||||
protected void discard(Cell discard)
|
||||
{
|
||||
reclaimer.reclaim(discard);
|
||||
}
|
||||
|
||||
public boolean abortEarly()
|
||||
{
|
||||
return updating.ref != ref;
|
||||
}
|
||||
|
||||
public void allocated(long heapSize)
|
||||
{
|
||||
this.heapSize += heapSize;
|
||||
}
|
||||
|
||||
protected void swap(Cell old, Cell updated)
|
||||
protected void finish()
|
||||
{
|
||||
dataSize += updated.dataSize() - old.dataSize();
|
||||
heapSize += updated.excessHeapSizeExcludingData() - old.excessHeapSizeExcludingData();
|
||||
discarded.add(old);
|
||||
}
|
||||
|
||||
protected void insert(Cell insert)
|
||||
{
|
||||
this.dataSize += insert.dataSize();
|
||||
this.heapSize += insert.excessHeapSizeExcludingData();
|
||||
}
|
||||
|
||||
private void abort(Cell neverUsed)
|
||||
{
|
||||
if (aborted == null)
|
||||
aborted = new ArrayList<>();
|
||||
aborted.add(neverUsed);
|
||||
}
|
||||
|
||||
public long dataSize()
|
||||
{
|
||||
return dataSize;
|
||||
}
|
||||
|
||||
public long excessHeapSize()
|
||||
{
|
||||
return heapSize;
|
||||
}
|
||||
|
||||
public Iterable<Cell> reclaimed()
|
||||
{
|
||||
if (aborted == null)
|
||||
return discarded;
|
||||
return Iterables.concat(discarded, aborted);
|
||||
allocator.onHeap().allocate(heapSize, writeOp);
|
||||
reclaimer.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNames;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class BufferCell extends AbstractCell
|
||||
{
|
||||
private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferCell(CellNames.simpleDense(ByteBuffer.allocate(1))));
|
||||
|
||||
protected final CellName name;
|
||||
protected final ByteBuffer value;
|
||||
protected final long timestamp;
|
||||
|
||||
BufferCell(CellName name)
|
||||
{
|
||||
this(name, ByteBufferUtil.EMPTY_BYTE_BUFFER);
|
||||
}
|
||||
|
||||
public BufferCell(CellName name, ByteBuffer value)
|
||||
{
|
||||
this(name, value, 0);
|
||||
}
|
||||
|
||||
public BufferCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
assert name != null;
|
||||
assert value != null;
|
||||
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new BufferCell(newName, value, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
return new BufferCell(name, value, newTimestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellName name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long excessHeapSizeExcludingData()
|
||||
{
|
||||
return EMPTY_SIZE + name.excessHeapSizeExcludingData() + ObjectSizes.sizeOnHeapExcludingData(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferCell(name.copy(metadata, allocator), allocator.clone(value), timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class BufferCounterCell extends BufferCell implements CounterCell
|
||||
{
|
||||
private final long timestampOfLastDelete;
|
||||
|
||||
public BufferCounterCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
this(name, value, timestamp, Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
public BufferCounterCell(CellName name, ByteBuffer value, long timestamp, long timestampOfLastDelete)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
this.timestampOfLastDelete = timestampOfLastDelete;
|
||||
}
|
||||
|
||||
public static CounterCell create(CellName name, ByteBuffer value, long timestamp, long timestampOfLastDelete, ColumnSerializer.Flag flag)
|
||||
{
|
||||
if (flag == ColumnSerializer.Flag.FROM_REMOTE || (flag == ColumnSerializer.Flag.LOCAL && contextManager.shouldClearLocal(value)))
|
||||
value = contextManager.clearAllLocal(value);
|
||||
return new BufferCounterCell(name, value, timestamp, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
// For use by tests of compatibility with pre-2.1 counter only.
|
||||
public static CounterCell createLocal(CellName name, long value, long timestamp, long timestampOfLastDelete)
|
||||
{
|
||||
return new BufferCounterCell(name, contextManager.createLocal(value), timestamp, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new BufferCounterCell(newName, value, timestamp, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timestampOfLastDelete()
|
||||
{
|
||||
return timestampOfLastDelete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long total()
|
||||
{
|
||||
return contextManager.total(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cellDataSize()
|
||||
{
|
||||
// A counter column adds 8 bytes for timestampOfLastDelete to Cell.
|
||||
return super.cellDataSize() + TypeSizes.NATIVE.sizeof(timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
return super.serializedSize(type, typeSizes) + typeSizes.sizeof(timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
return diff(this, cell);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to special case digest creation for counter column because
|
||||
* we don't want to include the information about which shard of the
|
||||
* context is a delta or not, since this information differs from node to
|
||||
* node.
|
||||
*/
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name().toByteBuffer().duplicate());
|
||||
// We don't take the deltas into account in a digest
|
||||
contextManager.updateDigest(digest, value());
|
||||
|
||||
FBUtilities.updateWithLong(digest, timestamp);
|
||||
FBUtilities.updateWithByte(digest, serializationFlags());
|
||||
FBUtilities.updateWithLong(digest, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
return reconcile(this, cell);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLegacyShards()
|
||||
{
|
||||
return contextManager.hasLegacyShards(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CounterCell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferCounterCell(name.copy(metadata, allocator), allocator.clone(value), timestamp, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CounterCell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s:false:%s@%d!%d",
|
||||
comparator.getString(name()),
|
||||
contextManager.toString(value()),
|
||||
timestamp(),
|
||||
timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.COUNTER_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
// We cannot use the value validator as for other columns as the CounterColumnType validate a long,
|
||||
// which is not the internal representation of counters
|
||||
contextManager.validateContext(value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell markLocalToBeCleared()
|
||||
{
|
||||
ByteBuffer marked = contextManager.markLocalToBeCleared(value());
|
||||
return marked == value() ? this : new BufferCounterCell(name(), marked, timestamp(), timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return cell instanceof CounterCell && equals((CounterCell) cell);
|
||||
}
|
||||
|
||||
public boolean equals(CounterCell cell)
|
||||
{
|
||||
return super.equals(cell) && timestampOfLastDelete == cell.timestampOfLastDelete();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class BufferCounterUpdateCell extends BufferCell implements CounterUpdateCell
|
||||
{
|
||||
public BufferCounterUpdateCell(CellName name, long value, long timestamp)
|
||||
{
|
||||
this(name, ByteBufferUtil.bytes(value), timestamp);
|
||||
}
|
||||
|
||||
public BufferCounterUpdateCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
}
|
||||
|
||||
public long delta()
|
||||
{
|
||||
return value().getLong(value.position());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
// Diff is used during reads, but we should never read those columns
|
||||
throw new UnsupportedOperationException("This operation is unsupported on CounterUpdateCell.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
// The only time this could happen is if a batchAdd ships two
|
||||
// increment for the same cell. Hence we simply sums the delta.
|
||||
|
||||
// tombstones take precedence
|
||||
if (cell.isMarkedForDelete(Long.MIN_VALUE)) // can't be an expired cell, so the current time is irrelevant
|
||||
return timestamp > cell.timestamp() ? this : cell;
|
||||
|
||||
// neither is tombstoned
|
||||
assert cell instanceof CounterUpdateCell : "Wrong class type.";
|
||||
CounterUpdateCell c = (CounterUpdateCell) cell;
|
||||
return new BufferCounterUpdateCell(name, delta() + c.delta(), Math.max(timestamp, c.timestamp()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.COUNTER_UPDATE_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s:%s@%d", comparator.getString(name()), ByteBufferUtil.toLong(value), timestamp());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.dht.Token;
|
||||
|
||||
public class BufferDecoratedKey extends DecoratedKey
|
||||
{
|
||||
private final ByteBuffer key;
|
||||
|
||||
public BufferDecoratedKey(Token token, ByteBuffer key)
|
||||
{
|
||||
super(token);
|
||||
assert key != null;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public ByteBuffer getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class BufferDeletedCell extends BufferCell implements DeletedCell
|
||||
{
|
||||
public BufferDeletedCell(CellName name, int localDeletionTime, long timestamp)
|
||||
{
|
||||
this(name, ByteBufferUtil.bytes(localDeletionTime), timestamp);
|
||||
}
|
||||
|
||||
public BufferDeletedCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new BufferDeletedCell(newName, value, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
return new BufferDeletedCell(name, value, newTimestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return value().getInt(value.position());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
if (cell instanceof DeletedCell)
|
||||
return super.reconcile(cell);
|
||||
return cell.reconcile(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeletedCell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferDeletedCell(name.copy(metadata, allocator), allocator.clone(value), timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeletedCell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.DELETION_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
if (value().remaining() != 4)
|
||||
throw new MarshalException("A tombstone value should be 4 bytes long");
|
||||
if (getLocalDeletionTime() < 0)
|
||||
throw new MarshalException("The local deletion time should not be negative");
|
||||
}
|
||||
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return timestamp() == cell.timestamp() && getLocalDeletionTime() == cell.getLocalDeletionTime() && name().equals(cell.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name().toByteBuffer().duplicate());
|
||||
|
||||
FBUtilities.updateWithLong(digest, timestamp());
|
||||
FBUtilities.updateWithByte(digest, serializationFlags());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class BufferExpiringCell extends BufferCell implements ExpiringCell
|
||||
{
|
||||
private final int localExpirationTime;
|
||||
private final int timeToLive;
|
||||
|
||||
public BufferExpiringCell(CellName name, ByteBuffer value, long timestamp, int timeToLive)
|
||||
{
|
||||
this(name, value, timestamp, timeToLive, (int) (System.currentTimeMillis() / 1000) + timeToLive);
|
||||
}
|
||||
|
||||
public BufferExpiringCell(CellName name, ByteBuffer value, long timestamp, int timeToLive, int localExpirationTime)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
assert timeToLive > 0 : timeToLive;
|
||||
assert localExpirationTime > 0 : localExpirationTime;
|
||||
this.timeToLive = timeToLive;
|
||||
this.localExpirationTime = localExpirationTime;
|
||||
}
|
||||
|
||||
public int getTimeToLive()
|
||||
{
|
||||
return timeToLive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new BufferExpiringCell(newName, value(), timestamp(), timeToLive, localExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
return new BufferExpiringCell(name(), value(), newTimestamp, timeToLive, localExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cellDataSize()
|
||||
{
|
||||
return super.cellDataSize() + TypeSizes.NATIVE.sizeof(localExpirationTime) + TypeSizes.NATIVE.sizeof(timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
/*
|
||||
* An expired column adds to a Cell :
|
||||
* 4 bytes for the localExpirationTime
|
||||
* + 4 bytes for the timeToLive
|
||||
*/
|
||||
return super.serializedSize(type, typeSizes) + typeSizes.sizeof(localExpirationTime) + typeSizes.sizeof(timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
super.updateDigest(digest);
|
||||
FBUtilities.updateWithInt(digest, timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return localExpirationTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpiringCell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferExpiringCell(name.copy(metadata, allocator), allocator.clone(value), timestamp, timeToLive, localExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpiringCell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s!%d", super.getString(comparator), timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return (int) (now / 1000) >= getLocalDeletionTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.EXPIRATION_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
super.validateFields(metadata);
|
||||
|
||||
if (timeToLive <= 0)
|
||||
throw new MarshalException("A column TTL should be > 0");
|
||||
if (localExpirationTime < 0)
|
||||
throw new MarshalException("The local expiration time should not be negative");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return cell instanceof ExpiringCell && equals((ExpiringCell) cell);
|
||||
}
|
||||
|
||||
public boolean equals(ExpiringCell cell)
|
||||
{
|
||||
// super.equals() returns false if o is not a CounterCell
|
||||
return super.equals(cell)
|
||||
&& getLocalDeletionTime() == cell.getLocalDeletionTime()
|
||||
&& getTimeToLive() == cell.getTimeToLive();
|
||||
}
|
||||
|
||||
/** @return Either a DeletedCell, or an ExpiringCell. */
|
||||
public static Cell create(CellName name, ByteBuffer value, long timestamp, int timeToLive, int localExpirationTime, int expireBefore, ColumnSerializer.Flag flag)
|
||||
{
|
||||
if (localExpirationTime >= expireBefore || flag == ColumnSerializer.Flag.PRESERVE_SIZE)
|
||||
return new BufferExpiringCell(name, value, timestamp, timeToLive, localExpirationTime);
|
||||
// The column is now expired, we can safely return a simple tombstone. Note that
|
||||
// as long as the expiring column and the tombstone put together live longer than GC grace seconds,
|
||||
// we'll fulfil our responsibility to repair. See discussion at
|
||||
// http://cassandra-user-incubator-apache-org.3065146.n2.nabble.com/repair-compaction-and-tombstone-rows-td7583481.html
|
||||
return new BufferDeletedCell(name, localExpirationTime - timeToLive, timestamp);
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ public class CFRowAdder
|
|||
|
||||
// If a CQL3 table, add the row marker
|
||||
if (cf.metadata().isCQL3Table() && !prefix.isStatic())
|
||||
cf.addColumn(new Cell(cf.getComparator().rowMarker(prefix), ByteBufferUtil.EMPTY_BYTE_BUFFER, timestamp));
|
||||
cf.addColumn(new BufferCell(cf.getComparator().rowMarker(prefix), ByteBufferUtil.EMPTY_BYTE_BUFFER, timestamp));
|
||||
}
|
||||
|
||||
public CFRowAdder add(String cql3ColumnName, Object value)
|
||||
|
|
@ -96,14 +96,14 @@ public class CFRowAdder
|
|||
{
|
||||
if (value == null)
|
||||
{
|
||||
cf.addColumn(new DeletedCell(name, ldt, timestamp));
|
||||
cf.addColumn(new BufferDeletedCell(name, ldt, timestamp));
|
||||
}
|
||||
else
|
||||
{
|
||||
AbstractType valueType = def.type.isCollection()
|
||||
? ((CollectionType) def.type).valueComparator()
|
||||
: def.type;
|
||||
cf.addColumn(new Cell(name, value instanceof ByteBuffer ? (ByteBuffer)value : valueType.decompose(value), timestamp));
|
||||
cf.addColumn(new BufferCell(name, value instanceof ByteBuffer ? (ByteBuffer)value : valueType.decompose(value), timestamp));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,261 +17,58 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.db.composites.CellNames;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.io.sstable.Descriptor;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
/**
|
||||
* Cell is immutable, which prevents all kinds of confusion in a multithreaded environment.
|
||||
*/
|
||||
public class Cell implements OnDiskAtom
|
||||
public interface Cell extends OnDiskAtom
|
||||
{
|
||||
public static final int MAX_NAME_LENGTH = FBUtilities.MAX_UNSIGNED_SHORT;
|
||||
|
||||
private static final long EMPTY_SIZE = ObjectSizes.measure(new Cell(CellNames.simpleDense(ByteBuffer.allocate(1))));
|
||||
public Cell withUpdatedName(CellName newName);
|
||||
|
||||
public static Iterator<OnDiskAtom> onDiskIterator(final DataInput in,
|
||||
final ColumnSerializer.Flag flag,
|
||||
final int expireBefore,
|
||||
final Descriptor.Version version,
|
||||
final CellNameType type)
|
||||
{
|
||||
return new AbstractIterator<OnDiskAtom>()
|
||||
{
|
||||
protected OnDiskAtom computeNext()
|
||||
{
|
||||
OnDiskAtom atom;
|
||||
try
|
||||
{
|
||||
atom = type.onDiskAtomSerializer().deserializeFromSSTable(in, flag, expireBefore, version);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IOError(e);
|
||||
}
|
||||
if (atom == null)
|
||||
return endOfData();
|
||||
public Cell withUpdatedTimestamp(long newTimestamp);
|
||||
|
||||
return atom;
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public CellName name();
|
||||
|
||||
protected final CellName name;
|
||||
protected final ByteBuffer value;
|
||||
protected final long timestamp;
|
||||
public ByteBuffer value();
|
||||
|
||||
Cell(CellName name)
|
||||
{
|
||||
this(name, ByteBufferUtil.EMPTY_BYTE_BUFFER);
|
||||
}
|
||||
public boolean isMarkedForDelete(long now);
|
||||
|
||||
public Cell(CellName name, ByteBuffer value)
|
||||
{
|
||||
this(name, value, 0);
|
||||
}
|
||||
|
||||
public Cell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
assert name != null;
|
||||
assert value != null;
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new Cell(newName, value, timestamp);
|
||||
}
|
||||
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
return new Cell(name, value, newTimestamp);
|
||||
}
|
||||
|
||||
public CellName name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public ByteBuffer value()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public long timestamp()
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isLive(long now)
|
||||
{
|
||||
return !isMarkedForDelete(now);
|
||||
}
|
||||
public boolean isLive(long now);
|
||||
|
||||
// Don't call unless the column is actually marked for delete.
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
public long getMarkedForDeleteAt();
|
||||
|
||||
public int dataSize()
|
||||
{
|
||||
return name.dataSize() + value.remaining() + TypeSizes.NATIVE.sizeof(timestamp);
|
||||
}
|
||||
public int cellDataSize();
|
||||
|
||||
// returns the size of the Cell and all references on the heap, excluding any costs associated with byte arrays
|
||||
// that would be allocated by a localCopy, as these will be accounted for by the allocator
|
||||
public long excessHeapSizeExcludingData()
|
||||
{
|
||||
return EMPTY_SIZE + name.excessHeapSizeExcludingData() + ObjectSizes.sizeOnHeapExcludingData(value);
|
||||
}
|
||||
public long excessHeapSizeExcludingData();
|
||||
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
/*
|
||||
* Size of a column is =
|
||||
* size of a name (short + length of the string)
|
||||
* + 1 byte to indicate if the column has been deleted
|
||||
* + 8 bytes for timestamp
|
||||
* + 4 bytes which basically indicates the size of the byte array
|
||||
* + entire byte array.
|
||||
*/
|
||||
int valueSize = value.remaining();
|
||||
return ((int)type.cellSerializer().serializedSize(name, typeSizes)) + 1 + typeSizes.sizeof(timestamp) + typeSizes.sizeof(valueSize) + valueSize;
|
||||
}
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes);
|
||||
public int serializationFlags();
|
||||
|
||||
public int serializationFlags()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public Cell diff(Cell cell);
|
||||
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
if (timestamp() < cell.timestamp())
|
||||
return cell;
|
||||
return null;
|
||||
}
|
||||
public Cell reconcile(Cell cell);
|
||||
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name.toByteBuffer().duplicate());
|
||||
digest.update(value.duplicate());
|
||||
public Cell localCopy(CFMetaData metadata, AbstractAllocator allocator);
|
||||
|
||||
DataOutputBuffer buffer = new DataOutputBuffer();
|
||||
try
|
||||
{
|
||||
buffer.writeLong(timestamp);
|
||||
buffer.writeByte(serializationFlags());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
digest.update(buffer.getData(), 0, buffer.getLength());
|
||||
}
|
||||
public Cell localCopy(CFMetaData metaData, MemtableAllocator allocator, OpOrder.Group opGroup);
|
||||
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
public String getString(CellNameType comparator);
|
||||
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
// tombstones take precedence. (if both are tombstones, then it doesn't matter which one we use.)
|
||||
if (isMarkedForDelete(System.currentTimeMillis()))
|
||||
return timestamp() < cell.timestamp() ? cell : this;
|
||||
if (cell.isMarkedForDelete(System.currentTimeMillis()))
|
||||
return timestamp() > cell.timestamp() ? this : cell;
|
||||
// break ties by comparing values.
|
||||
if (timestamp() == cell.timestamp())
|
||||
return value().compareTo(cell.value()) < 0 ? cell : this;
|
||||
// neither is tombstoned and timestamps are different
|
||||
return timestamp() < cell.timestamp() ? cell : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
Cell cell = (Cell)o;
|
||||
|
||||
return timestamp == cell.timestamp && name.equals(cell.name) && value.equals(cell.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = name != null ? name.hashCode() : 0;
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
result = 31 * result + (int)(timestamp ^ (timestamp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
public Cell localCopy(AbstractAllocator allocator)
|
||||
{
|
||||
return new Cell(name.copy(allocator), allocator.clone(value), timestamp);
|
||||
}
|
||||
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s:%b:%d@%d",
|
||||
comparator.getString(name),
|
||||
isMarkedForDelete(System.currentTimeMillis()),
|
||||
value.remaining(),
|
||||
timestamp);
|
||||
}
|
||||
|
||||
protected void validateName(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
metadata.comparator.validate(name());
|
||||
}
|
||||
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
|
||||
AbstractType<?> valueValidator = metadata.getValueValidator(name());
|
||||
if (valueValidator != null)
|
||||
valueValidator.validate(value());
|
||||
}
|
||||
|
||||
public static Cell create(CellName name, ByteBuffer value, long timestamp, int ttl, CFMetaData metadata)
|
||||
{
|
||||
if (ttl <= 0)
|
||||
ttl = metadata.getDefaultTimeToLive();
|
||||
|
||||
return ttl > 0
|
||||
? new ExpiringCell(name, value, timestamp, ttl)
|
||||
: new Cell(name, value, timestamp);
|
||||
}
|
||||
void validateName(CFMetaData metadata) throws MarshalException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public class CollationController
|
|||
{
|
||||
OnDiskAtom atom = iter.next();
|
||||
if (copyOnHeap)
|
||||
atom = ((Cell) atom).localCopy(HeapAllocator.instance);
|
||||
atom = ((Cell) atom).localCopy(cfs.metadata, HeapAllocator.instance);
|
||||
container.addAtom(atom);
|
||||
}
|
||||
}
|
||||
|
|
@ -148,7 +148,7 @@ public class CollationController
|
|||
&& cfs.getCompactionStrategy() instanceof SizeTieredCompactionStrategy)
|
||||
{
|
||||
Tracing.trace("Defragmenting requested data");
|
||||
Mutation mutation = new Mutation(cfs.keyspace.getName(), filter.key.key, returnCF.cloneMe());
|
||||
Mutation mutation = new Mutation(cfs.keyspace.getName(), filter.key.getKey(), returnCF.cloneMe());
|
||||
// skipping commitlog and index updates is fine since we're just de-fragmenting existing data
|
||||
Keyspace.open(mutation.getKeyspaceName()).apply(mutation, false, false);
|
||||
}
|
||||
|
|
@ -206,7 +206,7 @@ public class CollationController
|
|||
ColumnFamily newCf = cf.cloneMeShallow(ArrayBackedSortedColumns.factory, false);
|
||||
for (Cell cell : cf)
|
||||
{
|
||||
newCf.addColumn(cell.localCopy(HeapAllocator.instance));
|
||||
newCf.addColumn(cell.localCopy(cfs.metadata, HeapAllocator.instance));
|
||||
}
|
||||
cf = newCf;
|
||||
iter = filter.getColumnFamilyIterator(cf);
|
||||
|
|
|
|||
|
|
@ -128,23 +128,23 @@ public abstract class ColumnFamily implements Iterable<Cell>, IRowCacheEntry
|
|||
public void addColumn(CellName name, ByteBuffer value, long timestamp, int timeToLive)
|
||||
{
|
||||
assert !metadata().isCounter();
|
||||
Cell cell = Cell.create(name, value, timestamp, timeToLive, metadata());
|
||||
Cell cell = AbstractCell.create(name, value, timestamp, timeToLive, metadata());
|
||||
addColumn(cell);
|
||||
}
|
||||
|
||||
public void addCounter(CellName name, long value)
|
||||
{
|
||||
addColumn(new CounterUpdateCell(name, value, System.currentTimeMillis()));
|
||||
addColumn(new BufferCounterUpdateCell(name, value, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
public void addTombstone(CellName name, ByteBuffer localDeletionTime, long timestamp)
|
||||
{
|
||||
addColumn(new DeletedCell(name, localDeletionTime, timestamp));
|
||||
addColumn(new BufferDeletedCell(name, localDeletionTime, timestamp));
|
||||
}
|
||||
|
||||
public void addTombstone(CellName name, int localDeletionTime, long timestamp)
|
||||
{
|
||||
addColumn(new DeletedCell(name, localDeletionTime, timestamp));
|
||||
addColumn(new BufferDeletedCell(name, localDeletionTime, timestamp));
|
||||
}
|
||||
|
||||
public void addAtom(OnDiskAtom atom)
|
||||
|
|
@ -327,7 +327,7 @@ public abstract class ColumnFamily implements Iterable<Cell>, IRowCacheEntry
|
|||
{
|
||||
long size = 0;
|
||||
for (Cell cell : this)
|
||||
size += cell.dataSize();
|
||||
size += cell.cellDataSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
|
|
@ -426,8 +426,8 @@ public abstract class ColumnFamily implements Iterable<Cell>, IRowCacheEntry
|
|||
int deletionTime = cell.getLocalDeletionTime();
|
||||
if (deletionTime < Integer.MAX_VALUE)
|
||||
tombstones.update(deletionTime);
|
||||
minColumnNamesSeen = ColumnNameHelper.minComponents(minColumnNamesSeen, cell.name, metadata.comparator);
|
||||
maxColumnNamesSeen = ColumnNameHelper.maxComponents(maxColumnNamesSeen, cell.name, metadata.comparator);
|
||||
minColumnNamesSeen = ColumnNameHelper.minComponents(minColumnNamesSeen, cell.name(), metadata.comparator);
|
||||
maxColumnNamesSeen = ColumnNameHelper.maxComponents(maxColumnNamesSeen, cell.name(), metadata.comparator);
|
||||
if (cell instanceof CounterCell)
|
||||
hasLegacyCounterShards = hasLegacyCounterShards || ((CounterCell) cell).hasLegacyShards();
|
||||
}
|
||||
|
|
@ -476,7 +476,7 @@ public abstract class ColumnFamily implements Iterable<Cell>, IRowCacheEntry
|
|||
{
|
||||
ImmutableMap.Builder<CellName, ByteBuffer> builder = ImmutableMap.builder();
|
||||
for (Cell cell : this)
|
||||
builder.put(cell.name, cell.value);
|
||||
builder.put(cell.name(), cell.value());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ import org.apache.cassandra.streaming.StreamLockfile;
|
|||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.utils.*;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
||||
{
|
||||
|
|
@ -843,12 +844,13 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
|
||||
for (SecondaryIndex index : indexManager.getIndexes())
|
||||
{
|
||||
if (index.getAllocator() != null)
|
||||
if (index.getIndexCfs() != null)
|
||||
{
|
||||
onHeapRatio += index.getAllocator().onHeap().ownershipRatio();
|
||||
offHeapRatio += index.getAllocator().offHeap().ownershipRatio();
|
||||
onHeapTotal += index.getAllocator().onHeap().owns();
|
||||
offHeapTotal += index.getAllocator().offHeap().owns();
|
||||
MemtableAllocator allocator = index.getIndexCfs().getDataTracker().getView().getCurrentMemtable().getAllocator();
|
||||
onHeapRatio += allocator.onHeap().ownershipRatio();
|
||||
offHeapRatio += allocator.offHeap().ownershipRatio();
|
||||
onHeapTotal += allocator.onHeap().owns();
|
||||
offHeapTotal += allocator.offHeap().owns();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1095,10 +1097,11 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
|
||||
for (SecondaryIndex index : cfs.indexManager.getIndexes())
|
||||
{
|
||||
if (index.getAllocator() != null)
|
||||
if (index.getIndexCfs() != null)
|
||||
{
|
||||
onHeap += index.getAllocator().onHeap().ownershipRatio();
|
||||
offHeap += index.getAllocator().offHeap().ownershipRatio();
|
||||
MemtableAllocator allocator = index.getIndexCfs().getDataTracker().getView().getCurrentMemtable().getAllocator();
|
||||
onHeap += allocator.onHeap().ownershipRatio();
|
||||
offHeap += allocator.offHeap().ownershipRatio();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1213,7 +1216,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
// 2. if it has been re-added since then, this particular column was inserted before the last drop
|
||||
private static boolean isDroppedColumn(Cell c, CFMetaData meta)
|
||||
{
|
||||
Long droppedAt = meta.getDroppedColumns().get(c.name().cql3ColumnName());
|
||||
Long droppedAt = meta.getDroppedColumns().get(c.name().cql3ColumnName(meta));
|
||||
return droppedAt != null && c.timestamp() <= droppedAt;
|
||||
}
|
||||
|
||||
|
|
@ -1869,7 +1872,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
ColumnFamily columns;
|
||||
try (OpOrder.Group op = readOrdering.start())
|
||||
{
|
||||
columns = controller.getTopLevelColumns(Memtable.memoryPool.needToCopyOnHeap());
|
||||
columns = controller.getTopLevelColumns(Memtable.MEMORY_POOL.needToCopyOnHeap());
|
||||
}
|
||||
metric.updateSSTableIterated(controller.getSstablesIterated());
|
||||
return columns;
|
||||
|
|
@ -1882,7 +1885,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
for (RowCacheKey key : CacheService.instance.rowCache.getKeySet())
|
||||
{
|
||||
DecoratedKey dk = partitioner.decorateKey(ByteBuffer.wrap(key.key));
|
||||
if (key.cfId == metadata.cfId && !Range.isInRanges(dk.token, ranges))
|
||||
if (key.cfId == metadata.cfId && !Range.isInRanges(dk.getToken(), ranges))
|
||||
invalidateCachedRow(dk);
|
||||
}
|
||||
|
||||
|
|
@ -1891,7 +1894,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
for (CounterCacheKey key : CacheService.instance.counterCache.getKeySet())
|
||||
{
|
||||
DecoratedKey dk = partitioner.decorateKey(ByteBuffer.wrap(key.partitionKey));
|
||||
if (key.cfId == metadata.cfId && !Range.isInRanges(dk.token, ranges))
|
||||
if (key.cfId == metadata.cfId && !Range.isInRanges(dk.getToken(), ranges))
|
||||
CacheService.instance.counterCache.remove(key);
|
||||
}
|
||||
}
|
||||
|
|
@ -1939,7 +1942,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
|||
return computeNext();
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
logger.trace("scanned {}", metadata.getKeyValidator().getString(key.key));
|
||||
logger.trace("scanned {}", metadata.getKeyValidator().getString(key.getKey()));
|
||||
|
||||
return current;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public class ColumnSerializer implements ISerializer<Cell>
|
|||
long timestampOfLastDelete = in.readLong();
|
||||
long ts = in.readLong();
|
||||
ByteBuffer value = ByteBufferUtil.readWithLength(in);
|
||||
return CounterCell.create(name, value, ts, timestampOfLastDelete, flag);
|
||||
return BufferCounterCell.create(name, value, ts, timestampOfLastDelete, flag);
|
||||
}
|
||||
else if ((mask & EXPIRATION_MASK) != 0)
|
||||
{
|
||||
|
|
@ -124,17 +124,17 @@ public class ColumnSerializer implements ISerializer<Cell>
|
|||
int expiration = in.readInt();
|
||||
long ts = in.readLong();
|
||||
ByteBuffer value = ByteBufferUtil.readWithLength(in);
|
||||
return ExpiringCell.create(name, value, ts, ttl, expiration, expireBefore, flag);
|
||||
return BufferExpiringCell.create(name, value, ts, ttl, expiration, expireBefore, flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
long ts = in.readLong();
|
||||
ByteBuffer value = ByteBufferUtil.readWithLength(in);
|
||||
return (mask & COUNTER_UPDATE_MASK) != 0
|
||||
? new CounterUpdateCell(name, value, ts)
|
||||
? new BufferCounterUpdateCell(name, value, ts)
|
||||
: ((mask & DELETION_MASK) == 0
|
||||
? new Cell(name, value, ts)
|
||||
: new DeletedCell(name, value, ts));
|
||||
? new BufferCell(name, value, ts)
|
||||
: new BufferDeletedCell(name, value, ts));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,223 +17,28 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
/**
|
||||
* A column that represents a partitioned counter.
|
||||
*/
|
||||
public class CounterCell extends Cell
|
||||
public interface CounterCell extends Cell
|
||||
{
|
||||
protected static final CounterContext contextManager = CounterContext.instance();
|
||||
static final CounterContext contextManager = CounterContext.instance();
|
||||
|
||||
private final long timestampOfLastDelete;
|
||||
public long timestampOfLastDelete();
|
||||
|
||||
public CounterCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
this(name, value, timestamp, Long.MIN_VALUE);
|
||||
}
|
||||
public long total();
|
||||
|
||||
public CounterCell(CellName name, ByteBuffer value, long timestamp, long timestampOfLastDelete)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
this.timestampOfLastDelete = timestampOfLastDelete;
|
||||
}
|
||||
public boolean hasLegacyShards();
|
||||
|
||||
public static CounterCell create(CellName name, ByteBuffer value, long timestamp, long timestampOfLastDelete, ColumnSerializer.Flag flag)
|
||||
{
|
||||
if (flag == ColumnSerializer.Flag.FROM_REMOTE || (flag == ColumnSerializer.Flag.LOCAL && contextManager.shouldClearLocal(value)))
|
||||
value = contextManager.clearAllLocal(value);
|
||||
return new CounterCell(name, value, timestamp, timestampOfLastDelete);
|
||||
}
|
||||
public Cell markLocalToBeCleared();
|
||||
|
||||
// For use by tests of compatibility with pre-2.1 counter only.
|
||||
public static CounterCell createLocal(CellName name, long value, long timestamp, long timestampOfLastDelete)
|
||||
{
|
||||
return new CounterCell(name, contextManager.createLocal(value), timestamp, timestampOfLastDelete);
|
||||
}
|
||||
CounterCell localCopy(CFMetaData metadata, AbstractAllocator allocator);
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new CounterCell(newName, value, timestamp, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
public long timestampOfLastDelete()
|
||||
{
|
||||
return timestampOfLastDelete;
|
||||
}
|
||||
|
||||
public long total()
|
||||
{
|
||||
return contextManager.total(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dataSize()
|
||||
{
|
||||
// A counter column adds 8 bytes for timestampOfLastDelete to Cell.
|
||||
return super.dataSize() + TypeSizes.NATIVE.sizeof(timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
return super.serializedSize(type, typeSizes) + typeSizes.sizeof(timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
assert (cell instanceof CounterCell) || (cell instanceof DeletedCell) : "Wrong class type: " + cell.getClass();
|
||||
|
||||
if (timestamp() < cell.timestamp())
|
||||
return cell;
|
||||
|
||||
// Note that if at that point, cell can't be a tombstone. Indeed,
|
||||
// cell is the result of merging us with other nodes results, and
|
||||
// merging a CounterCell with a tombstone never return a tombstone
|
||||
// unless that tombstone timestamp is greater that the CounterCell
|
||||
// one.
|
||||
assert cell instanceof CounterCell : "Wrong class type: " + cell.getClass();
|
||||
|
||||
if (timestampOfLastDelete() < ((CounterCell) cell).timestampOfLastDelete())
|
||||
return cell;
|
||||
CounterContext.Relationship rel = contextManager.diff(cell.value(), value());
|
||||
if (rel == CounterContext.Relationship.GREATER_THAN || rel == CounterContext.Relationship.DISJOINT)
|
||||
return cell;
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to special case digest creation for counter column because
|
||||
* we don't want to include the information about which shard of the
|
||||
* context is a delta or not, since this information differs from node to
|
||||
* node.
|
||||
*/
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name.toByteBuffer().duplicate());
|
||||
// We don't take the deltas into account in a digest
|
||||
contextManager.updateDigest(digest, value);
|
||||
DataOutputBuffer buffer = new DataOutputBuffer();
|
||||
try
|
||||
{
|
||||
buffer.writeLong(timestamp);
|
||||
buffer.writeByte(serializationFlags());
|
||||
buffer.writeLong(timestampOfLastDelete);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
digest.update(buffer.getData(), 0, buffer.getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
// live + tombstone: track last tombstone
|
||||
if (cell.isMarkedForDelete(Long.MIN_VALUE)) // cannot be an expired cell, so the current time is irrelevant
|
||||
{
|
||||
// live < tombstone
|
||||
if (timestamp() < cell.timestamp())
|
||||
{
|
||||
return cell;
|
||||
}
|
||||
// live last delete >= tombstone
|
||||
if (timestampOfLastDelete() >= cell.timestamp())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
// live last delete < tombstone
|
||||
return new CounterCell(name(), value(), timestamp(), cell.timestamp());
|
||||
}
|
||||
|
||||
assert cell instanceof CounterCell : "Wrong class type: " + cell.getClass();
|
||||
|
||||
// live < live last delete
|
||||
if (timestamp() < ((CounterCell) cell).timestampOfLastDelete())
|
||||
return cell;
|
||||
// live last delete > live
|
||||
if (timestampOfLastDelete() > cell.timestamp())
|
||||
return this;
|
||||
|
||||
// live + live. return one of the cells if its context is a superset of the other's, or merge them otherwise
|
||||
ByteBuffer context = contextManager.merge(value(), cell.value());
|
||||
if (context == value() && timestamp() >= cell.timestamp() && timestampOfLastDelete() >= ((CounterCell) cell).timestampOfLastDelete())
|
||||
return this;
|
||||
else if (context == cell.value() && cell.timestamp() >= timestamp() && ((CounterCell) cell).timestampOfLastDelete() >= timestampOfLastDelete())
|
||||
return cell;
|
||||
else // merge clocks and timsestamps.
|
||||
return new CounterCell(name(),
|
||||
context,
|
||||
Math.max(timestamp(), cell.timestamp()),
|
||||
Math.max(timestampOfLastDelete(), ((CounterCell) cell).timestampOfLastDelete()));
|
||||
}
|
||||
|
||||
public boolean hasLegacyShards()
|
||||
{
|
||||
return contextManager.hasLegacyShards(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
// super.equals() returns false if o is not a CounterCell
|
||||
return super.equals(o) && timestampOfLastDelete == ((CounterCell)o).timestampOfLastDelete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return 31 * super.hashCode() + (int)(timestampOfLastDelete ^ (timestampOfLastDelete >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(AbstractAllocator allocator)
|
||||
{
|
||||
return new CounterCell(name.copy(allocator), allocator.clone(value), timestamp, timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s:false:%s@%d!%d",
|
||||
comparator.getString(name),
|
||||
contextManager.toString(value),
|
||||
timestamp,
|
||||
timestampOfLastDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.COUNTER_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
// We cannot use the value validator as for other columns as the CounterColumnType validate a long,
|
||||
// which is not the internal representation of counters
|
||||
contextManager.validateContext(value());
|
||||
}
|
||||
|
||||
public Cell markLocalToBeCleared()
|
||||
{
|
||||
ByteBuffer marked = contextManager.markLocalToBeCleared(value);
|
||||
return marked == value ? this : new CounterCell(name, marked, timestamp, timestampOfLastDelete);
|
||||
}
|
||||
CounterCell localCopy(CFMetaData metaData, MemtableAllocator allocator, OpOrder.Group opGroup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,9 +200,9 @@ public class CounterMutation implements IMutation
|
|||
long clock = currentValue.clock + 1L;
|
||||
long count = currentValue.count + update.delta();
|
||||
|
||||
resultCF.addColumn(new CounterCell(update.name(),
|
||||
CounterContext.instance().createGlobal(CounterId.getLocalId(), clock, count),
|
||||
update.timestamp()));
|
||||
resultCF.addColumn(new BufferCounterCell(update.name(),
|
||||
CounterContext.instance().createGlobal(CounterId.getLocalId(), clock, count),
|
||||
update.timestamp()));
|
||||
}
|
||||
|
||||
return resultCF;
|
||||
|
|
@ -253,7 +253,7 @@ public class CounterMutation implements IMutation
|
|||
SortedSet<CellName> names = new TreeSet<>(cfs.metadata.comparator);
|
||||
for (int i = 0; i < currentValues.length; i++)
|
||||
if (currentValues[i] == null)
|
||||
names.add(counterUpdateCells.get(i).name);
|
||||
names.add(counterUpdateCells.get(i).name());
|
||||
|
||||
ReadCommand cmd = new SliceByNamesReadCommand(getKeyspaceName(), key(), cfs.metadata.cfName, Long.MIN_VALUE, new NamesQueryFilter(names));
|
||||
Row row = cmd.getRow(cfs.keyspace);
|
||||
|
|
|
|||
|
|
@ -17,13 +17,6 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
|
||||
/**
|
||||
* A counter update while it hasn't been applied yet by the leader replica.
|
||||
*
|
||||
|
|
@ -31,61 +24,7 @@ import org.apache.cassandra.db.composites.CellNameType;
|
|||
* is transformed to a relevant CounterCell. This Cell is a temporary data
|
||||
* structure that should never be stored inside a memtable or an sstable.
|
||||
*/
|
||||
public class CounterUpdateCell extends Cell
|
||||
public interface CounterUpdateCell extends Cell
|
||||
{
|
||||
public CounterUpdateCell(CellName name, long value, long timestamp)
|
||||
{
|
||||
this(name, ByteBufferUtil.bytes(value), timestamp);
|
||||
}
|
||||
|
||||
public CounterUpdateCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
}
|
||||
|
||||
public long delta()
|
||||
{
|
||||
return value().getLong(value().position());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
// Diff is used during reads, but we should never read those columns
|
||||
throw new UnsupportedOperationException("This operation is unsupported on CounterUpdateCell.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
// The only time this could happen is if a batchAdd ships two
|
||||
// increment for the same cell. Hence we simply sums the delta.
|
||||
|
||||
// tombstones take precedence
|
||||
if (cell.isMarkedForDelete(Long.MIN_VALUE)) // can't be an expired cell, so the current time is irrelevant
|
||||
return timestamp() > cell.timestamp() ? this : cell;
|
||||
|
||||
// neither is tombstoned
|
||||
assert cell instanceof CounterUpdateCell : "Wrong class type.";
|
||||
CounterUpdateCell c = (CounterUpdateCell) cell;
|
||||
return new CounterUpdateCell(name(), delta() + c.delta(), Math.max(timestamp(), c.timestamp()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.COUNTER_UPDATE_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(AbstractAllocator allocator)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s:%s@%d", comparator.getString(name), ByteBufferUtil.toLong(value), timestamp);
|
||||
}
|
||||
public long delta();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ public class DataRange
|
|||
|
||||
private boolean equals(RowPosition pos, ByteBuffer rowKey)
|
||||
{
|
||||
return pos instanceof DecoratedKey && ((DecoratedKey)pos).key.equals(rowKey);
|
||||
return pos instanceof DecoratedKey && ((DecoratedKey)pos).getKey().equals(rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.Comparator;
|
|||
|
||||
import org.apache.cassandra.dht.IPartitioner;
|
||||
import org.apache.cassandra.dht.Token;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
/**
|
||||
|
|
@ -33,7 +34,7 @@ import org.apache.cassandra.utils.ByteBufferUtil;
|
|||
* if this matters, you can subclass RP to use a stronger hash, or use a non-lossy tokenization scheme (as in the
|
||||
* OrderPreservingPartitioner classes).
|
||||
*/
|
||||
public class DecoratedKey extends RowPosition
|
||||
public abstract class DecoratedKey implements RowPosition
|
||||
{
|
||||
public static final Comparator<DecoratedKey> comparator = new Comparator<DecoratedKey>()
|
||||
{
|
||||
|
|
@ -43,20 +44,18 @@ public class DecoratedKey extends RowPosition
|
|||
}
|
||||
};
|
||||
|
||||
public final Token token;
|
||||
public final ByteBuffer key;
|
||||
private final Token token;
|
||||
|
||||
public DecoratedKey(Token token, ByteBuffer key)
|
||||
public DecoratedKey(Token token)
|
||||
{
|
||||
assert token != null && key != null;
|
||||
assert token != null;
|
||||
this.token = token;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return key.hashCode(); // hash of key is enough
|
||||
return getKey().hashCode(); // hash of key is enough
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -64,12 +63,11 @@ public class DecoratedKey extends RowPosition
|
|||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || this.getClass() != obj.getClass())
|
||||
if (obj == null || !(obj instanceof DecoratedKey))
|
||||
return false;
|
||||
|
||||
DecoratedKey other = (DecoratedKey)obj;
|
||||
|
||||
return ByteBufferUtil.compareUnsigned(key, other.key) == 0; // we compare faster than BB.equals for array backed BB
|
||||
return ByteBufferUtil.compareUnsigned(getKey(), other.getKey()) == 0; // we compare faster than BB.equals for array backed BB
|
||||
}
|
||||
|
||||
public int compareTo(RowPosition pos)
|
||||
|
|
@ -82,8 +80,8 @@ public class DecoratedKey extends RowPosition
|
|||
return -pos.compareTo(this);
|
||||
|
||||
DecoratedKey otherKey = (DecoratedKey) pos;
|
||||
int cmp = token.compareTo(otherKey.getToken());
|
||||
return cmp == 0 ? ByteBufferUtil.compareUnsigned(key, otherKey.key) : cmp;
|
||||
int cmp = getToken().compareTo(otherKey.getToken());
|
||||
return cmp == 0 ? ByteBufferUtil.compareUnsigned(getKey(), otherKey.getKey()) : cmp;
|
||||
}
|
||||
|
||||
public static int compareTo(IPartitioner partitioner, ByteBuffer key, RowPosition position)
|
||||
|
|
@ -94,7 +92,7 @@ public class DecoratedKey extends RowPosition
|
|||
|
||||
DecoratedKey otherKey = (DecoratedKey) position;
|
||||
int cmp = partitioner.getToken(key).compareTo(otherKey.getToken());
|
||||
return cmp == 0 ? ByteBufferUtil.compareUnsigned(key, otherKey.key) : cmp;
|
||||
return cmp == 0 ? ByteBufferUtil.compareUnsigned(key, otherKey.getKey()) : cmp;
|
||||
}
|
||||
|
||||
public boolean isMinimum(IPartitioner partitioner)
|
||||
|
|
@ -103,6 +101,11 @@ public class DecoratedKey extends RowPosition
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isMinimum()
|
||||
{
|
||||
return isMinimum(StorageService.getPartitioner());
|
||||
}
|
||||
|
||||
public RowPosition.Kind kind()
|
||||
{
|
||||
return RowPosition.Kind.ROW_KEY;
|
||||
|
|
@ -111,12 +114,14 @@ public class DecoratedKey extends RowPosition
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String keystring = key == null ? "null" : ByteBufferUtil.bytesToHex(key);
|
||||
return "DecoratedKey(" + token + ", " + keystring + ")";
|
||||
String keystring = getKey() == null ? "null" : ByteBufferUtil.bytesToHex(getKey());
|
||||
return "DecoratedKey(" + getToken() + ", " + keystring + ")";
|
||||
}
|
||||
|
||||
public Token getToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
|
||||
public abstract ByteBuffer getKey();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ public class DefsTables
|
|||
if (newState.hasColumns())
|
||||
updateKeyspace(KSMetaData.fromSchema(new Row(key, newState), Collections.<CFMetaData>emptyList(), new UTMetaData()));
|
||||
else
|
||||
keyspacesToDrop.add(AsciiType.instance.getString(key.key));
|
||||
keyspacesToDrop.add(AsciiType.instance.getString(key.getKey()));
|
||||
}
|
||||
|
||||
return keyspacesToDrop;
|
||||
|
|
@ -297,7 +297,7 @@ public class DefsTables
|
|||
}
|
||||
else // has modifications in the nested ColumnFamilies, need to perform nested diff to determine what was really changed
|
||||
{
|
||||
String ksName = AsciiType.instance.getString(keyspace.key);
|
||||
String ksName = AsciiType.instance.getString(keyspace.getKey());
|
||||
|
||||
Map<String, CFMetaData> oldCfDefs = new HashMap<String, CFMetaData>();
|
||||
for (CFMetaData cfm : Schema.instance.getKSMetaData(ksName).cfMetaData().values())
|
||||
|
|
|
|||
|
|
@ -17,104 +17,14 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
public class DeletedCell extends Cell
|
||||
public interface DeletedCell extends Cell
|
||||
{
|
||||
public DeletedCell(CellName name, int localDeletionTime, long timestamp)
|
||||
{
|
||||
this(name, ByteBufferUtil.bytes(localDeletionTime), timestamp);
|
||||
}
|
||||
DeletedCell localCopy(CFMetaData metadata, AbstractAllocator allocator);
|
||||
|
||||
public DeletedCell(CellName name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new DeletedCell(newName, value, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
return new DeletedCell(name, value, newTimestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name.toByteBuffer().duplicate());
|
||||
|
||||
DataOutputBuffer buffer = new DataOutputBuffer();
|
||||
try
|
||||
{
|
||||
buffer.writeLong(timestamp);
|
||||
buffer.writeByte(serializationFlags());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
digest.update(buffer.getData(), 0, buffer.getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return value.getInt(value.position());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
if (cell instanceof DeletedCell)
|
||||
return super.reconcile(cell);
|
||||
return cell.reconcile(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(AbstractAllocator allocator)
|
||||
{
|
||||
return new DeletedCell(name.copy(allocator), allocator.clone(value), timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.DELETION_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
if (value().remaining() != 4)
|
||||
throw new MarshalException("A tombstone value should be 4 bytes long");
|
||||
if (getLocalDeletionTime() < 0)
|
||||
throw new MarshalException("The local deletion time should not be negative");
|
||||
}
|
||||
DeletedCell localCopy(CFMetaData metaData, MemtableAllocator allocator, OpOrder.Group opGroup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,10 @@
|
|||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.io.util.DataOutputBuffer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
/**
|
||||
* Alternative to Cell that have an expiring time.
|
||||
|
|
@ -38,154 +32,13 @@ import org.apache.cassandra.utils.memory.AbstractAllocator;
|
|||
* we can't mix it with the timestamp field, which is client-supplied and whose resolution we
|
||||
* can't assume anything about.)
|
||||
*/
|
||||
public class ExpiringCell extends Cell
|
||||
public interface ExpiringCell extends Cell
|
||||
{
|
||||
public static final int MAX_TTL = 20 * 365 * 24 * 60 * 60; // 20 years in seconds
|
||||
|
||||
private final int localExpirationTime;
|
||||
private final int timeToLive;
|
||||
public int getTimeToLive();
|
||||
|
||||
public ExpiringCell(CellName name, ByteBuffer value, long timestamp, int timeToLive)
|
||||
{
|
||||
this(name, value, timestamp, timeToLive, (int) (System.currentTimeMillis() / 1000) + timeToLive);
|
||||
}
|
||||
ExpiringCell localCopy(CFMetaData metadata, AbstractAllocator allocator);
|
||||
|
||||
public ExpiringCell(CellName name, ByteBuffer value, long timestamp, int timeToLive, int localExpirationTime)
|
||||
{
|
||||
super(name, value, timestamp);
|
||||
assert timeToLive > 0 : timeToLive;
|
||||
assert localExpirationTime > 0 : localExpirationTime;
|
||||
this.timeToLive = timeToLive;
|
||||
this.localExpirationTime = localExpirationTime;
|
||||
}
|
||||
|
||||
/** @return Either a DeletedCell, or an ExpiringCell. */
|
||||
public static Cell create(CellName name, ByteBuffer value, long timestamp, int timeToLive, int localExpirationTime, int expireBefore, ColumnSerializer.Flag flag)
|
||||
{
|
||||
if (localExpirationTime >= expireBefore || flag == ColumnSerializer.Flag.PRESERVE_SIZE)
|
||||
return new ExpiringCell(name, value, timestamp, timeToLive, localExpirationTime);
|
||||
// The column is now expired, we can safely return a simple tombstone. Note that
|
||||
// as long as the expiring column and the tombstone put together live longer than GC grace seconds,
|
||||
// we'll fulfil our responsibility to repair. See discussion at
|
||||
// http://cassandra-user-incubator-apache-org.3065146.n2.nabble.com/repair-compaction-and-tombstone-rows-td7583481.html
|
||||
return new DeletedCell(name, localExpirationTime - timeToLive, timestamp);
|
||||
}
|
||||
|
||||
public int getTimeToLive()
|
||||
{
|
||||
return timeToLive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedName(CellName newName)
|
||||
{
|
||||
return new ExpiringCell(newName, value, timestamp, timeToLive, localExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell withUpdatedTimestamp(long newTimestamp)
|
||||
{
|
||||
return new ExpiringCell(name, value, newTimestamp, timeToLive, localExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dataSize()
|
||||
{
|
||||
return super.dataSize() + TypeSizes.NATIVE.sizeof(localExpirationTime) + TypeSizes.NATIVE.sizeof(timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
/*
|
||||
* An expired column adds to a Cell :
|
||||
* 4 bytes for the localExpirationTime
|
||||
* + 4 bytes for the timeToLive
|
||||
*/
|
||||
return super.serializedSize(type, typeSizes) + typeSizes.sizeof(localExpirationTime) + typeSizes.sizeof(timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
digest.update(name.toByteBuffer().duplicate());
|
||||
digest.update(value.duplicate());
|
||||
|
||||
DataOutputBuffer buffer = new DataOutputBuffer();
|
||||
try
|
||||
{
|
||||
buffer.writeLong(timestamp);
|
||||
buffer.writeByte(serializationFlags());
|
||||
buffer.writeInt(timeToLive);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
digest.update(buffer.getData(), 0, buffer.getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return localExpirationTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(AbstractAllocator allocator)
|
||||
{
|
||||
return new ExpiringCell(name.copy(allocator), allocator.clone(value), timestamp, timeToLive, localExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s!%d", super.getString(comparator), timeToLive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return (int) (now / 1000) >= getLocalDeletionTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.EXPIRATION_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
super.validateFields(metadata);
|
||||
if (timeToLive <= 0)
|
||||
throw new MarshalException("A column TTL should be > 0");
|
||||
if (localExpirationTime < 0)
|
||||
throw new MarshalException("The local expiration time should not be negative");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
// super.equals() returns false if o is not a CounterCell
|
||||
return super.equals(o)
|
||||
&& localExpirationTime == ((ExpiringCell)o).localExpirationTime
|
||||
&& timeToLive == ((ExpiringCell)o).timeToLive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + localExpirationTime;
|
||||
result = 31 * result + timeToLive;
|
||||
return result;
|
||||
}
|
||||
ExpiringCell localCopy(CFMetaData metaData, MemtableAllocator allocator, OpOrder.Group opGroup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ public class HintedHandOffManager implements HintedHandOffManagerMBean
|
|||
List<Row> rows = hintStore.getRangeSlice(range, null, filter, Integer.MAX_VALUE, System.currentTimeMillis());
|
||||
for (Row row : rows)
|
||||
{
|
||||
UUID hostId = UUIDGen.getUUID(row.key.key);
|
||||
UUID hostId = UUIDGen.getUUID(row.key.getKey());
|
||||
InetAddress target = StorageService.instance.getTokenMetadata().getEndpointForHostId(hostId);
|
||||
// token may have since been removed (in which case we have just read back a tombstone)
|
||||
if (target != null)
|
||||
|
|
@ -573,7 +573,7 @@ public class HintedHandOffManager implements HintedHandOffManagerMBean
|
|||
for (Row row : getHintsSlice(1))
|
||||
{
|
||||
if (row.cf != null) //ignore removed rows
|
||||
result.addFirst(tokenFactory.toString(row.key.token));
|
||||
result.addFirst(tokenFactory.toString(row.key.getToken()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,13 +410,13 @@ public class Keyspace
|
|||
public static void indexRow(DecoratedKey key, ColumnFamilyStore cfs, Set<String> idxNames)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Indexing row {} ", cfs.metadata.getKeyValidator().getString(key.key));
|
||||
logger.debug("Indexing row {} ", cfs.metadata.getKeyValidator().getString(key.getKey()));
|
||||
|
||||
try (OpOrder.Group opGroup = cfs.keyspace.writeOrder.start())
|
||||
{
|
||||
Set<SecondaryIndex> indexes = cfs.indexManager.getIndexesByNames(idxNames);
|
||||
|
||||
Iterator<ColumnFamily> pager = QueryPagers.pageRowLocally(cfs, key.key, DEFAULT_PAGE_SIZE);
|
||||
Iterator<ColumnFamily> pager = QueryPagers.pageRowLocally(cfs, key.getKey(), DEFAULT_PAGE_SIZE);
|
||||
while (pager.hasNext())
|
||||
{
|
||||
ColumnFamily cf = pager.next();
|
||||
|
|
@ -426,7 +426,7 @@ public class Keyspace
|
|||
if (cfs.indexManager.indexes(cell.name(), indexes))
|
||||
cf2.addColumn(cell);
|
||||
}
|
||||
cfs.indexManager.indexRow(key.key, cf2, opGroup);
|
||||
cfs.indexManager.indexRow(key.getKey(), cf2, opGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,19 +46,16 @@ import org.apache.cassandra.service.ActiveRepairService;
|
|||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.ContextAllocator;
|
||||
import org.apache.cassandra.utils.memory.HeapAllocator;
|
||||
import org.apache.cassandra.utils.memory.Pool;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
import org.apache.cassandra.utils.memory.*;
|
||||
|
||||
public class Memtable
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Memtable.class);
|
||||
|
||||
static final Pool memoryPool = DatabaseDescriptor.getMemtableAllocatorPool();
|
||||
static final MemtablePool MEMORY_POOL = DatabaseDescriptor.getMemtableAllocatorPool();
|
||||
private static final int ROW_OVERHEAD_HEAP_SIZE;
|
||||
|
||||
private final PoolAllocator allocator;
|
||||
private final MemtableAllocator allocator;
|
||||
private final AtomicLong liveDataSize = new AtomicLong(0);
|
||||
private final AtomicLong currentOperations = new AtomicLong(0);
|
||||
|
||||
|
|
@ -85,12 +82,12 @@ public class Memtable
|
|||
public Memtable(ColumnFamilyStore cfs)
|
||||
{
|
||||
this.cfs = cfs;
|
||||
this.allocator = memoryPool.newAllocator();
|
||||
this.allocator = MEMORY_POOL.newAllocator();
|
||||
this.initialComparator = cfs.metadata.comparator;
|
||||
this.cfs.scheduleFlush();
|
||||
}
|
||||
|
||||
public PoolAllocator getAllocator()
|
||||
public MemtableAllocator getAllocator()
|
||||
{
|
||||
return allocator;
|
||||
}
|
||||
|
|
@ -177,7 +174,7 @@ public class Memtable
|
|||
if (previous == null)
|
||||
{
|
||||
AtomicBTreeColumns empty = cf.cloneMeShallow(AtomicBTreeColumns.factory, false);
|
||||
final DecoratedKey cloneKey = new DecoratedKey(key.token, allocator.clone(key.key, opGroup));
|
||||
final DecoratedKey cloneKey = allocator.clone(key, opGroup);
|
||||
// We'll add the columns later. This avoids wasting works if we get beaten in the putIfAbsent
|
||||
previous = rows.putIfAbsent(cloneKey, empty);
|
||||
if (previous == null)
|
||||
|
|
@ -185,27 +182,17 @@ public class Memtable
|
|||
previous = empty;
|
||||
// allocate the row overhead after the fact; this saves over allocating and having to free after, but
|
||||
// means we can overshoot our declared limit.
|
||||
int overhead = (int) (cfs.partitioner.getHeapSizeOf(key.token) + ROW_OVERHEAD_HEAP_SIZE);
|
||||
allocator.allocate(overhead, opGroup);
|
||||
int overhead = (int) (cfs.partitioner.getHeapSizeOf(key.getToken()) + ROW_OVERHEAD_HEAP_SIZE);
|
||||
allocator.onHeap().allocate(overhead, opGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
allocator.free(cloneKey.key);
|
||||
allocator.reclaimer().reclaimImmediately(cloneKey);
|
||||
}
|
||||
}
|
||||
|
||||
ContextAllocator contextAllocator = allocator.wrap(opGroup);
|
||||
AtomicBTreeColumns.Delta delta = previous.addAllWithSizeDelta(cf, contextAllocator, indexer, new AtomicBTreeColumns.Delta());
|
||||
liveDataSize.addAndGet(delta.dataSize());
|
||||
liveDataSize.addAndGet(previous.addAllWithSizeDelta(cf, allocator, opGroup, indexer));
|
||||
currentOperations.addAndGet(cf.getColumnCount() + (cf.isMarkedForDelete() ? 1 : 0) + cf.deletionInfo().rangeCount());
|
||||
|
||||
// allocate or free the delta in column overhead after the fact
|
||||
for (Cell cell : delta.reclaimed())
|
||||
{
|
||||
cell.name.free(allocator);
|
||||
allocator.free(cell.value);
|
||||
}
|
||||
allocator.allocate((int) delta.excessHeapSize(), opGroup);
|
||||
}
|
||||
|
||||
// for debugging
|
||||
|
|
@ -256,10 +243,10 @@ public class Memtable
|
|||
Map.Entry<? extends RowPosition, ? extends ColumnFamily> entry = iter.next();
|
||||
// Actual stored key should be true DecoratedKey
|
||||
assert entry.getKey() instanceof DecoratedKey;
|
||||
if (memoryPool.needToCopyOnHeap())
|
||||
if (MEMORY_POOL.needToCopyOnHeap())
|
||||
{
|
||||
DecoratedKey key = (DecoratedKey) entry.getKey();
|
||||
key = new DecoratedKey(key.token, HeapAllocator.instance.clone(key.key));
|
||||
key = new BufferDecoratedKey(key.getToken(), HeapAllocator.instance.clone(key.getKey()));
|
||||
ColumnFamily cells = ArrayBackedSortedColumns.localCopy(entry.getValue(), HeapAllocator.instance);
|
||||
entry = new AbstractMap.SimpleImmutableEntry<>(key, cells);
|
||||
}
|
||||
|
|
@ -307,7 +294,7 @@ public class Memtable
|
|||
{
|
||||
// make sure we don't write non-sensical keys
|
||||
assert key instanceof DecoratedKey;
|
||||
keySize += ((DecoratedKey)key).key.remaining();
|
||||
keySize += ((DecoratedKey)key).getKey().remaining();
|
||||
}
|
||||
estimatedSize = (long) ((keySize // index entries
|
||||
+ keySize // keys in data file
|
||||
|
|
@ -410,16 +397,20 @@ public class Memtable
|
|||
static
|
||||
{
|
||||
// calculate row overhead
|
||||
final OpOrder.Group group = new OpOrder().start();
|
||||
int rowOverhead;
|
||||
MemtableAllocator allocator = MEMORY_POOL.newAllocator();
|
||||
ConcurrentNavigableMap<RowPosition, Object> rows = new ConcurrentSkipListMap<>();
|
||||
final int count = 100000;
|
||||
final Object val = new Object();
|
||||
for (int i = 0 ; i < count ; i++)
|
||||
rows.put(new DecoratedKey(new LongToken((long) i), ByteBufferUtil.EMPTY_BYTE_BUFFER), val);
|
||||
rows.put(allocator.clone(new BufferDecoratedKey(new LongToken((long) i), ByteBufferUtil.EMPTY_BYTE_BUFFER), group), val);
|
||||
double avgSize = ObjectSizes.measureDeep(rows) / (double) count;
|
||||
rowOverhead = (int) ((avgSize - Math.floor(avgSize)) < 0.05 ? Math.floor(avgSize) : Math.ceil(avgSize));
|
||||
rowOverhead -= ObjectSizes.measureDeep(new LongToken((long) 0));
|
||||
rowOverhead += AtomicBTreeColumns.HEAP_SIZE;
|
||||
rowOverhead += AtomicBTreeColumns.EMPTY_SIZE;
|
||||
allocator.setDiscarding();
|
||||
allocator.setDiscarded();
|
||||
ROW_OVERHEAD_HEAP_SIZE = rowOverhead;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class Mutation implements IMutation
|
|||
|
||||
public Mutation(String keyspaceName, Row row)
|
||||
{
|
||||
this(keyspaceName, row.key.key, row.cf);
|
||||
this(keyspaceName, row.key.getKey(), row.cf);
|
||||
}
|
||||
|
||||
protected Mutation(String keyspaceName, ByteBuffer key, Map<UUID, ColumnFamily> modifications)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
import org.apache.cassandra.utils.memory.NativeAllocator;
|
||||
|
||||
public class NativeCell extends AbstractNativeCell
|
||||
{
|
||||
private static final long SIZE = ObjectSizes.measure(new NativeCell());
|
||||
|
||||
NativeCell()
|
||||
{}
|
||||
|
||||
public NativeCell(NativeAllocator allocator, OpOrder.Group writeOp, Cell copyOf)
|
||||
{
|
||||
super(allocator, writeOp, copyOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellName name()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timestamp()
|
||||
{
|
||||
return getLong(TIMESTAMP_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferCell(copy(metadata, allocator), allocator.clone(value()), timestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
updateWithName(digest); // name
|
||||
updateWithValue(digest); // value
|
||||
|
||||
FBUtilities.updateWithLong(digest, timestamp());
|
||||
FBUtilities.updateWithByte(digest, serializationFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long excessHeapSizeExcludingData()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long unsharedHeapSize()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
import org.apache.cassandra.utils.memory.NativeAllocator;
|
||||
|
||||
public class NativeCounterCell extends NativeCell implements CounterCell
|
||||
{
|
||||
private static final long SIZE = ObjectSizes.measure(new NativeCounterCell());
|
||||
|
||||
private NativeCounterCell()
|
||||
{}
|
||||
|
||||
public NativeCounterCell(NativeAllocator allocator, OpOrder.Group writeOp, CounterCell copyOf)
|
||||
{
|
||||
super(allocator, writeOp, copyOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void construct(Cell from)
|
||||
{
|
||||
super.construct(from);
|
||||
setLong(internalSize() - 8, ((CounterCell) from).timestampOfLastDelete());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int postfixSize()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int sizeOf(Cell cell)
|
||||
{
|
||||
return 8 + super.sizeOf(cell);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timestampOfLastDelete()
|
||||
{
|
||||
return getLong(internalSize() - 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long total()
|
||||
{
|
||||
return contextManager.total(value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLegacyShards()
|
||||
{
|
||||
return contextManager.hasLegacyShards(value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell markLocalToBeCleared()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell diff(Cell cell)
|
||||
{
|
||||
return diff(this, cell);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
return reconcile(this, cell);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.COUNTER_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cellDataSize()
|
||||
{
|
||||
// A counter column adds 8 bytes for timestampOfLastDelete to Cell.
|
||||
return super.cellDataSize() + TypeSizes.NATIVE.sizeof(timestampOfLastDelete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
return super.serializedSize(type, typeSizes) + typeSizes.sizeof(timestampOfLastDelete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
// We cannot use the value validator as for other columns as the CounterColumnType validate a long,
|
||||
// which is not the internal representation of counters
|
||||
contextManager.validateContext(value());
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to special case digest creation for counter column because
|
||||
* we don't want to include the information about which shard of the
|
||||
* context is a delta or not, since this information differs from node to
|
||||
* node.
|
||||
*/
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
updateWithName(digest);
|
||||
|
||||
// We don't take the deltas into account in a digest
|
||||
contextManager.updateDigest(digest, value());
|
||||
|
||||
FBUtilities.updateWithLong(digest, timestamp());
|
||||
FBUtilities.updateWithByte(digest, serializationFlags());
|
||||
FBUtilities.updateWithLong(digest, timestampOfLastDelete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s(%s:false:%s@%d!%d)",
|
||||
getClass().getSimpleName(),
|
||||
comparator.getString(name()),
|
||||
contextManager.toString(value()),
|
||||
timestamp(),
|
||||
timestampOfLastDelete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CounterCell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferCounterCell(copy(metadata, allocator), allocator.clone(value()), timestamp(), timestampOfLastDelete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CounterCell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long excessHeapSizeExcludingData()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long unsharedHeapSize()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return cell instanceof CounterCell && equals((CounterCell) this);
|
||||
}
|
||||
|
||||
public boolean equals(CounterCell cell)
|
||||
{
|
||||
return super.equals(cell) && timestampOfLastDelete() == cell.timestampOfLastDelete();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.dht.Token;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.MemoryUtil;
|
||||
import org.apache.cassandra.utils.memory.NativeAllocator;
|
||||
|
||||
public class NativeDecoratedKey extends DecoratedKey
|
||||
{
|
||||
private final long peer;
|
||||
|
||||
public NativeDecoratedKey(Token token, NativeAllocator allocator, OpOrder.Group writeOp, ByteBuffer key)
|
||||
{
|
||||
super(token);
|
||||
assert key != null;
|
||||
int size = key.remaining();
|
||||
this.peer = allocator.allocate(4 + size, writeOp);
|
||||
MemoryUtil.setInt(peer, size);
|
||||
MemoryUtil.setBytes(peer + 4, key);
|
||||
}
|
||||
|
||||
public ByteBuffer getKey()
|
||||
{
|
||||
return MemoryUtil.getByteBuffer(peer + 4, MemoryUtil.getInt(peer));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemoryUtil;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
import org.apache.cassandra.utils.memory.NativeAllocator;
|
||||
|
||||
public class NativeDeletedCell extends NativeCell implements DeletedCell
|
||||
{
|
||||
private static final long SIZE = ObjectSizes.measure(new NativeDeletedCell());
|
||||
|
||||
private NativeDeletedCell()
|
||||
{}
|
||||
|
||||
public NativeDeletedCell(NativeAllocator allocator, OpOrder.Group writeOp, DeletedCell copyOf)
|
||||
{
|
||||
super(allocator, writeOp, copyOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cell reconcile(Cell cell)
|
||||
{
|
||||
if (cell instanceof DeletedCell)
|
||||
return super.reconcile(cell);
|
||||
return cell.reconcile(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return timestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
int v = getInt(valueStartOffset());
|
||||
return MemoryUtil.INVERTED_ORDER ? Integer.reverseBytes(v) : v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.DELETION_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
validateName(metadata);
|
||||
|
||||
if ((int) (internalSize() - valueStartOffset()) != 4)
|
||||
throw new MarshalException("A tombstone value should be 4 bytes long");
|
||||
if (getLocalDeletionTime() < 0)
|
||||
throw new MarshalException("The local deletion time should not be negative");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
updateWithName(digest);
|
||||
FBUtilities.updateWithLong(digest, timestamp());
|
||||
FBUtilities.updateWithByte(digest, serializationFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeletedCell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferDeletedCell(copy(metadata, allocator), allocator.clone(value()), timestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeletedCell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return timestamp() == cell.timestamp() && getLocalDeletionTime() == cell.getLocalDeletionTime() && name().equals(cell.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long excessHeapSizeExcludingData()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long unsharedHeapSize()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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.security.MessageDigest;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
import org.apache.cassandra.utils.memory.NativeAllocator;
|
||||
|
||||
public class NativeExpiringCell extends NativeCell implements ExpiringCell
|
||||
{
|
||||
private static final long SIZE = ObjectSizes.measure(new NativeExpiringCell());
|
||||
|
||||
private NativeExpiringCell()
|
||||
{}
|
||||
|
||||
public NativeExpiringCell(NativeAllocator allocator, OpOrder.Group writeOp, ExpiringCell copyOf)
|
||||
{
|
||||
super(allocator, writeOp, copyOf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int sizeOf(Cell cell)
|
||||
{
|
||||
return super.sizeOf(cell) + 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void construct(Cell from)
|
||||
{
|
||||
ExpiringCell expiring = (ExpiringCell) from;
|
||||
|
||||
setInt(internalSize() - 4, expiring.getTimeToLive());
|
||||
setInt(internalSize() - 8, expiring.getLocalDeletionTime());
|
||||
super.construct(from);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int postfixSize()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeToLive()
|
||||
{
|
||||
return getInt(internalSize() - 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return getInt(internalSize() - 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedForDelete(long now)
|
||||
{
|
||||
return (int) (now / 1000) >= getLocalDeletionTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return timestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializationFlags()
|
||||
{
|
||||
return ColumnSerializer.EXPIRATION_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cellDataSize()
|
||||
{
|
||||
return super.cellDataSize() + TypeSizes.NATIVE.sizeof(getLocalDeletionTime()) + TypeSizes.NATIVE.sizeof(getTimeToLive());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serializedSize(CellNameType type, TypeSizes typeSizes)
|
||||
{
|
||||
/*
|
||||
* An expired column adds to a Cell :
|
||||
* 4 bytes for the localExpirationTime
|
||||
* + 4 bytes for the timeToLive
|
||||
*/
|
||||
return super.serializedSize(type, typeSizes) + typeSizes.sizeof(getLocalDeletionTime()) + typeSizes.sizeof(getTimeToLive());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFields(CFMetaData metadata) throws MarshalException
|
||||
{
|
||||
super.validateFields(metadata);
|
||||
|
||||
if (getTimeToLive() <= 0)
|
||||
throw new MarshalException("A column TTL should be > 0");
|
||||
if (getLocalDeletionTime() < 0)
|
||||
throw new MarshalException("The local expiration time should not be negative");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDigest(MessageDigest digest)
|
||||
{
|
||||
super.updateDigest(digest);
|
||||
FBUtilities.updateWithInt(digest, getTimeToLive());
|
||||
}
|
||||
|
||||
public boolean equals(Cell cell)
|
||||
{
|
||||
return cell instanceof ExpiringCell && equals((ExpiringCell) this);
|
||||
}
|
||||
|
||||
protected boolean equals(ExpiringCell cell)
|
||||
{
|
||||
// super.equals() returns false if o is not a CounterCell
|
||||
return super.equals(cell)
|
||||
&& getLocalDeletionTime() == cell.getLocalDeletionTime()
|
||||
&& getTimeToLive() == cell.getTimeToLive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(CellNameType comparator)
|
||||
{
|
||||
return String.format("%s(%s!%d)", getClass().getSimpleName(), super.getString(comparator), getTimeToLive());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpiringCell localCopy(CFMetaData metadata, AbstractAllocator allocator)
|
||||
{
|
||||
return new BufferExpiringCell(name().copy(metadata, allocator), allocator.clone(value()), timestamp(), getTimeToLive(), getLocalDeletionTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpiringCell localCopy(CFMetaData metadata, MemtableAllocator allocator, OpOrder.Group opGroup)
|
||||
{
|
||||
return allocator.clone(this, metadata, opGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long excessHeapSizeExcludingData()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long unsharedHeapSize()
|
||||
{
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ public class Row
|
|||
{
|
||||
public void serialize(Row row, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
ByteBufferUtil.writeWithShortLength(row.key.key, out);
|
||||
ByteBufferUtil.writeWithShortLength(row.key.getKey(), out);
|
||||
ColumnFamily.serializer.serialize(row.cf, out, version);
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ public class Row
|
|||
|
||||
public long serializedSize(Row row, int version)
|
||||
{
|
||||
int keySize = row.key.key.remaining();
|
||||
int keySize = row.key.getKey().remaining();
|
||||
return TypeSizes.NATIVE.sizeof((short) keySize) + keySize + ColumnFamily.serializer.serializedSize(row.cf, TypeSizes.NATIVE, version);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public class RowIteratorFactory
|
|||
{
|
||||
// First check if this row is in the rowCache. If it is and it covers our filter, we can skip the rest
|
||||
ColumnFamily cached = cfs.getRawCachedRow(key);
|
||||
IDiskAtomFilter filter = range.columnFilter(key.key);
|
||||
IDiskAtomFilter filter = range.columnFilter(key.getKey());
|
||||
|
||||
if (cached == null || !cfs.isFilterFullyCoveredBy(filter, cached, now))
|
||||
{
|
||||
|
|
@ -150,7 +150,7 @@ public class RowIteratorFactory
|
|||
{
|
||||
public OnDiskAtomIterator create()
|
||||
{
|
||||
return range.columnFilter(entry.getKey().key).getColumnFamilyIterator(entry.getKey(), entry.getValue());
|
||||
return range.columnFilter(entry.getKey().getKey()).getColumnFamilyIterator(entry.getKey(), entry.getValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import org.apache.cassandra.io.util.DataOutputPlus;
|
|||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public abstract class RowPosition implements RingPosition<RowPosition>
|
||||
public interface RowPosition extends RingPosition<RowPosition>
|
||||
{
|
||||
public static enum Kind
|
||||
{
|
||||
|
|
@ -43,20 +43,18 @@ public abstract class RowPosition implements RingPosition<RowPosition>
|
|||
}
|
||||
}
|
||||
|
||||
public static final class ForKey
|
||||
{
|
||||
public static RowPosition get(ByteBuffer key, IPartitioner p)
|
||||
{
|
||||
return key == null || key.remaining() == 0 ? p.getMinimumToken().minKeyBound() : p.decorateKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
public static final RowPositionSerializer serializer = new RowPositionSerializer();
|
||||
|
||||
public static RowPosition forKey(ByteBuffer key, IPartitioner p)
|
||||
{
|
||||
return key == null || key.remaining() == 0 ? p.getMinimumToken().minKeyBound() : p.decorateKey(key);
|
||||
}
|
||||
|
||||
public abstract Token getToken();
|
||||
public abstract Kind kind();
|
||||
|
||||
public boolean isMinimum()
|
||||
{
|
||||
return isMinimum(StorageService.getPartitioner());
|
||||
}
|
||||
public Kind kind();
|
||||
public boolean isMinimum();
|
||||
|
||||
public static class RowPositionSerializer implements ISerializer<RowPosition>
|
||||
{
|
||||
|
|
@ -76,7 +74,7 @@ public abstract class RowPosition implements RingPosition<RowPosition>
|
|||
Kind kind = pos.kind();
|
||||
out.writeByte(kind.ordinal());
|
||||
if (kind == Kind.ROW_KEY)
|
||||
ByteBufferUtil.writeWithShortLength(((DecoratedKey)pos).key, out);
|
||||
ByteBufferUtil.writeWithShortLength(((DecoratedKey)pos).getKey(), out);
|
||||
else
|
||||
Token.serializer.serialize(pos.getToken(), out);
|
||||
}
|
||||
|
|
@ -102,7 +100,7 @@ public abstract class RowPosition implements RingPosition<RowPosition>
|
|||
int size = 1; // 1 byte for enum
|
||||
if (kind == Kind.ROW_KEY)
|
||||
{
|
||||
int keySize = ((DecoratedKey)pos).key.remaining();
|
||||
int keySize = ((DecoratedKey)pos).getKey().remaining();
|
||||
size += typeSizes.sizeof((short) keySize) + keySize;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -696,7 +696,7 @@ public class SystemKeyspace
|
|||
public static void setIndexBuilt(String keyspaceName, String indexName)
|
||||
{
|
||||
ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Keyspace.SYSTEM_KS, INDEX_CF);
|
||||
cf.addColumn(new Cell(cf.getComparator().makeCellName(indexName), ByteBufferUtil.EMPTY_BYTE_BUFFER, FBUtilities.timestampMicros()));
|
||||
cf.addColumn(new BufferCell(cf.getComparator().makeCellName(indexName), ByteBufferUtil.EMPTY_BYTE_BUFFER, FBUtilities.timestampMicros()));
|
||||
new Mutation(Keyspace.SYSTEM_KS, ByteBufferUtil.bytes(keyspaceName), cf).apply();
|
||||
}
|
||||
|
||||
|
|
@ -774,7 +774,7 @@ public class SystemKeyspace
|
|||
ByteBuffer ip = ByteBuffer.wrap(FBUtilities.getBroadcastAddress().getAddress());
|
||||
|
||||
ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Keyspace.SYSTEM_KS, COUNTER_ID_CF);
|
||||
cf.addColumn(new Cell(cf.getComparator().makeCellName(newCounterId.bytes()), ip, now));
|
||||
cf.addColumn(new BufferCell(cf.getComparator().makeCellName(newCounterId.bytes()), ip, now));
|
||||
new Mutation(Keyspace.SYSTEM_KS, ALL_LOCAL_NODE_ID_KEY, cf).apply();
|
||||
forceBlockingFlush(COUNTER_ID_CF);
|
||||
}
|
||||
|
|
@ -833,7 +833,7 @@ public class SystemKeyspace
|
|||
Mutation mutation = mutationMap.get(schemaRow.key);
|
||||
if (mutation == null)
|
||||
{
|
||||
mutation = new Mutation(Keyspace.SYSTEM_KS, schemaRow.key.key);
|
||||
mutation = new Mutation(Keyspace.SYSTEM_KS, schemaRow.key.getKey());
|
||||
mutationMap.put(schemaRow.key, mutation);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ public abstract class AbstractCompactionStrategy
|
|||
long keys = sstable.estimatedKeys();
|
||||
Set<Range<Token>> ranges = new HashSet<Range<Token>>(overlaps.size());
|
||||
for (SSTableReader overlap : overlaps)
|
||||
ranges.add(new Range<Token>(overlap.first.token, overlap.last.token, overlap.partitioner));
|
||||
ranges.add(new Range<Token>(overlap.first.getToken(), overlap.last.getToken(), overlap.partitioner));
|
||||
long remainingKeys = keys - sstable.estimatedKeysForRanges(ranges);
|
||||
// next, calculate what percentage of columns we have within those keys
|
||||
long columns = sstable.getEstimatedColumnCount().mean() * remainingKeys;
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ public class CompactionController implements AutoCloseable
|
|||
// we check index file instead.
|
||||
if (sstable.getBloomFilter() instanceof AlwaysPresentFilter && sstable.getPosition(key, SSTableReader.Operator.EQ, false) != null)
|
||||
min = Math.min(min, sstable.getMinTimestamp());
|
||||
else if (sstable.getBloomFilter().isPresent(key.key))
|
||||
else if (sstable.getBloomFilter().isPresent(key.getKey()))
|
||||
min = Math.min(min, sstable.getMinTimestamp());
|
||||
}
|
||||
return min;
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
SSTableReader sstable = sstableIterator.next();
|
||||
for (Range<Token> r : Range.normalize(ranges))
|
||||
{
|
||||
Range<Token> sstableRange = new Range<>(sstable.first.token, sstable.last.token, sstable.partitioner);
|
||||
Range<Token> sstableRange = new Range<>(sstable.first.getToken(), sstable.last.getToken(), sstable.partitioner);
|
||||
if (r.contains(sstableRange))
|
||||
{
|
||||
logger.info("SSTable {} fully contained in range {}, mutating repairedAt instead of anticompacting", sstable, r);
|
||||
|
|
@ -602,7 +602,7 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
// see if there are any keys LTE the token for the start of the first range
|
||||
// (token range ownership is exclusive on the LHS.)
|
||||
Range<Token> firstRange = sortedRanges.get(0);
|
||||
if (sstable.first.token.compareTo(firstRange.left) <= 0)
|
||||
if (sstable.first.getToken().compareTo(firstRange.left) <= 0)
|
||||
return true;
|
||||
|
||||
// then, iterate over all owned ranges and see if the next key beyond the end of the owned
|
||||
|
|
@ -631,7 +631,7 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
}
|
||||
|
||||
Range<Token> nextRange = sortedRanges.get(i + 1);
|
||||
if (!nextRange.contains(firstBeyondRange.token))
|
||||
if (!nextRange.contains(firstBeyondRange.getToken()))
|
||||
{
|
||||
// we found a key in between the owned ranges
|
||||
return true;
|
||||
|
|
@ -651,7 +651,7 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
{
|
||||
assert !cfs.isIndex();
|
||||
|
||||
if (!hasIndexes && !new Bounds<>(sstable.first.token, sstable.last.token).intersects(ranges))
|
||||
if (!hasIndexes && !new Bounds<>(sstable.first.getToken(), sstable.last.getToken()).intersects(ranges))
|
||||
{
|
||||
cfs.getDataTracker().markCompactedSSTablesReplaced(Arrays.asList(sstable), Collections.<SSTableReader>emptyList(), OperationType.CLEANUP);
|
||||
return;
|
||||
|
|
@ -796,7 +796,7 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
@Override
|
||||
public SSTableIdentityIterator cleanup(SSTableIdentityIterator row)
|
||||
{
|
||||
if (Range.isInRanges(row.getKey().token, ranges))
|
||||
if (Range.isInRanges(row.getKey().getToken(), ranges))
|
||||
return row;
|
||||
|
||||
cfs.invalidateCachedRow(row.getKey());
|
||||
|
|
@ -972,7 +972,7 @@ public class CompactionManager implements CompactionManagerMBean
|
|||
{
|
||||
AbstractCompactedRow row = iter.next();
|
||||
// if current range from sstable is repaired, save it into the new repaired sstable
|
||||
if (Range.isInRanges(row.key.token, ranges))
|
||||
if (Range.isInRanges(row.key.getToken(), ranges))
|
||||
{
|
||||
repairedSSTableWriter.append(row);
|
||||
repairedKeyCount++;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public class LazilyCompactedRow extends AbstractCompactedRow
|
|||
ColumnIndex columnsIndex;
|
||||
try
|
||||
{
|
||||
indexBuilder = new ColumnIndex.Builder(emptyColumnFamily, key.key, out);
|
||||
indexBuilder = new ColumnIndex.Builder(emptyColumnFamily, key.getKey(), out);
|
||||
columnsIndex = indexBuilder.buildForCompaction(merger);
|
||||
|
||||
// if there aren't any columns or tombstones, return null
|
||||
|
|
@ -156,7 +156,7 @@ public class LazilyCompactedRow extends AbstractCompactedRow
|
|||
}
|
||||
|
||||
// initialize indexBuilder for the benefit of its tombstoneTracker, used by our reducing iterator
|
||||
indexBuilder = new ColumnIndex.Builder(emptyColumnFamily, key.key, out);
|
||||
indexBuilder = new ColumnIndex.Builder(emptyColumnFamily, key.getKey(), out);
|
||||
while (merger.hasNext())
|
||||
merger.next().updateDigest(digest);
|
||||
close();
|
||||
|
|
|
|||
|
|
@ -456,13 +456,13 @@ public class LeveledManifest
|
|||
*/
|
||||
Iterator<SSTableReader> iter = candidates.iterator();
|
||||
SSTableReader sstable = iter.next();
|
||||
Token first = sstable.first.token;
|
||||
Token last = sstable.last.token;
|
||||
Token first = sstable.first.getToken();
|
||||
Token last = sstable.last.getToken();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
sstable = iter.next();
|
||||
first = first.compareTo(sstable.first.token) <= 0 ? first : sstable.first.token;
|
||||
last = last.compareTo(sstable.last.token) >= 0 ? last : sstable.last.token;
|
||||
first = first.compareTo(sstable.first.getToken()) <= 0 ? first : sstable.first.getToken();
|
||||
last = last.compareTo(sstable.last.getToken()) >= 0 ? last : sstable.last.getToken();
|
||||
}
|
||||
return overlapping(first, last, others);
|
||||
}
|
||||
|
|
@ -470,7 +470,7 @@ public class LeveledManifest
|
|||
@VisibleForTesting
|
||||
static Set<SSTableReader> overlapping(SSTableReader sstable, Iterable<SSTableReader> others)
|
||||
{
|
||||
return overlapping(sstable.first.token, sstable.last.token, others);
|
||||
return overlapping(sstable.first.getToken(), sstable.last.getToken(), others);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -483,7 +483,7 @@ public class LeveledManifest
|
|||
Bounds<Token> promotedBounds = new Bounds<Token>(start, end);
|
||||
for (SSTableReader candidate : sstables)
|
||||
{
|
||||
Bounds<Token> candidateBounds = new Bounds<Token>(candidate.first.token, candidate.last.token);
|
||||
Bounds<Token> candidateBounds = new Bounds<Token>(candidate.first.getToken(), candidate.last.getToken());
|
||||
if (candidateBounds.intersects(promotedBounds))
|
||||
overlapped.add(candidate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ public class Scrubber implements Closeable
|
|||
|
||||
dataSize = dataSizeFromIndex;
|
||||
// avoid an NPE if key is null
|
||||
String keyName = key == null ? "(unreadable key)" : ByteBufferUtil.bytesToHex(key.key);
|
||||
String keyName = key == null ? "(unreadable key)" : ByteBufferUtil.bytesToHex(key.getKey());
|
||||
outputHandler.debug(String.format("row %s is %s bytes", keyName, dataSize));
|
||||
|
||||
assert currentIndexKey != null || indexFile.isEOF();
|
||||
|
|
@ -188,7 +188,7 @@ public class Scrubber implements Closeable
|
|||
else
|
||||
goodRows++;
|
||||
prevKey = key;
|
||||
if (!key.key.equals(currentIndexKey) || dataStart != dataStartFromIndex)
|
||||
if (!key.getKey().equals(currentIndexKey) || dataStart != dataStartFromIndex)
|
||||
outputHandler.warn("Index file contained a different key or row size; using key from data file");
|
||||
}
|
||||
catch (Throwable th)
|
||||
|
|
@ -197,7 +197,7 @@ public class Scrubber implements Closeable
|
|||
outputHandler.warn("Error reading row (stacktrace follows):", th);
|
||||
|
||||
if (currentIndexKey != null
|
||||
&& (key == null || !key.key.equals(currentIndexKey) || dataStart != dataStartFromIndex || dataSize != dataSizeFromIndex))
|
||||
&& (key == null || !key.getKey().equals(currentIndexKey) || dataStart != dataStartFromIndex || dataSize != dataSizeFromIndex))
|
||||
{
|
||||
outputHandler.output(String.format("Retrying from row index; data is %s bytes starting at %s",
|
||||
dataSizeFromIndex, dataStartFromIndex));
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.*;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.CQL3Row;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
|
|
@ -294,19 +295,20 @@ public abstract class AbstractCellNameType extends AbstractCType implements Cell
|
|||
}
|
||||
}
|
||||
|
||||
protected static CQL3Row.Builder makeSparseCQL3RowBuilder(final CellNameType type, final long now)
|
||||
protected static CQL3Row.Builder makeSparseCQL3RowBuilder(final CFMetaData cfMetaData, final CellNameType type, final long now)
|
||||
{
|
||||
return new CQL3Row.Builder()
|
||||
{
|
||||
public CQL3Row.RowIterator group(Iterator<Cell> cells)
|
||||
{
|
||||
return new SparseRowIterator(type, cells, now);
|
||||
return new SparseRowIterator(cfMetaData, type, cells, now);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class SparseRowIterator extends AbstractIterator<CQL3Row> implements CQL3Row.RowIterator
|
||||
{
|
||||
private final CFMetaData cfMetaData;
|
||||
private final CellNameType type;
|
||||
private final Iterator<Cell> cells;
|
||||
private final long now;
|
||||
|
|
@ -316,8 +318,9 @@ public abstract class AbstractCellNameType extends AbstractCType implements Cell
|
|||
private CellName previous;
|
||||
private CQL3RowOfSparse currentRow;
|
||||
|
||||
public SparseRowIterator(CellNameType type, Iterator<Cell> cells, long now)
|
||||
public SparseRowIterator(CFMetaData cfMetaData, CellNameType type, Iterator<Cell> cells, long now)
|
||||
{
|
||||
this.cfMetaData = cfMetaData;
|
||||
this.type = type;
|
||||
this.cells = cells;
|
||||
this.now = now;
|
||||
|
|
@ -357,7 +360,7 @@ public abstract class AbstractCellNameType extends AbstractCType implements Cell
|
|||
if (currentRow == null || !current.isSameCQL3RowAs(type, previous))
|
||||
{
|
||||
toReturn = currentRow;
|
||||
currentRow = new CQL3RowOfSparse(current);
|
||||
currentRow = new CQL3RowOfSparse(cfMetaData, current);
|
||||
}
|
||||
currentRow.add(nextCell);
|
||||
nextCell = null;
|
||||
|
|
@ -378,12 +381,14 @@ public abstract class AbstractCellNameType extends AbstractCType implements Cell
|
|||
|
||||
private static class CQL3RowOfSparse implements CQL3Row
|
||||
{
|
||||
private final CFMetaData cfMetaData;
|
||||
private final CellName cell;
|
||||
private Map<ColumnIdentifier, Cell> columns;
|
||||
private Map<ColumnIdentifier, List<Cell>> collections;
|
||||
|
||||
CQL3RowOfSparse(CellName cell)
|
||||
CQL3RowOfSparse(CFMetaData metadata, CellName cell)
|
||||
{
|
||||
this.cfMetaData = metadata;
|
||||
this.cell = cell;
|
||||
}
|
||||
|
||||
|
|
@ -395,7 +400,7 @@ public abstract class AbstractCellNameType extends AbstractCType implements Cell
|
|||
void add(Cell cell)
|
||||
{
|
||||
CellName cellName = cell.name();
|
||||
ColumnIdentifier columnName = cellName.cql3ColumnName();
|
||||
ColumnIdentifier columnName = cellName.cql3ColumnName(cfMetaData);
|
||||
if (cellName.isCollectionCell())
|
||||
{
|
||||
if (collections == null)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package org.apache.cassandra.db.composites;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.db.filter.ColumnSlice;
|
||||
import org.apache.cassandra.db.marshal.AbstractCompositeType;
|
||||
import org.apache.cassandra.db.marshal.CompositeType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public class BoundedComposite extends AbstractComposite
|
||||
{
|
||||
|
|
@ -94,14 +94,8 @@ public class BoundedComposite extends AbstractComposite
|
|||
return EMPTY_SIZE + wrapped.unsharedHeapSize();
|
||||
}
|
||||
|
||||
public Composite copy(AbstractAllocator allocator)
|
||||
public Composite copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return new BoundedComposite(wrapped.copy(allocator), isStart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
wrapped.free(allocator);
|
||||
return new BoundedComposite(wrapped.copy(cfm, allocator), isStart);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
|
||||
|
|
@ -52,8 +53,9 @@ public interface CellName extends Composite
|
|||
* The name of the CQL3 column this cell represents.
|
||||
*
|
||||
* Will be null for cells of "dense" tables.
|
||||
* @param metadata
|
||||
*/
|
||||
public ColumnIdentifier cql3ColumnName();
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata);
|
||||
|
||||
/**
|
||||
* The value of the collection element, or null if the cell is not part
|
||||
|
|
@ -70,7 +72,7 @@ public interface CellName extends Composite
|
|||
// If cellnames were sharing some prefix components, this will break it, so
|
||||
// we might want to try to do better.
|
||||
@Override
|
||||
public CellName copy(AbstractAllocator allocator);
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator);
|
||||
|
||||
public long excessHeapSizeExcludingData();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.CQL3Row;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
|
|
@ -152,7 +153,7 @@ public interface CellNameType extends CType
|
|||
/**
|
||||
* Creates a new CQL3Row builder for this type. See CQL3Row for details.
|
||||
*/
|
||||
public CQL3Row.Builder CQL3RowBuilder(long now);
|
||||
public CQL3Row.Builder CQL3RowBuilder(CFMetaData metadata, long now);
|
||||
|
||||
// The two following methods are used to pass the declared regular column names (in CFMetaData)
|
||||
// to the CellNameType. This is only used for optimization sake, see SparseCellNameType.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.apache.cassandra.db.composites;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.Cell;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.ColumnToCollectionType;
|
||||
|
|
@ -75,6 +76,11 @@ public abstract class CellNames
|
|||
return new SimpleDenseCellName(bb);
|
||||
}
|
||||
|
||||
public static CellName simpleSparse(ColumnIdentifier identifier)
|
||||
{
|
||||
return new SimpleSparseCellName(identifier);
|
||||
}
|
||||
|
||||
// Mainly for tests and a few cases where we know what we need and didn't wanted to pass the type around
|
||||
// Avoid in general, prefer the CellNameType methods.
|
||||
public static CellName compositeDense(ByteBuffer... bbs)
|
||||
|
|
@ -82,6 +88,16 @@ public abstract class CellNames
|
|||
return new CompoundDenseCellName(bbs);
|
||||
}
|
||||
|
||||
public static CellName compositeSparse(ByteBuffer[] bbs, ColumnIdentifier identifier, boolean isStatic)
|
||||
{
|
||||
return new CompoundSparseCellName(bbs, identifier, isStatic);
|
||||
}
|
||||
|
||||
public static CellName compositeSparseWithCollection(ByteBuffer[] bbs, ByteBuffer collectionElement, ColumnIdentifier identifier, boolean isStatic)
|
||||
{
|
||||
return new CompoundSparseCellName.WithCollection(bbs, identifier, collectionElement, isStatic);
|
||||
}
|
||||
|
||||
public static String getColumnsString(CellNameType type, Iterable<Cell> columns)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ package org.apache.cassandra.db.composites;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.cache.IMeasurableMemory;
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.filter.ColumnSlice;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
/**
|
||||
* A composite value.
|
||||
|
|
@ -75,6 +75,5 @@ public interface Composite extends IMeasurableMemory
|
|||
public ByteBuffer toByteBuffer();
|
||||
|
||||
public int dataSize();
|
||||
public Composite copy(AbstractAllocator allocator);
|
||||
public void free(PoolAllocator allocator);
|
||||
public Composite copy(CFMetaData cfm, AbstractAllocator allocator);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.filter.ColumnSlice;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public abstract class Composites
|
||||
{
|
||||
|
|
@ -108,15 +108,9 @@ public abstract class Composites
|
|||
return true;
|
||||
}
|
||||
|
||||
public Composite copy(AbstractAllocator allocator)
|
||||
public Composite copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
/**
|
||||
* A "truly-composite" Composite.
|
||||
|
|
@ -81,16 +81,8 @@ public class CompoundComposite extends AbstractComposite
|
|||
return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(elements);
|
||||
}
|
||||
|
||||
public Composite copy(AbstractAllocator allocator)
|
||||
public Composite copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return new CompoundComposite(elementsCopy(allocator), size, isStatic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
for (ByteBuffer element : elements)
|
||||
allocator.free(element);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
|
|
@ -44,7 +45,7 @@ public class CompoundDenseCellName extends CompoundComposite implements CellName
|
|||
return size;
|
||||
}
|
||||
|
||||
public ColumnIdentifier cql3ColumnName()
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
@ -77,7 +78,7 @@ public class CompoundDenseCellName extends CompoundComposite implements CellName
|
|||
return HEAP_SIZE + ObjectSizes.sizeOnHeapExcludingData(elements);
|
||||
}
|
||||
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return new CompoundDenseCellName(elementsCopy(allocator));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.CQL3Row;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
|
|
@ -80,7 +81,7 @@ public class CompoundDenseCellNameType extends AbstractCompoundCellNameType
|
|||
public void addCQL3Column(ColumnIdentifier id) {}
|
||||
public void removeCQL3Column(ColumnIdentifier id) {}
|
||||
|
||||
public CQL3Row.Builder CQL3RowBuilder(long now)
|
||||
public CQL3Row.Builder CQL3RowBuilder(CFMetaData metadata, long now)
|
||||
{
|
||||
return makeDenseCQL3RowBuilder(now);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public class CompoundSparseCellName extends CompoundComposite implements CellName
|
||||
{
|
||||
|
|
@ -65,7 +65,7 @@ public class CompoundSparseCellName extends CompoundComposite implements CellNam
|
|||
return size;
|
||||
}
|
||||
|
||||
public ColumnIdentifier cql3ColumnName()
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata)
|
||||
{
|
||||
return columnName;
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ public class CompoundSparseCellName extends CompoundComposite implements CellNam
|
|||
return true;
|
||||
}
|
||||
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
if (elements.length == 0)
|
||||
return this;
|
||||
|
|
@ -147,7 +147,7 @@ public class CompoundSparseCellName extends CompoundComposite implements CellNam
|
|||
}
|
||||
|
||||
@Override
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
// We don't copy columnName because it's interned in SparseCellNameType
|
||||
return new CompoundSparseCellName.WithCollection(elements.length == 0 ? elements : elementsCopy(allocator), size, columnName, allocator.clone(collectionElement), isStatic());
|
||||
|
|
@ -164,12 +164,5 @@ public class CompoundSparseCellName extends CompoundComposite implements CellNam
|
|||
{
|
||||
return super.excessHeapSizeExcludingData() + ObjectSizes.sizeOnHeapExcludingData(collectionElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
super.free(allocator);
|
||||
allocator.free(collectionElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.apache.cassandra.db.composites;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.CQL3Row;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
|
|
@ -29,11 +30,10 @@ import org.apache.cassandra.db.marshal.ColumnToCollectionType;
|
|||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public class CompoundSparseCellNameType extends AbstractCompoundCellNameType
|
||||
{
|
||||
private static final ColumnIdentifier rowMarkerId = new ColumnIdentifier(ByteBufferUtil.EMPTY_BYTE_BUFFER, UTF8Type.instance);
|
||||
public static final ColumnIdentifier rowMarkerId = new ColumnIdentifier(ByteBufferUtil.EMPTY_BYTE_BUFFER, UTF8Type.instance);
|
||||
private static final CellName rowMarkerNoPrefix = new CompoundSparseCellName(rowMarkerId, false);
|
||||
|
||||
// For CQL3 columns, this is always UTF8Type. However, for compatibility with super columns, we need to allow it to be non-UTF8.
|
||||
|
|
@ -87,15 +87,10 @@ public class CompoundSparseCellNameType extends AbstractCompoundCellNameType
|
|||
}
|
||||
|
||||
@Override
|
||||
public Composite copy(AbstractAllocator allocator)
|
||||
public Composite copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -204,9 +199,9 @@ public class CompoundSparseCellNameType extends AbstractCompoundCellNameType
|
|||
internedIds.remove(id.bytes);
|
||||
}
|
||||
|
||||
public CQL3Row.Builder CQL3RowBuilder(long now)
|
||||
public CQL3Row.Builder CQL3RowBuilder(CFMetaData metadata, long now)
|
||||
{
|
||||
return makeSparseCQL3RowBuilder(this, now);
|
||||
return makeSparseCQL3RowBuilder(metadata, this, now);
|
||||
}
|
||||
|
||||
public static class WithCollection extends CompoundSparseCellNameType
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
/**
|
||||
* A "simple" (not-truly-composite) Composite.
|
||||
|
|
@ -72,14 +72,8 @@ public class SimpleComposite extends AbstractComposite
|
|||
return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(element);
|
||||
}
|
||||
|
||||
public Composite copy(AbstractAllocator allocator)
|
||||
public Composite copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return new SimpleComposite(allocator.clone(element));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
allocator.free(element);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
|
|
@ -38,7 +39,7 @@ public class SimpleDenseCellName extends SimpleComposite implements CellName
|
|||
return 1;
|
||||
}
|
||||
|
||||
public ColumnIdentifier cql3ColumnName()
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
@ -74,7 +75,7 @@ public class SimpleDenseCellName extends SimpleComposite implements CellName
|
|||
// If cellnames were sharing some prefix components, this will break it, so
|
||||
// we might want to try to do better.
|
||||
@Override
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return new SimpleDenseCellName(allocator.clone(element));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.CQL3Row;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
|
|
@ -72,7 +73,7 @@ public class SimpleDenseCellNameType extends AbstractSimpleCellNameType
|
|||
public void addCQL3Column(ColumnIdentifier id) {}
|
||||
public void removeCQL3Column(ColumnIdentifier id) {}
|
||||
|
||||
public CQL3Row.Builder CQL3RowBuilder(long now)
|
||||
public CQL3Row.Builder CQL3RowBuilder(CFMetaData metadata, long now)
|
||||
{
|
||||
return makeDenseCQL3RowBuilder(now);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package org.apache.cassandra.db.composites;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.ObjectSizes;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public class SimpleSparseCellName extends AbstractComposite implements CellName
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ public class SimpleSparseCellName extends AbstractComposite implements CellName
|
|||
return 0;
|
||||
}
|
||||
|
||||
public ColumnIdentifier cql3ColumnName()
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata)
|
||||
{
|
||||
return columnName;
|
||||
}
|
||||
|
|
@ -97,13 +97,8 @@ public class SimpleSparseCellName extends AbstractComposite implements CellName
|
|||
return EMPTY_SIZE + columnName.unsharedHeapSize();
|
||||
}
|
||||
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
return new SimpleSparseCellName(columnName.clone(allocator));
|
||||
}
|
||||
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
allocator.free(columnName.bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.CQL3Row;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
|
|
@ -92,8 +93,8 @@ public class SimpleSparseCellNameType extends AbstractSimpleCellNameType
|
|||
internedNames.remove(id.bytes);
|
||||
}
|
||||
|
||||
public CQL3Row.Builder CQL3RowBuilder(long now)
|
||||
public CQL3Row.Builder CQL3RowBuilder(CFMetaData metadata, long now)
|
||||
{
|
||||
return makeSparseCQL3RowBuilder(this, now);
|
||||
return makeSparseCQL3RowBuilder(metadata, this, now);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
*/
|
||||
package org.apache.cassandra.db.composites;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public class SimpleSparseInternedCellName extends SimpleSparseCellName
|
||||
{
|
||||
|
|
@ -43,16 +43,9 @@ public class SimpleSparseInternedCellName extends SimpleSparseCellName
|
|||
}
|
||||
|
||||
@Override
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
// We're interning those instance in SparceCellNameType so don't need to copy.
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
// no-op, never copied
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import java.util.NavigableSet;
|
|||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.composites.*;
|
||||
|
|
@ -35,7 +36,6 @@ import org.apache.cassandra.io.IVersionedSerializer;
|
|||
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.memory.AbstractAllocator;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
|
||||
public class ColumnSlice
|
||||
{
|
||||
|
|
@ -219,7 +219,7 @@ public class ColumnSlice
|
|||
|
||||
private static Cell fakeCell(Composite name)
|
||||
{
|
||||
return new Cell(new FakeCellName(name), ByteBufferUtil.EMPTY_BYTE_BUFFER);
|
||||
return new BufferCell(new FakeCellName(name), ByteBufferUtil.EMPTY_BYTE_BUFFER);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -265,7 +265,7 @@ public class ColumnSlice
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ColumnIdentifier cql3ColumnName()
|
||||
public ColumnIdentifier cql3ColumnName(CFMetaData metadata)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
|
@ -285,7 +285,7 @@ public class ColumnSlice
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public CellName copy(AbstractAllocator allocator)
|
||||
public CellName copy(CFMetaData cfm, AbstractAllocator allocator)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
|
@ -296,12 +296,6 @@ public class ColumnSlice
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free(PoolAllocator allocator)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public long unsharedHeapSize()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ public abstract class ExtendedFilter
|
|||
assert !(cfs.getComparator().isCompound()) : "Sequential scan with filters is not supported (if you just created an index, you "
|
||||
+ "need to wait for the creation to be propagated to all nodes before querying it)";
|
||||
|
||||
if (!needsExtraQuery(rowKey.key, data))
|
||||
if (!needsExtraQuery(rowKey.getKey(), data))
|
||||
return null;
|
||||
|
||||
// Note: for counters we must be careful to not add a column that was already there (to avoid overcount). That is
|
||||
|
|
@ -278,7 +278,7 @@ public abstract class ExtendedFilter
|
|||
return data;
|
||||
|
||||
ColumnFamily pruned = data.cloneMeShallow();
|
||||
IDiskAtomFilter filter = dataRange.columnFilter(rowKey.key);
|
||||
IDiskAtomFilter filter = dataRange.columnFilter(rowKey.getKey());
|
||||
OnDiskAtomIterator iter = filter.getColumnFamilyIterator(rowKey, data);
|
||||
filter.collectReducedColumns(pruned, QueryFilter.gatherTombstones(pruned, iter), cfs.gcBefore(timestamp), timestamp);
|
||||
return pruned;
|
||||
|
|
@ -311,7 +311,7 @@ public abstract class ExtendedFilter
|
|||
continue;
|
||||
}
|
||||
|
||||
dataValue = extractDataValue(def, rowKey.key, data, prefix);
|
||||
dataValue = extractDataValue(def, rowKey.getKey(), data, prefix);
|
||||
validator = def.type;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,13 +22,7 @@ import java.util.concurrent.Future;
|
|||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.db.ArrayBackedSortedColumns;
|
||||
import org.apache.cassandra.db.Cell;
|
||||
import org.apache.cassandra.db.ColumnFamily;
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.ExpiringCell;
|
||||
import org.apache.cassandra.db.IndexExpression;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.composites.CellName;
|
||||
import org.apache.cassandra.db.composites.CellNameType;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
|
|
@ -37,7 +31,7 @@ import org.apache.cassandra.dht.LocalToken;
|
|||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.OpOrder;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
/**
|
||||
* Implements a secondary index for a column family using a second column family
|
||||
|
|
@ -75,7 +69,7 @@ public abstract class AbstractSimplePerColumnSecondaryIndex extends PerColumnSec
|
|||
@Override
|
||||
public DecoratedKey getIndexKeyFor(ByteBuffer value)
|
||||
{
|
||||
return new DecoratedKey(new LocalToken(getIndexKeyComparator(), value), value);
|
||||
return new BufferDecoratedKey(new LocalToken(getIndexKeyComparator(), value), value);
|
||||
}
|
||||
|
||||
protected abstract CellName makeIndexColumnName(ByteBuffer rowKey, Cell cell);
|
||||
|
|
@ -115,14 +109,14 @@ public abstract class AbstractSimplePerColumnSecondaryIndex extends PerColumnSec
|
|||
if (cell instanceof ExpiringCell)
|
||||
{
|
||||
ExpiringCell ec = (ExpiringCell) cell;
|
||||
cfi.addColumn(new ExpiringCell(name, ByteBufferUtil.EMPTY_BYTE_BUFFER, ec.timestamp(), ec.getTimeToLive(), ec.getLocalDeletionTime()));
|
||||
cfi.addColumn(new BufferExpiringCell(name, ByteBufferUtil.EMPTY_BYTE_BUFFER, ec.timestamp(), ec.getTimeToLive(), ec.getLocalDeletionTime()));
|
||||
}
|
||||
else
|
||||
{
|
||||
cfi.addColumn(new Cell(name, ByteBufferUtil.EMPTY_BYTE_BUFFER, cell.timestamp()));
|
||||
cfi.addColumn(new BufferCell(name, ByteBufferUtil.EMPTY_BYTE_BUFFER, cell.timestamp()));
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("applying index row {} in {}", indexCfs.metadata.getKeyValidator().getString(valueKey.key), cfi);
|
||||
logger.debug("applying index row {} in {}", indexCfs.metadata.getKeyValidator().getString(valueKey.getKey()), cfi);
|
||||
|
||||
indexCfs.apply(valueKey, cfi, SecondaryIndexManager.nullUpdater, opGroup, null);
|
||||
}
|
||||
|
|
@ -171,11 +165,6 @@ public abstract class AbstractSimplePerColumnSecondaryIndex extends PerColumnSec
|
|||
return indexCfs.name;
|
||||
}
|
||||
|
||||
public PoolAllocator getAllocator()
|
||||
{
|
||||
return indexCfs.getDataTracker().getView().getCurrentMemtable().getAllocator();
|
||||
}
|
||||
|
||||
public void reload()
|
||||
{
|
||||
indexCfs.metadata.reloadSecondaryIndexMetadata(baseCfs.metadata);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.db.Cell;
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
|
|
@ -51,7 +52,7 @@ import org.apache.cassandra.io.sstable.ReducingKeyIterator;
|
|||
import org.apache.cassandra.io.sstable.SSTableReader;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.memory.PoolAllocator;
|
||||
import org.apache.cassandra.utils.memory.MemtableAllocator;
|
||||
|
||||
/**
|
||||
* Abstract base class for different types of secondary indexes.
|
||||
|
|
@ -149,11 +150,6 @@ public abstract class SecondaryIndex
|
|||
*/
|
||||
public abstract void forceBlockingFlush();
|
||||
|
||||
/**
|
||||
* Get current amount of memory this index is consuming (in bytes)
|
||||
*/
|
||||
public abstract PoolAllocator getAllocator();
|
||||
|
||||
/**
|
||||
* Allow access to the underlying column family store if there is one
|
||||
* @return the underlying column family store or null
|
||||
|
|
@ -284,7 +280,7 @@ public abstract class SecondaryIndex
|
|||
{
|
||||
// FIXME: this imply one column definition per index
|
||||
ByteBuffer name = columnDefs.iterator().next().name.bytes;
|
||||
return new DecoratedKey(new LocalToken(baseCfs.metadata.getColumnDefinition(name).type, value), value);
|
||||
return new BufferDecoratedKey(new LocalToken(baseCfs.metadata.getColumnDefinition(name).type, value), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -496,7 +496,7 @@ public class SecondaryIndexManager
|
|||
}
|
||||
else
|
||||
{
|
||||
((PerColumnSecondaryIndex) index).delete(key.key, cell, opGroup);
|
||||
((PerColumnSecondaryIndex) index).delete(key.getKey(), cell, opGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -665,7 +665,7 @@ public class SecondaryIndexManager
|
|||
{
|
||||
try (OpOrder.Group opGroup = baseCfs.keyspace.writeOrder.start())
|
||||
{
|
||||
((PerColumnSecondaryIndex) index).delete(key.key, cell, opGroup);
|
||||
((PerColumnSecondaryIndex) index).delete(key.getKey(), cell, opGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -674,7 +674,7 @@ public class SecondaryIndexManager
|
|||
public void updateRowLevelIndexes()
|
||||
{
|
||||
for (SecondaryIndex index : rowLevelIndexMap.values())
|
||||
((PerRowSecondaryIndex) index).index(key.key, null);
|
||||
((PerRowSecondaryIndex) index).index(key.getKey(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -698,7 +698,7 @@ public class SecondaryIndexManager
|
|||
|
||||
for (SecondaryIndex index : indexFor(cell.name()))
|
||||
if (index instanceof PerColumnSecondaryIndex)
|
||||
((PerColumnSecondaryIndex) index).insert(key.key, cell, opGroup);
|
||||
((PerColumnSecondaryIndex) index).insert(key.getKey(), cell, opGroup);
|
||||
}
|
||||
|
||||
public void update(Cell oldCell, Cell cell)
|
||||
|
|
@ -711,9 +711,9 @@ public class SecondaryIndexManager
|
|||
if (index instanceof PerColumnSecondaryIndex)
|
||||
{
|
||||
if (!cell.isMarkedForDelete(System.currentTimeMillis()))
|
||||
((PerColumnSecondaryIndex) index).update(key.key, oldCell, cell, opGroup);
|
||||
((PerColumnSecondaryIndex) index).update(key.getKey(), oldCell, cell, opGroup);
|
||||
else
|
||||
((PerColumnSecondaryIndex) index).delete(key.key, oldCell, opGroup);
|
||||
((PerColumnSecondaryIndex) index).delete(key.getKey(), oldCell, opGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -725,13 +725,13 @@ public class SecondaryIndexManager
|
|||
|
||||
for (SecondaryIndex index : indexFor(cell.name()))
|
||||
if (index instanceof PerColumnSecondaryIndex)
|
||||
((PerColumnSecondaryIndex) index).delete(key.key, cell, opGroup);
|
||||
((PerColumnSecondaryIndex) index).delete(key.getKey(), cell, opGroup);
|
||||
}
|
||||
|
||||
public void updateRowLevelIndexes()
|
||||
{
|
||||
for (SecondaryIndex index : rowLevelIndexMap.values())
|
||||
((PerRowSecondaryIndex) index).index(key.key, cf);
|
||||
((PerRowSecondaryIndex) index).index(key.getKey(), cf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class CompositesIndexOnClusteringKey extends CompositesIndex
|
|||
for (int i = 0; i < columnDef.position(); i++)
|
||||
builder.add(indexEntry.name().get(i + 1));
|
||||
|
||||
builder.add(indexedValue.key);
|
||||
builder.add(indexedValue.getKey());
|
||||
|
||||
for (int i = columnDef.position() + 1; i < ckCount; i++)
|
||||
builder.add(indexEntry.name().get(i));
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public class CompositesIndexOnCollectionKey extends CompositesIndex
|
|||
|
||||
public boolean isStale(IndexedEntry entry, ColumnFamily data, long now)
|
||||
{
|
||||
CellName name = data.getComparator().create(entry.indexedEntryPrefix, columnDef, entry.indexValue.key);
|
||||
CellName name = data.getComparator().create(entry.indexedEntryPrefix, columnDef, entry.indexValue.getKey());
|
||||
Cell liveCell = data.getColumn(name);
|
||||
return (liveCell == null || liveCell.isMarkedForDelete(now));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,6 @@ public class CompositesIndexOnCollectionValue extends CompositesIndex
|
|||
return true;
|
||||
|
||||
ByteBuffer liveValue = liveCell.value();
|
||||
return ((CollectionType)columnDef.type).valueComparator().compare(entry.indexValue.key, liveValue) != 0;
|
||||
return ((CollectionType)columnDef.type).valueComparator().compare(entry.indexValue.getKey(), liveValue) != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,6 @@ public class CompositesIndexOnRegular extends CompositesIndex
|
|||
return true;
|
||||
|
||||
ByteBuffer liveValue = liveCell.value();
|
||||
return columnDef.type.compare(entry.indexValue.key, liveValue) != 0;
|
||||
return columnDef.type.compare(entry.indexValue.getKey(), liveValue) != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@ public class CompositesSearcher extends SecondaryIndexSearcher
|
|||
* indexed row.
|
||||
*/
|
||||
final AbstractBounds<RowPosition> range = filter.dataRange.keyRange();
|
||||
ByteBuffer startKey = range.left instanceof DecoratedKey ? ((DecoratedKey)range.left).key : ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
ByteBuffer endKey = range.right instanceof DecoratedKey ? ((DecoratedKey)range.right).key : ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
ByteBuffer startKey = range.left instanceof DecoratedKey ? ((DecoratedKey)range.left).getKey() : ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
ByteBuffer endKey = range.right instanceof DecoratedKey ? ((DecoratedKey)range.right).getKey() : ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
|
||||
final CellNameType baseComparator = baseCfs.getComparator();
|
||||
final CellNameType indexComparator = index.getIndexCfs().getComparator();
|
||||
|
|
@ -243,14 +243,14 @@ public class CompositesSearcher extends SecondaryIndexSearcher
|
|||
}
|
||||
else
|
||||
{
|
||||
logger.debug("Skipping entry {} before assigned scan range", dk.token);
|
||||
logger.debug("Skipping entry {} before assigned scan range", dk.getToken());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this entry cannot be a hit due to the original cell filter
|
||||
Composite start = entry.indexedEntryPrefix;
|
||||
if (!filter.columnFilter(dk.key).maySelectPrefix(baseComparator, start))
|
||||
if (!filter.columnFilter(dk.getKey()).maySelectPrefix(baseComparator, start))
|
||||
continue;
|
||||
|
||||
// If we've record the previous prefix, it means we're dealing with an index on the collection value. In
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ public class KeysSearcher extends SecondaryIndexSearcher
|
|||
*/
|
||||
final AbstractBounds<RowPosition> range = filter.dataRange.keyRange();
|
||||
CellNameType type = index.getIndexCfs().getComparator();
|
||||
final Composite startKey = range.left instanceof DecoratedKey ? type.make(((DecoratedKey)range.left).key) : Composites.EMPTY;
|
||||
final Composite endKey = range.right instanceof DecoratedKey ? type.make(((DecoratedKey)range.right).key) : Composites.EMPTY;
|
||||
final Composite startKey = range.left instanceof DecoratedKey ? type.make(((DecoratedKey)range.left).getKey()) : Composites.EMPTY;
|
||||
final Composite endKey = range.right instanceof DecoratedKey ? type.make(((DecoratedKey)range.right).getKey()) : Composites.EMPTY;
|
||||
|
||||
final CellName primaryColumn = baseCfs.getComparator().cellFromByteBuffer(primary.column);
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ public class KeysSearcher extends SecondaryIndexSearcher
|
|||
}
|
||||
if (!range.contains(dk))
|
||||
{
|
||||
logger.trace("Skipping entry {} outside of assigned scan range", dk.token);
|
||||
logger.trace("Skipping entry {} outside of assigned scan range", dk.getToken());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -188,11 +188,11 @@ public class KeysSearcher extends SecondaryIndexSearcher
|
|||
data.addAll(cf);
|
||||
}
|
||||
|
||||
if (((KeysIndex)index).isIndexEntryStale(indexKey.key, data, filter.timestamp))
|
||||
if (((KeysIndex)index).isIndexEntryStale(indexKey.getKey(), data, filter.timestamp))
|
||||
{
|
||||
// delete the index entry w/ its own timestamp
|
||||
Cell dummyCell = new Cell(primaryColumn, indexKey.key, cell.timestamp());
|
||||
((PerColumnSecondaryIndex)index).delete(dk.key, dummyCell, writeOp);
|
||||
Cell dummyCell = new BufferCell(primaryColumn, indexKey.getKey(), cell.timestamp());
|
||||
((PerColumnSecondaryIndex)index).delete(dk.getKey(), dummyCell, writeOp);
|
||||
continue;
|
||||
}
|
||||
return new Row(dk, data);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class LocalByPartionerType<T extends Token> extends AbstractType<ByteBuff
|
|||
public int compare(ByteBuffer o1, ByteBuffer o2)
|
||||
{
|
||||
// o1 and o2 can be empty so we need to use RowPosition, not DecoratedKey
|
||||
return RowPosition.forKey(o1, partitioner).compareTo(RowPosition.forKey(o2, partitioner));
|
||||
return RowPosition.ForKey.get(o1, partitioner).compareTo(RowPosition.ForKey.get(o2, partitioner));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package org.apache.cassandra.dht;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
|
@ -100,7 +99,7 @@ public abstract class AbstractBounds<T extends RingPosition> implements Serializ
|
|||
{
|
||||
if (value instanceof DecoratedKey)
|
||||
{
|
||||
return keyValidator.getString(((DecoratedKey)value).key);
|
||||
return keyValidator.getString(((DecoratedKey)value).getKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.*;
|
||||
|
||||
import org.apache.cassandra.config.*;
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
|
|
@ -42,7 +43,7 @@ public abstract class AbstractByteOrderedPartitioner extends AbstractPartitioner
|
|||
|
||||
public DecoratedKey decorateKey(ByteBuffer key)
|
||||
{
|
||||
return new DecoratedKey(getToken(key), key);
|
||||
return new BufferDecoratedKey(getToken(key), key);
|
||||
}
|
||||
|
||||
public BytesToken midpoint(Token ltoken, Token rtoken)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
|
@ -40,7 +41,7 @@ public class LocalPartitioner extends AbstractPartitioner<LocalToken>
|
|||
|
||||
public DecoratedKey decorateKey(ByteBuffer key)
|
||||
{
|
||||
return new DecoratedKey(getToken(key), key);
|
||||
return new BufferDecoratedKey(getToken(key), key);
|
||||
}
|
||||
|
||||
public Token midpoint(Token left, Token right)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.LongType;
|
||||
|
|
@ -46,7 +47,7 @@ public class Murmur3Partitioner extends AbstractPartitioner<LongToken>
|
|||
|
||||
public DecoratedKey decorateKey(ByteBuffer key)
|
||||
{
|
||||
return new DecoratedKey(getToken(key), key);
|
||||
return new BufferDecoratedKey(getToken(key), key);
|
||||
}
|
||||
|
||||
public Token midpoint(Token lToken, Token rToken)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.nio.charset.CharacterCodingException;
|
|||
import java.util.*;
|
||||
|
||||
import org.apache.cassandra.config.*;
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
|
|
@ -44,7 +45,7 @@ public class OrderPreservingPartitioner extends AbstractPartitioner<StringToken>
|
|||
|
||||
public DecoratedKey decorateKey(ByteBuffer key)
|
||||
{
|
||||
return new DecoratedKey(getToken(key), key);
|
||||
return new BufferDecoratedKey(getToken(key), key);
|
||||
}
|
||||
|
||||
public StringToken midpoint(Token ltoken, Token rtoken)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.math.BigInteger;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
|
|
@ -45,7 +46,7 @@ public class RandomPartitioner extends AbstractPartitioner<BigIntegerToken>
|
|||
|
||||
public DecoratedKey decorateKey(ByteBuffer key)
|
||||
{
|
||||
return new DecoratedKey(getToken(key), key);
|
||||
return new BufferDecoratedKey(getToken(key), key);
|
||||
}
|
||||
|
||||
public Token midpoint(Token ltoken, Token rtoken)
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ public abstract class Token<T> implements RingPosition<Token<T>>, Serializable
|
|||
return (R)maxKeyBound();
|
||||
}
|
||||
|
||||
public static class KeyBound extends RowPosition
|
||||
public static class KeyBound implements RowPosition
|
||||
{
|
||||
private final Token token;
|
||||
public final boolean isMinimumBound;
|
||||
|
|
@ -209,6 +209,11 @@ public abstract class Token<T> implements RingPosition<Token<T>>, Serializable
|
|||
return getToken().isMinimum(partitioner);
|
||||
}
|
||||
|
||||
public boolean isMinimum()
|
||||
{
|
||||
return isMinimum(StorageService.getPartitioner());
|
||||
}
|
||||
|
||||
public RowPosition.Kind kind()
|
||||
{
|
||||
return isMinimumBound ? RowPosition.Kind.MIN_BOUND : RowPosition.Kind.MAX_BOUND;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.*;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import org.apache.cassandra.db.BufferCell;
|
||||
import org.apache.cassandra.db.Cell;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -304,14 +305,14 @@ public class ColumnFamilyRecordReader extends RecordReader<ByteBuffer, SortedMap
|
|||
|
||||
protected Cell unthriftifySimple(org.apache.cassandra.thrift.Column column)
|
||||
{
|
||||
return new Cell(comparator.cellFromByteBuffer(column.name), column.value, column.timestamp);
|
||||
return new BufferCell(comparator.cellFromByteBuffer(column.name), column.value, column.timestamp);
|
||||
}
|
||||
|
||||
private Cell unthriftifyCounter(CounterColumn column)
|
||||
{
|
||||
//CounterColumns read the counterID from the System keyspace, so need the StorageService running and access
|
||||
//to cassandra.yaml. To avoid a Hadoop needing access to yaml return a regular Cell.
|
||||
return new Cell(comparator.cellFromByteBuffer(column.name), ByteBufferUtil.bytes(column.value), 0);
|
||||
return new BufferCell(comparator.cellFromByteBuffer(column.name), ByteBufferUtil.bytes(column.value), 0);
|
||||
}
|
||||
|
||||
private List<Cell> unthriftifySuperCounter(CounterSuperColumn super_column)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.*;
|
|||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.db.BufferCell;
|
||||
import org.apache.cassandra.db.composites.CellNames;
|
||||
import org.apache.cassandra.db.Cell;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
|
|
@ -112,7 +113,7 @@ public class CqlStorage extends AbstractCassandraStorage
|
|||
ByteBuffer columnValue = columns.get(ByteBufferUtil.string(cdef.name.duplicate()));
|
||||
if (columnValue != null)
|
||||
{
|
||||
Cell cell = new Cell(CellNames.simpleDense(cdef.name), columnValue);
|
||||
Cell cell = new BufferCell(CellNames.simpleDense(cdef.name), columnValue);
|
||||
AbstractType<?> validator = getValidatorMap(cfDef).get(cdef.name);
|
||||
setTupleValue(tuple, i, cqlColumnToObj(cell, cfDef), validator);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ public abstract class AbstractSSTableSimpleWriter
|
|||
*/
|
||||
public void addColumn(ByteBuffer name, ByteBuffer value, long timestamp)
|
||||
{
|
||||
addColumn(new Cell(metadata.comparator.cellFromByteBuffer(name), value, timestamp));
|
||||
addColumn(new BufferCell(metadata.comparator.cellFromByteBuffer(name), value, timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -146,7 +146,7 @@ public abstract class AbstractSSTableSimpleWriter
|
|||
*/
|
||||
public void addExpiringColumn(ByteBuffer name, ByteBuffer value, long timestamp, int ttl, long expirationTimestampMS)
|
||||
{
|
||||
addColumn(new ExpiringCell(metadata.comparator.cellFromByteBuffer(name), value, timestamp, ttl, (int)(expirationTimestampMS / 1000)));
|
||||
addColumn(new BufferExpiringCell(metadata.comparator.cellFromByteBuffer(name), value, timestamp, ttl, (int)(expirationTimestampMS / 1000)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -156,9 +156,9 @@ public abstract class AbstractSSTableSimpleWriter
|
|||
*/
|
||||
public void addCounterColumn(ByteBuffer name, long value)
|
||||
{
|
||||
addColumn(new CounterCell(metadata.comparator.cellFromByteBuffer(name),
|
||||
CounterContext.instance().createGlobal(counterid, 1L, value),
|
||||
System.currentTimeMillis()));
|
||||
addColumn(new BufferCounterCell(metadata.comparator.cellFromByteBuffer(name),
|
||||
CounterContext.instance().createGlobal(counterid, 1L, value),
|
||||
System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ public class CQLSSTableWriter
|
|||
|
||||
for (ByteBuffer key: keys)
|
||||
{
|
||||
if (writer.currentKey() == null || !key.equals(writer.currentKey().key))
|
||||
if (writer.currentKey() == null || !key.equals(writer.currentKey().getKey()))
|
||||
writer.newRow(key);
|
||||
insert.addUpdateForKey(writer.currentColumnFamily(), key, clusteringPrefix, params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.apache.cassandra.db.TypeSizes;
|
|||
import org.apache.cassandra.dht.IPartitioner;
|
||||
|
||||
import static org.apache.cassandra.io.sstable.Downsampling.BASE_SAMPLING_LEVEL;
|
||||
import static org.apache.cassandra.io.sstable.SSTable.getMinimalKey;
|
||||
|
||||
public class IndexSummaryBuilder
|
||||
{
|
||||
|
|
@ -109,8 +110,8 @@ public class IndexSummaryBuilder
|
|||
|
||||
if (!shouldSkip)
|
||||
{
|
||||
keys.add(decoratedKey);
|
||||
offheapSize += decoratedKey.key.remaining();
|
||||
keys.add(getMinimalKey(decoratedKey));
|
||||
offheapSize += decoratedKey.getKey().remaining();
|
||||
positions.add(indexPosition);
|
||||
offheapSize += TypeSizes.NATIVE.sizeof(indexPosition);
|
||||
}
|
||||
|
|
@ -143,7 +144,7 @@ public class IndexSummaryBuilder
|
|||
long offheapSize = this.offheapSize;
|
||||
if (length < keys.size())
|
||||
for (int i = length ; i < keys.size() ; i++)
|
||||
offheapSize -= keys.get(i).key.remaining() + TypeSizes.NATIVE.sizeof(positions.get(i));
|
||||
offheapSize -= keys.get(i).getKey().remaining() + TypeSizes.NATIVE.sizeof(positions.get(i));
|
||||
|
||||
// first we write out the position in the *summary* for each key in the summary,
|
||||
// then we write out (key, actual index position) pairs
|
||||
|
|
@ -157,7 +158,7 @@ public class IndexSummaryBuilder
|
|||
idxPosition += TypeSizes.NATIVE.sizeof(keyPosition);
|
||||
|
||||
// write the key
|
||||
ByteBuffer keyBytes = keys.get(i).key;
|
||||
ByteBuffer keyBytes = keys.get(i).getKey();
|
||||
memory.setBytes(keyPosition, keyBytes);
|
||||
keyPosition += keyBytes.remaining();
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.db.BufferDecoratedKey;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.RowIndexEntry;
|
||||
import org.apache.cassandra.dht.IPartitioner;
|
||||
|
|
@ -123,8 +124,8 @@ public abstract class SSTable
|
|||
*/
|
||||
public static DecoratedKey getMinimalKey(DecoratedKey key)
|
||||
{
|
||||
return key.key.position() > 0 || key.key.hasRemaining() || !key.key.hasArray()
|
||||
? new DecoratedKey(key.token, HeapAllocator.instance.clone(key.key))
|
||||
return key.getKey().position() > 0 || key.getKey().hasRemaining() || !key.getKey().hasArray()
|
||||
? new BufferDecoratedKey(key.getToken(), HeapAllocator.instance.clone(key.getKey()))
|
||||
: key;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -791,7 +791,7 @@ public class SSTableReader extends SSTable
|
|||
last = decoratedKey;
|
||||
|
||||
if (recreateBloomFilter)
|
||||
bf.add(decoratedKey.key);
|
||||
bf.add(decoratedKey.getKey());
|
||||
|
||||
// if summary was already read from disk we don't want to re-populate it using primary index
|
||||
if (!summaryLoaded)
|
||||
|
|
@ -879,8 +879,8 @@ public class SSTableReader extends SSTable
|
|||
{
|
||||
oStream = new DataOutputStreamAndChannel(new FileOutputStream(summariesFile));
|
||||
IndexSummary.serializer.serialize(summary, oStream, descriptor.version.hasSamplingLevel);
|
||||
ByteBufferUtil.writeWithLength(first.key, oStream);
|
||||
ByteBufferUtil.writeWithLength(last.key, oStream);
|
||||
ByteBufferUtil.writeWithLength(first.getKey(), oStream);
|
||||
ByteBufferUtil.writeWithLength(last.getKey(), oStream);
|
||||
ibuilder.serializeBounds(oStream);
|
||||
dbuilder.serializeBounds(oStream);
|
||||
}
|
||||
|
|
@ -1309,7 +1309,7 @@ public class SSTableReader extends SSTable
|
|||
|
||||
public void invalidateCacheKey(DecoratedKey key)
|
||||
{
|
||||
KeyCacheKey cacheKey = new KeyCacheKey(metadata.cfId, descriptor, key.key);
|
||||
KeyCacheKey cacheKey = new KeyCacheKey(metadata.cfId, descriptor, key.getKey());
|
||||
keyCache.remove(cacheKey);
|
||||
}
|
||||
|
||||
|
|
@ -1324,14 +1324,14 @@ public class SSTableReader extends SSTable
|
|||
return;
|
||||
}
|
||||
|
||||
KeyCacheKey cacheKey = new KeyCacheKey(metadata.cfId, descriptor, key.key);
|
||||
KeyCacheKey cacheKey = new KeyCacheKey(metadata.cfId, descriptor, key.getKey());
|
||||
logger.trace("Adding cache entry for {} -> {}", cacheKey, info);
|
||||
keyCache.put(cacheKey, info);
|
||||
}
|
||||
|
||||
public RowIndexEntry getCachedPosition(DecoratedKey key, boolean updateStats)
|
||||
{
|
||||
return getCachedPosition(new KeyCacheKey(metadata.cfId, descriptor, key.key), updateStats);
|
||||
return getCachedPosition(new KeyCacheKey(metadata.cfId, descriptor, key.getKey()), updateStats);
|
||||
}
|
||||
|
||||
private RowIndexEntry getCachedPosition(KeyCacheKey unifiedKey, boolean updateStats)
|
||||
|
|
@ -1375,7 +1375,7 @@ public class SSTableReader extends SSTable
|
|||
if (op == Operator.EQ)
|
||||
{
|
||||
assert key instanceof DecoratedKey; // EQ only make sense if the key is a valid row key
|
||||
if (!bf.isPresent(((DecoratedKey)key).key))
|
||||
if (!bf.isPresent(((DecoratedKey)key).getKey()))
|
||||
{
|
||||
Tracing.trace("Bloom filter allows skipping sstable {}", descriptor.generation);
|
||||
return null;
|
||||
|
|
@ -1386,7 +1386,7 @@ public class SSTableReader extends SSTable
|
|||
if ((op == Operator.EQ || op == Operator.GE) && (key instanceof DecoratedKey))
|
||||
{
|
||||
DecoratedKey decoratedKey = (DecoratedKey)key;
|
||||
KeyCacheKey cacheKey = new KeyCacheKey(metadata.cfId, descriptor, decoratedKey.key);
|
||||
KeyCacheKey cacheKey = new KeyCacheKey(metadata.cfId, descriptor, decoratedKey.getKey());
|
||||
RowIndexEntry cachedPosition = getCachedPosition(cacheKey, updateCacheAndStats);
|
||||
if (cachedPosition != null)
|
||||
{
|
||||
|
|
@ -1442,7 +1442,7 @@ public class SSTableReader extends SSTable
|
|||
// Compare raw keys if possible for performance, otherwise compare decorated keys.
|
||||
if (op == Operator.EQ)
|
||||
{
|
||||
opSatisfied = exactMatch = indexKey.equals(((DecoratedKey) key).key);
|
||||
opSatisfied = exactMatch = indexKey.equals(((DecoratedKey) key).getKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ public class SSTableScanner implements ICompactionScanner
|
|||
}
|
||||
}
|
||||
|
||||
if (dataRange == null || dataRange.selectsFullRowFor(currentKey.key))
|
||||
if (dataRange == null || dataRange.selectsFullRowFor(currentKey.getKey()))
|
||||
{
|
||||
dfile.seek(currentEntry.position);
|
||||
ByteBufferUtil.readWithShortLength(dfile); // key
|
||||
|
|
@ -269,7 +269,7 @@ public class SSTableScanner implements ICompactionScanner
|
|||
{
|
||||
public OnDiskAtomIterator create()
|
||||
{
|
||||
return dataRange.columnFilter(currentKey.key).getSSTableColumnIterator(sstable, dfile, currentKey, currentEntry);
|
||||
return dataRange.columnFilter(currentKey.getKey()).getSSTableColumnIterator(sstable, dfile, currentKey, currentEntry);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public class SSTableSimpleUnsortedWriter extends AbstractSSTableSimpleWriter
|
|||
|
||||
protected void writeRow(DecoratedKey key, ColumnFamily columnFamily) throws IOException
|
||||
{
|
||||
currentSize += key.key.remaining() + ColumnFamily.serializer.serializedSize(columnFamily, MessagingService.current_version) * 1.2;
|
||||
currentSize += key.getKey().remaining() + ColumnFamily.serializer.serializedSize(columnFamily, MessagingService.current_version) * 1.2;
|
||||
|
||||
if (currentSize > bufferSize)
|
||||
sync();
|
||||
|
|
@ -118,7 +118,7 @@ public class SSTableSimpleUnsortedWriter extends AbstractSSTableSimpleWriter
|
|||
{
|
||||
// We will reuse a CF that we have counted already. But because it will be easier to add the full size
|
||||
// of the CF in the next writeRow call than to find out the delta, we just remove the size until that next call
|
||||
currentSize -= currentKey.key.remaining() + ColumnFamily.serializer.serializedSize(previous, MessagingService.current_version) * 1.2;
|
||||
currentSize -= currentKey.getKey().remaining() + ColumnFamily.serializer.serializedSize(previous, MessagingService.current_version) * 1.2;
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue