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]

Reply via email to