blob: 4cc886d9583c6313554b283f7d86ab209c7f5cb6 [file] [log] [blame]
/*
* 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.db;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.apache.cassandra.db.marshal.BytesType;
import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.db.rows.ArrayCell;
import org.apache.cassandra.db.rows.BufferCell;
import org.apache.cassandra.db.rows.Cell;
import org.apache.cassandra.db.rows.CellPath;
import org.apache.cassandra.db.rows.NativeCell;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.UUIDGen;
import org.apache.cassandra.utils.concurrent.OpOrder;
import org.apache.cassandra.utils.memory.NativeAllocator;
import org.apache.cassandra.utils.memory.NativePool;
import org.assertj.core.api.Assertions;
import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
@RunWith(Parameterized.class)
public class CellSpecTest
{
private final Cell<?> cell;
@SuppressWarnings("unused")
public CellSpecTest(String ignoreOnlyUsedForBetterTestName, Cell<?> cell)
{
this.cell = cell;
}
@Test
public void unsharedHeapSizeExcludingData()
{
long empty = ObjectSizes.measure(cell);
long expected;
if (cell instanceof NativeCell)
{
// NativeCell stores the contents off-heap, so the cost on-heap is just the object's empty case
expected = empty;
}
else
{
// size should be: empty + valuePtr + path.unsharedHeapSizeExcludingData() if present
expected = empty + valuePtrSize(cell.value());
if (cell.path() != null)
expected += cell.path().unsharedHeapSizeExcludingData();
}
Assertions.assertThat(cell.unsharedHeapSizeExcludingData())
.isEqualTo(expected);
}
private static long valuePtrSize(Object value)
{
if (value instanceof ByteBuffer)
return ObjectSizes.sizeOnHeapExcludingData((ByteBuffer) value);
else if (value instanceof byte[])
return ObjectSizes.sizeOfArray((byte[]) value) - ((byte[]) value).length;
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
}
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data() {
TableMetadata table = TableMetadata.builder("testing", "testing")
.addPartitionKeyColumn("pk", BytesType.instance)
.build();
byte[] rawBytes = { 0, 1, 2, 3, 4, 5, 6 };
ByteBuffer bbBytes = ByteBuffer.wrap(rawBytes);
NativePool pool = new NativePool(1024, 1024, 1, () -> CompletableFuture.completedFuture(true));
NativeAllocator allocator = pool.newAllocator();
OpOrder order = new OpOrder();
List<Cell<?>> tests = new ArrayList<>();
BiConsumer<ColumnMetadata, CellPath> fn = (column, path) -> {
tests.add(new ArrayCell(column, 1234, 1, 1, rawBytes, path));
tests.add(new BufferCell(column, 1234, 1, 1, bbBytes, path));
tests.add(new NativeCell(allocator, order.getCurrent(), column, 1234, 1, 1, bbBytes, path));
};
// simple
fn.accept(ColumnMetadata.regularColumn(table, bytes("simple"), BytesType.instance), null);
// complex
// seems NativeCell does not allow CellPath.TOP, or CellPath.BOTTOM
fn.accept(ColumnMetadata.regularColumn(table, bytes("complex"), ListType.getInstance(BytesType.instance, true)), CellPath.create(bytes(UUIDGen.getTimeUUID())));
return tests.stream().map(a -> new Object[] {a.getClass().getSimpleName() + ":" + (a.path() == null ? "simple" : "complex"), a}).collect(Collectors.toList());
}
}