diff --git a/core/trino-main/src/main/java/io/trino/server/protocol/Query.java b/core/trino-main/src/main/java/io/trino/server/protocol/Query.java
index c8f245488d43..8fdb3bfeb6b1 100644
--- a/core/trino-main/src/main/java/io/trino/server/protocol/Query.java
+++ b/core/trino-main/src/main/java/io/trino/server/protocol/Query.java
@@ -51,7 +51,14 @@
import io.trino.spi.ErrorCode;
import io.trino.spi.Page;
import io.trino.spi.QueryId;
+import io.trino.spi.block.ArrayBlock;
+import io.trino.spi.block.Block;
import io.trino.spi.block.BlockEncodingSerde;
+import io.trino.spi.block.DictionaryBlock;
+import io.trino.spi.block.MapBlock;
+import io.trino.spi.block.RowBlock;
+import io.trino.spi.block.RunLengthEncodedBlock;
+import io.trino.spi.block.ValueBlock;
import io.trino.spi.exchange.ExchangeId;
import io.trino.spi.security.SelectedRole;
import io.trino.spi.type.Type;
@@ -562,7 +569,9 @@ private synchronized QueryResultRows removePagesFromExchange(ResultQueryInfo que
}
Page page = deserializer.deserialize(serializedPage);
- bytes += page.getLogicalSizeInBytes();
+ // page should already be loaded since it was just deserialized
+ page = page.getLoadedPage();
+ bytes += estimateJsonSize(page);
resultBuilder.addPage(page);
}
if (exchangeDataSource.isFinished()) {
@@ -577,6 +586,38 @@ private synchronized QueryResultRows removePagesFromExchange(ResultQueryInfo que
return resultBuilder.build();
}
+ private static long estimateJsonSize(Page page)
+ {
+ long estimatedSize = 0;
+ for (int i = 0; i < page.getChannelCount(); i++) {
+ estimatedSize += estimateJsonSize(page.getBlock(i));
+ }
+ return estimatedSize;
+ }
+
+ private static long estimateJsonSize(Block block)
+ {
+ switch (block) {
+ case RunLengthEncodedBlock rleBlock:
+ return estimateJsonSize(rleBlock.getValue()) * rleBlock.getPositionCount();
+ case DictionaryBlock dictionaryBlock:
+ ValueBlock dictionary = dictionaryBlock.getDictionary();
+ double averageSizePerEntry = (double) estimateJsonSize(dictionary) / dictionary.getPositionCount();
+ return (long) (averageSizePerEntry * block.getPositionCount());
+ case RowBlock rowBlock:
+ return rowBlock.getFieldBlocks().stream()
+ .mapToLong(Query::estimateJsonSize)
+ .sum();
+ case ArrayBlock arrayBlock:
+ return estimateJsonSize(arrayBlock.getElementsBlock());
+ case MapBlock mapBlock:
+ return estimateJsonSize(mapBlock.getKeyBlock()) +
+ estimateJsonSize(mapBlock.getValueBlock());
+ default:
+ return block.getSizeInBytes();
+ }
+ }
+
private void closeExchangeIfNecessary(ResultQueryInfo queryInfo)
{
if (queryInfo.state() != FAILED && queryInfo.outputStage().isPresent()) {
diff --git a/core/trino-main/src/test/java/io/trino/block/TestDictionaryBlock.java b/core/trino-main/src/test/java/io/trino/block/TestDictionaryBlock.java
index 81d44cf104af..dc054c8f7222 100644
--- a/core/trino-main/src/test/java/io/trino/block/TestDictionaryBlock.java
+++ b/core/trino-main/src/test/java/io/trino/block/TestDictionaryBlock.java
@@ -84,31 +84,6 @@ public void testSizeInBytes()
assertThat(dictionaryBlock.getSizeInBytes()).isEqualTo(dictionaryBlock.getDictionary().getSizeInBytes() + (100 * SIZE_OF_INT));
}
- @Test
- public void testLogicalSizeInBytes()
- {
- // The 10 Slices in the array will be of lengths 0 to 9.
- Slice[] expectedValues = createExpectedValues(10);
-
- // The dictionary within the dictionary block is expected to be a VariableWidthBlock of size 95 bytes.
- // 45 bytes for the expectedValues Slices (sum of seq(0,9)) and 50 bytes for the position and isNull array (total 10 positions).
- DictionaryBlock dictionaryBlock = createDictionaryBlock(expectedValues, 100);
- assertThat(dictionaryBlock.getDictionary().getLogicalSizeInBytes()).isEqualTo(95);
-
- // The 100 positions in the dictionary block index to 10 positions in the underlying dictionary (10 each).
- // Logical size calculation accounts for 4 bytes of offset and 1 byte of isNull. Therefore the expected unoptimized
- // size is 10 times the size of the underlying dictionary (VariableWidthBlock).
- assertThat(dictionaryBlock.getLogicalSizeInBytes()).isEqualTo(95 * 10);
-
- // With alternating nulls, we have 21 positions, with the same size calculation as above.
- dictionaryBlock = createDictionaryBlock(alternatingNullValues(expectedValues), 210);
- assertThat(dictionaryBlock.getDictionary().getPositionCount()).isEqualTo(21);
- assertThat(dictionaryBlock.getDictionary().getLogicalSizeInBytes()).isEqualTo(150);
-
- // The null positions should be included in the logical size.
- assertThat(dictionaryBlock.getLogicalSizeInBytes()).isEqualTo(150 * 10);
- }
-
@Test
public void testCopyRegionCreatesCompactBlock()
{
diff --git a/core/trino-spi/pom.xml b/core/trino-spi/pom.xml
index c9bbaeba1fbe..3d276d25d7f4 100644
--- a/core/trino-spi/pom.xml
+++ b/core/trino-spi/pom.xml
@@ -265,6 +265,26 @@
java.method.removed
+ java.method.removed
+ java.method.removed
+ java.method.removed
+
- * This can differ substantially from {@link #getSizeInBytes} for certain block
- * types. For RLE, it will be {@code N} times larger. For dictionary, it will be
- * larger based on how many times dictionary entries are reused.
- */
- default long getLogicalSizeInBytes()
- {
- return getSizeInBytes();
- }
-
/**
* Returns the size of {@code block.getRegion(position, length)}.
* The method can be expensive. Do not use it outside an implementation of Block.
diff --git a/core/trino-spi/src/main/java/io/trino/spi/block/DictionaryBlock.java b/core/trino-spi/src/main/java/io/trino/spi/block/DictionaryBlock.java
index 0a95b107b44a..61425cdb21a6 100644
--- a/core/trino-spi/src/main/java/io/trino/spi/block/DictionaryBlock.java
+++ b/core/trino-spi/src/main/java/io/trino/spi/block/DictionaryBlock.java
@@ -42,7 +42,6 @@ public final class DictionaryBlock
private final int[] ids;
private final long retainedSizeInBytes;
private volatile long sizeInBytes = -1;
- private volatile long logicalSizeInBytes = -1;
private volatile int uniqueIds = -1;
// isSequentialIds is only valid when uniqueIds is computed
private volatile boolean isSequentialIds;
@@ -192,36 +191,6 @@ private void calculateCompactSize()
this.isSequentialIds = isSequentialIds;
}
- @Override
- public long getLogicalSizeInBytes()
- {
- if (logicalSizeInBytes >= 0) {
- return logicalSizeInBytes;
- }
-
- OptionalInt dictionarySizePerPosition = dictionary.fixedSizeInBytesPerPosition();
- if (dictionarySizePerPosition.isPresent()) {
- logicalSizeInBytes = dictionarySizePerPosition.getAsInt() * (long) getPositionCount();
- return logicalSizeInBytes;
- }
-
- // Calculation of logical size can be performed as part of calculateCompactSize() with minor modifications.
- // Keeping this calculation separate as this is a little more expensive and may not be called as often.
- long sizeInBytes = 0;
- long[] seenSizes = new long[dictionary.getPositionCount()];
- Arrays.fill(seenSizes, -1L);
- for (int i = 0; i < getPositionCount(); i++) {
- int position = getId(i);
- if (seenSizes[position] < 0) {
- seenSizes[position] = dictionary.getRegionSizeInBytes(position, 1);
- }
- sizeInBytes += seenSizes[position];
- }
-
- logicalSizeInBytes = sizeInBytes;
- return sizeInBytes;
- }
-
@Override
public long getRegionSizeInBytes(int positionOffset, int length)
{
diff --git a/core/trino-spi/src/main/java/io/trino/spi/block/RunLengthEncodedBlock.java b/core/trino-spi/src/main/java/io/trino/spi/block/RunLengthEncodedBlock.java
index cfb0530c4959..22393bea9fbc 100644
--- a/core/trino-spi/src/main/java/io/trino/spi/block/RunLengthEncodedBlock.java
+++ b/core/trino-spi/src/main/java/io/trino/spi/block/RunLengthEncodedBlock.java
@@ -118,12 +118,6 @@ public long getSizeInBytes()
return value.getSizeInBytes();
}
- @Override
- public long getLogicalSizeInBytes()
- {
- return positionCount * value.getLogicalSizeInBytes();
- }
-
@Override
public long getRetainedSizeInBytes()
{
diff --git a/core/trino-spi/src/test/java/io/trino/spi/TestPage.java b/core/trino-spi/src/test/java/io/trino/spi/TestPage.java
index 382cc46f7fad..b8d01fd855b1 100644
--- a/core/trino-spi/src/test/java/io/trino/spi/TestPage.java
+++ b/core/trino-spi/src/test/java/io/trino/spi/TestPage.java
@@ -68,8 +68,6 @@ public void testSizesForNoColumnPage()
{
Page page = new Page(100);
assertThat(page.getSizeInBytes()).isEqualTo(0);
- assertThat(page.getLogicalSizeInBytes()).isEqualTo(0);
- assertThat(page.getRetainedSizeInBytes()).isEqualTo(Page.INSTANCE_SIZE); // does not include the blocks array
}
@Test
diff --git a/lib/trino-orc/src/main/java/io/trino/orc/OrcWriter.java b/lib/trino-orc/src/main/java/io/trino/orc/OrcWriter.java
index 73b3d4bca307..c4bedba75083 100644
--- a/lib/trino-orc/src/main/java/io/trino/orc/OrcWriter.java
+++ b/lib/trino-orc/src/main/java/io/trino/orc/OrcWriter.java
@@ -100,7 +100,7 @@ public final class OrcWriter
private final List, Type> primitiveTypes;
private final CompressionCodec compressionCodec;
private final Optional