Description
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:
IntegerType.java
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:
TBaseHelper.java
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.