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 2012/08/14 23:53:28 UTC

[3/3] git commit: generify collection types patch by slebresnse; reviewed by Paul Cannon for CASSANDRA-4453

generify collection types
patch by slebresnse; reviewed by Paul Cannon for CASSANDRA-4453


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

Branch: refs/heads/trunk
Commit: 5e5fbc6853468e47abe5d25817be1220e90c980f
Parents: 1a44fa7
Author: Jonathan Ellis <jb...@apache.org>
Authored: Tue Aug 14 16:48:19 2012 -0500
Committer: Jonathan Ellis <jb...@apache.org>
Committed: Tue Aug 14 16:48:19 2012 -0500

----------------------------------------------------------------------
 src/java/org/apache/cassandra/cql3/ResultSet.java  |    6 +-
 .../cassandra/cql3/statements/SelectStatement.java |    2 +-
 .../cassandra/db/marshal/CollectionType.java       |   27 +++--
 .../org/apache/cassandra/db/marshal/ListType.java  |   61 +++++++++--
 .../org/apache/cassandra/db/marshal/MapType.java   |   81 ++++++++++++---
 .../org/apache/cassandra/db/marshal/SetType.java   |   66 +++++++++---
 6 files changed, 185 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/5e5fbc68/src/java/org/apache/cassandra/cql3/ResultSet.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ResultSet.java b/src/java/org/apache/cassandra/cql3/ResultSet.java
index 568e3ee..cb5e89f 100644
--- a/src/java/org/apache/cassandra/cql3/ResultSet.java
+++ b/src/java/org/apache/cassandra/cql3/ResultSet.java
@@ -33,6 +33,7 @@ import org.apache.cassandra.thrift.CqlResult;
 import org.apache.cassandra.thrift.CqlResultType;
 import org.apache.cassandra.thrift.CqlRow;
 import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.FBUtilities;
 
 public class ResultSet
 {
@@ -121,7 +122,10 @@ public class ResultSet
             for (int i = 0; i < metadata.names.size(); i++)
             {
                 Column col = new Column(ByteBufferUtil.bytes(metadata.names.get(i).toString()));
-                col.setValue(row.get(i));
+                if (row.get(i) != null && metadata.names.get(i).type.isCollection())
+                    col.setValue(ByteBufferUtil.bytes(FBUtilities.json(metadata.names.get(i).type.compose(row.get(i)))));
+                else
+                    col.setValue(row.get(i));
                 thriftCols.add(col);
             }
             // The key of CqlRow shoudn't be needed in CQL3

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5e5fbc68/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 95a1fee..37dd205 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -863,7 +863,7 @@ public class SelectStatement implements CQLStatement
                         if (collection == null)
                             cqlRows.addColumnValue(null);
                         else
-                            cqlRows.addColumnValue(((CollectionType)name.type).serializeForThrift(collection));
+                            cqlRows.addColumnValue(((CollectionType)name.type).serialize(collection));
                         break;
                     }
                     IColumn c = columns.getSimple(name.name.key);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5e5fbc68/src/java/org/apache/cassandra/db/marshal/CollectionType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CollectionType.java b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
index 21e96d3..a19912b 100644
--- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
@@ -30,7 +30,7 @@ import org.apache.cassandra.utils.Pair;
  * Please note that this comparator shouldn't be used "manually" (through thrift for instance).
  *
  */
-public abstract class CollectionType extends AbstractType<ByteBuffer>
+public abstract class CollectionType<T> extends AbstractType<T>
 {
     public enum Kind
     {
@@ -49,7 +49,7 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
 
     protected abstract void appendToStringBuilder(StringBuilder sb);
 
-    public abstract ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns);
+    public abstract ByteBuffer serialize(List<Pair<ByteBuffer, IColumn>> columns);
 
     @Override
     public String toString()
@@ -64,16 +64,6 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
         throw new UnsupportedOperationException("CollectionType should not be use directly as a comparator");
     }
 
