IntergerType uses Thrift method that attempts to unsafely access backing array
of ByteBuffer and fails
------------------------------------------------------------------------------------------------------
Key: CASSANDRA-2684
URL: https://issues.apache.org/jira/browse/CASSANDRA-2684
Project: Cassandra
Issue Type: Bug
Reporter: Ed Anuff
I get the following exception:
ERROR 13:27:38,153 Fatal exception in thread Thread[ReadStage:36,5,main]
java.lang.RuntimeException: java.lang.UnsupportedOperationException
at
org.apache.cassandra.utils.WrappedRunnable.run(WrappedRunnable.java:34)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.UnsupportedOperationException
at java.nio.ByteBuffer.array(ByteBuffer.java:940)
at
org.apache.thrift.TBaseHelper.byteBufferToByteArray(TBaseHelper.java:264)
at
org.apache.thrift.TBaseHelper.byteBufferToByteArray(TBaseHelper.java:251)
at
org.apache.cassandra.db.marshal.IntegerType.getString(IntegerType.java:136)
at
org.apache.cassandra.db.marshal.AbstractCompositeType.getString(AbstractCompositeType.java:131)
at org.apache.cassandra.db.Column.getString(Column.java:228)
at
org.apache.cassandra.db.filter.SliceQueryFilter.collectReducedColumns(SliceQueryFilter.java:123)
at
org.apache.cassandra.db.filter.QueryFilter.collectCollatedColumns(QueryFilter.java:130)
at
org.apache.cassandra.db.ColumnFamilyStore.getTopLevelColumns(ColumnFamilyStore.java:1303)
at
org.apache.cassandra.db.ColumnFamilyStore.getColumnFamily(ColumnFamilyStore.java:1188)
at
org.apache.cassandra.db.ColumnFamilyStore.getColumnFamily(ColumnFamilyStore.java:1145)
at org.apache.cassandra.db.Table.getRow(Table.java:385)
at
org.apache.cassandra.db.SliceFromReadCommand.getRow(SliceFromReadCommand.java:61)
at
org.apache.cassandra.service.StorageProxy$LocalReadRunnable.runMayThrow(StorageProxy.java:641)
at
org.apache.cassandra.utils.WrappedRunnable.run(WrappedRunnable.java:30)
... 3 more
Tracing it down, I find that IntegerType's getString method() looks like this:
public String getString(ByteBuffer bytes)
{
if (bytes == null)
return "null";
if (bytes.remaining() == 0)
return "empty";
return new
java.math.BigInteger(TBaseHelper.byteBufferToByteArray(bytes)).toString(10);
}
TBaseHelper.byteBufferToByteArray() looks like this:
public static byte[] byteBufferToByteArray(ByteBuffer byteBuffer) {
if (wrapsFullArray(byteBuffer)) {
return byteBuffer.array();
}
byte[] target = new byte[byteBuffer.remaining()];
byteBufferToByteArray(byteBuffer, target, 0);
return target;
}
public static boolean wrapsFullArray(ByteBuffer byteBuffer) {
return byteBuffer.hasArray()
&& byteBuffer.position() == 0
&& byteBuffer.arrayOffset() == 0
&& byteBuffer.remaining() == byteBuffer.capacity();
}
public static int byteBufferToByteArray(ByteBuffer byteBuffer, byte[] target,
int offset) {
int remaining = byteBuffer.remaining();
System.arraycopy(byteBuffer.array(),
byteBuffer.arrayOffset() + byteBuffer.position(),
target,
offset,
remaining);
return remaining;
}
The second overloaded implementation of byteBufferToByteArray is calling the
bytebuffer's array() method.
Suggested fixes:
1) Don't use TBaseHelper in IntegerType.getString(), use
ByteBufferUtil.getArray()
2) Report problem upstream to Thrift.
3) Find a better way to deserialize BigIntegers that doesn't require an array
copy.
--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira