This is an automated email from the ASF dual-hosted git repository.
adelapena pushed a commit to branch cassandra-4.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-4.0 by this push:
new a690f33 Fix ObjectSizes implementation and usages
a690f33 is described below
commit a690f339ab0f2b98c69621ca5a0bad10ae9a7919
Author: jacek-lewandowski <[email protected]>
AuthorDate: Mon Mar 7 16:22:30 2022 +0000
Fix ObjectSizes implementation and usages
patch by Jacek Lewandowski; reviewed by Andrés de la Peña and Branimir
Lambov for CASSANDRA-17402
---
CHANGES.txt | 1 +
.../apache/cassandra/cql3/ColumnIdentifier.java | 2 +-
.../org/apache/cassandra/db/rows/ArrayCell.java | 2 +-
.../org/apache/cassandra/db/rows/BufferCell.java | 2 +-
.../org/apache/cassandra/db/rows/CellPath.java | 2 +-
.../org/apache/cassandra/fql/FullQueryLogger.java | 49 ++++---
.../org/apache/cassandra/utils/ObjectSizes.java | 123 ++++++++++++-----
.../unit/org/apache/cassandra/db/CellSpecTest.java | 4 +-
.../apache/cassandra/utils/ObjectSizesTest.java | 149 +++++++++++++++++++++
9 files changed, 269 insertions(+), 65 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d9d4a77..9320244 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
4.0.4
+ * Fix ObjectSizes implementation and usages (CASSANDRA-17402)
* Fix race condition bug during local session repair (CASSANDRA-17335)
* Fix ignored streaming encryption settings in sstableloader (CASSANDRA-17367)
* Streaming tasks handle empty SSTables correctly (CASSANDRA-16349)
diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
index 889f23a..e7bf7b9 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
@@ -205,7 +205,7 @@ public class ColumnIdentifier implements IMeasurableMemory,
Comparable<ColumnIde
public long unsharedHeapSizeExcludingData()
{
return EMPTY_SIZE
- + ObjectSizes.sizeOfEmptyHeapByteBuffer()
+ + ObjectSizes.sizeOnHeapExcludingData(bytes)
+ ObjectSizes.sizeOf(text);
}
diff --git a/src/java/org/apache/cassandra/db/rows/ArrayCell.java
b/src/java/org/apache/cassandra/db/rows/ArrayCell.java
index c4fdd14..c097249 100644
--- a/src/java/org/apache/cassandra/db/rows/ArrayCell.java
+++ b/src/java/org/apache/cassandra/db/rows/ArrayCell.java
@@ -112,6 +112,6 @@ public class ArrayCell extends AbstractCell<byte[]>
public long unsharedHeapSizeExcludingData()
{
- return EMPTY_SIZE + ObjectSizes.sizeOfEmptyByteArray() + (path == null
? 0 : path.unsharedHeapSizeExcludingData());
+ return EMPTY_SIZE + ObjectSizes.sizeOfArray(value) - value.length +
(path == null ? 0 : path.unsharedHeapSizeExcludingData());
}
}
diff --git a/src/java/org/apache/cassandra/db/rows/BufferCell.java
b/src/java/org/apache/cassandra/db/rows/BufferCell.java
index 55fc4b4..f5994f1 100644
--- a/src/java/org/apache/cassandra/db/rows/BufferCell.java
+++ b/src/java/org/apache/cassandra/db/rows/BufferCell.java
@@ -144,6 +144,6 @@ public class BufferCell extends AbstractCell<ByteBuffer>
public long unsharedHeapSizeExcludingData()
{
- return EMPTY_SIZE + ObjectSizes.sizeOfEmptyHeapByteBuffer() + (path ==
null ? 0 : path.unsharedHeapSizeExcludingData());
+ return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(value) + (path
== null ? 0 : path.unsharedHeapSizeExcludingData());
}
}
diff --git a/src/java/org/apache/cassandra/db/rows/CellPath.java
b/src/java/org/apache/cassandra/db/rows/CellPath.java
index 50496a1..1bf8b8f 100644
--- a/src/java/org/apache/cassandra/db/rows/CellPath.java
+++ b/src/java/org/apache/cassandra/db/rows/CellPath.java
@@ -127,7 +127,7 @@ public abstract class CellPath
public long unsharedHeapSizeExcludingData()
{
- return EMPTY_SIZE + ObjectSizes.sizeOfEmptyHeapByteBuffer();
+ return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(value);
}
}
diff --git a/src/java/org/apache/cassandra/fql/FullQueryLogger.java
b/src/java/org/apache/cassandra/fql/FullQueryLogger.java
index cb35fcf..0604df6 100644
--- a/src/java/org/apache/cassandra/fql/FullQueryLogger.java
+++ b/src/java/org/apache/cassandra/fql/FullQueryLogger.java
@@ -52,6 +52,8 @@ import org.apache.cassandra.utils.binlog.BinLogOptions;
import org.apache.cassandra.utils.concurrent.WeightedQueue;
import org.github.jamm.MemoryLayoutSpecification;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* A logger that logs entire query contents after the query finishes (or times
out).
*/
@@ -80,9 +82,7 @@ public class FullQueryLogger implements QueryEvents.Listener
public static final String QUERIES = "queries";
public static final String VALUES = "values";
- private static final int EMPTY_BYTEBUFFER_SIZE =
Ints.checkedCast(ObjectSizes.sizeOfEmptyHeapByteBuffer());
-
- private static final int EMPTY_LIST_SIZE =
Ints.checkedCast(ObjectSizes.measureDeep(new ArrayList(0)));
+ private static final int EMPTY_LIST_SIZE =
Ints.checkedCast(ObjectSizes.measureDeep(new ArrayList<>(0)));
private static final int EMPTY_BYTEBUF_SIZE;
private static final int OBJECT_HEADER_SIZE =
MemoryLayoutSpecification.SPEC.getObjectHeaderSize();
@@ -278,11 +278,11 @@ public class FullQueryLogger implements
QueryEvents.Listener
long batchTimeMillis,
Message.Response response)
{
- Preconditions.checkNotNull(type, "type was null");
- Preconditions.checkNotNull(queries, "queries was null");
- Preconditions.checkNotNull(values, "value was null");
- Preconditions.checkNotNull(queryOptions, "queryOptions was null");
- Preconditions.checkNotNull(queryState, "queryState was null");
+ checkNotNull(type, "type was null");
+ checkNotNull(queries, "queries was null");
+ checkNotNull(values, "value was null");
+ checkNotNull(queryOptions, "queryOptions was null");
+ checkNotNull(queryState, "queryState was null");
Preconditions.checkArgument(batchTimeMillis > 0, "batchTimeMillis must
be > 0");
//Don't construct the wrapper if the log is disabled
@@ -311,9 +311,9 @@ public class FullQueryLogger implements QueryEvents.Listener
long queryTimeMillis,
Message.Response response)
{
- Preconditions.checkNotNull(query, "query was null");
- Preconditions.checkNotNull(queryOptions, "queryOptions was null");
- Preconditions.checkNotNull(queryState, "queryState was null");
+ checkNotNull(query, "query was null");
+ checkNotNull(queryOptions, "queryOptions was null");
+ checkNotNull(queryState, "queryState was null");
Preconditions.checkArgument(queryTimeMillis > 0, "queryTimeMillis must
be > 0");
//Don't construct the wrapper if the log is disabled
@@ -383,18 +383,19 @@ public class FullQueryLogger implements
QueryEvents.Listener
int weight = super.weight();
// weight, queries, values, batch type
- weight += 4 + // cached weight
- 2 * EMPTY_LIST_SIZE + // queries + values lists
- OBJECT_REFERENCE_SIZE; // batchType reference, worst case
+ weight += Integer.BYTES + // cached weight
+ 2 * EMPTY_LIST_SIZE + // queries + values lists
+ 3 * OBJECT_REFERENCE_SIZE; // batchType and two lists
references
for (String query : queries)
- weight += ObjectSizes.sizeOf(query);
+ weight += ObjectSizes.sizeOf(checkNotNull(query)) +
OBJECT_REFERENCE_SIZE;
for (List<ByteBuffer> subValues : values)
{
- weight += EMPTY_LIST_SIZE;
+ weight += EMPTY_LIST_SIZE + OBJECT_REFERENCE_SIZE;
+
for (ByteBuffer value : subValues)
- weight += EMPTY_BYTEBUFFER_SIZE + value.capacity();
+ weight += ObjectSizes.sizeOnHeapOf(value) +
OBJECT_REFERENCE_SIZE;
}
this.weight = weight;
@@ -511,14 +512,12 @@ public class FullQueryLogger implements
QueryEvents.Listener
public int weight()
{
return OBJECT_HEADER_SIZE
- + 8 //
queryStartTime
- + 4 //
protocolVersion
- + EMPTY_BYTEBUF_SIZE + queryOptionsBuffer.capacity() //
queryOptionsBuffer
- + 8 //
generatedTimestamp
- + 4 //
generatedNowInSeconds
- + (keyspace != null
- ? Ints.checkedCast(ObjectSizes.sizeOf(keyspace)) //
keyspace
- : OBJECT_REFERENCE_SIZE); // null
+ + Long.BYTES
// queryStartTime
+ + Integer.BYTES
// protocolVersion
+ + OBJECT_REFERENCE_SIZE + EMPTY_BYTEBUF_SIZE +
queryOptionsBuffer.capacity() // queryOptionsBuffer
+ + Long.BYTES
// generatedTimestamp
+ + Integer.BYTES
// generatedNowInSeconds
+ + OBJECT_REFERENCE_SIZE +
Ints.checkedCast(ObjectSizes.sizeOf(keyspace)); // keyspace
}
}
diff --git a/src/java/org/apache/cassandra/utils/ObjectSizes.java
b/src/java/org/apache/cassandra/utils/ObjectSizes.java
index 04e5c65..468522c 100644
--- a/src/java/org/apache/cassandra/utils/ObjectSizes.java
+++ b/src/java/org/apache/cassandra/utils/ObjectSizes.java
@@ -1,6 +1,4 @@
-package org.apache.cassandra.utils;
/*
- *
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -17,9 +15,9 @@ package org.apache.cassandra.utils;
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
*/
+package org.apache.cassandra.utils;
import java.nio.ByteBuffer;
@@ -31,47 +29,61 @@ import org.github.jamm.MemoryMeter;
*/
public class ObjectSizes
{
- private static final MemoryMeter meter = new MemoryMeter()
- .omitSharedBufferOverhead()
-
.withGuessing(MemoryMeter.Guess.FALLBACK_UNSAFE)
- .ignoreKnownSingletons();
+ private static final MemoryMeter meter = new
MemoryMeter().omitSharedBufferOverhead()
+
.withGuessing(MemoryMeter.Guess.FALLBACK_UNSAFE)
+
.ignoreKnownSingletons();
- private static final long BUFFER_EMPTY_SIZE =
measure(ByteBufferUtil.EMPTY_BYTE_BUFFER);
- private static final long BYTE_ARRAY_EMPTY_SIZE = measure(new byte[0]);
- private static final long STRING_EMPTY_SIZE = measure("");
+ private static final long EMPTY_HEAP_BUFFER_SIZE =
measure(ByteBufferUtil.EMPTY_BYTE_BUFFER);
+ private static final long EMPTY_BYTE_ARRAY_SIZE = measure(new byte[0]);
+ private static final long EMPTY_STRING_SIZE = measure("");
+
+ private static final long DIRECT_BUFFER_HEAP_SIZE =
measure(ByteBuffer.allocateDirect(0));
/**
* Memory a byte array consumes
+ *
* @param bytes byte array to get memory size
* @return heap-size of the array
*/
public static long sizeOfArray(byte[] bytes)
{
+ if (bytes == null)
+ return 0;
+
return sizeOfArray(bytes.length, 1);
}
/**
* Memory a long array consumes
+ *
* @param longs byte array to get memory size
* @return heap-size of the array
*/
public static long sizeOfArray(long[] longs)
{
+ if (longs == null)
+ return 0;
+
return sizeOfArray(longs.length, 8);
}
/**
* Memory an int array consumes
+ *
* @param ints byte array to get memory size
* @return heap-size of the array
*/
public static long sizeOfArray(int[] ints)
{
+ if (ints == null)
+ return 0;
+
return sizeOfArray(ints.length, 4);
}
/**
* Memory a reference array consumes
+ *
* @param length the length of the reference array
* @return heap-size of the array
*/
@@ -82,11 +94,15 @@ public class ObjectSizes
/**
* Memory a reference array consumes itself only
+ *
* @param objects the array to size
* @return heap-size of the array (excluding memory retained by referenced
objects)
*/
public static long sizeOfArray(Object[] objects)
{
+ if (objects == null)
+ return 0;
+
return sizeOfReferenceArray(objects.length);
}
@@ -96,58 +112,97 @@ public class ObjectSizes
}
/**
- * Memory a ByteBuffer array consumes.
+ * Amount of heap memory consumed by the array of byte buffers. It sums
memory consumed by the array itself
+ * and for each included byte buffer using {@link
#sizeOnHeapOf(ByteBuffer)}.
*/
public static long sizeOnHeapOf(ByteBuffer[] array)
{
- long allElementsSize = 0;
- for (int i = 0; i < array.length; i++)
- if (array[i] != null)
- allElementsSize += sizeOnHeapOf(array[i]);
+ if (array == null)
+ return 0;
- return allElementsSize + sizeOfArray(array);
+ long sum = sizeOfArray(array);
+ for (ByteBuffer buffer : array)
+ sum += sizeOnHeapOf(buffer);
+
+ return sum;
}
+ /**
+ * Amount of non-data heap memory consumed by the array of byte buffers.
It sums memory consumed
+ * by the array itself and for each included byte buffer using {@link
#sizeOnHeapExcludingData(ByteBuffer)}.
+ */
public static long sizeOnHeapExcludingData(ByteBuffer[] array)
{
- return BUFFER_EMPTY_SIZE * array.length + sizeOfArray(array);
+ if (array == null)
+ return 0;
+
+ long sum = sizeOfArray(array);
+ for (ByteBuffer b : array)
+ sum += sizeOnHeapExcludingData(b);
+
+ return sum;
}
/**
- * Memory a byte buffer consumes
- * @param buffer ByteBuffer to calculate in memory size
- * @return Total in-memory size of the byte buffer
+ * @return heap memory consumed by the byte buffer. If it is a slice, it
counts the data size, but it does not
+ * include the internal array overhead.
*/
public static long sizeOnHeapOf(ByteBuffer buffer)
{
+ if (buffer == null)
+ return 0;
+
if (buffer.isDirect())
- return BUFFER_EMPTY_SIZE;
- // if we're only referencing a sub-portion of the ByteBuffer, don't
count the array overhead (assume it's slab
- // allocated, so amortized over all the allocations the overhead is
negligible and better to undercount than over)
- if (buffer.capacity() > buffer.remaining())
- return buffer.remaining();
- return BUFFER_EMPTY_SIZE + sizeOfArray(buffer.capacity(), 1);
- }
+ return DIRECT_BUFFER_HEAP_SIZE;
- public static long sizeOfEmptyHeapByteBuffer()
- {
- return BUFFER_EMPTY_SIZE;
+ int arrayLen = buffer.array().length;
+ int bufLen = buffer.remaining();
+
+ // if we're only referencing a sub-portion of the ByteBuffer, don't
count the array overhead (assume it is SLAB
+ // allocated - the overhead amortized over all the allocations is
negligible and better to undercount than over)
+ if (arrayLen > bufLen)
+ return EMPTY_HEAP_BUFFER_SIZE + bufLen;
+
+ return EMPTY_HEAP_BUFFER_SIZE + (arrayLen == 0 ? EMPTY_BYTE_ARRAY_SIZE
: sizeOfArray(arrayLen, 1));
}
- public static long sizeOfEmptyByteArray()
+ /**
+ * @return non-data heap memory consumed by the byte buffer. If it is a
slice, it does not include the internal
+ * array overhead.
+ */
+ public static long sizeOnHeapExcludingData(ByteBuffer buffer)
{
- return BYTE_ARRAY_EMPTY_SIZE;
+ if (buffer == null)
+ return 0;
+
+ if (buffer.isDirect())
+ return DIRECT_BUFFER_HEAP_SIZE;
+
+ int arrayLen = buffer.array().length;
+ int bufLen = buffer.remaining();
+
+ // if we're only referencing a sub-portion of the ByteBuffer, don't
count the array overhead (assume it is SLAB
+ // allocated - the overhead amortized over all the allocations is
negligible and better to undercount than over)
+ if (arrayLen > bufLen)
+ return EMPTY_HEAP_BUFFER_SIZE;
+
+ // If buffers are dedicated, account for byte array size and any
padding overhead
+ return EMPTY_HEAP_BUFFER_SIZE + (arrayLen == 0 ? EMPTY_BYTE_ARRAY_SIZE
: (sizeOfArray(arrayLen, 1) - arrayLen));
}
/**
* Memory a String consumes
+ *
* @param str String to calculate memory size of
* @return Total in-memory size of the String
*/
- //@TODO hard coding this to 2 isn't necessarily correct in Java 11
+ // TODO hard coding this to 2 isn't necessarily correct in Java 11
public static long sizeOf(String str)
{
- return STRING_EMPTY_SIZE + sizeOfArray(str.length(), 2);
+ if (str == null)
+ return 0;
+
+ return EMPTY_STRING_SIZE + sizeOfArray(str.length(), Character.BYTES);
}
/**
diff --git a/test/unit/org/apache/cassandra/db/CellSpecTest.java
b/test/unit/org/apache/cassandra/db/CellSpecTest.java
index 44fc625..4cc886d 100644
--- a/test/unit/org/apache/cassandra/db/CellSpecTest.java
+++ b/test/unit/org/apache/cassandra/db/CellSpecTest.java
@@ -84,9 +84,9 @@ public class CellSpecTest
private static long valuePtrSize(Object value)
{
if (value instanceof ByteBuffer)
- return ObjectSizes.sizeOfEmptyHeapByteBuffer();
+ return ObjectSizes.sizeOnHeapExcludingData((ByteBuffer) value);
else if (value instanceof byte[])
- return ObjectSizes.sizeOfEmptyByteArray();
+ return ObjectSizes.sizeOfArray((byte[]) value) - ((byte[])
value).length;
throw new IllegalArgumentException("Unsupported type: " +
value.getClass());
}
diff --git a/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java
b/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java
new file mode 100644
index 0000000..a4c77bc
--- /dev/null
+++ b/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.utils;
+
+import java.nio.ByteBuffer;
+
+import org.junit.Test;
+
+import org.github.jamm.MemoryLayoutSpecification;
+import org.github.jamm.MemoryMeter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ObjectSizesTest
+{
+ private static final MemoryMeter meter = new
MemoryMeter().withGuessing(MemoryMeter.Guess.FALLBACK_UNSAFE).omitSharedBufferOverhead().ignoreKnownSingletons();
+
+ private static final long EMPTY_HEAP_BUFFER_RAW_SIZE =
meter.measure(ByteBuffer.allocate(0));
+ private static final long EMPTY_OFFHEAP_BUFFER_RAW_SIZE =
meter.measure(ByteBuffer.allocateDirect(0));
+ private static final ByteBuffer[] EMPTY_BYTE_BUFFER_ARRAY = new
ByteBuffer[0];
+
+ public static final long REF_ARRAY_0_SIZE =
MemoryLayoutSpecification.sizeOfArray(0,
MemoryLayoutSpecification.SPEC.getReferenceSize());
+ public static final long REF_ARRAY_1_SIZE =
MemoryLayoutSpecification.sizeOfArray(1,
MemoryLayoutSpecification.SPEC.getReferenceSize());
+ public static final long REF_ARRAY_2_SIZE =
MemoryLayoutSpecification.sizeOfArray(2,
MemoryLayoutSpecification.SPEC.getReferenceSize());
+
+ public static final long BYTE_ARRAY_0_SIZE =
MemoryLayoutSpecification.sizeOfArray(0, 1);
+ public static final long BYTE_ARRAY_10_SIZE =
MemoryLayoutSpecification.sizeOfArray(10, 1);
+ public static final long BYTE_ARRAY_10_EXCEPT_DATA_SIZE =
MemoryLayoutSpecification.sizeOfArray(10, 1) - 10;
+
+ private ByteBuffer buf10 = ByteBuffer.allocate(10);
+ private ByteBuffer prefixBuf8 = buf10.duplicate();
+ private ByteBuffer suffixBuf9 = buf10.duplicate();
+ private ByteBuffer infixBuf7 = buf10.duplicate();
+
+ {
+ prefixBuf8.limit(8);
+
+ suffixBuf9.position(1);
+ suffixBuf9 = suffixBuf9.slice();
+
+ infixBuf7.limit(8);
+ infixBuf7.position(1);
+ infixBuf7 = infixBuf7.slice();
+ }
+
+ @Test
+ public void testSizeOnHeapExcludingData()
+ {
+ // empty array of byte buffers
+ ByteBuffer[] buffers = EMPTY_BYTE_BUFFER_ARRAY;
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_0_SIZE);
+
+ // single empty heap buffer
+ buffers = new ByteBuffer[]{ ByteBuffer.allocate(0) };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE);
+
+ // single non-empty heap buffer
+ buffers = new ByteBuffer[]{ buf10 };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_EXCEPT_DATA_SIZE);
+
+ // single empty direct buffer
+ buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(0) };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // single non-empty direct buffer
+ buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(10) };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // two different empty byte buffers
+ buffers = new ByteBuffer[]{ ByteBuffer.allocate(0),
ByteBuffer.allocateDirect(0) };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_2_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE +
EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // two different non-empty byte buffers
+ buffers = new ByteBuffer[]{ buf10, ByteBuffer.allocateDirect(500) };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_2_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_EXCEPT_DATA_SIZE +
EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // heap buffer being a prefix slice of other buffer
+ buffers = new ByteBuffer[]{ prefixBuf8 };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE);
+
+ // heap buffer being a suffix slice of other buffer
+ buffers = new ByteBuffer[]{ suffixBuf9 };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE);
+
+ // heap buffer being an infix slice of other buffer
+ buffers = new ByteBuffer[]{ infixBuf7 };
+
assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE
+ EMPTY_HEAP_BUFFER_RAW_SIZE);
+ }
+
+ @Test
+ public void testSizeOnHeapOf()
+ {
+ // empty array of byte buffers
+ ByteBuffer[] buffers = EMPTY_BYTE_BUFFER_ARRAY;
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_0_SIZE);
+
+ // single empty heap buffer
+ buffers = new ByteBuffer[]{ ByteBuffer.allocate(0) };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE);
+
+ // single non-empty heap buffer
+ buffers = new ByteBuffer[]{ buf10 };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_SIZE);
+
+ // single empty direct buffer
+ buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(0) };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // single non-empty direct buffer
+ buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(10) };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // two different empty byte buffers
+ buffers = new ByteBuffer[]{ ByteBuffer.allocate(0),
ByteBuffer.allocateDirect(0) };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_2_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // two different non-empty byte buffers
+ buffers = new ByteBuffer[]{ buf10, ByteBuffer.allocateDirect(500) };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_2_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_SIZE +
EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+
+ // heap buffer being a prefix slice of other buffer
+ buffers = new ByteBuffer[]{ prefixBuf8 };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + 8);
+
+ // heap buffer being a suffix slice of other buffer
+ buffers = new ByteBuffer[]{ suffixBuf9 };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + 9);
+
+ // heap buffer being an infix slice of other buffer
+ buffers = new ByteBuffer[]{ infixBuf7 };
+
assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE +
EMPTY_HEAP_BUFFER_RAW_SIZE + 7);
+ }
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]