Support collections natively in the binary protocol

patch by slebresne; reviewed by Paul Cannon for CASSANDRA-4453
This commit is contained in:
Jonathan Ellis 2012-08-14 16:50:39 -05:00
parent 5e5fbc6853
commit ba231f4eb5
4 changed files with 91 additions and 10 deletions

View File

@ -49,6 +49,8 @@ Table of Contents
. . . .
+---------------------------------------- +----------------------------------------
The protocol is big-endian (network byte order).
Each frame contains a fixed size header (8 bytes) followed by a variable size Each frame contains a fixed size header (8 bytes) followed by a variable size
body. The header is described in Section 2. The content of the body depends body. The header is described in Section 2. The content of the body depends
on the header opcode value (the body can in particular be empty for some on the header opcode value (the body can in particular be empty for some
@ -355,6 +357,12 @@ Table of Contents
0x000D Varchar 0x000D Varchar
0x000E Varint 0x000E Varint
0x000F Timeuuid 0x000F Timeuuid
0x0020 List: the value is an [option], representing the type
of the elements of the list.
0x0021 Map: the value is two [option], representing the types of the
keys and values of the map
0x0022 Set: the value is an [option], representing the type
of the elements of the set
- <rows_count> is an [int] representing the number of rows present in this - <rows_count> is an [int] representing the number of rows present in this
result. Those rows are serialized in the <rows_content> part. result. Those rows are serialized in the <rows_content> part.
- <rows_content> is composed of <row_1>...<row_m> where m is <rows_count>. - <rows_content> is composed of <row_1>...<row_m> where m is <rows_count>.

View File

@ -204,7 +204,6 @@ public class ResultSet
public static class Metadata public static class Metadata
{ {
private static OptionCodec<DataType> dataTypeCodec = new OptionCodec<DataType>(DataType.class);
public static final CBCodec<Metadata> codec = new Codec(); public static final CBCodec<Metadata> codec = new Codec();
public final EnumSet<Flag> flags; public final EnumSet<Flag> flags;
@ -277,7 +276,7 @@ public class ResultSet
String ksName = globalTablesSpec ? globalKsName : CBUtil.readString(body); String ksName = globalTablesSpec ? globalKsName : CBUtil.readString(body);
String cfName = globalTablesSpec ? globalCfName : CBUtil.readString(body); String cfName = globalTablesSpec ? globalCfName : CBUtil.readString(body);
ColumnIdentifier colName = new ColumnIdentifier(CBUtil.readString(body), true); ColumnIdentifier colName = new ColumnIdentifier(CBUtil.readString(body), true);
AbstractType type = DataType.toType(dataTypeCodec.decodeOne(body)); AbstractType type = DataType.toType(DataType.codec.decodeOne(body));
names.add(new ColumnSpecification(ksName, cfName, colName, type)); names.add(new ColumnSpecification(ksName, cfName, colName, type));
} }
return new Metadata(flags, names); return new Metadata(flags, names);
@ -309,7 +308,7 @@ public class ResultSet
builder.addString(name.cfName); builder.addString(name.cfName);
} }
builder.addString(name.toString()); builder.addString(name.toString());
builder.add(dataTypeCodec.encodeOne(DataType.fromType(name.type))); builder.add(DataType.codec.encodeOne(DataType.fromType(name.type)));
} }
return builder.build(); return builder.build();
} }

View File