-    public ByteBuffer compose(ByteBuffer bytes)
-    {
-        return BytesType.instance.compose(bytes);
-    }
-
-    public ByteBuffer decompose(ByteBuffer value)
-    {
-        return BytesType.instance.decompose(value);
-    }
-
     public String getString(ByteBuffer bytes)
     {
         return BytesType.instance.getString(bytes);
@@ -100,4 +90,17 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
     {
         return true;
     }
+
+    // Utilitary method
+    protected ByteBuffer pack(List<ByteBuffer> buffers, int elements, int size)
+    {
+        ByteBuffer result = ByteBuffer.allocate(2 + size);
+        result.putShort((short)elements);
+        for (ByteBuffer bb : buffers)
+        {
+            result.putShort((short)bb.remaining());
+            result.put(bb.duplicate());
+        }
+        return (ByteBuffer)result.flip();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5e5fbc68/src/java/org/apache/cassandra/db/marshal/ListType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ListType.java b/src/java/org/apache/cassandra/db/marshal/ListType.java
index ad1211d..f18fc00 100644
--- a/src/java/org/apache/cassandra/db/marshal/ListType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ListType.java
@@ -26,14 +26,14 @@ import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
 
-public class ListType extends CollectionType
+public class ListType<T> extends CollectionType<List<T>>
 {
     // interning instances
     private static final Map<AbstractType<?>, ListType> instances = new HashMap<AbstractType<?>, ListType>();
 
-    public final AbstractType<?> elements;
+    public final AbstractType<T> elements;
 
-    public static ListType getInstance(TypeParser parser) throws ConfigurationException
+    public static ListType<?> getInstance(TypeParser parser) throws ConfigurationException
     {
         List<AbstractType<?>> l = parser.getTypeParameters();
         if (l.size() != 1)
@@ -42,7 +42,7 @@ public class ListType extends CollectionType
         return getInstance(l.get(0));
     }
 
-    public static synchronized ListType getInstance(AbstractType<?> elements)
+    public static synchronized <T> ListType<T> getInstance(AbstractType<T> elements)
     {
         ListType t = instances.get(elements);
         if (t == null)
@@ -53,32 +53,71 @@ public class ListType extends CollectionType
         return t;
     }
 
-    private ListType(AbstractType<?> elements)
+    private ListType(AbstractType<T> elements)
     {
         super(Kind.LIST);
         this.elements = elements;
     }
 
-    public AbstractType<?> nameComparator()
+    public AbstractType<UUID> nameComparator()
     {
         return TimeUUIDType.instance;
     }
 
-    public AbstractType<?> valueComparator()
+    public AbstractType<T> valueComparator()
     {
         return elements;
     }
 
+    public List<T> compose(ByteBuffer bytes)
+    {
+        ByteBuffer input = bytes.duplicate();
+        int n = input.getShort();
+        List<T> l = new ArrayList<T>(n);
+        for (int i = 0; i < n; i++)
+        {
+            int s = input.getShort();
+            byte[] data = new byte[s];
+            input.get(data);
+            l.add(elements.compose(ByteBuffer.wrap(data)));
+        }
+        return l;
+    }
+
+    /**
+     * Layout is: {@code <n><s_1><b_1>...<s_n><b_n> }
+     * where:
+     *   n is the number of elements
+     *   s_i is the number of bytes composing the ith element
+     *   b_i is the s_i bytes composing the ith element
+     */
+    public ByteBuffer decompose(List<T> value)
+    {
+        List<ByteBuffer> bbs = new ArrayList<ByteBuffer>(value.size());
+        int size = 0;
+        for (T elt : value)
+        {
+            ByteBuffer bb = elements.decompose(elt);
+            bbs.add(bb);
+            size += 2 + bb.remaining();
+        }
+        return pack(bbs, value.size(), size);
+    }
+
     protected void appendToStringBuilder(StringBuilder sb)
     {
         sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Collections.<AbstractType<?>>singletonList(elements)));
     }
 
-    public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
+    public ByteBuffer serialize(List<Pair<ByteBuffer, IColumn>> columns)
     {
-        List<Object> l = new ArrayList<Object>(columns.size());
+        List<ByteBuffer> bbs = new ArrayList<ByteBuffer>(columns.size());
+        int size = 0;
         for (Pair<ByteBuffer, IColumn> p : columns)
-            l.add(elements.compose(p.right.value()));
-        return ByteBufferUtil.bytes(FBUtilities.json(l));
+        {
+            bbs.add(p.right.value());
+            size += 2 + p.right.value().remaining();
+        }
+        return pack(bbs, columns.size(), size);
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5e5fbc68/src/java/org/apache/cassandra/db/marshal/MapType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/MapType.java b/src/java/org/apache/cassandra/db/marshal/MapType.java
index a5a6caa..2ac65cf 100644
--- a/src/java/org/apache/cassandra/db/marshal/MapType.java
+++ b/src/java/org/apache/cassandra/db/marshal/MapType.java
@@ -18,11 +18,7 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.cassandra.db.IColumn;
 import org.apache.cassandra.config.ConfigurationException;
@@ -30,15 +26,15 @@ import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
 
-public class MapType extends CollectionType
+public class MapType<K, V> extends CollectionType<Map<K, V>>
 {
     // interning instances
     private static final Map<Pair<AbstractType<?>, AbstractType<?>>, MapType> instances = new HashMap<Pair<AbstractType<?>, AbstractType<?>>, MapType>();
 
-    public final AbstractType<?> keys;
-    public final AbstractType<?> values;
+    public final AbstractType<K> keys;
+    public final AbstractType<V> values;
 
-    public static MapType getInstance(TypeParser parser) throws ConfigurationException
+    public static MapType<?, ?> getInstance(TypeParser parser) throws ConfigurationException
     {
         List<AbstractType<?>> l = parser.getTypeParameters();
         if (l.size() != 2)
@@ -47,7 +43,7 @@ public class MapType extends CollectionType
         return getInstance(l.get(0), l.get(1));
     }
 
-    public static synchronized MapType getInstance(AbstractType<?> keys, AbstractType<?> values)
+    public static synchronized <K, V> MapType<K, V> getInstance(AbstractType<K> keys, AbstractType<V> values)
     {
         Pair<AbstractType<?>, AbstractType<?>> p = Pair.<AbstractType<?>, AbstractType<?>>create(keys, values);
         MapType t = instances.get(p);
@@ -59,33 +55,84 @@ public class MapType extends CollectionType
         return t;
     }
 
-    private MapType(AbstractType<?> keys, AbstractType<?> values)
+    private MapType(AbstractType<K> keys, AbstractType<V> values)
     {
         super(Kind.MAP);
         this.keys = keys;
         this.values = values;
     }
 
-    public AbstractType<?> nameComparator()
+    public AbstractType<K> nameComparator()
     {
         return keys;
     }
 
-    public AbstractType<?> valueComparator()
+    public AbstractType<V> valueComparator()
     {
         return values;
     }
 
+    public Map<K, V> compose(ByteBuffer bytes)
+    {
+        ByteBuffer input = bytes.duplicate();
+        int n = input.getShort();
+        Map<K, V> m = new LinkedHashMap<K, V>(n);
+        for (int i = 0; i < n; i++)
+        {
+            int sk = input.getShort();
+            byte[] datak = new byte[sk];
+            input.get(datak);
+
+            int sv = input.getShort();
+            byte[] datav = new byte[sv];
+            input.get(datav);
+            m.put(keys.compose(ByteBuffer.wrap(datak)), values.compose(ByteBuffer.wrap(datav)));
+        }
+        return m;
+    }
+
+    /**
+     * Layout is: {@code <n><sk_1><k_1><sv_1><v_1>...<sk_n><k_n><sv_n><v_n> }
+     * where:
+     *   n is the number of elements
+     *   sk_i is the number of bytes composing the ith key k_i
+     *   k_i is the sk_i bytes composing the ith key
+     *   sv_i is the number of bytes composing the ith value v_i
+     *   v_i is the sv_i bytes composing the ith value
+     */
+    public ByteBuffer decompose(Map<K, V> value)
+    {
+        List<ByteBuffer> bbs = new ArrayList<ByteBuffer>(2 * value.size());
+        int size = 0;
+        for (Map.Entry<K, V> entry : value.entrySet())
+        {
+            ByteBuffer bbk = keys.decompose(entry.getKey());
+            ByteBuffer bbv = values.decompose(entry.getValue());
+            bbs.add(bbk);
+            bbs.add(bbv);
+            size += 4 + bbk.remaining() + bbv.remaining();
+        }
+        return pack(bbs, value.size(), size);
+    }
+
     protected void appendToStringBuilder(StringBuilder sb)
     {
         sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Arrays.asList(keys, values)));
     }
 
-    public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
+    /**
+     * Creates the same output than decompose, but from the internal representation.
+     */
+    public ByteBuffer serialize(List<Pair<ByteBuffer, IColumn>> columns)
     {
-        Map<String, Object> m = new LinkedHashMap<String, Object>();
+        List<ByteBuffer> bbs = new ArrayList<ByteBuffer>(2 * columns.size());
+        int size = 0;
         for (Pair<ByteBuffer, IColumn> p : columns)
-            m.put(keys.getString(p.left), values.compose(p.right.value()));
-        return ByteBufferUtil.bytes(FBUtilities.json(m));
+        {
+            bbs.add(p.left);
+            bbs.add(p.right.value());
+            size += 4 + p.left.remaining() + p.right.value().remaining();
+        }
+        return pack(bbs, columns.size(), size);
     }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5e5fbc68/src/java/org/apache/cassandra/db/marshal/SetType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/SetType.java b/src/java/org/apache/cassandra/db/marshal/SetType.java
index a4fa9e3..7c71baf 100644
--- a/src/java/org/apache/cassandra/db/marshal/SetType.java
+++ b/src/java/org/apache/cassandra/db/marshal/SetType.java
@@ -18,11 +18,7 @@
 package org.apache.cassandra.db.marshal;
 
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.cassandra.db.IColumn;
 import org.apache.cassandra.config.ConfigurationException;
@@ -30,14 +26,14 @@ import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
 
-public class SetType extends CollectionType
+public class SetType<T> extends CollectionType<Set<T>>
 {
     // interning instances
     private static final Map<AbstractType<?>, SetType> instances = new HashMap<AbstractType<?>, SetType>();
 
-    public final AbstractType<?> elements;
+    public final AbstractType<T> elements;
 
-    public static SetType getInstance(TypeParser parser) throws ConfigurationException
+    public static SetType<?> getInstance(TypeParser parser) throws ConfigurationException
     {
         List<AbstractType<?>> l = parser.getTypeParameters();
         if (l.size() != 1)
@@ -46,7 +42,7 @@ public class SetType extends CollectionType
         return getInstance(l.get(0));
     }
 
-    public static synchronized SetType getInstance(AbstractType<?> elements)
+    public static synchronized <T> SetType getInstance(AbstractType<T> elements)
     {
         SetType t = instances.get(elements);
         if (t == null)
@@ -57,13 +53,13 @@ public class SetType extends CollectionType
         return t;
     }
 
-    public SetType(AbstractType<?> elements)
+    public SetType(AbstractType<T> elements)
     {
         super(Kind.SET);
         this.elements = elements;
     }
 
-    public AbstractType<?> nameComparator()
+    public AbstractType<T> nameComparator()
     {
         return elements;
     }
@@ -73,17 +69,55 @@ public class SetType extends CollectionType
         return EmptyType.instance;
     }
 
+    public Set<T> compose(ByteBuffer bytes)
+    {
+        ByteBuffer input = bytes.duplicate();
+        int n = input.getShort();
+        Set<T> l = new LinkedHashSet<T>(n);
+        for (int i = 0; i < n; i++)
+        {
+            int s = input.getShort();
+            byte[] data = new byte[s];
+            input.get(data);
+            l.add(elements.compose(ByteBuffer.wrap(data)));
+        }
+        return l;
+    }
+
+    /**
+     * Layout is: {@code <n><s_1><b_1>...<s_n><b_n> }
+     * where:
+     *   n is the number of elements
+     *   s_i is the number of bytes composing the ith element
+     *   b_i is the s_i bytes composing the ith element
+     */
+    public ByteBuffer decompose(Set<T> value)
+    {
+        List<ByteBuffer> bbs = new ArrayList<ByteBuffer>(value.size());
+        int size = 0;
+        for (T elt : value)
+        {
+            ByteBuffer bb = elements.decompose(elt);
+            bbs.add(bb);
+            size += 2 + bb.remaining();
+        }
+        return pack(bbs, value.size(), size);
+    }
+
     protected void appendToStringBuilder(StringBuilder sb)
     {
         sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Collections.<AbstractType<?>>singletonList(elements)));
     }
 
-    public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
+    public ByteBuffer serialize(List<Pair<ByteBuffer, IColumn>> columns)
     {
-        // We're using a list for now, since json doesn't have maps
-        List<Object> l = new ArrayList<Object>(columns.size());
+        List<ByteBuffer> bbs = new ArrayList<ByteBuffer>(columns.size());
+        int size = 0;
         for (Pair<ByteBuffer, IColumn> p : columns)
-            l.add(elements.compose(p.left));
-        return ByteBufferUtil.bytes(FBUtilities.json(l));
+        {
+            bbs.add(p.left);
+            size += 2 + p.left.remaining();
+        }
+        return pack(bbs, columns.size(), size);
     }
 }