You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2012/04/11 16:34:16 UTC
git commit: Fix get_paged_slice
Updated Branches:
refs/heads/cassandra-1.1.0 c14e266eb -> fc7e86404
Fix get_paged_slice
patch by slebresne; reviewed by jbellis for CASSANDRA-4136
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/fc7e8640
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/fc7e8640
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/fc7e8640
Branch: refs/heads/cassandra-1.1.0
Commit: fc7e86404a27963071e416ff4deb0c7143e68bfc
Parents: c14e266
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Wed Apr 11 16:31:36 2012 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Wed Apr 11 16:31:36 2012 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/cql3/statements/SelectStatement.java | 3 +-
.../org/apache/cassandra/db/ColumnFamilyStore.java | 10 +-
.../org/apache/cassandra/db/RangeSliceCommand.java | 23 +++--
.../apache/cassandra/db/filter/ExtendedFilter.java | 30 ++++--
.../cassandra/db/filter/SliceQueryFilter.java | 3 +-
.../cassandra/db/index/keys/KeysSearcher.java | 2 +-
.../cassandra/service/RangeSliceVerbHandler.java | 2 +-
.../org/apache/cassandra/service/StorageProxy.java | 3 +-
.../apache/cassandra/thrift/CassandraServer.java | 2 +-
.../apache/cassandra/db/ColumnFamilyStoreTest.java | 92 +++++++++++++--
11 files changed, 133 insertions(+), 38 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 26315be..df030b9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -12,6 +12,7 @@
* fix terminination of the stress.java when errors were encountered
(CASSANDRA-4128)
* Move CfDef and KsDef validation out of thrift (CASSANDRA-4037)
+ * Fix get_paged_slice (CASSANDRA-4136)
Merged from 1.0:
* add auto_snapshot option allowing disabling snapshot before drop/truncate
(CASSANDRA-3710)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index b95d6ba..5bcd37a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -285,7 +285,8 @@ public class SelectStatement implements CQLStatement
bounds,
expressions,
getLimit(),
- true), // limit by columns, not keys
+ true, // limit by columns, not keys
+ false),
parameters.consistencyLevel);
}
catch (IOException e)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
index cea2fee..a4e2e51 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
@@ -1353,12 +1353,12 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
public List<Row> getRangeSlice(ByteBuffer superColumn, final AbstractBounds<RowPosition> range, int maxResults, IFilter columnFilter, List<IndexExpression> rowFilter)
{
- return getRangeSlice(superColumn, range, maxResults, columnFilter, rowFilter, false);
+ return getRangeSlice(superColumn, range, maxResults, columnFilter, rowFilter, false, false);
}
- public List<Row> getRangeSlice(ByteBuffer superColumn, final AbstractBounds<RowPosition> range, int maxResults, IFilter columnFilter, List<IndexExpression> rowFilter, boolean maxIsColumns)
+ public List<Row> getRangeSlice(ByteBuffer superColumn, final AbstractBounds<RowPosition> range, int maxResults, IFilter columnFilter, List<IndexExpression> rowFilter, boolean maxIsColumns, boolean isPaging)
{
- return filter(getSequentialIterator(superColumn, range, columnFilter), ExtendedFilter.create(this, columnFilter, rowFilter, maxResults, maxIsColumns));
+ return filter(getSequentialIterator(superColumn, range, columnFilter), ExtendedFilter.create(this, columnFilter, rowFilter, maxResults, maxIsColumns, isPaging));
}
public List<Row> search(List<IndexExpression> clause, AbstractBounds<RowPosition> range, int maxResults, IFilter dataFilter)
@@ -1404,8 +1404,8 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
rows.add(new Row(rawRow.key, data));
if (data != null)
columnsCount += data.getLiveColumnCount();
- // Update the underlying filter to avoid querying more columns per slice than necessary
- filter.updateColumnsLimit(columnsCount);
+ // Update the underlying filter to avoid querying more columns per slice than necessary and to handle paging
+ filter.updateFilter(columnsCount);
}
return rows;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/db/RangeSliceCommand.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/RangeSliceCommand.java b/src/java/org/apache/cassandra/db/RangeSliceCommand.java
index 80dc719..013dfc5 100644
--- a/src/java/org/apache/cassandra/db/RangeSliceCommand.java
+++ b/src/java/org/apache/cassandra/db/RangeSliceCommand.java
@@ -75,33 +75,34 @@ public class RangeSliceCommand implements MessageProducer, IReadCommand
public final AbstractBounds<RowPosition> range;
public final int maxResults;
public final boolean maxIsColumns;
+ public final boolean isPaging;
public RangeSliceCommand(String keyspace, String column_family, ByteBuffer super_column, SlicePredicate predicate, AbstractBounds<RowPosition> range, int maxResults)
{
- this(keyspace, column_family, super_column, predicate, range, null, maxResults, false);
+ this(keyspace, column_family, super_column, predicate, range, null, maxResults, false, false);
}
- public RangeSliceCommand(String keyspace, String column_family, ByteBuffer super_column, SlicePredicate predicate, AbstractBounds<RowPosition> range, int maxResults, boolean maxIsColumns)
+ public RangeSliceCommand(String keyspace, String column_family, ByteBuffer super_column, SlicePredicate predicate, AbstractBounds<RowPosition> range, int maxResults, boolean maxIsColumns, boolean isPaging)
{
- this(keyspace, column_family, super_column, predicate, range, null, maxResults, maxIsColumns);
+ this(keyspace, column_family, super_column, predicate, range, null, maxResults, maxIsColumns, false);
}
public RangeSliceCommand(String keyspace, ColumnParent column_parent, SlicePredicate predicate, AbstractBounds<RowPosition> range, List<IndexExpression> row_filter, int maxResults)
{
- this(keyspace, column_parent.getColumn_family(), column_parent.super_column, predicate, range, row_filter, maxResults, false);
+ this(keyspace, column_parent.getColumn_family(), column_parent.super_column, predicate, range, row_filter, maxResults, false, false);
}
- public RangeSliceCommand(String keyspace, ColumnParent column_parent, SlicePredicate predicate, AbstractBounds<RowPosition> range, List<IndexExpression> row_filter, int maxResults, boolean maxIsColumns)
+ public RangeSliceCommand(String keyspace, ColumnParent column_parent, SlicePredicate predicate, AbstractBounds<RowPosition> range, List<IndexExpression> row_filter, int maxResults, boolean maxIsColumns, boolean isPaging)
{
- this(keyspace, column_parent.getColumn_family(), column_parent.super_column, predicate, range, row_filter, maxResults, maxIsColumns);
+ this(keyspace, column_parent.getColumn_family(), column_parent.super_column, predicate, range, row_filter, maxResults, maxIsColumns, isPaging);
}
public RangeSliceCommand(String keyspace, String column_family, ByteBuffer super_column, SlicePredicate predicate, AbstractBounds<RowPosition> range, List<IndexExpression> row_filter, int maxResults)
{
- this(keyspace, column_family, super_column, predicate, range, row_filter, maxResults, false);
+ this(keyspace, column_family, super_column, predicate, range, row_filter, maxResults, false, false);
}
- public RangeSliceCommand(String keyspace, String column_family, ByteBuffer super_column, SlicePredicate predicate, AbstractBounds<RowPosition> range, List<IndexExpression> row_filter, int maxResults, boolean maxIsColumns)
+ public RangeSliceCommand(String keyspace, String column_family, ByteBuffer super_column, SlicePredicate predicate, AbstractBounds<RowPosition> range, List<IndexExpression> row_filter, int maxResults, boolean maxIsColumns, boolean isPaging)
{
this.keyspace = keyspace;
this.column_family = column_family;
@@ -111,6 +112,7 @@ public class RangeSliceCommand implements MessageProducer, IReadCommand
this.row_filter = row_filter;
this.maxResults = maxResults;
this.maxIsColumns = maxIsColumns;
+ this.isPaging = isPaging;
}
public Message getMessage(Integer version) throws IOException
@@ -182,6 +184,7 @@ class RangeSliceCommandSerializer implements IVersionedSerializer<RangeSliceComm
if (version >= MessagingService.VERSION_11)
{
dos.writeBoolean(sliceCommand.maxIsColumns);
+ dos.writeBoolean(sliceCommand.isPaging);
}
}
@@ -219,11 +222,13 @@ class RangeSliceCommandSerializer implements IVersionedSerializer<RangeSliceComm
int maxResults = dis.readInt();
boolean maxIsColumns = false;
+ boolean isPaging = false;
if (version >= MessagingService.VERSION_11)
{
maxIsColumns = dis.readBoolean();
+ isPaging = dis.readBoolean();
}
- return new RangeSliceCommand(keyspace, columnFamily, superColumn, pred, range, rowFilter, maxResults, maxIsColumns);
+ return new RangeSliceCommand(keyspace, columnFamily, superColumn, pred, range, rowFilter, maxResults, maxIsColumns, isPaging);
}
public long serializedSize(RangeSliceCommand rangeSliceCommand, int version)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/db/filter/ExtendedFilter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/ExtendedFilter.java b/src/java/org/apache/cassandra/db/filter/ExtendedFilter.java
index df55c25..4d620f8 100644
--- a/src/java/org/apache/cassandra/db/filter/ExtendedFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/ExtendedFilter.java
@@ -47,16 +47,23 @@ public abstract class ExtendedFilter
protected final IFilter originalFilter;
private final int maxResults;
private final boolean maxIsColumns;
+ private final boolean isPaging;
- public static ExtendedFilter create(ColumnFamilyStore cfs, IFilter filter, List<IndexExpression> clause, int maxResults, boolean maxIsColumns)
+ public static ExtendedFilter create(ColumnFamilyStore cfs, IFilter filter, List<IndexExpression> clause, int maxResults, boolean maxIsColumns, boolean isPaging)
{
if (clause == null || clause.isEmpty())
- return new EmptyClauseFilter(cfs, filter, maxResults, maxIsColumns);
+ {
+ return new EmptyClauseFilter(cfs, filter, maxResults, maxIsColumns, isPaging);
+ }
else
+ {
+ if (isPaging)
+ throw new IllegalArgumentException("Cross-row paging is not supported along with index clauses");
return new FilterWithClauses(cfs, filter, clause, maxResults, maxIsColumns);
+ }
}
- protected ExtendedFilter(ColumnFamilyStore cfs, IFilter filter, int maxResults, boolean maxIsColumns)
+ protected ExtendedFilter(ColumnFamilyStore cfs, IFilter filter, int maxResults, boolean maxIsColumns, boolean isPaging)
{
assert cfs != null;
assert filter != null;
@@ -64,8 +71,11 @@ public abstract class ExtendedFilter
this.originalFilter = filter;
this.maxResults = maxResults;
this.maxIsColumns = maxIsColumns;
+ this.isPaging = isPaging;
if (maxIsColumns)
originalFilter.updateColumnsLimit(maxResults);
+ if (isPaging && (!(originalFilter instanceof SliceQueryFilter) || ((SliceQueryFilter)originalFilter).finish.remaining() != 0))
+ throw new IllegalArgumentException("Cross-row paging is only supported for SliceQueryFilter having an empty finish column");
}
public int maxRows()
@@ -82,12 +92,16 @@ public abstract class ExtendedFilter
* Update the filter if necessary given the number of column already
* fetched.
*/
- public void updateColumnsLimit(int columnsCount)
+ public void updateFilter(int currentColumnsCount)
{
+ // As soon as we'd done our first call, we want to reset the start column if we're paging
+ if (isPaging)
+ ((SliceQueryFilter)initialFilter()).start = ByteBufferUtil.EMPTY_BYTE_BUFFER;
+
if (!maxIsColumns)
return;
- int remaining = maxResults - columnsCount;
+ int remaining = maxResults - currentColumnsCount;
initialFilter().updateColumnsLimit(remaining);
}
@@ -140,7 +154,7 @@ public abstract class ExtendedFilter
public FilterWithClauses(ColumnFamilyStore cfs, IFilter filter, List<IndexExpression> clause, int maxResults, boolean maxIsColumns)
{
- super(cfs, filter, maxResults, maxIsColumns);
+ super(cfs, filter, maxResults, maxIsColumns, false);
assert clause != null;
this.clause = clause;
this.initialFilter = computeInitialFilter();
@@ -265,9 +279,9 @@ public abstract class ExtendedFilter
private static class EmptyClauseFilter extends ExtendedFilter
{
- public EmptyClauseFilter(ColumnFamilyStore cfs, IFilter filter, int maxResults, boolean maxIsColumns)
+ public EmptyClauseFilter(ColumnFamilyStore cfs, IFilter filter, int maxResults, boolean maxIsColumns, boolean isPaging)
{
- super(cfs, filter, maxResults, maxIsColumns);
+ super(cfs, filter, maxResults, maxIsColumns, isPaging);
}
public IFilter initialFilter()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java b/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
index e6372c2..1a4a912 100644
--- a/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
@@ -43,7 +43,8 @@ public class SliceQueryFilter implements IFilter
{
private static Logger logger = LoggerFactory.getLogger(SliceQueryFilter.class);
- public final ByteBuffer start; public final ByteBuffer finish;
+ public volatile ByteBuffer start;
+ public volatile ByteBuffer finish;
public final boolean reversed;
public volatile int count;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/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 686f810..a66d040 100644
--- a/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java
+++ b/src/java/org/apache/cassandra/db/index/keys/KeysSearcher.java
@@ -84,7 +84,7 @@ public class KeysSearcher extends SecondaryIndexSearcher
public List<Row> search(List<IndexExpression> clause, AbstractBounds<RowPosition> range, int maxResults, IFilter dataFilter, boolean maxIsColumns)
{
assert clause != null && !clause.isEmpty();
- ExtendedFilter filter = ExtendedFilter.create(baseCfs, dataFilter, clause, maxResults, maxIsColumns);
+ ExtendedFilter filter = ExtendedFilter.create(baseCfs, dataFilter, clause, maxResults, maxIsColumns, false);
return baseCfs.filter(getIndexedIterator(range, filter), filter);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/service/RangeSliceVerbHandler.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/RangeSliceVerbHandler.java b/src/java/org/apache/cassandra/service/RangeSliceVerbHandler.java
index 76823de..ad085ba 100644
--- a/src/java/org/apache/cassandra/service/RangeSliceVerbHandler.java
+++ b/src/java/org/apache/cassandra/service/RangeSliceVerbHandler.java
@@ -47,7 +47,7 @@ public class RangeSliceVerbHandler implements IVerbHandler
if (cfs.indexManager.hasIndexFor(command.row_filter))
return cfs.search(command.row_filter, command.range, command.maxResults, columnFilter, command.maxIsColumns);
else
- return cfs.getRangeSlice(command.super_column, command.range, command.maxResults, columnFilter, command.row_filter, command.maxIsColumns);
+ return cfs.getRangeSlice(command.super_column, command.range, command.maxResults, columnFilter, command.row_filter, command.maxIsColumns, command.isPaging);
}
public void doVerb(Message message, String id)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/service/StorageProxy.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/StorageProxy.java b/src/java/org/apache/cassandra/service/StorageProxy.java
index 802a477..cd1a1eb 100644
--- a/src/java/org/apache/cassandra/service/StorageProxy.java
+++ b/src/java/org/apache/cassandra/service/StorageProxy.java
@@ -851,7 +851,8 @@ public class StorageProxy implements StorageProxyMBean
range,
command.row_filter,
command.maxResults,
- command.maxIsColumns);
+ command.maxIsColumns,
+ command.isPaging);
List<InetAddress> liveEndpoints = StorageService.instance.getLiveNaturalEndpoints(nodeCmd.keyspace, range.right);
DatabaseDescriptor.getEndpointSnitch().sortByProximity(FBUtilities.getBroadcastAddress(), liveEndpoints);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/src/java/org/apache/cassandra/thrift/CassandraServer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/thrift/CassandraServer.java b/src/java/org/apache/cassandra/thrift/CassandraServer.java
index 61a3233..7aceb0e 100644
--- a/src/java/org/apache/cassandra/thrift/CassandraServer.java
+++ b/src/java/org/apache/cassandra/thrift/CassandraServer.java
@@ -749,7 +749,7 @@ public class CassandraServer implements Cassandra.Iface
schedule(DatabaseDescriptor.getRpcTimeout());
try
{
- rows = StorageProxy.getRangeSlice(new RangeSliceCommand(keyspace, column_family, null, predicate, bounds, range.row_filter, range.count, true), consistency_level);
+ rows = StorageProxy.getRangeSlice(new RangeSliceCommand(keyspace, column_family, null, predicate, bounds, range.row_filter, range.count, true, true), consistency_level);
}
finally
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/fc7e8640/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
index e3fed41..3f40464 100644
--- a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
+++ b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java
@@ -820,11 +820,11 @@ public class ColumnFamilyStoreTest extends SchemaLoader
sp.getSlice_range().setStart(ArrayUtils.EMPTY_BYTE_ARRAY);
sp.getSlice_range().setFinish(ArrayUtils.EMPTY_BYTE_ARRAY);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 3, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 3);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 5, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 5);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 8, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 8);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 10, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 10);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 100, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 11);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 3, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 3);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 5, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 5);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 8, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 8);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 10, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 10);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 100, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 11);
// Check that when querying by name, we always include all names for a
// gien row even if it means returning more columns than requested (this is necesseray for CQL)
@@ -835,11 +835,83 @@ public class ColumnFamilyStoreTest extends SchemaLoader
ByteBufferUtil.bytes("c2")
));
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 1, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 3);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 4, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 5);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 5, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 5);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 6, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 8);
- assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 100, QueryFilter.getFilter(sp, cfs.getComparator()), null, true), 8);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 1, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 3);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 4, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 5);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 5, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 5);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 6, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 8);
+ assertTotalColCount(cfs.getRangeSlice(null, Util.range("", ""), 100, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, false), 8);
+ }
+
+ @Test
+ public void testRangeSlicePaging() throws Throwable
+ {
+ String tableName = "Keyspace1";
+ String cfName = "Standard1";
+ Table table = Table.open(tableName);
+ ColumnFamilyStore cfs = table.getColumnFamilyStore(cfName);
+ cfs.clearUnsafe();
+
+ Column[] cols = new Column[4];
+ for (int i = 0; i < 4; i++)
+ cols[i] = column("c" + i, "value", 1);
+
+ putColsStandard(cfs, Util.dk("a"), cols[0], cols[1], cols[2], cols[3]);
+ putColsStandard(cfs, Util.dk("b"), cols[0], cols[1], cols[2]);
+ putColsStandard(cfs, Util.dk("c"), cols[0], cols[1], cols[2], cols[3]);
+ cfs.forceBlockingFlush();
+
+ SlicePredicate sp = new SlicePredicate();
+ sp.setSlice_range(new SliceRange());
+ sp.getSlice_range().setCount(1);
+ sp.getSlice_range().setStart(ArrayUtils.EMPTY_BYTE_ARRAY);
+ sp.getSlice_range().setFinish(ArrayUtils.EMPTY_BYTE_ARRAY);
+
+ Collection<Row> rows = cfs.getRangeSlice(null, Util.range("", ""), 3, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, true);
+ assert rows.size() == 1 : "Expected 1 row, got " + rows;
+ Row row = rows.iterator().next();
+ assertColumnNames(row, "c0", "c1", "c2");
+
+ sp.getSlice_range().setStart(ByteBufferUtil.getArray(ByteBufferUtil.bytes("c2")));
+ rows = cfs.getRangeSlice(null, Util.range("", ""), 3, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, true);
+ assert rows.size() == 2 : "Expected 2 rows, got " + rows;
+ Iterator<Row> iter = rows.iterator();
+ Row row1 = iter.next();
+ Row row2 = iter.next();
+ assertColumnNames(row1, "c2", "c3");
+ assertColumnNames(row2, "c0");
+
+ sp.getSlice_range().setStart(ByteBufferUtil.getArray(ByteBufferUtil.bytes("c0")));
+ rows = cfs.getRangeSlice(null, new Bounds<RowPosition>(row2.key, Util.rp("")), 3, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, true);
+ assert rows.size() == 1 : "Expected 1 row, got " + rows;
+ row = rows.iterator().next();
+ assertColumnNames(row, "c0", "c1", "c2");
+
+ sp.getSlice_range().setStart(ByteBufferUtil.getArray(ByteBufferUtil.bytes("c2")));
+ rows = cfs.getRangeSlice(null, new Bounds<RowPosition>(row.key, Util.rp("")), 3, QueryFilter.getFilter(sp, cfs.getComparator()), null, true, true);
+ assert rows.size() == 2 : "Expected 2 rows, got " + rows;
+ iter = rows.iterator();
+ row1 = iter.next();
+ row2 = iter.next();
+ assertColumnNames(row1, "c2");
+ assertColumnNames(row2, "c0", "c1");
+ }
+
+ private static void assertColumnNames(Row row, String ... columnNames) throws Exception
+ {
+ if (row == null || row.cf == null)
+ throw new AssertionError("The row should not be empty");
+
+ Iterator<IColumn> columns = row.cf.getSortedColumns().iterator();
+ Iterator<String> names = Arrays.asList(columnNames).iterator();
+
+ while (columns.hasNext())
+ {
+ IColumn c = columns.next();
+ assert names.hasNext() : "Got more columns that expected (first unexpected column: " + ByteBufferUtil.string(c.name()) + ")";
+ String n = names.next();
+ assert c.name().equals(ByteBufferUtil.bytes(n)) : "Expected " + n + ", got " + ByteBufferUtil.string(c.name());
+ }
+ assert !names.hasNext() : "Missing expected column " + names.next();
}
private static DecoratedKey idk(int i)