@ -17,8 +17,11 @@
*/ */
package org.apache.cassandra.transport; package org.apache.cassandra.transport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.List;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
@ -44,7 +47,12 @@ public enum DataType implements OptionCodec.Codecable<DataType>
UUID (12, UUIDType.instance), UUID (12, UUIDType.instance),
VARCHAR (13, UTF8Type.instance), VARCHAR (13, UTF8Type.instance),
VARINT (14, IntegerType.instance), VARINT (14, IntegerType.instance),
TIMEUUID (15, TimeUUIDType.instance); TIMEUUID (15, TimeUUIDType.instance),
LIST (32, null),
MAP (33, null),
SET (34, null);
public static final OptionCodec<DataType> codec = new OptionCodec<DataType>(DataType.class);
private final int id; private final int id;
private final AbstractType type; private final AbstractType type;
@ -75,6 +83,15 @@ public enum DataType implements OptionCodec.Codecable<DataType>
{ {
case CUSTOM: case CUSTOM:
return CBUtil.readString(cb); return CBUtil.readString(cb);
case LIST:
return DataType.toType(codec.decodeOne(cb));
case SET:
return DataType.toType(codec.decodeOne(cb));
case MAP:
List<AbstractType> l = new ArrayList<AbstractType>(2);
l.add(DataType.toType(codec.decodeOne(cb)));
l.add(DataType.toType(codec.decodeOne(cb)));
return l;
default: default:
return null; return null;
} }
@ -88,6 +105,17 @@ public enum DataType implements OptionCodec.Codecable<DataType>
assert value instanceof String; assert value instanceof String;
cb.writeBytes(CBUtil.stringToCB((String)value)); cb.writeBytes(CBUtil.stringToCB((String)value));
break; break;
case LIST:
cb.writeBytes(codec.encodeOne(DataType.fromType((AbstractType)value)));
break;
case SET:
cb.writeBytes(codec.encodeOne(DataType.fromType((AbstractType)value)));
break;
case MAP:
List<AbstractType> l = (List<AbstractType>)value;
cb.writeBytes(codec.encodeOne(DataType.fromType(l.get(0))));
cb.writeBytes(codec.encodeOne(DataType.fromType(l.get(1))));
break;
} }
} }
@ -97,6 +125,15 @@ public enum DataType implements OptionCodec.Codecable<DataType>
{ {
case CUSTOM: case CUSTOM:
return 2 + ((String)value).getBytes(Charsets.UTF_8).length; return 2 + ((String)value).getBytes(Charsets.UTF_8).length;
case LIST:
case SET:
return codec.oneSerializedSize(DataType.fromType((AbstractType)value));
case MAP:
List<AbstractType> l = (List<AbstractType>)value;
int s = 0;
s += codec.oneSerializedSize(DataType.fromType(l.get(0)));
s += codec.oneSerializedSize(DataType.fromType(l.get(1)));
return s;
default: default:
return 0; return 0;
} }
@ -106,19 +143,50 @@ public enum DataType implements OptionCodec.Codecable<DataType>
{ {
DataType dt = dataTypeMap.get(type); DataType dt = dataTypeMap.get(type);
if (dt == null) if (dt == null)
{
if (type.isCollection())
{
if (type instanceof ListType)
{
return Pair.<DataType, Object>create(LIST, ((ListType)type).elements);
}
else if (type instanceof MapType)
{
MapType mt = (MapType)type;
return Pair.<DataType, Object>create(MAP, Arrays.asList(mt.keys, mt.values));
}
else
{
assert type instanceof SetType;
return Pair.<DataType, Object>create(LIST, ((SetType)type).elements);
}
}
return Pair.<DataType, Object>create(CUSTOM, type.toString()); return Pair.<DataType, Object>create(CUSTOM, type.toString());
}
else else
{
return Pair.create(dt, null); return Pair.create(dt, null);
}
} }
public static AbstractType toType(Pair<DataType, Object> entry) public static AbstractType toType(Pair<DataType, Object> entry)
{ {
try try
{ {
if (entry.left == CUSTOM) switch (entry.left)
return TypeParser.parse((String)entry.right); {
else case CUSTOM:
return entry.left.type; return TypeParser.parse((String)entry.right);
case LIST:
return ListType.getInstance((AbstractType)entry.right);
case SET:
return SetType.getInstance((AbstractType)entry.right);
case MAP:
List<AbstractType> l = (List<AbstractType>)entry.right;
return MapType.getInstance(l.get(0), l.get(1));
default:
return entry.left.type;
}
} }
catch (ConfigurationException e) catch (ConfigurationException e)
{ {

View File

@ -109,11 +109,17 @@ public class OptionCodec<T extends Enum<T> & OptionCodec.Codecable<T>>
T opt = option.left; T opt = option.left;
Object obj = option.right; Object obj = option.right;
int l = 2 + opt.serializedValueSize(obj); ChannelBuffer cb = ChannelBuffers.buffer(oneSerializedSize(option));
ChannelBuffer cb = ChannelBuffers.buffer(l);
cb.writeShort(opt.getId()); cb.writeShort(opt.getId());
opt.writeValue(obj, cb); opt.writeValue(obj, cb);
return cb; return cb;
} }
public int oneSerializedSize(Pair<T, Object> option)
{
T opt = option.left;
Object obj = option.right;
return 2 + opt.serializedValueSize(obj);
}
} }