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 2013/04/03 01:01:14 UTC

[3/3] git commit: Merge ColumnFamily, ISortedColumns. Add EmptyColumns and UnsortedColumns; clean up TMBSC, ABSC, and ASC patch by jbellis; reviewed by Carl Yeksigian for CASSANDRA-5403

Merge ColumnFamily, ISortedColumns.  Add EmptyColumns and UnsortedColumns; clean up TMBSC, ABSC, and ASC
patch by jbellis; reviewed by Carl Yeksigian for CASSANDRA-5403


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/aa763947
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/aa763947
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/aa763947

Branch: refs/heads/trunk
Commit: aa76394764bcb4af54150f12528fed9ddfa66044
Parents: 1d092ac
Author: Jonathan Ellis <jb...@apache.org>
Authored: Tue Apr 2 18:01:05 2013 -0500
Committer: Jonathan Ellis <jb...@apache.org>
Committed: Tue Apr 2 18:01:05 2013 -0500

----------------------------------------------------------------------
 .../org/apache/cassandra/config/CFMetaData.java    |    6 +
 .../cassandra/cql3/statements/DeleteStatement.java |    8 +-
 .../cassandra/cql3/statements/UpdateStatement.java |    2 +-
 .../db/AbstractThreadUnsafeSortedColumns.java      |   20 +-
 .../cassandra/db/ArrayBackedSortedColumns.java     |  164 ++-----
 .../apache/cassandra/db/AtomicSortedColumns.java   |   73 +--
 .../org/apache/cassandra/db/BatchlogManager.java   |    4 +-
 .../apache/cassandra/db/CollationController.java   |   12 +-
 src/java/org/apache/cassandra/db/ColumnFamily.java |  381 +++++++--------
 .../cassandra/db/ColumnFamilySerializer.java       |    7 +-
 .../org/apache/cassandra/db/ColumnFamilyStore.java |    2 +-
 .../org/apache/cassandra/db/CounterMutation.java   |    6 +-
 src/java/org/apache/cassandra/db/DefsTable.java    |    9 +-
 src/java/org/apache/cassandra/db/EmptyColumns.java |   98 ++++
 .../apache/cassandra/db/HintedHandOffManager.java  |    4 +-
 .../org/apache/cassandra/db/ISortedColumns.java    |  179 -------
 src/java/org/apache/cassandra/db/Memtable.java     |   55 +--
 .../apache/cassandra/db/RowIteratorFactory.java    |   12 +-
 src/java/org/apache/cassandra/db/RowMutation.java  |    4 +-
 .../org/apache/cassandra/db/SliceQueryPager.java   |    2 +-
 src/java/org/apache/cassandra/db/SystemTable.java  |    6 +-
 .../cassandra/db/TreeMapBackedSortedColumns.java   |   59 +--
 .../org/apache/cassandra/db/UnsortedColumns.java   |  143 ++++++
 .../db/columniterator/IndexedSliceReader.java      |   12 +-
 .../db/columniterator/SSTableNamesIterator.java    |   14 +-
 .../db/columniterator/SimpleSliceReader.java       |   10 +-
 .../db/compaction/LazilyCompactedRow.java          |    2 +-
 .../db/compaction/ParallelCompactionIterable.java  |    4 +-
 .../cassandra/db/compaction/PrecompactedRow.java   |    4 +-
 .../cassandra/db/filter/SliceQueryFilter.java      |   38 +-
 .../AbstractSimplePerColumnSecondaryIndex.java     |    5 +-
 .../db/index/composites/CompositesSearcher.java    |    2 +-
 .../cassandra/db/index/keys/KeysSearcher.java      |    2 +-
 .../apache/cassandra/db/marshal/AbstractType.java  |    2 +-
 .../io/sstable/SSTableIdentityIterator.java        |    6 +-
 .../io/sstable/SSTableSimpleUnsortedWriter.java    |    2 +-
 .../cassandra/io/sstable/SSTableSimpleWriter.java  |    2 +-
 .../apache/cassandra/io/sstable/SSTableWriter.java |    2 +-
 .../apache/cassandra/service/MigrationManager.java |    3 +-
 .../org/apache/cassandra/service/StorageProxy.java |    2 +-
 .../apache/cassandra/thrift/CassandraServer.java   |    3 +-
 .../org/apache/cassandra/tools/SSTableImport.java  |   11 +-
 .../org/apache/cassandra/tracing/TraceState.java   |   11 +-
 src/java/org/apache/cassandra/tracing/Tracing.java |    9 +-
 .../org/apache/cassandra/db/LongTableTest.java     |    2 +-
 .../apache/cassandra/db/MeteredFlusherTest.java    |    2 +-
 .../apache/cassandra/cache/CacheProviderTest.java  |    3 +-
 .../cassandra/db/ArrayBackedSortedColumnsTest.java |   51 +--
 .../apache/cassandra/db/ColumnFamilyStoreTest.java |    4 +-
 .../org/apache/cassandra/db/ColumnFamilyTest.java  |   22 +-
 .../org/apache/cassandra/db/MultitableTest.java    |    4 +-
 .../apache/cassandra/db/RecoveryManager2Test.java  |    2 +-
 .../apache/cassandra/db/RecoveryManager3Test.java  |    4 +-
 .../apache/cassandra/db/RecoveryManagerTest.java   |    6 +-
 .../cassandra/db/RecoveryManagerTruncateTest.java  |    2 +-
 test/unit/org/apache/cassandra/db/RowTest.java     |    9 +-
 .../apache/cassandra/db/SerializationsTest.java    |    5 +-
 test/unit/org/apache/cassandra/db/TableTest.java   |   29 +-
 .../cassandra/io/LazilyCompactedRowTest.java       |    6 +-
 .../apache/cassandra/io/sstable/SSTableTest.java   |    4 +-
 .../apache/cassandra/io/sstable/SSTableUtils.java  |    9 +-
 .../service/AntiEntropyServiceTestAbstract.java    |    2 +-
 .../apache/cassandra/service/RowResolverTest.java  |   25 +-
 .../cassandra/streaming/StreamingTransferTest.java |    9 +-
 .../apache/cassandra/tools/SSTableExportTest.java  |   18 +-
 .../apache/cassandra/tools/SSTableImportTest.java  |   25 +-
 .../apache/cassandra/utils/EncodedStreamsTest.java |    5 +-
 67 files changed, 741 insertions(+), 909 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/config/CFMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java
index 01e7d0c..96b2eca 100644
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@ -1693,6 +1693,12 @@ public final class CFMetaData
         return false;
     }
 
+    public void validateColumns(Iterable<Column> columns)
+    {
+        for (Column column : columns)
+            column.validateFields(this);
+    }
+
     @Override
     public String toString()
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index 4fe52da..dd72bb3 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@ -23,14 +23,10 @@ import java.util.*;
 import org.apache.cassandra.config.Schema;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.config.CFMetaData;
-import org.apache.cassandra.db.ConsistencyLevel;
-import org.apache.cassandra.db.ColumnFamily;
-import org.apache.cassandra.db.DeletionInfo;
-import org.apache.cassandra.db.RowMutation;
+import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.thrift.ThriftValidation;
-import org.apache.cassandra.utils.Pair;
 
 /**
  * A <code>DELETE</code> parsed from a CQL query statement.
@@ -103,7 +99,7 @@ public class DeleteStatement extends ModificationStatement
     throws InvalidRequestException
     {
         QueryProcessor.validateKey(key);
-        ColumnFamily cf = ColumnFamily.create(Schema.instance.getCFMetaData(cfDef.cfm.ksName, columnFamily()));
+        ColumnFamily cf = TreeMapBackedSortedColumns.factory.create(Schema.instance.getCFMetaData(cfDef.cfm.ksName, columnFamily()));
 
         if (toRemove.isEmpty() && builder.componentCount() == 0)
         {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
index f1c2003..3213bd4 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@ -212,7 +212,7 @@ public class UpdateStatement extends ModificationStatement
         validateKey(key);
 
         QueryProcessor.validateKey(key);
-        ColumnFamily cf = ColumnFamily.create(Schema.instance.getCFMetaData(cfDef.cfm.ksName, cfDef.cfm.cfName));
+        ColumnFamily cf = UnsortedColumns.factory.create(Schema.instance.getCFMetaData(cfDef.cfm.ksName, cfDef.cfm.cfName));
 
         // Inserting the CQL row marker (see #4361)
         // We always need to insert a marker, because of the following situation:

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/AbstractThreadUnsafeSortedColumns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/AbstractThreadUnsafeSortedColumns.java b/src/java/org/apache/cassandra/db/AbstractThreadUnsafeSortedColumns.java
index 3782dd2..1c2fb54 100644
--- a/src/java/org/apache/cassandra/db/AbstractThreadUnsafeSortedColumns.java
+++ b/src/java/org/apache/cassandra/db/AbstractThreadUnsafeSortedColumns.java
@@ -17,16 +17,24 @@
  */
 package org.apache.cassandra.db;
 
