Repository: cassandra Updated Branches: refs/heads/trunk a0d070764 -> 5477083a2
Eliminate repeated allocation of Pair for default case Replace Objects.hashcode with handrolled to avoid allocation Eliminate allocations of byte array for UTF8 String serializations Patch by Nitsan Wakart; reviewed by tjake for CASSANDRA-11428 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/5477083a Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/5477083a Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/5477083a Branch: refs/heads/trunk Commit: 5477083a2f087758034703674c49e8012f295c42 Parents: a0d0707 Author: nitsanw <[email protected]> Authored: Thu Mar 24 10:54:14 2016 +0200 Committer: T Jake Luciani <[email protected]> Committed: Fri Apr 15 09:35:04 2016 -0400 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/config/ColumnDefinition.java | 18 ++++- .../org/apache/cassandra/transport/CBUtil.java | 78 ++++++++++++-------- .../apache/cassandra/transport/DataType.java | 4 +- 4 files changed, 66 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/5477083a/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 43d1c3c..7db486d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.6 + * Eliminate allocations in R/W path (CASSANDRA-11421) * Update Netty to 4.0.36 (CASSANDRA-11567) * Fix PER PARTITION LIMIT for queries requiring post-query ordering (CASSANDRA-11556) * Allow instantiation of UDTs and tuples in UDFs (CASSANDRA-10818) http://git-wip-us.apache.org/repos/asf/cassandra/blob/5477083a/src/java/org/apache/cassandra/config/ColumnDefinition.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/ColumnDefinition.java b/src/java/org/apache/cassandra/config/ColumnDefinition.java index 2c2cbb7..a18ed3f 100644 --- a/src/java/org/apache/cassandra/config/ColumnDefinition.java +++ b/src/java/org/apache/cassandra/config/ColumnDefinition.java @@ -81,6 +81,8 @@ public class ColumnDefinition extends ColumnSpecification implements Comparable< private final Comparator<Object> asymmetricCellPathComparator; private final Comparator<? super Cell> cellComparator; + private int hash; + /** * These objects are compared frequently, so we encode several of their comparison components * into a single long value so that this can be done efficiently @@ -262,9 +264,21 @@ public class ColumnDefinition extends ColumnSpecification implements Comparable< @Override public int hashCode() { - return Objects.hashCode(ksName, cfName, name, type, kind, position); + // This achieves the same as Objects.hashcode, but avoids the object array allocation + // which features significantly in the allocation profile and caches the result. + int result = hash; + if(result == 0) + { + result = 31 + (ksName == null ? 0 : ksName.hashCode()); + result = 31 * result + (cfName == null ? 0 : cfName.hashCode()); + result = 31 * result + (name == null ? 0 : name.hashCode()); + result = 31 * result + (type == null ? 0 : type.hashCode()); + result = 31 * result + (kind == null ? 0 : kind.hashCode()); + result = 31 * result + position; + hash = result; + } + return result; } - @Override public String toString() { http://git-wip-us.apache.org/repos/asf/cassandra/blob/5477083a/src/java/org/apache/cassandra/transport/CBUtil.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/transport/CBUtil.java b/src/java/org/apache/cassandra/transport/CBUtil.java index 800a9a8..43f4bbd 100644 --- a/src/java/org/apache/cassandra/transport/CBUtil.java +++ b/src/java/org/apache/cassandra/transport/CBUtil.java @@ -33,15 +33,19 @@ import java.util.List; import java.util.Map; import java.util.UUID; -import io.netty.buffer.*; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.util.CharsetUtil; - +import io.netty.util.concurrent.FastThreadLocal; import org.apache.cassandra.config.Config; import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.Pair; import org.apache.cassandra.utils.UUIDGen; -import org.apache.cassandra.utils.ByteBufferUtil; /** * ByteBuf utility methods. @@ -55,9 +59,7 @@ public abstract class CBUtil public static final boolean USE_HEAP_ALLOCATOR = Boolean.getBoolean(Config.PROPERTY_PREFIX + "netty_use_heap_allocator"); public static final ByteBufAllocator allocator = USE_HEAP_ALLOCATOR ? new UnpooledByteBufAllocator(false) : new PooledByteBufAllocator(true); - private CBUtil() {} - - private final static ThreadLocal<CharsetDecoder> decoder = new ThreadLocal<CharsetDecoder>() + private final static FastThreadLocal<CharsetDecoder> TL_UTF8_DECODER = new FastThreadLocal<CharsetDecoder>() { @Override protected CharsetDecoder initialValue() @@ -66,6 +68,40 @@ public abstract class CBUtil } }; + private final static FastThreadLocal<CharBuffer> TL_CHAR_BUFFER = new FastThreadLocal<>(); + + private CBUtil() {} + + + // Taken from Netty's ChannelBuffers.decodeString(). We need to use our own decoder to properly handle invalid + // UTF-8 sequences. See CASSANDRA-8101 for more details. This can be removed once https://github.com/netty/netty/pull/2999 + // is resolved in a release used by Cassandra. + private static String decodeString(ByteBuffer src) throws CharacterCodingException + { + // the decoder needs to be reset every time we use it, hence the copy per thread + CharsetDecoder theDecoder = TL_UTF8_DECODER.get(); + theDecoder.reset(); + CharBuffer dst = TL_CHAR_BUFFER.get(); + int capacity = (int) ((double) src.remaining() * theDecoder.maxCharsPerByte()); + if (dst == null) { + capacity = Math.max(capacity, 4096); + dst = CharBuffer.allocate(capacity); + TL_CHAR_BUFFER.set(dst); + } + else { + dst.clear(); + if (dst.capacity() < capacity){ + dst = CharBuffer.allocate(capacity); + TL_CHAR_BUFFER.set(dst); + } + } + CoderResult cr = theDecoder.decode(src, dst, true); + if (!cr.isUnderflow()) + cr.throwException(); + + return dst.flip().toString(); + } + private static String readString(ByteBuf cb, int length) { if (length == 0) @@ -97,34 +133,12 @@ public abstract class CBUtil } } - // Taken from Netty's ChannelBuffers.decodeString(). We need to use our own decoder to properly handle invalid - // UTF-8 sequences. See CASSANDRA-8101 for more details. This can be removed once https://github.com/netty/netty/pull/2999 - // is resolved in a release used by Cassandra. - private static String decodeString(ByteBuffer src) throws CharacterCodingException - { - // the decoder needs to be reset every time we use it, hence the copy per thread - CharsetDecoder theDecoder = decoder.get(); - theDecoder.reset(); - - final CharBuffer dst = CharBuffer.allocate( - (int) ((double) src.remaining() * theDecoder.maxCharsPerByte())); - - CoderResult cr = theDecoder.decode(src, dst, true); - if (!cr.isUnderflow()) - cr.throwException(); - - cr = theDecoder.flush(dst); - if (!cr.isUnderflow()) - cr.throwException(); - - return dst.flip().toString(); - } - public static void writeString(String str, ByteBuf cb) { - byte[] bytes = str.getBytes(CharsetUtil.UTF_8); - cb.writeShort(bytes.length); - cb.writeBytes(bytes); + int writerIndex = cb.writerIndex(); + cb.writeShort(0); + int lengthBytes = ByteBufUtil.writeUtf8(cb, str); + cb.setShort(writerIndex, lengthBytes); } public static int sizeOfString(String str) http://git-wip-us.apache.org/repos/asf/cassandra/blob/5477083a/src/java/org/apache/cassandra/transport/DataType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/transport/DataType.java b/src/java/org/apache/cassandra/transport/DataType.java index acaa9a3..7abcba7 100644 --- a/src/java/org/apache/cassandra/transport/DataType.java +++ b/src/java/org/apache/cassandra/transport/DataType.java @@ -66,6 +66,7 @@ public enum DataType implements OptionCodec.Codecable<DataType> private final int id; private final int protocolVersion; private final AbstractType type; + private final Pair<DataType, Object> pair; private static final Map<AbstractType, DataType> dataTypeMap = new HashMap<AbstractType, DataType>(); static { @@ -81,6 +82,7 @@ public enum DataType implements OptionCodec.Codecable<DataType> this.id = id; this.type = type; this.protocolVersion = protocolVersion; + pair = Pair.create(this, null); } public int getId(int version) @@ -261,7 +263,7 @@ public enum DataType implements OptionCodec.Codecable<DataType> // Fall back to CUSTOM if target doesn't know this data type if (version < dt.protocolVersion) return Pair.<DataType, Object>create(CUSTOM, type.toString()); - return Pair.create(dt, null); + return dt.pair; } }
