You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jb...@apache.org on 2009/07/21 04:58:20 UTC

svn commit: r796129 - in /incubator/cassandra/trunk: src/java/org/apache/cassandra/db/ src/java/org/apache/cassandra/db/filter/ src/java/org/apache/cassandra/db/marshal/ src/java/org/apache/cassandra/io/ src/java/org/apache/cassandra/service/ test/conf...

Author: jbellis
Date: Tue Jul 21 02:58:20 2009
New Revision: 796129

URL: http://svn.apache.org/viewvc?rev=796129&view=rev
Log:
add get_slice for supercolumn, tests.  add back updated TimeSortTest.  we need to pass gcBefore to the filters so Slice can count correctly.
patch by jbellis; reviewed by Eric Evans for CASSANDRA-303

Added:
    incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TimeSortTest.java
Modified:
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamily.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/IdentityQueryFilter.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/NamesQueryFilter.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/QueryFilter.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/LongType.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UTF8Type.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UUIDType.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/io/IndexHelper.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SequenceFile.java
    incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java
    incubator/cassandra/trunk/test/conf/storage-conf.xml
    incubator/cassandra/trunk/test/system/test_server.py

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamily.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamily.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamily.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamily.java Tue Jul 21 02:58:20 2009
@@ -207,8 +207,6 @@
 
     public void clear()
     {
-        if (logger_.isDebugEnabled())
-          logger_.debug("clearing");
     	columns_.clear();
     	size_.set(0);
     }

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/ColumnFamilyStore.java Tue Jul 21 02:58:20 2009
@@ -1441,7 +1441,7 @@
             {
                 for (IColumn column : cf.getSortedColumns())
                 {
-                    filter.filterSuperColumn((SuperColumn) column);
+                    filter.filterSuperColumn((SuperColumn)column, gcBefore);
                 }
             }
             return removeDeleted(cf, gcBefore);

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/IdentityQueryFilter.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/IdentityQueryFilter.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/IdentityQueryFilter.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/IdentityQueryFilter.java Tue Jul 21 02:58:20 2009
@@ -14,8 +14,7 @@
         super(key, path, ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.EMPTY_BYTE_ARRAY, true, Integer.MAX_VALUE);
     }
 
-    @Override
-    public void filterSuperColumn(SuperColumn superColumn)
+    public void filterSuperColumn(SuperColumn superColumn, int gcBefore)
     {
         // no filtering done, deliberately
     }

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/NamesQueryFilter.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/NamesQueryFilter.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/NamesQueryFilter.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/NamesQueryFilter.java Tue Jul 21 02:58:20 2009
@@ -53,7 +53,7 @@
         return new SSTableNamesIterator(sstable.getFilename(), key, getColumnFamilyName(), columns);
     }
 