-public abstract class AbstractThreadUnsafeSortedColumns implements ISortedColumns
+import org.apache.cassandra.config.CFMetaData;
+
+public abstract class AbstractThreadUnsafeSortedColumns extends ColumnFamily
 {
-    private DeletionInfo deletionInfo;
+    protected DeletionInfo deletionInfo;
+
+    public AbstractThreadUnsafeSortedColumns(CFMetaData metadata)
+    {
+        this(metadata, DeletionInfo.LIVE);
+    }
 
-    public AbstractThreadUnsafeSortedColumns()
+    protected AbstractThreadUnsafeSortedColumns(CFMetaData metadata, DeletionInfo deletionInfo)
     {
-        deletionInfo = DeletionInfo.LIVE;
+        super(metadata);
+        this.deletionInfo = deletionInfo;
     }
 
-    public DeletionInfo getDeletionInfo()
+    public DeletionInfo deletionInfo()
     {
         return deletionInfo;
     }
@@ -48,6 +56,6 @@ public abstract class AbstractThreadUnsafeSortedColumns implements ISortedColumn
 
     public boolean isEmpty()
     {
-        return size() == 0;
+        return getColumnCount() == 0;
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/ArrayBackedSortedColumns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ArrayBackedSortedColumns.java b/src/java/org/apache/cassandra/db/ArrayBackedSortedColumns.java
index 863e8f5..b80883a 100644
--- a/src/java/org/apache/cassandra/db/ArrayBackedSortedColumns.java
+++ b/src/java/org/apache/cassandra/db/ArrayBackedSortedColumns.java
@@ -22,72 +22,56 @@ import java.util.*;
 
 import com.google.common.base.Function;
 import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
+import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.db.filter.ColumnSlice;
-import org.apache.cassandra.db.index.SecondaryIndexManager;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.utils.Allocator;
 
 /**
- * A ISortedColumns backed by an ArrayList.
+ * A ColumnFamily backed by an ArrayList.
  * This implementation is not synchronized and should only be used when
  * thread-safety is not required. This implementation makes sense when the
  * main operations performed are iterating over the map and adding columns
  * (especially if insertion is in sorted order).
  */
-public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns implements ISortedColumns
+public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
 {
-    private final AbstractType<?> comparator;
     private final boolean reversed;
     private final ArrayList<Column> columns;
 
-    public static final ISortedColumns.Factory factory = new Factory()
+    public static final ColumnFamily.Factory<ArrayBackedSortedColumns> factory = new Factory<ArrayBackedSortedColumns>()
     {
-        public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed)
+        public ArrayBackedSortedColumns create(CFMetaData metadata, boolean insertReversed)
         {
-            return new ArrayBackedSortedColumns(comparator, insertReversed);
-        }
-
-        public ISortedColumns fromSorted(SortedMap<ByteBuffer, Column> sortedMap, boolean insertReversed)
-        {
-            return new ArrayBackedSortedColumns(sortedMap.values(), (AbstractType<?>)sortedMap.comparator(), insertReversed);
+            return new ArrayBackedSortedColumns(metadata, insertReversed);
         }
     };
 
-    public static ISortedColumns.Factory factory()
-    {
-        return factory;
-    }
-
-    private ArrayBackedSortedColumns(AbstractType<?> comparator, boolean reversed)
+    private ArrayBackedSortedColumns(CFMetaData metadata, boolean reversed)
     {
-        super();
-        this.comparator = comparator;
+        super(metadata);
         this.reversed = reversed;
         this.columns = new ArrayList<Column>();
     }
 
-    private ArrayBackedSortedColumns(Collection<Column> columns, AbstractType<?> comparator, boolean reversed)
+    private ArrayBackedSortedColumns(Collection<Column> columns, CFMetaData metadata, boolean reversed)
     {
-        this.comparator = comparator;
+        super(metadata);
         this.reversed = reversed;
         this.columns = new ArrayList<Column>(columns);
     }
 
-    public ISortedColumns.Factory getFactory()
-    {
-        return factory();
-    }
-
-    public AbstractType<?> getComparator()
+    public ColumnFamily.Factory getFactory()
     {
-        return comparator;
+        return factory;
     }
 
-    public ISortedColumns cloneMe()
+    public ColumnFamily cloneMe()
     {
-        return new ArrayBackedSortedColumns(columns, comparator, reversed);
+        return new ArrayBackedSortedColumns(columns, metadata, reversed);
     }
 
     public boolean isInsertReversed()
@@ -97,7 +81,7 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
 
     private Comparator<ByteBuffer> internalComparator()
     {
-        return reversed ? comparator.reverseComparator : comparator;
+        return reversed ? getComparator().reverseComparator : getComparator();
     }
 
     public Column getColumn(ByteBuffer name)
@@ -125,7 +109,7 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
         }
 
         // Fast path if inserting at the tail
-        int c = internalComparator().compare(columns.get(size() - 1).name(), column.name());
+        int c = internalComparator().compare(columns.get(getColumnCount() - 1).name(), column.name());
         // note that we want an assertion here (see addColumn javadoc), but we also want that if
         // assertion are disabled, addColumn works correctly with unsorted input
         assert c <= 0 : "Added column does not sort as the " + (reversed ? "first" : "last") + " column";
@@ -138,7 +122,7 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
         else if (c == 0)
         {
             // Resolve against last
-            resolveAgainst(size() - 1, column, allocator);
+            resolveAgainst(getColumnCount() - 1, column, allocator);
         }
         else
         {
@@ -199,18 +183,13 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
         return -mid - (result < 0 ? 1 : 2);
     }
 
-    public long addAllWithSizeDelta(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation, SecondaryIndexManager.Updater indexer)
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    public void addAll(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation)
+    public void addAll(ColumnFamily cm, Allocator allocator, Function<Column, Column> transformation)
     {
-        delete(cm.getDeletionInfo());
+        delete(cm.deletionInfo());
         if (cm.isEmpty())
             return;
 
-        Column[] copy = columns.toArray(new Column[size()]);
+        Column[] copy = columns.toArray(new Column[getColumnCount()]);
         int idx = 0;
         Iterator<Column> other = reversed ? cm.reverseIterator(ColumnSlice.ALL_COLUMNS_ARRAY) : cm.iterator();
         Column otherColumn = other.next();
@@ -233,7 +212,7 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
             else // c == 0
             {
                 columns.add(copy[idx]);
-                resolveAgainst(size() - 1, transformation.apply(otherColumn), allocator);
+                resolveAgainst(getColumnCount() - 1, transformation.apply(otherColumn), allocator);
                 idx++;
                 otherColumn = other.hasNext() ? other.next() : null;
             }
@@ -276,14 +255,7 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
         return reversed ? new ForwardSortedCollection() : new ReverseSortedCollection();
     }
 
-    public void removeColumn(ByteBuffer name)
-    {
-        int pos = binarySearch(name);
-        if (pos >= 0)
-            columns.remove(pos);
-    }
-
-    public int size()
+    public int getColumnCount()
     {
         return columns.size();
     }
@@ -293,10 +265,15 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
         columns.clear();
     }
 
-    public SortedSet<ByteBuffer> getColumnNames()
+    public Iterable<ByteBuffer> getColumnNames()
     {
-        // we could memoize the created set but it's unlikely we'll call this method a lot on the same object anyway
-        return new ColumnNamesSet();
+        return Iterables.transform(columns, new Function<Column, ByteBuffer>()
+        {
+            public ByteBuffer apply(Column column)
+            {
+                return column.name;
+            }
+        });
     }
 
     public Iterator<Column> iterator()
@@ -306,12 +283,12 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
 
     public Iterator<Column> iterator(ColumnSlice[] slices)
     {
-        return new SlicesIterator(columns, comparator, slices, reversed);
+        return new SlicesIterator(columns, getComparator(), slices, reversed);
     }
 
     public Iterator<Column> reverseIterator(ColumnSlice[] slices)
     {
-        return new SlicesIterator(columns, comparator, slices, !reversed);
+        return new SlicesIterator(columns, getComparator(), slices, !reversed);
     }
 
     private static class SlicesIterator extends AbstractIterator<Column>
@@ -410,79 +387,4 @@ public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
             return columns.iterator();
         }
     }
-
-    private class ColumnNamesSet extends AbstractSet<ByteBuffer> implements SortedSet<ByteBuffer>
-    {
-        public int size()
-        {
-            return columns.size();
-        }
-
-        public Iterator<ByteBuffer> iterator()
-        {
-            final Iterator<Column> outerIterator = ArrayBackedSortedColumns.this.iterator(); // handles reversed
-            return new Iterator<ByteBuffer>()
-            {
-                public boolean hasNext()
-                {
-                    return outerIterator.hasNext();
-                }
-
-                public ByteBuffer next()
-                {
-                    return outerIterator.next().name();
-                }
-
-                public void remove()
-                {
-                    outerIterator.remove();
-                }
-            };
-        }
-
-        public Comparator<ByteBuffer> comparator()
-        {
-            return getComparator();
-        }
-
-        public ByteBuffer first()
-        {
-            final ArrayBackedSortedColumns outerList = ArrayBackedSortedColumns.this;
-            if (outerList.isEmpty())
-                throw new NoSuchElementException();
-            return outerList.columns.get(outerList.reversed ? size() - 1 : 0).name();
-        }
-
-        public ByteBuffer last()
-        {
-            final ArrayBackedSortedColumns outerList = ArrayBackedSortedColumns.this;
-            if (outerList.isEmpty())
-                throw new NoSuchElementException();
-            return outerList.columns.get(outerList.reversed ? 0 : size() - 1).name();
-        }
-
-        /*
-         * It is fairly hard to implement headSet, tailSet and subSet so that they respect their specification.
-         * Namely, the part "The returned set is backed by this set, so changes in the returned set are reflected
-         * in this set, and vice-versa". Simply keeping a lower and upper index in the backing arrayList wouldn't
-         * ensure those property. Since we do not use those function so far, we prefer returning UnsupportedOperationException
-         * for now and revisit this when and if the need arise.
-         */
-        public SortedSet<ByteBuffer> headSet(ByteBuffer fromElement)
-        {
-            throw new UnsupportedOperationException();
-        }
-
-        // see headSet
-        public SortedSet<ByteBuffer> tailSet(ByteBuffer toElement)
-        {
-            throw new UnsupportedOperationException();
-        }
-
-        // see headSet
-        public SortedSet<ByteBuffer> subSet(ByteBuffer fromElement, ByteBuffer toElement)
-        {
-            throw new UnsupportedOperationException();
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/AtomicSortedColumns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/AtomicSortedColumns.java b/src/java/org/apache/cassandra/db/AtomicSortedColumns.java
index a199b49..bf0fce8 100644
--- a/src/java/org/apache/cassandra/db/AtomicSortedColumns.java
+++ b/src/java/org/apache/cassandra/db/AtomicSortedColumns.java
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import com.google.common.base.Function;
 import edu.stanford.ppl.concurrent.SnapTreeMap;
 
+import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.db.filter.ColumnSlice;
 import org.apache.cassandra.db.index.SecondaryIndexManager;
 import org.apache.cassandra.db.marshal.AbstractType;
@@ -45,40 +46,26 @@ import org.apache.cassandra.utils.Allocator;
  * isolated of other operations and could actually be fully ignored in the
  * face of a concurrent. Don't use it unless in a non-concurrent context.
  */
-public class AtomicSortedColumns implements ISortedColumns
+public class AtomicSortedColumns extends ColumnFamily
 {
     private final AtomicReference<Holder> ref;
 
-    public static final ISortedColumns.Factory factory = new Factory()
+    public static final ColumnFamily.Factory<AtomicSortedColumns> factory = new Factory<AtomicSortedColumns>()
     {
-        public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed)
+        public AtomicSortedColumns create(CFMetaData metadata, boolean insertReversed)
         {
-            return new AtomicSortedColumns(comparator);
-        }
-
-        public ISortedColumns fromSorted(SortedMap<ByteBuffer, Column> sortedMap, boolean insertReversed)
-        {
-            return new AtomicSortedColumns(sortedMap);
+            return new AtomicSortedColumns(metadata);
         }
     };
 
-    public static ISortedColumns.Factory factory()
-    {
-        return factory;
-    }
-
-    private AtomicSortedColumns(AbstractType<?> comparator)
-    {
-        this(new Holder(comparator));
-    }
-
-    private AtomicSortedColumns(SortedMap<ByteBuffer, Column> columns)
+    private AtomicSortedColumns(CFMetaData metadata)
     {
-        this(new Holder(columns));
+        this(metadata, new Holder(metadata.comparator));
     }
 
-    private AtomicSortedColumns(Holder holder)
+    private AtomicSortedColumns(CFMetaData metadata, Holder holder)
     {
+        super(metadata);
         this.ref = new AtomicReference<Holder>(holder);
     }
 
@@ -87,17 +74,17 @@ public class AtomicSortedColumns implements ISortedColumns
         return (AbstractType<?>)ref.get().map.comparator();
     }
 
-    public ISortedColumns.Factory getFactory()
+    public ColumnFamily.Factory getFactory()
     {
         return factory;
     }
 
-    public ISortedColumns cloneMe()
+    public ColumnFamily cloneMe()
     {
-        return new AtomicSortedColumns(ref.get().cloneMe());
+        return new AtomicSortedColumns(metadata, ref.get().cloneMe());
     }
 
-    public DeletionInfo getDeletionInfo()
+    public DeletionInfo deletionInfo()
     {
         return ref.get().deletionInfo;
     }
@@ -142,12 +129,17 @@ public class AtomicSortedColumns implements ISortedColumns
         while (!ref.compareAndSet(current, modified));
     }
 
-    public void addAll(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation)
+    public void addAll(ColumnFamily cm, Allocator allocator, Function<Column, Column> transformation)
     {
         addAllWithSizeDelta(cm, allocator, transformation, SecondaryIndexManager.nullUpdater);
     }
 
-    public long addAllWithSizeDelta(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation, SecondaryIndexManager.Updater indexer)
+    /**
+     *  This is only called by Memtable.resolve, so only AtomicSortedColumns needs to implement it.
+     *
+     *  @return the difference in size seen after merging the given columns
+     */
+    public long addAllWithSizeDelta(ColumnFamily cm, Allocator allocator, Function<Column, Column> transformation, SecondaryIndexManager.Updater indexer)
     {
         /*
          * This operation needs to atomicity and isolation. To that end, we
@@ -168,10 +160,10 @@ public class AtomicSortedColumns implements ISortedColumns
         {
             sizeDelta = 0;
             current = ref.get();
-            DeletionInfo newDelInfo = current.deletionInfo.add(cm.getDeletionInfo());
+            DeletionInfo newDelInfo = current.deletionInfo.add(cm.deletionInfo());
             modified = new Holder(current.map.clone(), newDelInfo);
 
-            for (Column column : cm.getSortedColumns())
+            for (Column column : cm)
             {
                 sizeDelta += modified.addColumn(transformation.apply(column), allocator, indexer);
                 // bail early if we know we've been beaten
@@ -201,18 +193,6 @@ public class AtomicSortedColumns implements ISortedColumns
         return replaced;
     }
 
-    public void removeColumn(ByteBuffer name)
-    {
-        Holder current, modified;
-        do
-        {
-            current = ref.get();
-            modified = current.cloneMe();
-            modified.map.remove(name);
-        }
-        while (!ref.compareAndSet(current, modified));
-    }
-
     public void clear()
     {
         Holder current, modified;
@@ -244,7 +224,7 @@ public class AtomicSortedColumns implements ISortedColumns
         return ref.get().map.descendingMap().values();
     }
 
-    public int size()
+    public int getColumnCount()
     {
         return ref.get().map.size();
     }
@@ -254,11 +234,6 @@ public class AtomicSortedColumns implements ISortedColumns
         return ref.get().map.isEmpty();
     }
 
-    public Iterator<Column> iterator()
-    {
-        return getSortedColumns().iterator();
-    }
-
     public Iterator<Column> iterator(ColumnSlice[] slices)
     {
         return new ColumnSlice.NavigableMapIterator(ref.get().map, slices);
@@ -345,7 +320,7 @@ public class AtomicSortedColumns implements ISortedColumns
             }
         }
 
-        void retainAll(ISortedColumns columns)
+        void retainAll(ColumnFamily columns)
         {
             Iterator<Column> iter = map.values().iterator();
             Iterator<Column> toRetain = columns.iterator();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/BatchlogManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/BatchlogManager.java b/src/java/org/apache/cassandra/db/BatchlogManager.java
index 946ec31..500021d 100644
--- a/src/java/org/apache/cassandra/db/BatchlogManager.java
+++ b/src/java/org/apache/cassandra/db/BatchlogManager.java
@@ -134,9 +134,9 @@ public class BatchlogManager implements BatchlogManagerMBean
         ByteBuffer writtenAt = LongType.instance.decompose(timestamp / 1000);
         ByteBuffer data = serializeRowMutations(mutations);
 
-        ColumnFamily cf = ColumnFamily.create(CFMetaData.BatchlogCF);
-        cf.addColumn(new Column(WRITTEN_AT, writtenAt, timestamp));
+        ColumnFamily cf = ArrayBackedSortedColumns.factory.create(CFMetaData.BatchlogCF);
         cf.addColumn(new Column(DATA, data, timestamp));
+        cf.addColumn(new Column(WRITTEN_AT, writtenAt, timestamp));
 
         return new RowMutation(Table.SYSTEM_KS, UUIDType.instance.decompose(uuid), cf);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/CollationController.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/CollationController.java b/src/java/org/apache/cassandra/db/CollationController.java
index 5e477a8..2ea2d01 100644
--- a/src/java/org/apache/cassandra/db/CollationController.java
+++ b/src/java/org/apache/cassandra/db/CollationController.java
@@ -43,7 +43,7 @@ public class CollationController
 
     private final ColumnFamilyStore cfs;
     private final QueryFilter filter;
-    private final ISortedColumns.Factory factory;
+    private final ColumnFamily.Factory factory;
     private final int gcBefore;
 
     private int sstablesIterated = 0;
@@ -55,8 +55,8 @@ public class CollationController
         this.gcBefore = gcBefore;
 
         this.factory = mutableColumns
-                     ? AtomicSortedColumns.factory()
-                     : ArrayBackedSortedColumns.factory();
+                     ? AtomicSortedColumns.factory
+                     : ArrayBackedSortedColumns.factory;
     }
 
     public ColumnFamily getTopLevelColumns()
@@ -75,7 +75,7 @@ public class CollationController
     private ColumnFamily collectTimeOrderedData()
     {
         logger.trace("collectTimeOrderedData");
-        ColumnFamily container = ColumnFamily.create(cfs.metadata, factory, filter.filter.isReversed());
+        ColumnFamily container = factory.create(cfs.metadata, filter.filter.isReversed());
         List<OnDiskAtomIterator> iterators = new ArrayList<OnDiskAtomIterator>();
         Tracing.trace("Acquiring sstable references");
         ColumnFamilyStore.ViewFragment view = cfs.markReferenced(filter.key);
@@ -84,7 +84,7 @@ public class CollationController
         // which requires addAtom to happen in sorted order.  Then we use addAll to merge into the final collection,
         // which allows a (sorted) set of columns to be merged even if they are not uniformly sorted after the existing
         // ones.
-        ColumnFamily temp = ColumnFamily.create(cfs.metadata, ArrayBackedSortedColumns.factory(), filter.filter.isReversed());
+        ColumnFamily temp = ArrayBackedSortedColumns.factory.create(cfs.metadata, filter.filter.isReversed());
 
         try
         {
@@ -229,7 +229,7 @@ public class CollationController
         Tracing.trace("Acquiring sstable references");
         ColumnFamilyStore.ViewFragment view = cfs.markReferenced(filter.key);
         List<OnDiskAtomIterator> iterators = new ArrayList<OnDiskAtomIterator>(Iterables.size(view.memtables) + view.sstables.size());
-        ColumnFamily returnCF = ColumnFamily.create(cfs.metadata, factory, filter.filter.isReversed());
+        ColumnFamily returnCF = factory.create(cfs.metadata, filter.filter.isReversed());
 
         try
         {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/ColumnFamily.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ColumnFamily.java b/src/java/org/apache/cassandra/db/ColumnFamily.java
index c183412..a72c1bd 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamily.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamily.java
@@ -21,97 +21,66 @@ import java.nio.ByteBuffer;
 import java.security.MessageDigest;
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.SortedSet;
 import java.util.UUID;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
 
-import org.apache.cassandra.db.filter.ColumnSlice;
-import org.apache.cassandra.db.index.SecondaryIndexManager;
-import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.cassandra.io.sstable.SSTable;
-import org.apache.cassandra.utils.*;
-
 import org.apache.commons.lang.builder.HashCodeBuilder;
 
 import org.apache.cassandra.cache.IRowCacheEntry;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.Schema;
-import org.apache.cassandra.db.marshal.MarshalException;
+import org.apache.cassandra.db.filter.ColumnSlice;
+import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.io.sstable.ColumnStats;
+import org.apache.cassandra.io.sstable.SSTable;
+import org.apache.cassandra.utils.*;
 
-public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
+/**
+ * A sorted map of columns.
+ * This represents the backing map of a colum family.
+ *
+ * Whether the implementation is thread safe or not is left to the
+ * implementing classes.
+ */
+public abstract class ColumnFamily implements Iterable<Column>, IRowCacheEntry
 {
     /* The column serializer for this Column Family. Create based on config. */
     public static final ColumnFamilySerializer serializer = new ColumnFamilySerializer();
-    private final CFMetaData cfm;
-    protected final ISortedColumns columns;
-
-    public static ColumnFamily create(UUID cfId)
-    {
-        return create(Schema.instance.getCFMetaData(cfId));
-    }
-
-    public static ColumnFamily create(UUID cfId, ISortedColumns.Factory factory)
-    {
-        return create(Schema.instance.getCFMetaData(cfId), factory);
-    }
-
-    public static ColumnFamily create(String tableName, String cfName)
-    {
-        return create(Schema.instance.getCFMetaData(tableName, cfName));
-    }
-
-    public static ColumnFamily create(CFMetaData cfm)
-    {
-        return create(cfm, TreeMapBackedSortedColumns.factory());
-    }
-
-    public static ColumnFamily create(CFMetaData cfm, ISortedColumns.Factory factory)
-    {
-        return create(cfm, factory, false);
-    }
 
-    public static ColumnFamily create(CFMetaData cfm, ISortedColumns.Factory factory, boolean reversedInsertOrder)
-    {
-        return new ColumnFamily(cfm, factory.create(cfm.comparator, reversedInsertOrder));
-    }
+    protected final CFMetaData metadata;
 
-    protected ColumnFamily(CFMetaData cfm, ISortedColumns columns)
+    protected ColumnFamily(CFMetaData metadata)
     {
-        this.columns = columns;
-        assert cfm != null;
-        this.cfm = cfm;
+        this.metadata = metadata;
     }
 
-    public ColumnFamily cloneMeShallow(ISortedColumns.Factory factory, boolean reversedInsertOrder)
+    public <T extends ColumnFamily> T cloneMeShallow(ColumnFamily.Factory<T> factory, boolean reversedInsertOrder)
     {
-        ColumnFamily cf = ColumnFamily.create(cfm, factory, reversedInsertOrder);
+        T cf = factory.create(metadata, reversedInsertOrder);
         cf.delete(this);
         return cf;
     }
 
     public ColumnFamily cloneMeShallow()
     {
-        return cloneMeShallow(columns.getFactory(), columns.isInsertReversed());
+        return cloneMeShallow(getFactory(), isInsertReversed());
     }
 
     public ColumnFamilyType getType()
     {
-        return cfm.cfType;
+        return metadata.cfType;
     }
 
-    public ColumnFamily cloneMe()
-    {
-        ColumnFamily cf = new ColumnFamily(cfm, columns.cloneMe());
-        cf.delete(this);
-        return cf;
-    }
+    /**
+     * Clones the column map.
+     */
+    public abstract ColumnFamily cloneMe();
 
     public UUID id()
     {
-        return cfm.cfId;
+        return metadata.cfId;
     }
 
     /**
@@ -119,7 +88,12 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
      */
     public CFMetaData metadata()
     {
-        return cfm;
+        return metadata;
+    }
+
+    public void addColumn(Column column)
+    {
+        addColumn(column, HeapAllocator.instance);
     }
 
     public void addColumn(ByteBuffer name, ByteBuffer value, long timestamp)
@@ -162,9 +136,108 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
         }
     }
 
