Repository: cassandra Updated Branches: refs/heads/trunk 6d266253a -> bf9c50313
Avoid memory allocation when searching index summary patch by benedict; reviewed by ariel for CASSANDRA-8793 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/bf9c5031 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/bf9c5031 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/bf9c5031 Branch: refs/heads/trunk Commit: bf9c5031301ef9ad310d5bb01142b5a67ce7f415 Parents: 6d26625 Author: Benedict Elliott Smith <[email protected]> Authored: Tue Mar 10 13:54:36 2015 +0000 Committer: Benedict Elliott Smith <[email protected]> Committed: Tue Mar 10 13:54:36 2015 +0000 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/io/sstable/IndexSummary.java | 12 ++++++++++- .../io/sstable/IndexSummaryBuilder.java | 4 ++-- .../org/apache/cassandra/io/util/Memory.java | 21 ++++++++++++++++---- .../cassandra/io/util/SafeMemoryWriter.java | 15 ++++++++++---- .../cassandra/utils/memory/MemoryUtil.java | 14 +++++++++++-- 6 files changed, 54 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf9c5031/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index d326313..a6adfe0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0 + * Avoid memory allocation when searching index summary (CASSANDRA-8793) * Optimise (Time)?UUIDType Comparisons (CASSANDRA-8730) * Make CRC32Ex into a separate maven dependency (CASSANDRA-8836) * Use preloaded jemalloc w/ Unsafe (CASSANDRA-8714) http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf9c5031/src/java/org/apache/cassandra/io/sstable/IndexSummary.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/io/sstable/IndexSummary.java b/src/java/org/apache/cassandra/io/sstable/IndexSummary.java index 7e4619e..c590d1a 100644 --- a/src/java/org/apache/cassandra/io/sstable/IndexSummary.java +++ b/src/java/org/apache/cassandra/io/sstable/IndexSummary.java @@ -30,6 +30,7 @@ import org.apache.cassandra.io.util.Memory; import org.apache.cassandra.io.util.MemoryOutputStream; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.concurrent.WrappedSharedCloseable; +import org.apache.cassandra.utils.memory.MemoryUtil; import static org.apache.cassandra.io.sstable.Downsampling.BASE_SAMPLING_LEVEL; @@ -105,11 +106,13 @@ public class IndexSummary extends WrappedSharedCloseable // Harmony's Collections implementation public int binarySearch(RowPosition key) { + ByteBuffer hollow = MemoryUtil.getHollowDirectByteBuffer(); int low = 0, mid = offsetCount, high = mid - 1, result = -1; while (low <= high) { mid = (low + high) >> 1; - result = -DecoratedKey.compareTo(partitioner, ByteBuffer.wrap(getKey(mid)), key); + fillTemporaryKey(mid, hollow); + result = -DecoratedKey.compareTo(partitioner, hollow, key); if (result > 0) { low = mid + 1; @@ -147,6 +150,13 @@ public class IndexSummary extends WrappedSharedCloseable return key; } + private void fillTemporaryKey(int index, ByteBuffer buffer) + { + long start = getPositionInSummary(index); + int keySize = (int) (calculateEnd(index) - start - 8L); + entries.setByteBuffer(buffer, start, keySize); + } + public long getPosition(int index) { return entries.getLong(calculateEnd(index) - 8); http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf9c5031/src/java/org/apache/cassandra/io/sstable/IndexSummaryBuilder.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/io/sstable/IndexSummaryBuilder.java b/src/java/org/apache/cassandra/io/sstable/IndexSummaryBuilder.java index 892e240..2e96d03 100644 --- a/src/java/org/apache/cassandra/io/sstable/IndexSummaryBuilder.java +++ b/src/java/org/apache/cassandra/io/sstable/IndexSummaryBuilder.java @@ -107,8 +107,8 @@ public class IndexSummaryBuilder implements AutoCloseable // for initializing data structures, adjust our estimates based on the sampling level maxExpectedEntries = Math.max(1, (maxExpectedEntries * samplingLevel) / BASE_SAMPLING_LEVEL); - offsets = new SafeMemoryWriter(4 * maxExpectedEntries).withByteOrder(ByteOrder.nativeOrder()); - entries = new SafeMemoryWriter(40 * maxExpectedEntries).withByteOrder(ByteOrder.nativeOrder()); + offsets = new SafeMemoryWriter(4 * maxExpectedEntries).order(ByteOrder.nativeOrder()); + entries = new SafeMemoryWriter(40 * maxExpectedEntries).order(ByteOrder.nativeOrder()); setNextSamplePosition(-minIndexInterval); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf9c5031/src/java/org/apache/cassandra/io/util/Memory.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/io/util/Memory.java b/src/java/org/apache/cassandra/io/util/Memory.java index e12064d..78a3ea5 100644 --- a/src/java/org/apache/cassandra/io/util/Memory.java +++ b/src/java/org/apache/cassandra/io/util/Memory.java @@ -182,7 +182,7 @@ public class Memory implements AutoCloseable public void setShort(long offset, short l) { - checkBounds(offset, offset + 4); + checkBounds(offset, offset + 2); if (unaligned) { unsafe.putShort(peer + offset, l); @@ -245,9 +245,7 @@ public class Memory implements AutoCloseable else if (count == 0) return; - long end = memoryOffset + count; - checkBounds(memoryOffset, end); - + checkBounds(memoryOffset, memoryOffset + count); unsafe.copyMemory(buffer, BYTE_ARRAY_BASE_OFFSET + bufferOffset, null, peer + memoryOffset, count); } @@ -343,6 +341,8 @@ public class Memory implements AutoCloseable public void put(long trgOffset, Memory memory, long srcOffset, long size) { + checkBounds(trgOffset, trgOffset + size); + memory.checkBounds(srcOffset, srcOffset + size); unsafe.copyMemory(memory.peer + srcOffset, peer + trgOffset, size); } @@ -401,6 +401,19 @@ public class Memory implements AutoCloseable return result; } + public ByteBuffer asByteBuffer(long offset, int length) + { + checkBounds(offset, offset + length); + return MemoryUtil.getByteBuffer(peer + offset, length); + } + + // MUST provide a buffer created via MemoryUtil.getHollowDirectByteBuffer() + public void setByteBuffer(ByteBuffer buffer, long offset, int length) + { + checkBounds(offset, offset + length); + MemoryUtil.setByteBuffer(buffer, peer + offset, length); + } + public String toString() { return toString(peer, size); http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf9c5031/src/java/org/apache/cassandra/io/util/SafeMemoryWriter.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/io/util/SafeMemoryWriter.java b/src/java/org/apache/cassandra/io/util/SafeMemoryWriter.java index 1998cc6..6c87cf9 100644 --- a/src/java/org/apache/cassandra/io/util/SafeMemoryWriter.java +++ b/src/java/org/apache/cassandra/io/util/SafeMemoryWriter.java @@ -33,6 +33,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl buffer = new SafeMemory(initialCapacity); } + @Override public void write(byte[] buffer, int offset, int count) { long newLength = ensureCapacity(count); @@ -40,6 +41,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl this.length = newLength; } + @Override public void write(int oneByte) { long newLength = ensureCapacity(1); @@ -47,6 +49,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl length = newLength; } + @Override public void writeShort(int val) throws IOException { if (order != ByteOrder.nativeOrder()) @@ -56,6 +59,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl length = newLength; } + @Override public void writeInt(int val) { if (order != ByteOrder.nativeOrder()) @@ -65,6 +69,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl length = newLength; } + @Override public void writeLong(long val) { if (order != ByteOrder.nativeOrder()) @@ -74,6 +79,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl length = newLength; } + @Override public void write(ByteBuffer buffer) { long newLength = ensureCapacity(buffer.remaining()); @@ -81,10 +87,11 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl length = newLength; } - public void write(Memory memory) + @Override + public void write(Memory memory, long offset, long size) { - long newLength = ensureCapacity(memory.size()); - buffer.put(length, memory, 0, memory.size()); + long newLength = ensureCapacity(size); + buffer.put(length, memory, offset, size); length = newLength; } @@ -128,7 +135,7 @@ public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPl // TODO: consider hoisting this into DataOutputPlus, since most implementations can copy with this gracefully // this would simplify IndexSummary.IndexSummarySerializer.serialize() - public SafeMemoryWriter withByteOrder(ByteOrder order) + public SafeMemoryWriter order(ByteOrder order) { this.order = order; return this; http://git-wip-us.apache.org/repos/asf/cassandra/blob/bf9c5031/src/java/org/apache/cassandra/utils/memory/MemoryUtil.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/utils/memory/MemoryUtil.java b/src/java/org/apache/cassandra/utils/memory/MemoryUtil.java index 60b2b7f..8304bd5 100644 --- a/src/java/org/apache/cassandra/utils/memory/MemoryUtil.java +++ b/src/java/org/apache/cassandra/utils/memory/MemoryUtil.java @@ -124,6 +124,13 @@ public abstract class MemoryUtil public static ByteBuffer getByteBuffer(long address, int length) { + ByteBuffer instance = getHollowDirectByteBuffer(); + setByteBuffer(instance, address, length); + return instance; + } + + public static ByteBuffer getHollowDirectByteBuffer() + { ByteBuffer instance; try { @@ -133,12 +140,15 @@ public abstract class MemoryUtil { throw new AssertionError(e); } + instance.order(ByteOrder.nativeOrder()); + return instance; + } + public static void setByteBuffer(ByteBuffer instance, long address, int length) + { unsafe.putLong(instance, DIRECT_BYTE_BUFFER_ADDRESS_OFFSET, address); unsafe.putInt(instance, DIRECT_BYTE_BUFFER_CAPACITY_OFFSET, length); unsafe.putInt(instance, DIRECT_BYTE_BUFFER_LIMIT_OFFSET, length); - instance.order(ByteOrder.nativeOrder()); - return instance; } public static long getLongByByte(long address)