-    public void filterSuperColumn(SuperColumn superColumn)
+    public void filterSuperColumn(SuperColumn superColumn, int gcBefore)
     {
         for (IColumn column : superColumn.getSubColumns())
         {

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/QueryFilter.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/QueryFilter.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/QueryFilter.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/QueryFilter.java Tue Jul 21 02:58:20 2009
@@ -44,7 +44,7 @@
      * subcolumns of a supercolumn are unindexed, so to pick out parts of those we operate in-memory.
      * @param superColumn
      */
-    public abstract void filterSuperColumn(SuperColumn superColumn);
+    public abstract void filterSuperColumn(SuperColumn superColumn, int gcBefore);
 
     public Comparator<IColumn> getColumnComparator(final AbstractType comparator)
     {

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java Tue Jul 21 02:58:20 2009
@@ -2,6 +2,7 @@
 
 import java.io.IOException;
 import java.util.Comparator;
+import java.util.Arrays;
 
 import org.apache.commons.collections.comparators.ReverseComparator;
 
@@ -35,10 +36,24 @@
         return new SSTableSliceIterator(sstable.getFilename(), key, getColumnFamilyName(), comparator, start, isAscending);
     }
 
-    public void filterSuperColumn(SuperColumn superColumn)
+    public void filterSuperColumn(SuperColumn superColumn, int gcBefore)
     {
-        // TODO write this after CASSANDRA-240 is done
-        throw new UnsupportedOperationException();
+        int liveColumns = 0;
+
+        for (IColumn column : superColumn.getSubColumns())
+        {
+            if ((start.length > 0 && superColumn.getComparator().compare(column.name(), start) < 0)
+                || (finish.length > 0 && superColumn.getComparator().compare(column.name(), finish) > 0)
+                || (column.isMarkedForDelete() && column.getLocalDeletionTime() <= gcBefore)
+                || liveColumns > count)
+            {
+                superColumn.remove(column.name());
+            }
+            else if (!column.isMarkedForDelete())
+            {
+                liveColumns++;
+            }
+        }
     }
 
     @Override

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/LongType.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/LongType.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/LongType.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/LongType.java Tue Jul 21 02:58:20 2009
@@ -7,6 +7,16 @@
 {
     public int compare(byte[] o1, byte[] o2)
     {
+        // TODO rm hack to support the "i'm going to pretend [] is an index entry if I didn't actually index anything" hack
+        if (o1.length == 0)
+        {
+            return o2.length == 0 ? 0 : -1;
+        }
+        if (o2.length == 0)
+        {
+            return -1;
+        }
+
         long L1 = ByteBuffer.wrap(o1).order(ByteOrder.LITTLE_ENDIAN).getLong();
         long L2 = ByteBuffer.wrap(o2).order(ByteOrder.LITTLE_ENDIAN).getLong();
         return new Long(L1).compareTo(L2);

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UTF8Type.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UTF8Type.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UTF8Type.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UTF8Type.java Tue Jul 21 02:58:20 2009
@@ -6,6 +6,16 @@
 {
     public int compare(byte[] o1, byte[] o2)
     {
+        // TODO rm hack to support the "i'm going to pretend [] is an index entry if I didn't actually index anything" hack
+        if (o1.length == 0)
+        {
+            return o2.length == 0 ? 0 : -1;
+        }
+        if (o2.length == 0)
+        {
+            return -1;
+        }
+
         try
         {
             return new String(o1, "UTF-8").compareTo(new String(o2, "UTF-8"));

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UUIDType.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UUIDType.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UUIDType.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/db/marshal/UUIDType.java Tue Jul 21 02:58:20 2009
@@ -13,6 +13,16 @@
 
     public int compare(byte[] o1, byte[] o2)
     {
+        // TODO rm hack to support the "i'm going to pretend [] is an index entry if I didn't actually index anything" hack
+        if (o1.length == 0)
+        {
+            return o2.length == 0 ? 0 : -1;
+        }
+        if (o2.length == 0)
+        {
+            return -1;
+        }
+
         return getUUID(o1).compareTo(getUUID(o2));
     }
 

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/io/IndexHelper.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/io/IndexHelper.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/io/IndexHelper.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/io/IndexHelper.java Tue Jul 21 02:58:20 2009
@@ -231,9 +231,9 @@
         else
         {
             Map<Long, Boolean> offset = new HashMap<Long, Boolean>();
-            for (byte[] column : columnNames)
+            for (byte[] name : columnNames)
             {
-                IndexHelper.ColumnIndexInfo cIndexInfo = new IndexHelper.ColumnIndexInfo(column, 0, 0, (AbstractType)columnNames.comparator());
+                IndexHelper.ColumnIndexInfo cIndexInfo = new IndexHelper.ColumnIndexInfo(name, 0, 0, (AbstractType)columnNames.comparator());
                 ColumnRange columnRange = getColumnRangeFromNameIndex(cIndexInfo, columnIndexList, dataSize, totalNumCols);
                 if (offset.get(columnRange.coordinate().start_) == null)
                 {
@@ -295,6 +295,7 @@
         public ColumnIndexInfo(byte[] name, long position, int columnCount, AbstractType comparator)
         {
             this(comparator);
+            assert name.length == 0 || !"".equals(comparator.getString(name)); // Todo r/m length == 0 hack
             name_ = name;
             position_ = position;
             columnCount_ = columnCount;

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SequenceFile.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SequenceFile.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SequenceFile.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/io/SequenceFile.java Tue Jul 21 02:58:20 2009
@@ -256,6 +256,7 @@
             if (columnIndexList.size() == 0)
             {
                 /* if there is no column index, add an index entry that covers the full space. */
+                // TODO can we remove this?  it causes a lot of ugliness in everything that touches Marshal
                 return Arrays.asList(new IndexHelper.ColumnIndexInfo(ArrayUtils.EMPTY_BYTE_ARRAY, 0, totalNumCols, comparator_));
             }
 

Modified: incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java (original)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/service/CassandraServer.java Tue Jul 21 02:58:20 2009
@@ -150,8 +150,6 @@
         logger.debug("get_slice_from");
         ThriftValidation.validateColumnParent(table, column_parent);
         // TODO support get_slice on super CFs
-        if (column_parent.super_column != null || !DatabaseDescriptor.getColumnFamilyType(table, column_parent.column_family).equals("Standard"))
-            throw new InvalidRequestException("get_slice does not yet support super columns (we need to fix this)");
         if (count <= 0)
             throw new InvalidRequestException("get_slice requires positive count");
 

Modified: incubator/cassandra/trunk/test/conf/storage-conf.xml
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/conf/storage-conf.xml?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/conf/storage-conf.xml (original)
+++ incubator/cassandra/trunk/test/conf/storage-conf.xml Tue Jul 21 02:58:20 2009
@@ -42,8 +42,8 @@
      <Table Name = "Table1">
        <ColumnFamily Name="Standard1"/>
        <ColumnFamily Name="Standard2"/>
-       <ColumnFamily CompareWith="LongType" Name="StandardByTime1"/>
-       <ColumnFamily CompareWith="LongType" Name="StandardByTime2"/>
+       <ColumnFamily CompareWith="LongType" Name="StandardLong1"/>
+       <ColumnFamily CompareWith="LongType" Name="StandardLong2"/>
        <ColumnFamily ColumnType="Super" Name="Super1"/>
        <ColumnFamily ColumnType="Super" Name="Super2"/>
      </Table>

Modified: incubator/cassandra/trunk/test/system/test_server.py
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/system/test_server.py?rev=796129&r1=796128&r2=796129&view=diff
==============================================================================
--- incubator/cassandra/trunk/test/system/test_server.py (original)
+++ incubator/cassandra/trunk/test/system/test_server.py Tue Jul 21 02:58:20 2009
@@ -114,6 +114,7 @@
         _insert_super()
         assert client.get_column_count('Table1', 'key1', ColumnParent('Standard2')) == 0
         assert client.get_column_count('Table1', 'key1', ColumnParent('Standard1')) == 2
+        assert client.get_column_count('Table1', 'key1', ColumnParent('Super1', 'sc2')) == 2
         assert client.get_column_count('Table1', 'key1', ColumnParent('Super1')) == 2
 
     def test_insert_blocking(self):
@@ -238,6 +239,34 @@
                                               Column(_i64(6), 'value6', 0), 
                                               Column(_i64(7), 'value7', 0)])], actual
 
+    def test_super_cf_remove_supercolumn(self):
+        _insert_simple()
+        _insert_super()
+
+        # Make sure remove clears out what it's supposed to, and _only_ that:
+        client.remove('Table1', 'key1', ColumnPathOrParent('Super1', 'sc2'), 5, True)
+        _expect_missing(lambda: client.get_column('Table1', 'key1', ColumnPath('Super1', 'sc2', _i64(5))))
+        actual = client.get_slice('Table1', 'key1', ColumnParent('Super1', 'sc2'), '', '', True, 1000)
+        assert actual == [], actual
+        scs = [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)])]
+        actual = client.get_slice_super('Table1', 'key1', 'Super1', '', '', True, 1000)
+        assert actual == scs, actual
+        _verify_simple()
+
+        # Test resurrection.  First, re-insert the value w/ older timestamp, 
+        # and make sure it stays removed:
+        client.insert('Table1', 'key1', ColumnPath('Super1', 'sc2', _i64(5)), 'value5', 0, True)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1', '', '', True, 1000)
+        assert actual == scs, actual
+
+        # Next, w/ a newer timestamp; it should come back
+        client.insert('Table1', 'key1', ColumnPath('Super1', 'sc2', _i64(5)), 'value5', 6, True)
+        actual = client.get_slice_super('Table1', 'key1', 'Super1', '', '', True, 1000)
+        assert actual == \
+            [SuperColumn(name='sc1', columns=[Column(_i64(4), 'value4', 0)]),
+             SuperColumn(name='sc2', columns=[Column(_i64(5), 'value5', 6)])], actual
+
+
     def test_empty_range(self):
         assert client.get_key_range('Table1', 'Standard1', '', '', 1000) == []
         _insert_simple()

Added: incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TimeSortTest.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TimeSortTest.java?rev=796129&view=auto
==============================================================================
--- incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TimeSortTest.java (added)
+++ incubator/cassandra/trunk/test/unit/org/apache/cassandra/db/TimeSortTest.java Tue Jul 21 02:58:20 2009
@@ -0,0 +1,130 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.cassandra.db;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.*;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+import org.apache.cassandra.CleanupHelper;
+import static org.apache.cassandra.Util.getBytes;
+import org.apache.cassandra.db.filter.QueryPath;
+import org.apache.cassandra.db.filter.NamesQueryFilter;
+import org.apache.cassandra.db.marshal.LongType;
+
+public class TimeSortTest extends CleanupHelper
+{
+    @Test
+    public void testMixedSources() throws IOException, ExecutionException, InterruptedException
+    {
+        Table table = Table.open("Table1");
+        ColumnFamilyStore cfStore = table.getColumnFamilyStore("StandardLong1");
+        RowMutation rm;
+
+        rm = new RowMutation("Table1", "key0");
+        rm.add(new QueryPath("StandardLong1", null, getBytes(100)), "a".getBytes(), 100);
+        rm.apply();
+        cfStore.forceBlockingFlush();
+
+        rm = new RowMutation("Table1", "key0");
+        rm.add(new QueryPath("StandardLong1", null, getBytes(0)), "b".getBytes(), 0);
+        rm.apply();
+
+        ColumnFamily cf = cfStore.getColumnFamily("key0", new QueryPath("StandardLong1"), getBytes(10), ArrayUtils.EMPTY_BYTE_ARRAY, true, 1000);
+        Collection<IColumn> columns = cf.getSortedColumns();
+        assert columns.size() == 1;
+    }
+
+    @Test
+    public void testTimeSort() throws IOException, ExecutionException, InterruptedException
+    {
+        Table table = Table.open("Table1");
+        ColumnFamilyStore cfStore = table.getColumnFamilyStore("StandardLong1");
+
+        for (int i = 900; i < 1000; ++i)
+        {
+            RowMutation rm = new RowMutation("Table1", Integer.toString(i));
+            for (int j = 0; j < 8; ++j)
+            {
+                rm.add(new QueryPath("StandardLong1", null, getBytes(j * 2)), "a".getBytes(), j * 2);
+            }
+            rm.apply();
+        }
+
+        validateTimeSort(table);
+
+        cfStore.forceBlockingFlush();
+        validateTimeSort(table);
+
+        // interleave some new data to test memtable + sstable
+        String key = "900";
+        RowMutation rm = new RowMutation("Table1", key);
+        for (int j = 0; j < 4; ++j)
+        {
+            rm.add(new QueryPath("StandardLong1", null, getBytes(j * 2 + 1)), "b".getBytes(), j * 2 + 1);
+        }
+        rm.apply();
+        // and some overwrites
+        rm = new RowMutation("Table1", key);
+        rm.add(new QueryPath("StandardLong1", null, getBytes(0)), "c".getBytes(), 100);
+        rm.add(new QueryPath("StandardLong1", null, getBytes(10)), "c".getBytes(), 100);
+        rm.apply();
+
+        // verify
+        ColumnFamily cf = cfStore.getColumnFamily(key, new QueryPath("StandardLong1"), getBytes(0), ArrayUtils.EMPTY_BYTE_ARRAY, true, 1000);
+        Collection<IColumn> columns = cf.getSortedColumns();
+        assertEquals(12, columns.size());
+        Iterator<IColumn> iter = columns.iterator();
+        IColumn column;
+        for (int j = 0; j < 8; j++)
+        {
+            column = iter.next();
+            assert Arrays.equals(column.name(), getBytes(j));
+        }
+        TreeSet<byte[]> columnNames = new TreeSet<byte[]>(new LongType());
+        columnNames.add(getBytes(10));
+        columnNames.add(getBytes(0));
+        cf = cfStore.getColumnFamily(new NamesQueryFilter("900", new QueryPath("StandardLong1"), columnNames));
+        assert "c".equals(new String(cf.getColumn(getBytes(0)).value()));
+        assert "c".equals(new String(cf.getColumn(getBytes(10)).value()));
+    }
+
+    private void validateTimeSort(Table table) throws IOException
+    {
+        for (int i = 900; i < 1000; ++i)
+        {
+            String key = Integer.toString(i);
+            for (int j = 0; j < 8; j += 3)
+            {
+                ColumnFamily cf = table.getColumnFamilyStore("StandardLong1").getColumnFamily(key, new QueryPath("StandardLong1"), getBytes(j * 2), ArrayUtils.EMPTY_BYTE_ARRAY, true, 1000);
+                Collection<IColumn> columns = cf.getSortedColumns();
+                assert columns.size() == 8 - j;
+                int k = j;
+                for (IColumn c : columns)
+                {
+                    assertEquals((k++) * 2, c.timestamp());
+                }
+            }
+        }
+    }
+}