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);
}
}