You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by be...@apache.org on 2015/08/12 23:53:43 UTC
[4/9] cassandra git commit: Remove ArrayBackedPartition and hierarchy
Remove ArrayBackedPartition and hierarchy
Introduces AbstractBTreePartition to share code between
ImmutableBTreePartition and AtomicBTreePartition,
eliminating much code duplication between the two hierarchies.
patch by benedict; reviewed by ariel for CASSANDRA-9932
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/e51f83b6
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/e51f83b6
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/e51f83b6
Branch: refs/heads/cassandra-3.0
Commit: e51f83b60edf1f9ee12ef6a3083d3acbf85805f7
Parents: a186ac6
Author: Benedict Elliott Smith <be...@apache.org>
Authored: Wed Jul 29 15:14:01 2015 +0100
Committer: Benedict Elliott Smith <be...@apache.org>
Committed: Wed Aug 12 23:48:30 2015 +0200
----------------------------------------------------------------------
.../apache/cassandra/cql3/UpdateParameters.java | 4 +-
src/java/org/apache/cassandra/db/Columns.java | 4 +-
.../cassandra/db/HintedHandOffManager.java | 4 +-
.../org/apache/cassandra/db/LegacyLayout.java | 7 +-
.../org/apache/cassandra/db/ReadResponse.java | 12 +-
.../apache/cassandra/db/RowUpdateBuilder.java | 7 +-
.../db/SinglePartitionNamesCommand.java | 8 +-
.../db/SinglePartitionReadCommand.java | 2 +-
.../cassandra/db/UnfilteredDeserializer.java | 2 +-
.../columniterator/SSTableReversedIterator.java | 44 +-
.../cassandra/db/compaction/Scrubber.java | 2 +-
.../apache/cassandra/db/filter/RowFilter.java | 2 +-
.../AbstractSimplePerColumnSecondaryIndex.java | 4 +-
.../db/index/composites/CompositesIndex.java | 2 +-
.../cassandra/db/index/keys/KeysSearcher.java | 2 +-
.../db/partitions/AbstractBTreePartition.java | 403 +++++++++++++
.../AbstractThreadUnsafePartition.java | 399 ------------
.../partitions/ArrayBackedCachedPartition.java | 294 ---------
.../db/partitions/ArrayBackedPartition.java | 114 ----
.../db/partitions/AtomicBTreePartition.java | 240 +-------
.../db/partitions/CachedBTreePartition.java | 249 ++++++++
.../db/partitions/CachedPartition.java | 10 +-
.../db/partitions/FilteredPartition.java | 89 +--
.../db/partitions/ImmutableBTreePartition.java | 93 +++
.../db/partitions/PartitionUpdate.java | 311 +++-------
.../cassandra/db/rows/BTreeBackedRow.java | 602 -------------------
.../org/apache/cassandra/db/rows/BTreeRow.java | 602 +++++++++++++++++++
.../apache/cassandra/db/rows/EncodingStats.java | 11 +
src/java/org/apache/cassandra/db/rows/Row.java | 2 +-
.../apache/cassandra/db/rows/RowIterators.java | 22 +-
src/java/org/apache/cassandra/db/rows/Rows.java | 4 +-
.../rows/UnfilteredRowIteratorSerializer.java | 2 +-
.../db/rows/UnfilteredRowIterators.java | 16 +-
.../cassandra/db/rows/UnfilteredSerializer.java | 2 +-
.../cassandra/db/view/MaterializedView.java | 18 +-
.../apache/cassandra/db/view/TemporalRow.java | 4 +-
.../io/sstable/SSTableSimpleIterator.java | 2 +-
.../apache/cassandra/service/CacheService.java | 6 +-
.../apache/cassandra/service/DataResolver.java | 2 +-
.../cassandra/thrift/CassandraServer.java | 8 +-
.../cassandra/thrift/ThriftResultsMerger.java | 4 +-
.../cassandra/triggers/TriggerExecutor.java | 4 +-
.../org/apache/cassandra/utils/btree/BTree.java | 89 ++-
.../cassandra/utils/btree/UpdateFunction.java | 27 +-
.../utils/memory/AbstractAllocator.java | 10 +-
.../utils/memory/MemtableBufferAllocator.java | 3 +-
.../apache/cassandra/utils/LongBTreeTest.java | 151 +++--
test/unit/org/apache/cassandra/Util.java | 10 +-
.../cassandra/cache/CacheProviderTest.java | 18 +-
.../org/apache/cassandra/cql3/CQLTester.java | 2 +-
.../cassandra/db/BatchlogManagerTest.java | 21 +-
.../cassandra/db/DeletePartitionTest.java | 2 +-
.../org/apache/cassandra/db/PartitionTest.java | 10 +-
.../apache/cassandra/db/RangeTombstoneTest.java | 4 +-
.../apache/cassandra/db/RowIndexEntryTest.java | 2 +-
test/unit/org/apache/cassandra/db/RowTest.java | 4 +-
.../db/compaction/CompactionsPurgeTest.java | 10 +-
.../cassandra/db/marshal/CompositeTypeTest.java | 4 +-
.../db/marshal/DynamicCompositeTypeTest.java | 6 +-
.../rows/RowAndDeletionMergeIteratorTest.java | 2 +-
.../rows/UnfilteredRowIteratorsMergeTest.java | 2 +-
.../io/sstable/SSTableRewriterTest.java | 4 +-
.../streaming/StreamingTransferTest.java | 4 +-
.../cassandra/triggers/TriggerExecutorTest.java | 2 +-
.../org/apache/cassandra/utils/BTreeTest.java | 118 +++-
65 files changed, 1943 insertions(+), 2181 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/cql3/UpdateParameters.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/UpdateParameters.java b/src/java/org/apache/cassandra/cql3/UpdateParameters.java
index 519eb4b..1c1dd43 100644
--- a/src/java/org/apache/cassandra/cql3/UpdateParameters.java
+++ b/src/java/org/apache/cassandra/cql3/UpdateParameters.java
@@ -120,13 +120,13 @@ public class UpdateParameters
if (clustering == Clustering.STATIC_CLUSTERING)
{
if (staticBuilder == null)
- staticBuilder = BTreeBackedRow.unsortedBuilder(updatedColumns.statics, nowInSec);
+ staticBuilder = BTreeRow.unsortedBuilder(updatedColumns.statics, nowInSec);
builder = staticBuilder;
}
else
{
if (regularBuilder == null)
- regularBuilder = BTreeBackedRow.unsortedBuilder(updatedColumns.regulars, nowInSec);
+ regularBuilder = BTreeRow.unsortedBuilder(updatedColumns.regulars, nowInSec);
builder = regularBuilder;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/Columns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/Columns.java b/src/java/org/apache/cassandra/db/Columns.java
index c584b4c..0b29830 100644
--- a/src/java/org/apache/cassandra/db/Columns.java
+++ b/src/java/org/apache/cassandra/db/Columns.java
@@ -38,6 +38,7 @@ import org.apache.cassandra.utils.ByteBufferUtil;
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.UpdateFunction;
/**
* An immutable and sorted list of (non-PK) columns for a given table.
@@ -243,7 +244,8 @@ public class Columns implements Iterable<ColumnDefinition>
if (this == NONE)
return other;
- Object[] tree = BTree.<ColumnDefinition>merge(this.columns, other.columns, Comparator.naturalOrder());
+ Object[] tree = BTree.<ColumnDefinition>merge(this.columns, other.columns, Comparator.naturalOrder(),
+ UpdateFunction.noOp());
if (tree == this.columns)
return this;
if (tree == other.columns)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/HintedHandOffManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/HintedHandOffManager.java b/src/java/org/apache/cassandra/db/HintedHandOffManager.java
index 4656d41..8bea2e8 100644
--- a/src/java/org/apache/cassandra/db/HintedHandOffManager.java
+++ b/src/java/org/apache/cassandra/db/HintedHandOffManager.java
@@ -150,7 +150,7 @@ public class HintedHandOffManager implements HintedHandOffManagerMBean
ByteBuffer value = ByteBuffer.wrap(FBUtilities.serialize(mutation, Mutation.serializer, MessagingService.current_version));
Cell cell = BufferCell.expiring(hintColumn, now, ttl, FBUtilities.nowInSeconds(), value);
- return new Mutation(PartitionUpdate.singleRowUpdate(SystemKeyspace.Hints, key, BTreeBackedRow.singleCellRow(clustering, cell)));
+ return new Mutation(PartitionUpdate.singleRowUpdate(SystemKeyspace.Hints, key, BTreeRow.singleCellRow(clustering, cell)));
}
/*
@@ -193,7 +193,7 @@ public class HintedHandOffManager implements HintedHandOffManagerMBean
private static void deleteHint(ByteBuffer tokenBytes, Clustering clustering, long timestamp)
{
Cell cell = BufferCell.tombstone(hintColumn, timestamp, FBUtilities.nowInSeconds());
- PartitionUpdate upd = PartitionUpdate.singleRowUpdate(SystemKeyspace.Hints, tokenBytes, BTreeBackedRow.singleCellRow(clustering, cell));
+ PartitionUpdate upd = PartitionUpdate.singleRowUpdate(SystemKeyspace.Hints, tokenBytes, BTreeRow.singleCellRow(clustering, cell));
new Mutation(upd).applyUnsafe(); // don't bother with commitlog since we're going to flush as soon as we're done with delivery
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/LegacyLayout.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/LegacyLayout.java b/src/java/org/apache/cassandra/db/LegacyLayout.java
index fb896f5..3900d96 100644
--- a/src/java/org/apache/cassandra/db/LegacyLayout.java
+++ b/src/java/org/apache/cassandra/db/LegacyLayout.java
@@ -319,7 +319,7 @@ public abstract class LegacyLayout
{
// we need to extract the range tombstone so materialize the partition. Since this is
// used for the on-wire format, this is not worst than it used to be.
- final ArrayBackedPartition partition = ArrayBackedPartition.create(iterator);
+ final ImmutableBTreePartition partition = ImmutableBTreePartition.create(iterator);
DeletionInfo info = partition.deletionInfo();
Pair<LegacyRangeTombstoneList, Iterator<LegacyCell>> pair = fromRowIterator(partition.metadata(), partition.iterator(), partition.staticRow());
@@ -538,7 +538,7 @@ public abstract class LegacyLayout
for (ColumnDefinition column : statics)
columnsToFetch.add(column.name.bytes);
- Row.Builder builder = BTreeBackedRow.unsortedBuilder(statics, FBUtilities.nowInSeconds());
+ Row.Builder builder = BTreeRow.unsortedBuilder(statics, FBUtilities.nowInSeconds());
builder.newRow(Clustering.STATIC_CLUSTERING);
boolean foundOne = false;
@@ -1058,8 +1058,7 @@ public abstract class LegacyLayout
// We cannot use a sorted builder because we don't have exactly the same ordering in 3.0 and pre-3.0. More precisely, within a row, we
// store all simple columns before the complex ones in 3.0, which we use to sort everything sorted by the column name before. Note however
// that the unsorted builder won't have to reconcile cells, so the exact value we pass for nowInSec doesn't matter.
- this.builder = BTreeBackedRow.unsortedBuilder(isStatic ? metadata.partitionColumns().statics : metadata.partitionColumns().regulars, FBUtilities.nowInSeconds());
-
+ this.builder = BTreeRow.unsortedBuilder(isStatic ? metadata.partitionColumns().statics : metadata.partitionColumns().regulars, FBUtilities.nowInSeconds());
}
public static CellGrouper staticGrouper(CFMetaData metadata, SerializationHelper helper)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/ReadResponse.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ReadResponse.java b/src/java/org/apache/cassandra/db/ReadResponse.java
index a66cb6a..5f40210 100644
--- a/src/java/org/apache/cassandra/db/ReadResponse.java
+++ b/src/java/org/apache/cassandra/db/ReadResponse.java
@@ -214,9 +214,9 @@ public abstract class ReadResponse
*/
private static class LegacyRemoteDataResponse extends ReadResponse
{
- private final List<ArrayBackedPartition> partitions;
+ private final List<ImmutableBTreePartition> partitions;
- private LegacyRemoteDataResponse(List<ArrayBackedPartition> partitions)
+ private LegacyRemoteDataResponse(List<ImmutableBTreePartition> partitions)
{
super(null); // we never serialize LegacyRemoteDataResponses, so we don't care about the metadata
this.partitions = partitions;
@@ -245,7 +245,7 @@ public abstract class ReadResponse
public UnfilteredRowIterator next()
{
- ArrayBackedPartition partition = partitions.get(idx++);
+ ImmutableBTreePartition partition = partitions.get(idx++);
ClusteringIndexFilter filter = command.clusteringIndexFilter(partition.partitionKey());
@@ -340,7 +340,7 @@ public abstract class ReadResponse
try
{
- return new LegacyRemoteDataResponse(Collections.singletonList(ArrayBackedPartition.create(rowIterator)));
+ return new LegacyRemoteDataResponse(Collections.singletonList(ImmutableBTreePartition.create(rowIterator)));
}
finally
{
@@ -440,13 +440,13 @@ public abstract class ReadResponse
{
// Contrarily to serialize, we have to read the number of serialized partitions here.
int partitionCount = in.readInt();
- ArrayList<ArrayBackedPartition> partitions = new ArrayList<>(partitionCount);
+ ArrayList<ImmutableBTreePartition> partitions = new ArrayList<>(partitionCount);
for (int i = 0; i < partitionCount; i++)
{
ByteBuffer key = ByteBufferUtil.readWithShortLength(in);
try (UnfilteredRowIterator partition = LegacyLayout.deserializeLegacyPartition(in, version, SerializationHelper.Flag.FROM_REMOTE, key))
{
- partitions.add(ArrayBackedPartition.create(partition));
+ partitions.add(ImmutableBTreePartition.create(partition));
}
}
return new LegacyRemoteDataResponse(partitions);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/RowUpdateBuilder.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/RowUpdateBuilder.java b/src/java/org/apache/cassandra/db/RowUpdateBuilder.java
index 372ba04..f1d17b6 100644
--- a/src/java/org/apache/cassandra/db/RowUpdateBuilder.java
+++ b/src/java/org/apache/cassandra/db/RowUpdateBuilder.java
@@ -31,7 +31,6 @@ import org.apache.cassandra.db.partitions.*;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.db.marshal.MapType;
-import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.*;
/**
@@ -80,7 +79,7 @@ public class RowUpdateBuilder
assert staticBuilder == null : "Cannot update both static and non-static columns with the same RowUpdateBuilder object";
assert regularBuilder == null : "Cannot add the clustering twice to the same row";
- regularBuilder = BTreeBackedRow.unsortedBuilder(update.columns().regulars, FBUtilities.nowInSeconds());
+ regularBuilder = BTreeRow.unsortedBuilder(update.columns().regulars, FBUtilities.nowInSeconds());
regularBuilder.newRow(clustering);
// If a CQL table, add the "row marker"
@@ -105,7 +104,7 @@ public class RowUpdateBuilder
assert regularBuilder == null : "Cannot update both static and non-static columns with the same RowUpdateBuilder object";
if (staticBuilder == null)
{
- staticBuilder = BTreeBackedRow.unsortedBuilder(update.columns().statics, FBUtilities.nowInSeconds());
+ staticBuilder = BTreeRow.unsortedBuilder(update.columns().statics, FBUtilities.nowInSeconds());
staticBuilder.newRow(Clustering.STATIC_CLUSTERING);
}
return staticBuilder;
@@ -186,7 +185,7 @@ public class RowUpdateBuilder
assert clusteringValues.length == update.metadata().comparator.size() || (clusteringValues.length == 0 && !update.columns().statics.isEmpty());
boolean isStatic = clusteringValues.length != update.metadata().comparator.size();
- Row.Builder builder = BTreeBackedRow.sortedBuilder(isStatic ? update.columns().statics : update.columns().regulars);
+ Row.Builder builder = BTreeRow.sortedBuilder(isStatic ? update.columns().statics : update.columns().regulars);
if (isStatic)
builder.newRow(Clustering.STATIC_CLUSTERING);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/SinglePartitionNamesCommand.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SinglePartitionNamesCommand.java b/src/java/org/apache/cassandra/db/SinglePartitionNamesCommand.java
index 518e299..f40da5b 100644
--- a/src/java/org/apache/cassandra/db/SinglePartitionNamesCommand.java
+++ b/src/java/org/apache/cassandra/db/SinglePartitionNamesCommand.java
@@ -96,7 +96,7 @@ public class SinglePartitionNamesCommand extends SinglePartitionReadCommand<Clus
Tracing.trace("Acquiring sstable references");
ColumnFamilyStore.ViewFragment view = cfs.select(View.select(SSTableSet.LIVE, partitionKey()));
- ArrayBackedPartition result = null;
+ ImmutableBTreePartition result = null;
ClusteringIndexNamesFilter filter = clusteringIndexFilter();
Tracing.trace("Merging memtable contents");
@@ -182,18 +182,18 @@ public class SinglePartitionNamesCommand extends SinglePartitionReadCommand<Clus
return result.unfilteredIterator(columnFilter(), Slices.ALL, clusteringIndexFilter().isReversed());
}
- private ArrayBackedPartition add(UnfilteredRowIterator iter, ArrayBackedPartition result, boolean isRepaired)
+ private ImmutableBTreePartition add(UnfilteredRowIterator iter, ImmutableBTreePartition result, boolean isRepaired)
{
if (!isRepaired)
oldestUnrepairedDeletionTime = Math.min(oldestUnrepairedDeletionTime, iter.stats().minLocalDeletionTime);
int maxRows = Math.max(clusteringIndexFilter().requestedRows().size(), 1);
if (result == null)
- return ArrayBackedPartition.create(iter, maxRows);
+ return ImmutableBTreePartition.create(iter, maxRows);
try (UnfilteredRowIterator merged = UnfilteredRowIterators.merge(Arrays.asList(iter, result.unfilteredIterator(columnFilter(), Slices.ALL, false)), nowInSec()))
{
- return ArrayBackedPartition.create(merged, maxRows);
+ return ImmutableBTreePartition.create(merged, maxRows);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java b/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
index 1b688c9..d9b0e2b 100644
--- a/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
+++ b/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
@@ -317,7 +317,7 @@ public abstract class SinglePartitionReadCommand<F extends ClusteringIndexFilter
try
{
// We want to cache only rowsToCache rows
- CachedPartition toCache = ArrayBackedCachedPartition.create(DataLimits.cqlLimits(rowsToCache).filter(iter, nowInSec()), nowInSec());
+ CachedPartition toCache = CachedBTreePartition.create(DataLimits.cqlLimits(rowsToCache).filter(iter, nowInSec()), nowInSec());
if (sentinelSuccess && !toCache.isEmpty())
{
Tracing.trace("Caching {} rows", toCache.rowCount());
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java b/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java
index c00597a..2f75f34 100644
--- a/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java
+++ b/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java
@@ -121,7 +121,7 @@ public abstract class UnfilteredDeserializer
super(metadata, in, helper);
this.header = header;
this.clusteringDeserializer = new ClusteringPrefix.Deserializer(metadata.comparator, in, header);
- this.builder = BTreeBackedRow.sortedBuilder(helper.fetchedRegularColumns(header));
+ this.builder = BTreeRow.sortedBuilder(helper.fetchedRegularColumns(header));
}
public boolean hasNext() throws IOException
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java b/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java
index f4acd6f..4d2e294 100644
--- a/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java
+++ b/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java
@@ -23,10 +23,11 @@ import java.util.*;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.filter.ColumnFilter;
+import org.apache.cassandra.db.partitions.ImmutableBTreePartition;
import org.apache.cassandra.db.rows.*;
-import org.apache.cassandra.db.partitions.AbstractThreadUnsafePartition;
import org.apache.cassandra.io.sstable.format.SSTableReader;
import org.apache.cassandra.io.util.FileDataInput;
+import org.apache.cassandra.utils.btree.BTree;
/**
* A Cell Iterator in reversed clustering order over SSTable
@@ -123,7 +124,7 @@ public class SSTableReversedIterator extends AbstractSSTableIterator
protected void setIterator(Slice slice)
{
assert buffer != null;
- iterator = buffer.unfilteredIterator(columns, Slices.with(metadata().comparator, slice), true);
+ iterator = buffer.built.unfilteredIterator(columns, Slices.with(metadata().comparator, slice), true);
}
protected boolean hasNextInternal() throws IOException
@@ -303,56 +304,49 @@ public class SSTableReversedIterator extends AbstractSSTableIterator
}
}
- private class ReusablePartitionData extends AbstractThreadUnsafePartition
+ private class ReusablePartitionData
{
+ private final CFMetaData metadata;
+ private final DecoratedKey partitionKey;
+ private final PartitionColumns columns;
+
private MutableDeletionInfo.Builder deletionBuilder;
private MutableDeletionInfo deletionInfo;
+ private BTree.Builder<Row> rowBuilder;
+ private ImmutableBTreePartition built;
private ReusablePartitionData(CFMetaData metadata,
DecoratedKey partitionKey,
PartitionColumns columns,
int initialRowCapacity)
{
- super(metadata, partitionKey, columns, new ArrayList<>(initialRowCapacity));
- }
-
- public DeletionInfo deletionInfo()
- {
- return deletionInfo;
+ this.metadata = metadata;
+ this.partitionKey = partitionKey;
+ this.columns = columns;
+ this.rowBuilder = BTree.builder(metadata.comparator, initialRowCapacity);
}
- protected boolean canHaveShadowedData()
- {
- return false;
- }
-
- public Row staticRow()
- {
- return Rows.EMPTY_STATIC_ROW; // we don't actually use that
- }
-
- public EncodingStats stats()
- {
- return EncodingStats.NO_STATS; // we don't actually use that
- }
public void add(Unfiltered unfiltered)
{
if (unfiltered.isRow())
- rows.add((Row)unfiltered);
+ rowBuilder.add((Row)unfiltered);
else
deletionBuilder.add((RangeTombstoneMarker)unfiltered);
}
public void reset()
{
- rows.clear();
+ built = null;
+ rowBuilder.reuse();
deletionBuilder = MutableDeletionInfo.builder(partitionLevelDeletion, metadata().comparator, false);
}
public void build()
{
deletionInfo = deletionBuilder.build();
+ built = new ImmutableBTreePartition(metadata, partitionKey, columns, Rows.EMPTY_STATIC_ROW, rowBuilder.build(),
+ DeletionInfo.LIVE, EncodingStats.NO_STATS);
deletionBuilder = null;
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/compaction/Scrubber.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/compaction/Scrubber.java b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
index f9e9e71..747b956 100644
--- a/src/java/org/apache/cassandra/db/compaction/Scrubber.java
+++ b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
@@ -385,7 +385,7 @@ public class Scrubber implements Closeable
{
// TODO bitch if the row is too large? if it is there's not much we can do ...
outputHandler.warn(String.format("Out of order row detected (%s found after %s)", key, prevKey));
- outOfOrder.add(ArrayBackedPartition.create(iterator));
+ outOfOrder.add(ImmutableBTreePartition.create(iterator));
}
private void throwIfFatal(Throwable th)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/filter/RowFilter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java b/src/java/org/apache/cassandra/db/filter/RowFilter.java
index 881e154..a5212aa 100644
--- a/src/java/org/apache/cassandra/db/filter/RowFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java
@@ -221,7 +221,7 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
// satisfied, which forces us to materialize the result (in theory we could materialize only
// what we need which might or might not be everything, but we keep it simple since in practice
// it's not worth that it has ever been).
- ArrayBackedPartition result = ArrayBackedPartition.create(iter);
+ ImmutableBTreePartition result = ImmutableBTreePartition.create(iter);
// The partition needs to have a row for every expression, and the expression needs to be valid.
for (Expression expr : expressions)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/index/AbstractSimplePerColumnSecondaryIndex.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/index/AbstractSimplePerColumnSecondaryIndex.java b/src/java/org/apache/cassandra/db/index/AbstractSimplePerColumnSecondaryIndex.java
index b5ed7f6..eccd7e2 100644
--- a/src/java/org/apache/cassandra/db/index/AbstractSimplePerColumnSecondaryIndex.java
+++ b/src/java/org/apache/cassandra/db/index/AbstractSimplePerColumnSecondaryIndex.java
@@ -116,7 +116,7 @@ public abstract class AbstractSimplePerColumnSecondaryIndex extends PerColumnSec
{
DecoratedKey valueKey = getIndexKeyFor(getIndexedValue(rowKey, clustering, cellValue, path));
- Row row = BTreeBackedRow.emptyDeletedRow(makeIndexClustering(rowKey, clustering, path), deletion);
+ Row row = BTreeRow.emptyDeletedRow(makeIndexClustering(rowKey, clustering, path), deletion);
PartitionUpdate upd = PartitionUpdate.singleRowUpdate(indexCfs.metadata, valueKey, row);
indexCfs.apply(upd, SecondaryIndexManager.nullUpdater, opGroup, null);
@@ -133,7 +133,7 @@ public abstract class AbstractSimplePerColumnSecondaryIndex extends PerColumnSec
{
DecoratedKey valueKey = getIndexKeyFor(getIndexedValue(rowKey, clustering, cell));
- Row row = BTreeBackedRow.noCellLiveRow(makeIndexClustering(rowKey, clustering, cell), info);
+ Row row = BTreeRow.noCellLiveRow(makeIndexClustering(rowKey, clustering, cell), info);
PartitionUpdate upd = PartitionUpdate.singleRowUpdate(indexCfs.metadata, valueKey, row);
if (logger.isDebugEnabled())
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/index/composites/CompositesIndex.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/index/composites/CompositesIndex.java b/src/java/org/apache/cassandra/db/index/composites/CompositesIndex.java
index 29f235c..df45ea2 100644
--- a/src/java/org/apache/cassandra/db/index/composites/CompositesIndex.java
+++ b/src/java/org/apache/cassandra/db/index/composites/CompositesIndex.java
@@ -112,7 +112,7 @@ public abstract class CompositesIndex extends AbstractSimplePerColumnSecondaryIn
public void delete(IndexedEntry entry, OpOrder.Group opGroup, int nowInSec)
{
- Row row = BTreeBackedRow.emptyDeletedRow(entry.indexClustering, new DeletionTime(entry.timestamp, nowInSec));
+ Row row = BTreeRow.emptyDeletedRow(entry.indexClustering, new DeletionTime(entry.timestamp, nowInSec));
PartitionUpdate upd = PartitionUpdate.singleRowUpdate(indexCfs.metadata, entry.indexValue, row);
indexCfs.apply(upd, SecondaryIndexManager.nullUpdater, opGroup, null);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java b/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java
index 53a9b4a..4b70dcf 100644
--- a/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java
+++ b/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java
@@ -142,7 +142,7 @@ public class KeysSearcher extends SecondaryIndexSearcher
{
// The data we got has gone though ThrifResultsMerger, so we're looking for the row whose clustering
// is the indexed name. Ans so we need to materialize the partition.
- ArrayBackedPartition result = ArrayBackedPartition.create(iterator);
+ ImmutableBTreePartition result = ImmutableBTreePartition.create(iterator);
iterator.close();
Row data = result.getRow(new Clustering(index.indexedColumn().name.bytes));
Cell cell = data == null ? null : data.getCell(baseCfs.metadata.compactValueColumn());
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java b/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java
new file mode 100644
index 0000000..41015b0
--- /dev/null
+++ b/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java
@@ -0,0 +1,403 @@
+/*
+* 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.partitions;
+
+import java.util.Iterator;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.filter.ColumnFilter;
+import org.apache.cassandra.db.rows.*;
+import org.apache.cassandra.utils.SearchIterator;
+import org.apache.cassandra.utils.btree.BTree;
+import org.apache.cassandra.utils.btree.BTreeSearchIterator;
+
+import static org.apache.cassandra.utils.btree.BTree.Dir.desc;
+
+public abstract class AbstractBTreePartition implements Partition, Iterable<Row>
+{
+ protected static final Holder EMPTY = new Holder(BTree.empty(), DeletionInfo.LIVE, Rows.EMPTY_STATIC_ROW, EncodingStats.NO_STATS);
+
+ protected final CFMetaData metadata;
+ protected final DecoratedKey partitionKey;
+ protected final PartitionColumns columns;
+ protected abstract Holder holder();
+ protected abstract boolean canHaveShadowedData();
+
+ protected AbstractBTreePartition(CFMetaData metadata, DecoratedKey partitionKey, PartitionColumns columns)
+ {
+ this.metadata = metadata;
+ this.partitionKey = partitionKey;
+ this.columns = columns;
+ }
+
+ protected static final class Holder
+ {
+ final DeletionInfo deletionInfo;
+ // the btree of rows
+ final Object[] tree;
+ final Row staticRow;
+ final EncodingStats stats;
+
+ Holder(Object[] tree, DeletionInfo deletionInfo, Row staticRow, EncodingStats stats)
+ {
+ this.tree = tree;
+ this.deletionInfo = deletionInfo;
+ this.staticRow = staticRow;
+ this.stats = stats;
+ }
+ }
+
+ public DeletionInfo deletionInfo()
+ {
+ return holder().deletionInfo;
+ }
+
+ public Row staticRow()
+ {
+ return holder().staticRow;
+ }
+
+ public boolean isEmpty()
+ {
+ Holder holder = holder();
+ return holder.deletionInfo.isLive() && BTree.isEmpty(holder.tree) && holder.staticRow.isEmpty();
+ }
+
+ public boolean hasRows()
+ {
+ Holder holder = holder();
+ return !BTree.isEmpty(holder.tree);
+ }
+
+ public CFMetaData metadata()
+ {
+ return metadata;
+ }
+
+ public DecoratedKey partitionKey()
+ {
+ return partitionKey;
+ }
+
+ public DeletionTime partitionLevelDeletion()
+ {
+ return holder().deletionInfo.getPartitionDeletion();
+ }
+
+ public PartitionColumns columns()
+ {
+ // We don't really know which columns will be part of the update, so assume it's all of them
+ return metadata.partitionColumns();
+ }
+
+ public EncodingStats stats()
+ {
+ return holder().stats;
+ }
+
+ public Row getRow(Clustering clustering)
+ {
+ Row row = searchIterator(ColumnFilter.selection(columns()), false).next(clustering);
+ // Note that for statics, this will never return null, this will return an empty row. However,
+ // it's more consistent for this method to return null if we don't really have a static row.
+ return row == null || (clustering == Clustering.STATIC_CLUSTERING && row.isEmpty()) ? null : row;
+ }
+
+ private Row staticRow(Holder current, ColumnFilter columns, boolean setActiveDeletionToRow)
+ {
+ DeletionTime partitionDeletion = current.deletionInfo.getPartitionDeletion();
+ if (columns.fetchedColumns().statics.isEmpty() || (current.staticRow.isEmpty() && partitionDeletion.isLive()))
+ return Rows.EMPTY_STATIC_ROW;
+
+ Row row = current.staticRow.filter(columns, partitionDeletion, setActiveDeletionToRow, metadata);
+ return row == null ? Rows.EMPTY_STATIC_ROW : row;
+ }
+
+ public SearchIterator<Clustering, Row> searchIterator(final ColumnFilter columns, final boolean reversed)
+ {
+ // TODO: we could optimize comparison for "NativeRow" à la #6755
+ final Holder current = holder();
+ return new SearchIterator<Clustering, Row>()
+ {
+ private final SearchIterator<Clustering, Row> rawIter = new BTreeSearchIterator<>(current.tree, metadata.comparator, desc(reversed));
+ private final DeletionTime partitionDeletion = current.deletionInfo.getPartitionDeletion();
+
+ public boolean hasNext()
+ {
+ return rawIter.hasNext();
+ }
+
+ public Row next(Clustering clustering)
+ {
+ if (clustering == Clustering.STATIC_CLUSTERING)
+ return staticRow(current, columns, true);
+
+ Row row = rawIter.next(clustering);
+ RangeTombstone rt = current.deletionInfo.rangeCovering(clustering);
+
+ // A search iterator only return a row, so it doesn't allow to directly account for deletion that should apply to to row
+ // (the partition deletion or the deletion of a range tombstone that covers it). So if needs be, reuse the row deletion
+ // to carry the proper deletion on the row.
+ DeletionTime activeDeletion = partitionDeletion;
+ if (rt != null && rt.deletionTime().supersedes(activeDeletion))
+ activeDeletion = rt.deletionTime();
+
+ if (row == null)
+ return activeDeletion.isLive() ? null : BTreeRow.emptyDeletedRow(clustering, activeDeletion);
+
+ return row.filter(columns, activeDeletion, true, metadata);
+ }
+ };
+ }
+
+ public UnfilteredRowIterator unfilteredIterator()
+ {
+ return unfilteredIterator(ColumnFilter.all(metadata()), Slices.ALL, false);
+ }
+
+ public UnfilteredRowIterator unfilteredIterator(ColumnFilter selection, Slices slices, boolean reversed)
+ {
+ return unfilteredIterator(holder(), selection, slices, reversed);
+ }
+
+ public UnfilteredRowIterator unfilteredIterator(Holder current, ColumnFilter selection, Slices slices, boolean reversed)
+ {
+ Row staticRow = staticRow(current, selection, false);
+ if (slices.size() == 0)
+ {
+ DeletionTime partitionDeletion = current.deletionInfo.getPartitionDeletion();
+ return UnfilteredRowIterators.noRowsIterator(metadata, partitionKey, staticRow, partitionDeletion, reversed);
+ }
+
+ return slices.size() == 1
+ ? sliceIterator(selection, slices.get(0), reversed, current, staticRow)
+ : new SlicesIterator(selection, slices, reversed, current, staticRow);
+ }
+
+ private UnfilteredRowIterator sliceIterator(ColumnFilter selection, Slice slice, boolean reversed, Holder current, Row staticRow)
+ {
+ Slice.Bound start = slice.start() == Slice.Bound.BOTTOM ? null : slice.start();
+ Slice.Bound end = slice.end() == Slice.Bound.TOP ? null : slice.end();
+ Iterator<Row> rowIter = BTree.slice(current.tree, metadata.comparator, start, true, end, true, desc(reversed));
+ Iterator<RangeTombstone> deleteIter = current.deletionInfo.rangeIterator(slice, reversed);
+
+ return merge(rowIter, deleteIter, selection, reversed, current, staticRow);
+ }
+
+ private RowAndDeletionMergeIterator merge(Iterator<Row> rowIter, Iterator<RangeTombstone> deleteIter,
+ ColumnFilter selection, boolean reversed, Holder current, Row staticRow)
+ {
+ return new RowAndDeletionMergeIterator(metadata, partitionKey, current.deletionInfo.getPartitionDeletion(),
+ selection, staticRow, reversed, current.stats,
+ rowIter, deleteIter,
+ canHaveShadowedData());
+ }
+
+ private abstract class AbstractIterator extends AbstractUnfilteredRowIterator
+ {
+ final Holder current;
+ final ColumnFilter selection;
+
+ private AbstractIterator(ColumnFilter selection, boolean isReversed)
+ {
+ this(AbstractBTreePartition.this.holder(), selection, isReversed);
+ }
+
+ private AbstractIterator(Holder current, ColumnFilter selection, boolean isReversed)
+ {
+ this(current,
+ AbstractBTreePartition.this.staticRow(current, selection, false),
+ selection, isReversed);
+ }
+
+ private AbstractIterator(Holder current, Row staticRow, ColumnFilter selection, boolean isReversed)
+ {
+ super(AbstractBTreePartition.this.metadata,
+ AbstractBTreePartition.this.partitionKey,
+ current.deletionInfo.getPartitionDeletion(),
+ AbstractBTreePartition.this.columns,
+ staticRow,
+ isReversed,
+ current.stats);
+ this.current = current;
+ this.selection = selection;
+ }
+ }
+
+ public class SlicesIterator extends AbstractIterator
+ {
+ private final Slices slices;
+
+ private int idx;
+ private Iterator<Unfiltered> currentSlice;
+
+ private SlicesIterator(ColumnFilter selection,
+ Slices slices,
+ boolean isReversed,
+ Holder current,
+ Row staticRow)
+ {
+ super(current, staticRow, selection, isReversed);
+ this.slices = slices;
+ }
+
+ protected Unfiltered computeNext()
+ {
+ while (true)
+ {
+ if (currentSlice == null)
+ {
+ if (idx >= slices.size())
+ return endOfData();
+
+ int sliceIdx = isReverseOrder ? slices.size() - idx - 1 : idx;
+ currentSlice = sliceIterator(selection, slices.get(sliceIdx), isReverseOrder, current, Rows.EMPTY_STATIC_ROW);
+ idx++;
+ }
+
+ if (currentSlice.hasNext())
+ return currentSlice.next();
+
+ currentSlice = null;
+ }
+ }
+ }
+
+ public class SliceableIterator extends AbstractIterator implements SliceableUnfilteredRowIterator
+ {
+ private Iterator<Unfiltered> iterator;
+
+ protected SliceableIterator(ColumnFilter selection, boolean isReversed)
+ {
+ super(selection, isReversed);
+ }
+
+ protected Unfiltered computeNext()
+ {
+ if (iterator == null)
+ iterator = unfilteredIterator(selection, Slices.ALL, isReverseOrder);
+ if (!iterator.hasNext())
+ return endOfData();
+ return iterator.next();
+ }
+
+ public Iterator<Unfiltered> slice(Slice slice)
+ {
+ return sliceIterator(selection, slice, isReverseOrder, current, staticRow);
+ }
+ }
+
+ public SliceableUnfilteredRowIterator sliceableUnfilteredIterator(ColumnFilter columns, boolean reversed)
+ {
+ return new SliceableIterator(columns, reversed);
+ }
+
+ protected SliceableUnfilteredRowIterator sliceableUnfilteredIterator()
+ {
+ return sliceableUnfilteredIterator(ColumnFilter.all(metadata), false);
+ }
+
+ protected static Holder build(UnfilteredRowIterator iterator, int initialRowCapacity)
+ {
+ CFMetaData metadata = iterator.metadata();
+ boolean reversed = iterator.isReverseOrder();
+
+ BTree.Builder<Row> builder = BTree.builder(metadata.comparator, initialRowCapacity);
+ builder.auto(false);
+ MutableDeletionInfo.Builder deletionBuilder = MutableDeletionInfo.builder(iterator.partitionLevelDeletion(), metadata.comparator, reversed);
+
+ while (iterator.hasNext())
+ {
+ Unfiltered unfiltered = iterator.next();
+ if (unfiltered.kind() == Unfiltered.Kind.ROW)
+ builder.add((Row)unfiltered);
+ else
+ deletionBuilder.add((RangeTombstoneMarker)unfiltered);
+ }
+
+ if (reversed)
+ builder.reverse();
+
+ return new Holder(builder.build(), deletionBuilder.build(), iterator.staticRow(), iterator.stats());
+ }
+
+ // live must (as the name suggests) not contain any deletion information
+ protected static Holder build(RowIterator rows, DeletionInfo live, boolean buildEncodingStats, int initialRowCapacity)
+ {
+ CFMetaData metadata = rows.metadata();
+ boolean reversed = rows.isReverseOrder();
+
+ BTree.Builder<Row> builder = BTree.builder(metadata.comparator, initialRowCapacity);
+ builder.auto(false);
+ while (rows.hasNext())
+ {
+ Row row = rows.next();
+ builder.add(row);
+ }
+
+ if (reversed)
+ builder.reverse();
+
+ Row staticRow = rows.staticRow();
+ Object[] tree = builder.build();
+ EncodingStats stats = buildEncodingStats ? EncodingStats.Collector.collect(staticRow, BTree.iterator(tree), live)
+ : EncodingStats.NO_STATS;
+ return new Holder(tree, live, staticRow, stats);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(String.format("[%s.%s] key=%s columns=%s",
+ metadata.ksName,
+ metadata.cfName,
+ metadata.getKeyValidator().getString(partitionKey().getKey()),
+ columns));
+
+ if (staticRow() != Rows.EMPTY_STATIC_ROW)
+ sb.append("\n ").append(staticRow().toString(metadata));
+
+ for (Row row : this)
+ sb.append("\n ").append(row.toString(metadata));
+
+ return sb.toString();
+ }
+
+ public int rowCount()
+ {
+ return BTree.size(holder().tree);
+ }
+
+ public Iterator<Row> iterator()
+ {
+ return BTree.<Row>iterator(holder().tree);
+ }
+
+ public Row lastRow()
+ {
+ Object[] tree = holder().tree;
+ if (BTree.isEmpty(tree))
+ return null;
+
+ return BTree.findByIndex(tree, BTree.size(tree) - 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/partitions/AbstractThreadUnsafePartition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/partitions/AbstractThreadUnsafePartition.java b/src/java/org/apache/cassandra/db/partitions/AbstractThreadUnsafePartition.java
deleted file mode 100644
index 0b218f5..0000000
--- a/src/java/org/apache/cassandra/db/partitions/AbstractThreadUnsafePartition.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.db.partitions;
-
-import java.util.*;
-
-import com.google.common.collect.Lists;
-
-import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.filter.ColumnFilter;
-import org.apache.cassandra.db.rows.*;
-import org.apache.cassandra.utils.SearchIterator;
-
-/**
- * Abstract common class for all non-thread safe Partition implementations.
- */
-public abstract class AbstractThreadUnsafePartition implements Partition, Iterable<Row>
-{
- protected final CFMetaData metadata;
- protected final DecoratedKey key;
-
- protected final PartitionColumns columns;
-
- protected final List<Row> rows;
-
- protected AbstractThreadUnsafePartition(CFMetaData metadata,
- DecoratedKey key,
- PartitionColumns columns,
- List<Row> rows)
- {
- this.metadata = metadata;
- this.key = key;
- this.columns = columns;
- this.rows = rows;
- }
-
- public CFMetaData metadata()
- {
- return metadata;
- }
-
- public DecoratedKey partitionKey()
- {
- return key;
- }
-
- public DeletionTime partitionLevelDeletion()
- {
- return deletionInfo().getPartitionDeletion();
- }
-
- public PartitionColumns columns()
- {
- return columns;
- }
-
- public abstract Row staticRow();
-
- protected abstract boolean canHaveShadowedData();
-
- /**
- * The deletion info for the partition update.
- *
- * Note: do not cast the result to a {@code MutableDeletionInfo} to modify it!
- *
- * @return the deletion info for the partition update for use as read-only.
- */
- public abstract DeletionInfo deletionInfo();
-
- public int rowCount()
- {
- return rows.size();
- }
-
- public boolean isEmpty()
- {
- return deletionInfo().isLive() && rows.isEmpty() && staticRow().isEmpty();
- }
-
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder();
- CFMetaData metadata = metadata();
- sb.append(String.format("Partition[%s.%s] key=%s columns=%s%s",
- metadata().ksName,
- metadata().cfName,
- metadata().getKeyValidator().getString(partitionKey().getKey()),
- columns(),
- deletionInfo().isLive() ? "" : " " + deletionInfo()));
-
- if (staticRow() != Rows.EMPTY_STATIC_ROW)
- sb.append("\n ").append(staticRow().toString(metadata, true));
-
- // We use createRowIterator() directly instead of iterator() because that avoids
- // sorting for PartitionUpdate (which inherit this method) and that is useful because
- // 1) it can help with debugging and 2) we can't write after sorting but we want to
- // be able to print an update while we build it (again for debugging)
- for (Row row : this)
- sb.append("\n ").append(row.toString(metadata, true));
-
- return sb.toString();
- }
-
- public Row getRow(Clustering clustering)
- {
- Row row = searchIterator(ColumnFilter.selection(columns()), false).next(clustering);
- // Note that for statics, this will never return null, this will return an empty row. However,
- // it's more consistent for this method to return null if we don't really have a static row.
- return row == null || (clustering == Clustering.STATIC_CLUSTERING && row.isEmpty()) ? null : row;
- }
-
- /**
- * Returns an iterator that iterators over the rows of this update in clustering order.
- *
- * @return an iterator over the rows of this partition.
- */
- public Iterator<Row> iterator()
- {
- return rows.iterator();
- }
-
- public SearchIterator<Clustering, Row> searchIterator(final ColumnFilter columns, boolean reversed)
- {
- final RowSearcher searcher = reversed ? new ReverseRowSearcher() : new ForwardRowSearcher();
- return new SearchIterator<Clustering, Row>()
- {
- public boolean hasNext()
- {
- return !searcher.isDone();
- }
-
- public Row next(Clustering clustering)
- {
- if (clustering == Clustering.STATIC_CLUSTERING)
- {
- Row staticRow = staticRow();
- return staticRow.isEmpty() || columns.fetchedColumns().statics.isEmpty()
- ? Rows.EMPTY_STATIC_ROW
- : staticRow.filter(columns, partitionLevelDeletion(), true, metadata);
- }
-
- Row row = searcher.search(clustering);
- RangeTombstone rt = deletionInfo().rangeCovering(clustering);
-
- // A search iterator only return a row, so it doesn't allow to directly account for deletion that should apply to to row
- // (the partition deletion or the deletion of a range tombstone that covers it). So if needs be, reuse the row deletion
- // to carry the proper deletion on the row.
- DeletionTime activeDeletion = partitionLevelDeletion();
- if (rt != null && rt.deletionTime().supersedes(activeDeletion))
- activeDeletion = rt.deletionTime();
-
- if (row == null)
- return activeDeletion.isLive() ? null : BTreeBackedRow.emptyDeletedRow(clustering, activeDeletion);
-
- return row.filter(columns, activeDeletion, true, metadata);
- }
- };
- }
-
- public UnfilteredRowIterator unfilteredIterator()
- {
- return unfilteredIterator(ColumnFilter.all(metadata()), Slices.ALL, false);
- }
-
- public UnfilteredRowIterator unfilteredIterator(ColumnFilter columns, Slices slices, boolean reversed)
- {
- return slices.makeSliceIterator(sliceableUnfilteredIterator(columns, reversed));
- }
-
- protected SliceableUnfilteredRowIterator sliceableUnfilteredIterator()
- {
- return sliceableUnfilteredIterator(ColumnFilter.all(metadata()), false);
- }
-
- public SliceableUnfilteredRowIterator sliceableUnfilteredIterator(ColumnFilter selection, boolean reversed)
- {
- return new SliceableIterator(this, selection, reversed);
- }
-
- /**
- * Simple binary search for a given row (in the rows list).
- *
- * The return value has the exact same meaning that the one of Collections.binarySearch() but
- * we don't use the later because we're searching for a 'Clustering' in an array of 'Row' (and while
- * both are Clusterable, it's slightly faster to use the 'Clustering' comparison (see comment on
- * ClusteringComparator.rowComparator())).
- */
- private int binarySearch(Clustering clustering, int fromIndex, int toIndex)
- {
- ClusteringComparator comparator = metadata().comparator;
- int low = fromIndex;
- int mid = toIndex;
- int high = mid - 1;
- int result = -1;
- while (low <= high)
- {
- mid = (low + high) >> 1;
- if ((result = comparator.compare(clustering, rows.get(mid).clustering())) > 0)
- low = mid + 1;
- else if (result == 0)
- return mid;
- else
- high = mid - 1;
- }
- return -mid - (result < 0 ? 1 : 2);
- }
-
- private class SliceableIterator extends AbstractUnfilteredRowIterator implements SliceableUnfilteredRowIterator
- {
- private final ColumnFilter columns;
- private RowSearcher searcher;
-
- private Iterator<Unfiltered> iterator;
-
- private SliceableIterator(AbstractThreadUnsafePartition partition, ColumnFilter columns, boolean isReverseOrder)
- {
- super(partition.metadata(),
- partition.partitionKey(),
- partition.partitionLevelDeletion(),
- columns.fetchedColumns(),
- partition.staticRow().isEmpty() ? Rows.EMPTY_STATIC_ROW : partition.staticRow().filter(columns, partition.partitionLevelDeletion(), false, partition.metadata()),
- isReverseOrder,
- partition.stats());
- this.columns = columns;
- }
-
- protected Unfiltered computeNext()
- {
- if (iterator == null)
- iterator = merge(isReverseOrder ? Lists.reverse(rows).iterator(): iterator(), deletionInfo().rangeIterator(isReverseOrder()));
-
- return iterator.hasNext() ? iterator.next() : endOfData();
- }
-
- public Iterator<Unfiltered> slice(Slice slice)
- {
- if (searcher == null)
- searcher = isReverseOrder() ? new ReverseRowSearcher() : new ForwardRowSearcher();
- return merge(searcher.slice(slice), deletionInfo().rangeIterator(slice, isReverseOrder()));
- }
-
- private Iterator<Unfiltered> merge(Iterator<Row> rows, Iterator<RangeTombstone> ranges)
- {
- return new RowAndDeletionMergeIterator(metadata,
- partitionKey,
- partitionLevelDeletion,
- columns,
- staticRow(),
- isReverseOrder(),
- stats(),
- rows,
- ranges,
- canHaveShadowedData());
- }
- }
-
- /**
- * Utility class to search for rows or slice of rows in order.
- */
- private abstract class RowSearcher
- {
- public abstract boolean isDone();
-
- public abstract Row search(Clustering name);
-
- public abstract Iterator<Row> slice(Slice slice);
-
- protected int search(Clustering clustering, int from, int to)
- {
- return binarySearch(clustering, from, to);
- }
-
- protected int search(Slice.Bound bound, int from, int to)
- {
- return Collections.binarySearch(rows.subList(from, to), bound, metadata.comparator);
- }
- }
-
- private class ForwardRowSearcher extends RowSearcher
- {
- private int nextIdx = 0;
-
- public boolean isDone()
- {
- return nextIdx >= rows.size();
- }
-
- public Row search(Clustering name)
- {
- if (isDone())
- return null;
-
- int idx = search(name, nextIdx, rows.size());
- if (idx < 0)
- {
- nextIdx = -idx - 1;
- return null;
- }
- else
- {
- nextIdx = idx + 1;
- return rows.get(idx);
- }
- }
-
- public Iterator<Row> slice(Slice slice)
- {
- // Note that because a Slice.Bound can never sort equally to a Clustering, we know none of the search will
- // be a match, so we save from testing for it.
-
- // since the binary search starts from nextIdx, the position returned will be an offset from nextIdx; to
- // get an absolute position, add nextIdx back in
- int searchResult = search(slice.start(), nextIdx, rows.size());
- final int start = nextIdx + (-searchResult - 1); // First index to include
-
- if (start >= rows.size())
- return Collections.emptyIterator();
-
- // similarly, add start to the returned position
- searchResult = search(slice.end(), start, rows.size());
- final int end = start + (-searchResult - 1); // First index to exclude
-
- // Remember the end to speed up potential further slice search
- nextIdx = end;
-
- if (start >= end)
- return Collections.emptyIterator();
-
- return rows.subList(start, end).iterator();
- }
- }
-
- private class ReverseRowSearcher extends RowSearcher
- {
- private int nextIdx = rows.size() - 1;
-
- public boolean isDone()
- {
- return nextIdx < 0;
- }
-
- public Row search(Clustering name)
- {
- if (isDone())
- return null;
-
- int idx = search(name, 0, nextIdx);
- if (idx < 0)
- {
- // The insertion point is the first element greater than name, so we want start from the previous one next time
- nextIdx = -idx - 2;
- return null;
- }
- else
- {
- nextIdx = idx - 1;
- return rows.get(idx);
- }
- }
-
- public Iterator<Row> slice(Slice slice)
- {
- // Note that because a Slice.Bound can never sort equally to a Clustering, we know none of the search will
- // be a match, so we save from testing for it.
-
- // The insertion point is the first element greater than slice.end(), so we want the previous index
- final int start = -search(slice.end(), 0, nextIdx + 1) - 2; // First index to include
- if (start < 0)
- return Collections.emptyIterator();
-
- final int end = -search(slice.start(), 0, start + 1) - 2; // First index to exclude
-
- // Remember the end to speed up potential further slice search
- nextIdx = end;
-
- if (start < end)
- return Collections.emptyIterator();
-
- return Lists.reverse(rows.subList(end+1, start+1)).iterator();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/partitions/ArrayBackedCachedPartition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/partitions/ArrayBackedCachedPartition.java b/src/java/org/apache/cassandra/db/partitions/ArrayBackedCachedPartition.java
deleted file mode 100644
index fab8591..0000000
--- a/src/java/org/apache/cassandra/db/partitions/ArrayBackedCachedPartition.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.db.partitions;
-
-import java.io.IOException;
-import java.util.*;
-
-import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.filter.DataLimits;
-import org.apache.cassandra.db.rows.*;
-import org.apache.cassandra.io.ISerializer;
-import org.apache.cassandra.io.util.DataInputPlus;
-import org.apache.cassandra.io.util.DataOutputPlus;
-import org.apache.cassandra.net.MessagingService;
-
-public class ArrayBackedCachedPartition extends ArrayBackedPartition implements CachedPartition
-{
- private final int createdAtInSec;
-
- private final int cachedLiveRows;
- private final int rowsWithNonExpiringCells;
-
- private final int nonTombstoneCellCount;
- private final int nonExpiringLiveCells;
-
- private ArrayBackedCachedPartition(CFMetaData metadata,
- DecoratedKey partitionKey,
- PartitionColumns columns,
- Row staticRow,
- List<Row> rows,
- DeletionInfo deletionInfo,
- EncodingStats stats,
- int createdAtInSec,
- int cachedLiveRows,
- int rowsWithNonExpiringCells,
- int nonTombstoneCellCount,
- int nonExpiringLiveCells)
- {
- super(metadata, partitionKey, columns, staticRow, rows, deletionInfo, stats);
- this.createdAtInSec = createdAtInSec;
- this.cachedLiveRows = cachedLiveRows;
- this.rowsWithNonExpiringCells = rowsWithNonExpiringCells;
- this.nonTombstoneCellCount = nonTombstoneCellCount;
- this.nonExpiringLiveCells = nonExpiringLiveCells;
- }
-
- /**
- * Creates an {@code ArrayBackedCachedPartition} holding all the data of the provided iterator.
- *
- * Warning: Note that this method does not close the provided iterator and it is
- * up to the caller to do so.
- *
- * @param iterator the iterator got gather in memory.
- * @param nowInSec the time of the creation in seconds. This is the time at which {@link #cachedLiveRows} applies.
- * @return the created partition.
- */
- public static ArrayBackedCachedPartition create(UnfilteredRowIterator iterator, int nowInSec)
- {
- return create(iterator, 16, nowInSec);
- }
-
- /**
- * Creates an {@code ArrayBackedCachedPartition} holding all the data of the provided iterator.
- *
- * Warning: Note that this method does not close the provided iterator and it is
- * up to the caller to do so.
- *
- * @param iterator the iterator got gather in memory.
- * @param initialRowCapacity sizing hint (in rows) to use for the created partition. It should ideally
- * correspond or be a good estimation of the number or rows in {@code iterator}.
- * @param nowInSec the time of the creation in seconds. This is the time at which {@link #cachedLiveRows} applies.
- * @return the created partition.
- */
- public static ArrayBackedCachedPartition create(UnfilteredRowIterator iterator, int initialRowCapacity, int nowInSec)
- {
- CFMetaData metadata = iterator.metadata();
- boolean reversed = iterator.isReverseOrder();
-
- List<Row> rows = new ArrayList<>(initialRowCapacity);
- MutableDeletionInfo.Builder deletionBuilder = MutableDeletionInfo.builder(iterator.partitionLevelDeletion(), metadata.comparator, reversed);
-
- int cachedLiveRows = 0;
- int rowsWithNonExpiringCells = 0;
-
- int nonTombstoneCellCount = 0;
- int nonExpiringLiveCells = 0;
-
- while (iterator.hasNext())
- {
- Unfiltered unfiltered = iterator.next();
- if (unfiltered.kind() == Unfiltered.Kind.ROW)
- {
- Row row = (Row)unfiltered;
- rows.add(row);
-
- // Collect stats
- if (row.hasLiveData(nowInSec))
- ++cachedLiveRows;
-
- boolean hasNonExpiringCell = false;
- for (Cell cell : row.cells())
- {
- if (!cell.isTombstone())
- {
- ++nonTombstoneCellCount;
- if (!cell.isExpiring())
- {
- hasNonExpiringCell = true;
- ++nonExpiringLiveCells;
- }
- }
- }
-
- if (hasNonExpiringCell)
- ++rowsWithNonExpiringCells;
- }
- else
- {
- deletionBuilder.add((RangeTombstoneMarker)unfiltered);
- }
- }
-
- if (reversed)
- Collections.reverse(rows);
-
- return new ArrayBackedCachedPartition(metadata,
- iterator.partitionKey(),
- iterator.columns(),
- iterator.staticRow(),
- rows,
- deletionBuilder.build(),
- iterator.stats(),
- nowInSec,
- cachedLiveRows,
- rowsWithNonExpiringCells,
- nonTombstoneCellCount,
- nonExpiringLiveCells);
- }
-
- public Row lastRow()
- {
- if (rows.isEmpty())
- return null;
-
- return rows.get(rows.size() - 1);
- }
-
- /**
- * The number of rows that were live at the time the partition was cached.
- *
- * See {@link ColumnFamilyStore#isFilterFullyCoveredBy} to see why we need this.
- *
- * @return the number of rows in this partition that were live at the time the
- * partition was cached (this can be different from the number of live rows now
- * due to expiring cells).
- */
- public int cachedLiveRows()
- {
- return cachedLiveRows;
- }
-
- /**
- * The number of rows in this cached partition that have at least one non-expiring
- * non-deleted cell.
- *
- * Note that this is generally not a very meaningful number, but this is used by
- * {@link DataLimits#hasEnoughLiveData} as an optimization.
- *
- * @return the number of row that have at least one non-expiring non-deleted cell.
- */
- public int rowsWithNonExpiringCells()
- {
- return rowsWithNonExpiringCells;
- }
-
- public int nonTombstoneCellCount()
- {
- return nonTombstoneCellCount;
- }
-
- public int nonExpiringLiveCells()
- {
- return nonExpiringLiveCells;
- }
-
- static class Serializer implements ISerializer<CachedPartition>
- {
- public void serialize(CachedPartition partition, DataOutputPlus out) throws IOException
- {
- int version = MessagingService.current_version;
-
- assert partition instanceof ArrayBackedCachedPartition;
- ArrayBackedCachedPartition p = (ArrayBackedCachedPartition)partition;
-
- out.writeInt(p.createdAtInSec);
- out.writeInt(p.cachedLiveRows);
- out.writeInt(p.rowsWithNonExpiringCells);
- out.writeInt(p.nonTombstoneCellCount);
- out.writeInt(p.nonExpiringLiveCells);
- CFMetaData.serializer.serialize(partition.metadata(), out, version);
- try (UnfilteredRowIterator iter = p.sliceableUnfilteredIterator())
- {
- UnfilteredRowIteratorSerializer.serializer.serialize(iter, null, out, version, p.rowCount());
- }
- }
-
- public CachedPartition deserialize(DataInputPlus in) throws IOException
- {
- int version = MessagingService.current_version;
-
- // Note that it would be slightly simpler to just do
- // ArrayBackedCachedPiartition.create(UnfilteredRowIteratorSerializer.serializer.deserialize(...));
- // However deserializing the header separatly is not a lot harder and allows us to:
- // 1) get the capacity of the partition so we can size it properly directly
- // 2) saves the creation of a temporary iterator: rows are directly written to the partition, which
- // is slightly faster.
-
- int createdAtInSec = in.readInt();
- int cachedLiveRows = in.readInt();
- int rowsWithNonExpiringCells = in.readInt();
- int nonTombstoneCellCount = in.readInt();
- int nonExpiringLiveCells = in.readInt();
-
- CFMetaData metadata = CFMetaData.serializer.deserialize(in, version);
- UnfilteredRowIteratorSerializer.Header header = UnfilteredRowIteratorSerializer.serializer.deserializeHeader(metadata, null, in, version, SerializationHelper.Flag.LOCAL);
- assert !header.isReversed && header.rowEstimate >= 0;
-
- MutableDeletionInfo.Builder deletionBuilder = MutableDeletionInfo.builder(header.partitionDeletion, metadata.comparator, false);
- List<Row> rows = new ArrayList<>(header.rowEstimate);
-
- try (UnfilteredRowIterator partition = UnfilteredRowIteratorSerializer.serializer.deserialize(in, version, metadata, SerializationHelper.Flag.LOCAL, header))
- {
- while (partition.hasNext())
- {
- Unfiltered unfiltered = partition.next();
- if (unfiltered.kind() == Unfiltered.Kind.ROW)
- rows.add((Row)unfiltered);
- else
- deletionBuilder.add((RangeTombstoneMarker)unfiltered);
- }
- }
-
- return new ArrayBackedCachedPartition(metadata,
- header.key,
- header.sHeader.columns(),
- header.staticRow,
- rows,
- deletionBuilder.build(),
- header.sHeader.stats(),
- createdAtInSec,
- cachedLiveRows,
- rowsWithNonExpiringCells,
- nonTombstoneCellCount,
- nonExpiringLiveCells);
-
- }
-
- public long serializedSize(CachedPartition partition)
- {
- int version = MessagingService.current_version;
-
- assert partition instanceof ArrayBackedCachedPartition;
- ArrayBackedCachedPartition p = (ArrayBackedCachedPartition)partition;
-
- try (UnfilteredRowIterator iter = p.sliceableUnfilteredIterator())
- {
- return TypeSizes.sizeof(p.createdAtInSec)
- + TypeSizes.sizeof(p.cachedLiveRows)
- + TypeSizes.sizeof(p.rowsWithNonExpiringCells)
- + TypeSizes.sizeof(p.nonTombstoneCellCount)
- + TypeSizes.sizeof(p.nonExpiringLiveCells)
- + CFMetaData.serializer.serializedSize(partition.metadata(), version)
- + UnfilteredRowIteratorSerializer.serializer.serializedSize(iter, null, MessagingService.current_version, p.rowCount());
- }
- }
- }
-}
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/e51f83b6/src/java/org/apache/cassandra/db/partitions/ArrayBackedPartition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/partitions/ArrayBackedPartition.java b/src/java/org/apache/cassandra/db/partitions/ArrayBackedPartition.java
deleted file mode 100644
index 79c65dc..0000000
--- a/src/java/org/apache/cassandra/db/partitions/ArrayBackedPartition.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.db.partitions;
-
-import java.util.*;
-
-import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.rows.*;
-
-public class ArrayBackedPartition extends AbstractThreadUnsafePartition
-{
- private final Row staticRow;
- private final DeletionInfo deletionInfo;
- private final EncodingStats stats;
-
- protected ArrayBackedPartition(CFMetaData metadata,
- DecoratedKey partitionKey,
- PartitionColumns columns,
- Row staticRow,
- List<Row> rows,
- DeletionInfo deletionInfo,
- EncodingStats stats)
- {
- super(metadata, partitionKey, columns, rows);
- this.staticRow = staticRow;
- this.deletionInfo = deletionInfo;
- this.stats = stats;
- }
-
- /**
- * Creates an {@code ArrayBackedPartition} holding all the data of the provided iterator.
- *
- * Warning: Note that this method does not close the provided iterator and it is
- * up to the caller to do so.
- *
- * @param iterator the iterator to gather in memory.
- * @return the created partition.
- */
- public static ArrayBackedPartition create(UnfilteredRowIterator iterator)
- {
- return create(iterator, 16);
- }
-
- /**
- * Creates an {@code ArrayBackedPartition} holding all the data of the provided iterator.
- *
- * Warning: Note that this method does not close the provided iterator and it is
- * up to the caller to do so.
- *
- * @param iterator the iterator to gather in memory.
- * @param initialRowCapacity sizing hint (in rows) to use for the created partition. It should ideally
- * correspond or be a good estimation of the number or rows in {@code iterator}.
- * @return the created partition.
- */
- public static ArrayBackedPartition create(UnfilteredRowIterator iterator, int initialRowCapacity)
- {
- CFMetaData metadata = iterator.metadata();
- boolean reversed = iterator.isReverseOrder();
-
- List<Row> rows = new ArrayList<>(initialRowCapacity);
- MutableDeletionInfo.Builder deletionBuilder = MutableDeletionInfo.builder(iterator.partitionLevelDeletion(), metadata.comparator, reversed);
-
- while (iterator.hasNext())
- {
- Unfiltered unfiltered = iterator.next();
- if (unfiltered.kind() == Unfiltered.Kind.ROW)
- rows.add((Row)unfiltered);
- else
- deletionBuilder.add((RangeTombstoneMarker)unfiltered);
- }
-
- if (reversed)
- Collections.reverse(rows);
-
- return new ArrayBackedPartition(metadata, iterator.partitionKey(), iterator.columns(), iterator.staticRow(), rows, deletionBuilder.build(), iterator.stats());
- }
-
- protected boolean canHaveShadowedData()
- {
- // We only create instances from UnfilteredRowIterator that don't have shadowed data
- return false;
- }
-
- public Row staticRow()
- {
- return staticRow;
- }
-
- public DeletionInfo deletionInfo()
- {
- return deletionInfo;
- }
-
- public EncodingStats stats()
- {
- return stats;
- }
-}