-    public void clear()
+    /**
+     * Clear this column map, removing all columns.
+     */
+    public abstract void clear();
+
+    /**
+     * Returns the factory used for this ISortedColumns implementation.
+     */
+    public abstract Factory getFactory();
+
+    public abstract DeletionInfo deletionInfo();
+    public abstract void setDeletionInfo(DeletionInfo info);
+
+    public abstract void delete(DeletionInfo info);
+    public abstract void maybeResetDeletionTimes(int gcBefore);
+
+    /**
+     * Adds a column to this column map.
+     * If a column with the same name is already present in the map, it will
+     * be replaced by the newly added column.
+     */
+    public abstract void addColumn(Column column, Allocator allocator);
+
+    /**
+     * Adds all the columns of a given column map to this column map.
+     * This is equivalent to:
+     *   <code>
+     *   for (Column c : cm)
+     *      addColumn(c, ...);
+     *   </code>
+     *  but is potentially faster.
+     */
+     public abstract void addAll(ColumnFamily cm, Allocator allocator, Function<Column, Column> transformation);
+
+    /**
+     * Replace oldColumn if present by newColumn.
+     * Returns true if oldColumn was present and thus replaced.
+     * oldColumn and newColumn should have the same name.
+     */
+    public abstract boolean replace(Column oldColumn, Column newColumn);
+
+    /**
+     * Get a column given its name, returning null if the column is not
+     * present.
+     */
+    public abstract Column getColumn(ByteBuffer name);
+
+    /**
+     * Returns an iterable with the names of columns in this column map in the same order
+     * as the underlying columns themselves.
+     */
+    public abstract Iterable<ByteBuffer> getColumnNames();
+
+    /**
+     * Returns the columns of this column map as a collection.
+     * The columns in the returned collection should be sorted as the columns
+     * in this map.
+     */
+    public abstract Collection<Column> getSortedColumns();
+
+    /**
+     * Returns the columns of this column map as a collection.
+     * The columns in the returned collection should be sorted in reverse
+     * order of the columns in this map.
+     */
+    public abstract Collection<Column> getReverseSortedColumns();
+
+    /**
+     * Returns the number of columns in this map.
+     */
+    public abstract int getColumnCount();
+
+    /**
+     * Returns true if this map is empty, false otherwise.
+     */
+    public abstract boolean isEmpty();
+
+    /**
+     * Returns an iterator over the columns of this map that returns only the matching @param slices.
+     * The provided slices must be in order and must be non-overlapping.
+     */
+    public abstract Iterator<Column> iterator(ColumnSlice[] slices);
+
+    /**
+     * Returns a reversed iterator over the columns of this map that returns only the matching @param slices.
+     * The provided slices must be in reversed order and must be non-overlapping.
+     */
+    public abstract Iterator<Column> reverseIterator(ColumnSlice[] slices);
+
+    /**
+     * Returns if this map only support inserts in reverse order.
+     */
+    public abstract boolean isInsertReversed();
+
+    public void delete(ColumnFamily columns)
     {
-        columns.clear();
+        delete(columns.deletionInfo());
+    }
+
+    public void addAll(ColumnFamily cf, Allocator allocator)
+    {
+        addAll(cf, allocator, Functions.<Column>identity());
     }
 
     /*
@@ -174,7 +247,7 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
     public ColumnFamily diff(ColumnFamily cfComposite)
     {
         assert cfComposite.id().equals(id());
-        ColumnFamily cfDiff = ColumnFamily.create(cfm);
+        ColumnFamily cfDiff = TreeMapBackedSortedColumns.factory.create(metadata);
         cfDiff.delete(cfComposite.deletionInfo());
 
         // (don't need to worry about cfNew containing Columns that are shadowed by
@@ -183,7 +256,7 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
         for (Column columnExternal : cfComposite)
         {
             ByteBuffer cName = columnExternal.name();
-            Column columnInternal = this.columns.getColumn(cName);
+            Column columnInternal = getColumn(cName);
             if (columnInternal == null)
             {
                 cfDiff.addColumn(columnExternal);
@@ -206,7 +279,7 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
     public long maxTimestamp()
     {
         long maxTimestamp = deletionInfo().maxTimestamp();
-        for (Column column : columns)
+        for (Column column : this)
             maxTimestamp = Math.max(maxTimestamp, column.maxTimestamp());
         return maxTimestamp;
     }
@@ -214,10 +287,12 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
     @Override
     public int hashCode()
     {
-        return new HashCodeBuilder(373, 75437)
-                    .append(cfm)
-                    .append(deletionInfo())
-                    .append(columns).toHashCode();
+        HashCodeBuilder builder = new HashCodeBuilder(373, 75437)
+                .append(metadata)
+                .append(deletionInfo());
+        for (Column column : this)
+            builder.append(column);
+        return builder.hashCode();
     }
 
     @Override
@@ -225,27 +300,26 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
     {
         if (this == o)
             return true;
-        if (o == null || this.getClass() != o.getClass())
+        if (o == null || !(o instanceof ColumnFamily))
             return false;
 
         ColumnFamily comparison = (ColumnFamily) o;
 
-        return cfm.equals(comparison.cfm)
-                && deletionInfo().equals(comparison.deletionInfo())
-                && ByteBufferUtil.compareUnsigned(digest(this), digest(comparison)) == 0;
+        return metadata.equals(comparison.metadata)
+               && deletionInfo().equals(comparison.deletionInfo())
+               && ByteBufferUtil.compareUnsigned(digest(this), digest(comparison)) == 0;
     }
 
     @Override
     public String toString()
     {
         StringBuilder sb = new StringBuilder("ColumnFamily(");
-        CFMetaData cfm = metadata();
-        sb.append(cfm == null ? "<anonymous>" : cfm.cfName);
+        sb.append(metadata == null ? "<anonymous>" : metadata.cfName);
 
         if (isMarkedForDelete())
             sb.append(" -").append(deletionInfo()).append("-");
 
-        sb.append(" [").append(getComparator().getColumnsString(getSortedColumns())).append("])");
+        sb.append(" [").append(getComparator().getColumnsString(this)).append("])");
         return sb.toString();
     }
 
@@ -259,7 +333,7 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
 
     public void updateDigest(MessageDigest digest)
     {
-        for (Column column : columns)
+        for (Column column : this)
             column.updateDigest(digest);
     }
 
@@ -283,20 +357,6 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
         addAll(cf, allocator);
     }
 
-    /**
-     * Goes over all columns and check the fields are valid (as far as we can
-     * tell).
-     * This is used to detect corruption after deserialization.
-     */
-    public void validateColumnFields() throws MarshalException
-    {
-        CFMetaData metadata = metadata();
-        for (Column column : this)
-        {
-            column.validateFields(metadata);
-        }
-    }
-
     public ColumnStats getColumnStats()
     {
         long minTimestampSeen = deletionInfo() == DeletionInfo.LIVE ? Long.MAX_VALUE : deletionInfo().minTimestamp();
@@ -304,7 +364,7 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
         StreamingHistogram tombstones = new StreamingHistogram(SSTable.TOMBSTONE_HISTOGRAM_BIN_SIZE);
         int maxLocalDeletionTime = Integer.MIN_VALUE;
 
-        for (Column column : columns)
+        for (Column column : this)
         {
             minTimestampSeen = Math.min(minTimestampSeen, column.minTimestamp());
             maxTimestampSeen = Math.max(maxTimestampSeen, column.maxTimestamp());
@@ -316,122 +376,22 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
         return new ColumnStats(getColumnCount(), minTimestampSeen, maxTimestampSeen, maxLocalDeletionTime, tombstones);
     }
 
-    public void delete(ColumnFamily cc2)
-    {
-        delete(cc2.columns.getDeletionInfo());
-    }
-
-    public void delete(DeletionInfo delInfo)
-    {
-        columns.delete(delInfo);
-    }
-
-    // Contrarily to delete(), this will use the provided info even if those
-    // are older that the current ones. Used for SuperColumn in QueryFilter.
-    // delete() is probably the right method in all other cases.
-    public void setDeletionInfo(DeletionInfo delInfo)
-    {
-        columns.setDeletionInfo(delInfo);
-    }
-
     public boolean isMarkedForDelete()
     {
         return !deletionInfo().isLive();
     }
 
-    public DeletionInfo deletionInfo()
-    {
-        return columns.getDeletionInfo();
-    }
-
-    public AbstractType<?> getComparator()
-    {
-        return columns.getComparator();
-    }
-
     /**
-     * Drops expired row-level tombstones.  Normally, these are dropped once the row no longer exists, but
-     * if new columns are inserted into the row post-deletion, they can keep the row tombstone alive indefinitely,
-     * with non-intuitive results.  See https://issues.apache.org/jira/browse/CASSANDRA-2317
+     * @return the comparator whose sorting order the contained columns conform to
      */
-    public void maybeResetDeletionTimes(int gcBefore)
-    {
-        columns.maybeResetDeletionTimes(gcBefore);
-    }
-
-    public long addAllWithSizeDelta(ColumnFamily cc, Allocator allocator, Function<Column, Column> transformation, SecondaryIndexManager.Updater indexer)
-    {
-        return columns.addAllWithSizeDelta(cc.columns, allocator, transformation, indexer);
-    }
-
-    public void addAll(ColumnFamily cc, Allocator allocator, Function<Column, Column> transformation)
-    {
-        columns.addAll(cc.columns, allocator, transformation);
-    }
-
-    public void addAll(ColumnFamily cc, Allocator allocator)
-    {
-        addAll(cc, allocator, Functions.<Column>identity());
-    }
-
-    public void addColumn(Column column)
-    {
-        addColumn(column, HeapAllocator.instance);
-    }
-
-    public void addColumn(Column column, Allocator allocator)
-    {
-        columns.addColumn(column, allocator);
-    }
-
-    public Column getColumn(ByteBuffer name)
-    {
-        return columns.getColumn(name);
-    }
-
-    public boolean replace(Column oldColumn, Column newColumn)
-    {
-        return columns.replace(oldColumn, newColumn);
-    }
-
-    /*
-    * Note that for some of the implementation backing the container, the
-    * return set may not have implementation for tailSet, headSet and subSet.
-    * See ColumnNamesSet in ArrayBackedSortedColumns for more details.
-    */
-    public SortedSet<ByteBuffer> getColumnNames()
-    {
-        return columns.getColumnNames();
-    }
-
-    public Collection<Column> getSortedColumns()
-    {
-        return columns.getSortedColumns();
-    }
-
-    public Collection<Column> getReverseSortedColumns()
-    {
-        return columns.getReverseSortedColumns();
-    }
-
-    public void remove(ByteBuffer columnName)
-    {
-        columns.removeColumn(columnName);
-    }
-
-    public int getColumnCount()
-    {
-        return columns.size();
-    }
-
-    public boolean isEmpty()
+    public AbstractType<?> getComparator()
     {
-        return columns.isEmpty();
+        return metadata.comparator;
     }
 
     public boolean hasOnlyTombstones()
     {
-        for (Column column : columns)
+        for (Column column : this)
         {
             if (column.isLive())
                 return false;
@@ -441,17 +401,7 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
 
     public Iterator<Column> iterator()
     {
-        return columns.iterator();
-    }
-
-    public Iterator<Column> iterator(ColumnSlice[] slices)
-    {
-        return columns.iterator(slices);
-    }
-
-    public Iterator<Column> reverseIterator(ColumnSlice[] slices)
-    {
-        return columns.reverseIterator(slices);
+        return getSortedColumns().iterator();
     }
 
     public boolean hasIrrelevantData(int gcBefore)
@@ -461,10 +411,33 @@ public class ColumnFamily implements IRowCacheEntry, Iterable<Column>
             return true;
 
         // Do we have colums that are either deleted by the container or gcable tombstone?
-        for (Column column : columns)
+        for (Column column : this)
             if (deletionInfo().isDeleted(column) || column.hasIrrelevantData(gcBefore))
                 return true;
 
         return false;
     }
+
+    public abstract static class Factory <T extends ColumnFamily>
+    {
+        /**
+         * Returns a (initially empty) column map whose columns are sorted
+         * according to the provided comparator.
+         * The {@code insertReversed} flag is an hint on how we expect insertion to be perfomed,
+         * either in sorted or reverse sorted order. This is used by ArrayBackedSortedColumns to
+         * allow optimizing for both forward and reversed slices. This does not matter for ThreadSafeSortedColumns.
+         * Note that this is only an hint on how we expect to do insertion, this does not change the map sorting.
+         */
+        public abstract T create(CFMetaData metadata, boolean insertReversed);
+
+        public T create(CFMetaData metadata)
+        {
+            return create(metadata, false);
+        }
+
+        public T create(String keyspace, String cfName)
+        {
+            return create(Schema.instance.getCFMetaData(keyspace, cfName));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/ColumnFamilySerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ColumnFamilySerializer.java b/src/java/org/apache/cassandra/db/ColumnFamilySerializer.java
index 0a1db4e..ff96795 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilySerializer.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilySerializer.java
@@ -93,10 +93,15 @@ public class ColumnFamilySerializer implements IVersionedSerializer<ColumnFamily
 
     public ColumnFamily deserialize(DataInput in, ColumnSerializer.Flag flag, int version) throws IOException
     {
+        return deserialize(in, ArrayBackedSortedColumns.factory, flag, version);
+    }
+
+    public ColumnFamily deserialize(DataInput in, ColumnFamily.Factory factory, ColumnSerializer.Flag flag, int version) throws IOException
+    {
         if (!in.readBoolean())
             return null;
 
-        ColumnFamily cf = ColumnFamily.create(deserializeCfId(in, version), ArrayBackedSortedColumns.factory());
+        ColumnFamily cf = factory.create(Schema.instance.getCFMetaData(deserializeCfId(in, version)));
         int expireBefore = (int) (System.currentTimeMillis() / 1000);
 
         if (cf.metadata().isSuper() && version < MessagingService.VERSION_20)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/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 f1bd877..972784a 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
@@ -1300,7 +1300,7 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
      */
     ColumnFamily filterColumnFamily(ColumnFamily cached, QueryFilter filter, int gcBefore)
     {
-        ColumnFamily cf = cached.cloneMeShallow(ArrayBackedSortedColumns.factory(), filter.filter.isReversed());
+        ColumnFamily cf = cached.cloneMeShallow(ArrayBackedSortedColumns.factory, filter.filter.isReversed());
         OnDiskAtomIterator ci = filter.getMemtableColumnIterator(cached, null);
         filter.collateOnDiskAtom(cf, Collections.singletonList(ci), gcBefore);
         return removeDeletedCF(cf, gcBefore);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/CounterMutation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/CounterMutation.java b/src/java/org/apache/cassandra/db/CounterMutation.java
index 6bb3f44..b414c05 100644
--- a/src/java/org/apache/cassandra/db/CounterMutation.java
+++ b/src/java/org/apache/cassandra/db/CounterMutation.java
@@ -28,6 +28,8 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
+import com.google.common.collect.Iterables;
+
 import org.apache.cassandra.db.filter.NamesQueryFilter;
 import org.apache.cassandra.io.IVersionedSerializer;
 import org.apache.cassandra.net.MessageOut;
@@ -101,8 +103,8 @@ public class CounterMutation implements IMutation
 
     private void addReadCommandFromColumnFamily(String table, ByteBuffer key, ColumnFamily columnFamily, List<ReadCommand> commands)
     {
-        SortedSet s = new TreeSet<ByteBuffer>(columnFamily.metadata().comparator);
-        s.addAll(columnFamily.getColumnNames());
+        SortedSet<ByteBuffer> s = new TreeSet<ByteBuffer>(columnFamily.metadata().comparator);
+        Iterables.addAll(s, columnFamily.getColumnNames());
         commands.add(new SliceByNamesReadCommand(table, key, columnFamily.metadata().cfName, new NamesQueryFilter(s)));
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/DefsTable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/DefsTable.java b/src/java/org/apache/cassandra/db/DefsTable.java
index be91314..dadf140 100644
--- a/src/java/org/apache/cassandra/db/DefsTable.java
+++ b/src/java/org/apache/cassandra/db/DefsTable.java
@@ -178,7 +178,7 @@ public class DefsTable
             if (Schema.invalidSchemaRow(row))
                 continue;
 
-            for (Column column : row.cf.columns)
+            for (Column column : row.cf)
             {
                 Date columnDate = new Date(column.timestamp());
 
@@ -218,7 +218,7 @@ public class DefsTable
 
             RowMutation mutation = new RowMutation(Table.SYSTEM_KS, row.key.key);
 
-            for (Column column : row.cf.columns)
+            for (Column column : row.cf)
             {
                 if (column.isLive())
                     mutation.add(columnFamily, column.name(), column.value(), microTimestamp);
@@ -275,10 +275,9 @@ public class DefsTable
             org.apache.avro.Schema schema = org.apache.avro.Schema.parse(ByteBufferUtil.string(value));
 
             // deserialize keyspaces using schema
-            Collection<Column> columns = cf.getSortedColumns();
-            keyspaces = new ArrayList<KSMetaData>(columns.size());
+            keyspaces = new ArrayList<KSMetaData>(Iterables.size(cf));
 
-            for (Column column : columns)
+            for (Column column : cf)
             {
                 if (column.name().equals(DEFINITION_SCHEMA_COLUMN_NAME))
                     continue;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/EmptyColumns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/EmptyColumns.java b/src/java/org/apache/cassandra/db/EmptyColumns.java
new file mode 100644
index 0000000..aa48375
--- /dev/null
+++ b/src/java/org/apache/cassandra/db/EmptyColumns.java
@@ -0,0 +1,98 @@
+package org.apache.cassandra.db;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import com.google.common.base.Function;
+
+import com.sun.xml.internal.xsom.impl.scd.Iterators;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.db.filter.ColumnSlice;
+import org.apache.cassandra.utils.Allocator;
+
+public class EmptyColumns extends AbstractThreadUnsafeSortedColumns
+{
+    public static final Factory<EmptyColumns> factory = new Factory<EmptyColumns>()
+    {
+        public EmptyColumns create(CFMetaData metadata, boolean insertReversed)
+        {
+            assert !insertReversed;
+            return new EmptyColumns(metadata, DeletionInfo.LIVE);
+        }
+    };
+
+    public EmptyColumns(CFMetaData metadata, DeletionInfo info)
+    {
+        super(metadata, info);
+    }
+
+    public ColumnFamily cloneMe()
+    {
+        return new EmptyColumns(metadata, deletionInfo);
+    }
+
+    public void clear() {
+    }
+
+    public Factory<EmptyColumns> getFactory()
+    {
+        return factory;
+    }
+
+    public void addColumn(Column column, Allocator allocator)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addAll(ColumnFamily cm, Allocator allocator, Function<Column, Column> transformation)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean replace(Column oldColumn, Column newColumn)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public Column getColumn(ByteBuffer name)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public Iterable<ByteBuffer> getColumnNames()
+    {
+        return Collections.emptyList();
+    }
+
+    public Collection<Column> getSortedColumns()
+    {
+        return Collections.emptyList();
+    }
+
+    public Collection<Column> getReverseSortedColumns()
+    {
+        return Collections.emptyList();
+    }
+
+    public int getColumnCount()
+    {
+        return 0;
+    }
+
+    public Iterator<Column> iterator(ColumnSlice[] slices)
+    {
+        return Iterators.empty();
+    }
+
+    public Iterator<Column> reverseIterator(ColumnSlice[] slices)
+    {
+        return Iterators.empty();
+    }
+
+    public boolean isInsertReversed()
+    {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/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 cb306ae..6f2ecb4 100644
--- a/src/java/org/apache/cassandra/db/HintedHandOffManager.java
+++ b/src/java/org/apache/cassandra/db/HintedHandOffManager.java
@@ -129,7 +129,7 @@ public class HintedHandOffManager implements HintedHandOffManagerMBean
         // serialize the hint with id and version as a composite column name
         ByteBuffer name = comparator.decompose(hintId, MessagingService.current_version);
         ByteBuffer value = ByteBuffer.wrap(FBUtilities.serialize(mutation, RowMutation.serializer, MessagingService.current_version));
-        ColumnFamily cf = ColumnFamily.create(Schema.instance.getCFMetaData(Table.SYSTEM_KS, SystemTable.HINTS_CF));
+        ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Schema.instance.getCFMetaData(Table.SYSTEM_KS, SystemTable.HINTS_CF));
         cf.addColumn(name, value, System.currentTimeMillis(), ttl);
 
         return new RowMutation(Table.SYSTEM_KS, UUIDType.instance.decompose(targetId), cf);
@@ -350,7 +350,7 @@ public class HintedHandOffManager implements HintedHandOffManagerMBean
 
             List<WriteResponseHandler> responseHandlers = Lists.newArrayList();
 
-            for (final Column hint : hintsPage.getSortedColumns())
+            for (final Column hint : hintsPage)
             {
                 // check if hints delivery has been paused during the process
                 if (hintedHandOffPaused)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/ISortedColumns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ISortedColumns.java b/src/java/org/apache/cassandra/db/ISortedColumns.java
deleted file mode 100644
index f9ab2bf..0000000
--- a/src/java/org/apache/cassandra/db/ISortedColumns.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.db;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.SortedMap;
-import java.util.SortedSet;
-
-import com.google.common.base.Function;
-
-import org.apache.cassandra.db.filter.ColumnSlice;
-import org.apache.cassandra.db.index.SecondaryIndexManager;
-import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.cassandra.utils.Allocator;
-
-/**
- * A sorted map of columns.
- * This represents the backing map of a colum family.
- *
- * Whether the implementation is thread safe or not is left to the
- * implementing classes.
- */
-public interface ISortedColumns extends Iterable<Column>
-{
-    /**
-     * Shallow cloning of the column map.
-     */
-    public ISortedColumns cloneMe();
-
-    /**
-     * Returns the factory used for this ISortedColumns implementation.
-     */
-    public Factory getFactory();
-
-    public DeletionInfo getDeletionInfo();
-    public void setDeletionInfo(DeletionInfo info);
-
-    public void delete(DeletionInfo info);
-    public void maybeResetDeletionTimes(int gcBefore);
-
-    /**
-     * Adds a column to this column map.
-     * If a column with the same name is already present in the map, it will
-     * be replaced by the newly added column.
-     */
-    public void addColumn(Column column, Allocator allocator);
-
-    /**
-     * Adds all the columns of a given column map to this column map.
-     * This is equivalent to:
-     *   <code>
-     *   for (Column c : cm)
-     *      add(c);
-     *   </code>
-     *  but is potentially faster.
-     *
-     *  @return the difference in size seen after merging the given columns
-     */
-    public long addAllWithSizeDelta(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation, SecondaryIndexManager.Updater indexer);
-
-    /**
-     * Adds the columns without necessarily computing the size delta
-     */
-    public void addAll(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation);
-
-    /**
-     * Replace oldColumn if present by newColumn.
-     * Returns true if oldColumn was present and thus replaced.
-     * oldColumn and newColumn should have the same name.
-     */
-    public boolean replace(Column oldColumn, Column newColumn);
-
-    /**
-     * Remove if present a column by name.
-     */
-    public void removeColumn(ByteBuffer name);
-
-    /**
-     * Clear this column map, removing all columns.
-     */
-    public void clear();
-
-    /**
-     * Get a column given its name, returning null if the column is not
-     * present.
-     */
-    public Column getColumn(ByteBuffer name);
-
-    /**
-     * Returns a set with the names of columns in this column map.
-     * The resulting set is sorted and the order is the one of the columns in
-     * this column map.
-     */
-    public SortedSet<ByteBuffer> getColumnNames();
-
-    /**
-     * Returns the columns of this column map as a collection.
-     * The columns in the returned collection should be sorted as the columns
-     * in this map.
-     */
-    public Collection<Column> getSortedColumns();
-
-    /**
-     * Returns the columns of this column map as a collection.
-     * The columns in the returned collection should be sorted in reverse
-     * order of the columns in this map.
-     */
-    public Collection<Column> getReverseSortedColumns();
-
-    /**
-     * Returns the number of columns in this map.
-     */
-    public int size();
-
-    /**
-     * Returns true if this map is empty, false otherwise.
-     */
-    public boolean isEmpty();
-
-    /**
-     * Returns an iterator over the columns of this map that returns only the matching @param slices.
-     * The provided slices must be in order and must be non-overlapping.
-     */
-    public Iterator<Column> iterator(ColumnSlice[] slices);
-
-    /**
-     * Returns a reversed iterator over the columns of this map that returns only the matching @param slices.
-     * The provided slices must be in reversed order and must be non-overlapping.
-     */
-    public Iterator<Column> reverseIterator(ColumnSlice[] slices);
-
-    /**
-     * Returns if this map only support inserts in reverse order.
-     */
-    public boolean isInsertReversed();
-
-    /**
-     * @return the comparator whose sorting order the contained columns conform to
-     */
-    public AbstractType<?> getComparator();
-
-    public interface Factory
-    {
-        /**
-         * Returns a (initially empty) column map whose columns are sorted
-         * according to the provided comparator.
-         * The {@code insertReversed} flag is an hint on how we expect insertion to be perfomed,
-         * either in sorted or reverse sorted order. This is used by ArrayBackedSortedColumns to
-         * allow optimizing for both forward and reversed slices. This does not matter for ThreadSafeSortedColumns.
-         * Note that this is only an hint on how we expect to do insertion, this does not change the map sorting.
-         */
-        public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed);
-
-        /**
-         * Returns a column map whose columns are sorted according to the comparator of the provided sorted
-         * map (which thus, is assumed to _not_ be sorted by natural order) and that initially contains the
-         * columns in the provided sorted map.
-         * See {@code create} for the description of {@code insertReversed}
-         */
-        public ISortedColumns fromSorted(SortedMap<ByteBuffer, Column> sm, boolean insertReversed);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/Memtable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/Memtable.java b/src/java/org/apache/cassandra/db/Memtable.java
index 0bf94e8..25c99f3 100644
--- a/src/java/org/apache/cassandra/db/Memtable.java
+++ b/src/java/org/apache/cassandra/db/Memtable.java
@@ -110,7 +110,7 @@ public class Memtable
     // We index the memtable by RowPosition only for the purpose of being able
     // to select key range using Token.KeyBound. However put() ensures that we
     // actually only store DecoratedKey.
-    private final ConcurrentNavigableMap<RowPosition, ColumnFamily> columnFamilies = new ConcurrentSkipListMap<RowPosition, ColumnFamily>();
+    private final ConcurrentNavigableMap<RowPosition, AtomicSortedColumns> rows = new ConcurrentSkipListMap<RowPosition, AtomicSortedColumns>();
     public final ColumnFamilyStore cfs;
     private final long creationTime;
 
@@ -121,7 +121,7 @@ public class Memtable
         public Column apply(Column c)
         {
             return c.localCopy(cfs, allocator);
-        };
+        }
     };
 
     // Record the comparator of the CFS at the creation of the memtable. This
@@ -154,11 +154,6 @@ public class Memtable
         return (long) (currentSize.get() * cfs.liveRatio);
     }
 
-    public long getSerializedSize()
-    {
-        return currentSize.get();
-    }
-
     public long getOperations()
     {
         return currentOperations.get();
@@ -201,9 +196,9 @@ public class Memtable
                     long start = System.currentTimeMillis();
                     // ConcurrentSkipListMap has cycles, so measureDeep will have to track a reference to EACH object it visits.
                     // So to reduce the memory overhead of doing a measurement, we break it up to row-at-a-time.
-                    long deepSize = meter.measure(columnFamilies);
+                    long deepSize = meter.measure(rows);
                     int objects = 0;
-                    for (Map.Entry<RowPosition, ColumnFamily> entry : columnFamilies.entrySet())
+                    for (Map.Entry<RowPosition, AtomicSortedColumns> entry : rows.entrySet())
                     {
                         deepSize += meter.measureDeep(entry.getKey()) + meter.measureDeep(entry.getValue());
                         objects += entry.getValue().getColumnCount();
@@ -229,7 +224,7 @@ public class Memtable
                         cfs.liveRatio = (cfs.liveRatio + newRatio) / 2.0;
 
                     logger.info("{} liveRatio is {} (just-counted was {}).  calculation took {}ms for {} columns",
-                                new Object[]{ cfs, cfs.liveRatio, newRatio, System.currentTimeMillis() - start, objects });
+                                cfs, cfs.liveRatio, newRatio, System.currentTimeMillis() - start, objects);
                     activelyMeasuring = null;
                 }
                 finally
@@ -244,13 +239,13 @@ public class Memtable
 
     private void resolve(DecoratedKey key, ColumnFamily cf, SecondaryIndexManager.Updater indexer)
     {
-        ColumnFamily previous = columnFamilies.get(key);
+        AtomicSortedColumns previous = rows.get(key);
 
         if (previous == null)
         {
-            ColumnFamily empty = cf.cloneMeShallow(AtomicSortedColumns.factory(), false);
+            AtomicSortedColumns empty = cf.cloneMeShallow(AtomicSortedColumns.factory, false);
             // We'll add the columns later. This avoids wasting works if we get beaten in the putIfAbsent
-            previous = columnFamilies.putIfAbsent(new DecoratedKey(key.token, allocator.clone(key.key)), empty);
+            previous = rows.putIfAbsent(new DecoratedKey(key.token, allocator.clone(key.key)), empty);
             if (previous == null)
                 previous = empty;
         }
@@ -267,7 +262,7 @@ public class Memtable
     {
         StringBuilder builder = new StringBuilder();
         builder.append("{");
-        for (Map.Entry<RowPosition, ColumnFamily> entry : columnFamilies.entrySet())
+        for (Map.Entry<RowPosition, AtomicSortedColumns> entry : rows.entrySet())
         {
             builder.append(entry.getKey()).append(": ").append(entry.getValue()).append(", ");
         }
@@ -290,25 +285,26 @@ public class Memtable
      * @param startWith Include data in the result from and including this key and to the end of the memtable
      * @return An iterator of entries with the data from the start key
      */
-    public Iterator<Map.Entry<DecoratedKey, ColumnFamily>> getEntryIterator(final RowPosition startWith, final RowPosition stopAt)
+    public Iterator<Map.Entry<DecoratedKey, AtomicSortedColumns>> getEntryIterator(final RowPosition startWith, final RowPosition stopAt)
     {
-        return new Iterator<Map.Entry<DecoratedKey, ColumnFamily>>()
+        return new Iterator<Map.Entry<DecoratedKey, AtomicSortedColumns>>()
         {
-            private Iterator<Map.Entry<RowPosition, ColumnFamily>> iter = stopAt.isMinimum()
-                                                                        ? columnFamilies.tailMap(startWith).entrySet().iterator()
-                                                                        : columnFamilies.subMap(startWith, true, stopAt, true).entrySet().iterator();
+            private Iterator<Map.Entry<RowPosition, AtomicSortedColumns>> iter = stopAt.isMinimum()
+                                                                                 ? rows.tailMap(startWith).entrySet().iterator()
+                                                                                 : rows.subMap(startWith, true, stopAt, true).entrySet().iterator();
 
             public boolean hasNext()
             {
                 return iter.hasNext();
             }
 
-            public Map.Entry<DecoratedKey, ColumnFamily> next()
+            public Map.Entry<DecoratedKey, AtomicSortedColumns> next()
             {
-                Map.Entry<RowPosition, ColumnFamily> entry = iter.next();
+                Map.Entry<RowPosition, AtomicSortedColumns> entry = iter.next();
                 // Actual stored key should be true DecoratedKey
                 assert entry.getKey() instanceof DecoratedKey;
-                return (Map.Entry<DecoratedKey, ColumnFamily>)(Object)entry; // yes, it's ugly
+                // Object cast is required since otherwise we can't turn RowPosition into DecoratedKey
+                return (Map.Entry<DecoratedKey, AtomicSortedColumns>) (Object)entry;
             }
 
             public void remove()
@@ -320,7 +316,7 @@ public class Memtable
 
     public boolean isClean()
     {
-        return columnFamilies.isEmpty();
+        return rows.isEmpty();
     }
 
     /**
@@ -398,12 +394,7 @@ public class Memtable
 
     public ColumnFamily getColumnFamily(DecoratedKey key)
     {
-        return columnFamilies.get(key);
-    }
-
-    void clearUnsafe()
-    {
-        columnFamilies.clear();
+        return rows.get(key);
     }
 
     public long creationTime()
@@ -423,7 +414,7 @@ public class Memtable
             this.context = context;
 
             long keySize = 0;
-            for (RowPosition key : columnFamilies.keySet())
+            for (RowPosition key : rows.keySet())
             {
                 //  make sure we don't write non-sensical keys
                 assert key instanceof DecoratedKey;
@@ -466,7 +457,7 @@ public class Memtable
             {
                 // (we can't clear out the map as-we-go to free up memory,
                 //  since the memtable is being used for queries in the "pending flush" category)
-                for (Map.Entry<RowPosition, ColumnFamily> entry : columnFamilies.entrySet())
+                for (Map.Entry<RowPosition, AtomicSortedColumns> entry : rows.entrySet())
                 {
                     ColumnFamily cf = entry.getValue();
                     if (cf.isMarkedForDelete())
@@ -514,7 +505,7 @@ public class Memtable
         {
             SSTableMetadata.Collector sstableMetadataCollector = SSTableMetadata.createCollector().replayPosition(context.get());
             return new SSTableWriter(filename,
-                                     columnFamilies.size(),
+                                     rows.size(),
                                      cfs.metadata,
                                      cfs.partitioner,
                                      sstableMetadataCollector);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/RowIteratorFactory.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/RowIteratorFactory.java b/src/java/org/apache/cassandra/db/RowIteratorFactory.java
index 38d0fc1..1bc506b 100644
--- a/src/java/org/apache/cassandra/db/RowIteratorFactory.java
+++ b/src/java/org/apache/cassandra/db/RowIteratorFactory.java
@@ -64,7 +64,7 @@ public class RowIteratorFactory
         // memtables
         for (Memtable memtable : memtables)
         {
-            iterators.add(new ConvertToColumnIterator(filter, memtable.getEntryIterator(startWith, stopAt)));
+            iterators.add(new ConvertToColumnIterator<AtomicSortedColumns>(filter, memtable.getEntryIterator(startWith, stopAt)));
         }
 
         for (SSTableReader sstable : sstables)
@@ -85,7 +85,7 @@ public class RowIteratorFactory
             @Override
             protected void onKeyChange()
             {
-                this.returnCF = ColumnFamily.create(cfs.metadata);
+                this.returnCF = TreeMapBackedSortedColumns.factory.create(cfs.metadata);
             }
 
             public void reduce(OnDiskAtomIterator current)
@@ -122,12 +122,12 @@ public class RowIteratorFactory
     /**
      * Get a ColumnIterator for a specific key in the memtable.
      */
-    private static class ConvertToColumnIterator implements CloseableIterator<OnDiskAtomIterator>
+    private static class ConvertToColumnIterator<T extends ColumnFamily> implements CloseableIterator<OnDiskAtomIterator>
     {
         private final QueryFilter filter;
-        private final Iterator<Map.Entry<DecoratedKey, ColumnFamily>> iter;
+        private final Iterator<Map.Entry<DecoratedKey, T>> iter;
 
-        public ConvertToColumnIterator(QueryFilter filter, Iterator<Map.Entry<DecoratedKey, ColumnFamily>> iter)
+        public ConvertToColumnIterator(QueryFilter filter, Iterator<Map.Entry<DecoratedKey, T>> iter)
         {
             this.filter = filter;
             this.iter = iter;
@@ -147,7 +147,7 @@ public class RowIteratorFactory
          */
         public OnDiskAtomIterator next()
         {
-            final Map.Entry<DecoratedKey, ColumnFamily> entry = iter.next();
+            final Map.Entry<DecoratedKey, T> entry = iter.next();
             return new LazyColumnIterator(entry.getKey(), new IColumnIteratorFactory()
             {
                 public OnDiskAtomIterator create()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/RowMutation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/RowMutation.java b/src/java/org/apache/cassandra/db/RowMutation.java
index 9f3efa0..e945138 100644
--- a/src/java/org/apache/cassandra/db/RowMutation.java
+++ b/src/java/org/apache/cassandra/db/RowMutation.java
@@ -116,7 +116,7 @@ public class RowMutation implements IMutation
         ColumnFamily cf = modifications.get(cfm.cfId);
         if (cf == null)
         {
-            cf = ColumnFamily.create(cfm);
+            cf = TreeMapBackedSortedColumns.factory.create(cfm);
             modifications.put(cfm.cfId, cf);
         }
         return cf;
@@ -280,7 +280,7 @@ public class RowMutation implements IMutation
             // We used to uselessly write the cf id here
             if (version < MessagingService.VERSION_12)
                 ColumnFamily.serializer.deserializeCfId(in, version);
-            ColumnFamily cf = ColumnFamily.serializer.deserialize(in, flag, version);
+            ColumnFamily cf = ColumnFamily.serializer.deserialize(in, UnsortedColumns.factory, flag, version);
             // We don't allow RowMutation with null column family, so we should never get null back.
             assert cf != null;
             return cf;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/SliceQueryPager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SliceQueryPager.java b/src/java/org/apache/cassandra/db/SliceQueryPager.java
index 551b50d..7b8e4d4 100644
--- a/src/java/org/apache/cassandra/db/SliceQueryPager.java
+++ b/src/java/org/apache/cassandra/db/SliceQueryPager.java
@@ -77,7 +77,7 @@ public class SliceQueryPager implements Iterator<ColumnFamily>
             else
                 slices = Arrays.copyOfRange(slices, i, slices.length);
         }
-        return cf == null ? ColumnFamily.create(cfs.metadata) : cf;
+        return cf == null ? EmptyColumns.factory.create(cfs.metadata) : cf;
     }
 
     public void remove()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/SystemTable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SystemTable.java b/src/java/org/apache/cassandra/db/SystemTable.java
index 95c7298..567cf06 100644
--- a/src/java/org/apache/cassandra/db/SystemTable.java
+++ b/src/java/org/apache/cassandra/db/SystemTable.java
@@ -154,7 +154,7 @@ public class SystemTable
             cols.add(ByteBufferUtil.bytes("Token"));
             QueryFilter filter = QueryFilter.getNamesFilter(decorate(ByteBufferUtil.bytes("L")), OLD_STATUS_CF, cols);
             ColumnFamily oldCf = oldStatusCfs.getColumnFamily(filter);
-            Iterator<Column> oldColumns = oldCf.columns.iterator();
+            Iterator<Column> oldColumns = oldCf.iterator();
 
             String clusterName = null;
             try
@@ -587,7 +587,7 @@ public class SystemTable
 
     public static void setIndexBuilt(String table, String indexName)
     {
-        ColumnFamily cf = ColumnFamily.create(Table.SYSTEM_KS, INDEX_CF);
+        ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Table.SYSTEM_KS, INDEX_CF);
         cf.addColumn(new Column(ByteBufferUtil.bytes(indexName), ByteBufferUtil.EMPTY_BYTE_BUFFER, FBUtilities.timestampMicros()));
         RowMutation rm = new RowMutation(Table.SYSTEM_KS, ByteBufferUtil.bytes(table), cf);
         rm.apply();
@@ -663,7 +663,7 @@ public class SystemTable
     {
         ByteBuffer ip = ByteBuffer.wrap(FBUtilities.getBroadcastAddress().getAddress());
 
-        ColumnFamily cf = ColumnFamily.create(Table.SYSTEM_KS, COUNTER_ID_CF);
+        ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Table.SYSTEM_KS, COUNTER_ID_CF);
         cf.addColumn(new Column(newCounterId.bytes(), ip, now));
         RowMutation rm = new RowMutation(Table.SYSTEM_KS, ALL_LOCAL_NODE_ID_KEY, cf);
         rm.apply();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/aa763947/src/java/org/apache/cassandra/db/TreeMapBackedSortedColumns.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/TreeMapBackedSortedColumns.java b/src/java/org/apache/cassandra/db/TreeMapBackedSortedColumns.java
index 20cbd90..a9b7c57 100644
--- a/src/java/org/apache/cassandra/db/TreeMapBackedSortedColumns.java
+++ b/src/java/org/apache/cassandra/db/TreeMapBackedSortedColumns.java
@@ -26,56 +26,50 @@ import java.util.TreeMap;
 
 import com.google.common.base.Function;
 
+import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.db.filter.ColumnSlice;
 import org.apache.cassandra.db.index.SecondaryIndexManager;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.utils.Allocator;
 
-public class TreeMapBackedSortedColumns extends AbstractThreadUnsafeSortedColumns implements ISortedColumns
+public class TreeMapBackedSortedColumns extends AbstractThreadUnsafeSortedColumns
 {
     private final TreeMap<ByteBuffer, Column> map;
 
-    public static final ISortedColumns.Factory factory = new Factory()
+    public static final ColumnFamily.Factory<TreeMapBackedSortedColumns> factory = new Factory<TreeMapBackedSortedColumns>()
     {
-        public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed)
+        public TreeMapBackedSortedColumns create(CFMetaData metadata, boolean insertReversed)
         {
-            return new TreeMapBackedSortedColumns(comparator);
-        }
-
-        public ISortedColumns fromSorted(SortedMap<ByteBuffer, Column> sortedMap, boolean insertReversed)
-        {
-            return new TreeMapBackedSortedColumns(sortedMap);
+            assert !insertReversed;
+            return new TreeMapBackedSortedColumns(metadata);
         }
     };
 
-    public static ISortedColumns.Factory factory()
-    {
-        return factory;
-    }
-
     public AbstractType<?> getComparator()
     {
         return (AbstractType<?>)map.comparator();
     }
 
-    private TreeMapBackedSortedColumns(AbstractType<?> comparator)
+    private TreeMapBackedSortedColumns(CFMetaData metadata)
     {
-        this.map = new TreeMap<ByteBuffer, Column>(comparator);
+        super(metadata);
+        this.map = new TreeMap<ByteBuffer, Column>(metadata.comparator);
     }
 
-    private TreeMapBackedSortedColumns(SortedMap<ByteBuffer, Column> columns)
+    private TreeMapBackedSortedColumns(CFMetaData metadata, SortedMap<ByteBuffer, Column> columns)
     {
+        super(metadata);
         this.map = new TreeMap<ByteBuffer, Column>(columns);
     }
 
-    public ISortedColumns.Factory getFactory()
+    public ColumnFamily.Factory getFactory()
     {
-        return factory();
+        return factory;
     }
 
-    public ISortedColumns cloneMe()
+    public ColumnFamily cloneMe()
     {
-        return new TreeMapBackedSortedColumns(map);
+        return new TreeMapBackedSortedColumns(metadata, map);
     }
 
     public boolean isInsertReversed()
@@ -115,22 +109,14 @@ public class TreeMapBackedSortedColumns extends AbstractThreadUnsafeSortedColumn
         return reconciledColumn.dataSize() - oldColumn.dataSize();
     }
 
-    public long addAllWithSizeDelta(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation, SecondaryIndexManager.Updater indexer)
-    {
-        delete(cm.getDeletionInfo());
-        for (Column column : cm.getSortedColumns())
-            addColumn(transformation.apply(column), allocator, indexer);
-
-        // we don't use this for memtables, so we don't bother computing size
-        return Long.MIN_VALUE;
-    }
-
     /**
      * We need to go through each column in the column container and resolve it before adding
      */
-    public void addAll(ISortedColumns cm, Allocator allocator, Function<Column, Column> transformation)
+    public void addAll(ColumnFamily cm, Allocator allocator, Function<Column, Column> transformation)
     {
-        addAllWithSizeDelta(cm, allocator, transformation, SecondaryIndexManager.nullUpdater);
+        delete(cm.deletionInfo());
+        for (Column column : cm)
+            addColumn(transformation.apply(column), allocator);
     }
 
     public boolean replace(Column oldColumn, Column newColumn)
@@ -161,17 +147,12 @@ public class TreeMapBackedSortedColumns extends AbstractThreadUnsafeSortedColumn
         return map.get(name);
     }
 
-    public void removeColumn(ByteBuffer name)
-    {
-        map.remove(name);
-    }
-
     public void clear()
     {
         map.clear();
     }
 
-    public int size()
+    public int getColumnCount()
     {
         return map.size();
     }