You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2025/04/01 09:29:35 UTC
(ignite-3) 01/01: Optimize column offset calculation for BinaryTuples.
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch ignite-24975
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit c26f8f49b961584f73088431c1ea439165a71b84
Author: amashenkov <am...@apache.org>
AuthorDate: Mon Mar 31 22:48:16 2025 +0300
Optimize column offset calculation for BinaryTuples.
---
.../internal/binarytuple/BinaryTupleBuilder.java | 36 +++------
.../internal/binarytuple/BinaryTupleCommon.java | 85 ++++++++++++++++++++++
.../internal/binarytuple/BinaryTupleParser.java | 71 +++++++-----------
.../ignite/internal/schema/BinaryTuplePrefix.java | 25 ++-----
4 files changed, 131 insertions(+), 86 deletions(-)
diff --git a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java
index cfa9eb52bf0..16b6e4a486b 100644
--- a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleBuilder.java
@@ -30,6 +30,8 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.util.UUID;
+import org.apache.ignite.internal.binarytuple.BinaryTupleCommon.OffsetReadFunction;
+import org.apache.ignite.internal.binarytuple.BinaryTupleCommon.OffsetWriteFunction;
import org.apache.ignite.internal.util.ByteUtils;
import org.jetbrains.annotations.Nullable;
@@ -55,6 +57,9 @@ public class BinaryTupleBuilder {
/** Starting position of variable-length values. */
private final int valueBase;
+ /** Offset table write function. */
+ private final OffsetWriteFunction offsetWriteFunc;
+
/** Buffer for tuple content. */
private ByteBuffer buffer;
@@ -99,6 +104,7 @@ public class BinaryTupleBuilder {
} else {
entrySize = BinaryTupleCommon.flagsToEntrySize(BinaryTupleCommon.valueSizeToFlags(totalValueSize));
}
+ offsetWriteFunc = BinaryTupleCommon.offsetWriteFunction(entrySize);
valueBase = entryBase + entrySize * numElements;
@@ -603,21 +609,15 @@ public class BinaryTupleBuilder {
int getIndex = valueBase;
int putIndex = valueBase;
+
+ OffsetReadFunction offsetSource = BinaryTupleCommon.offsetReadFunction(entrySize);
+ OffsetWriteFunction offsetTarget = BinaryTupleCommon.offsetWriteFunction(desiredEntrySize);
+
while (getIndex > entryBase) {
getIndex -= entrySize;
putIndex -= desiredEntrySize;
- int value;
- if (entrySize == 4) {
- value = buffer.getInt(getIndex);
- } else {
- value = Short.toUnsignedInt(buffer.getShort(getIndex));
- }
- if (desiredEntrySize == 1) {
- buffer.put(putIndex, (byte) value);
- } else {
- buffer.putShort(putIndex, (short) value);
- }
+ offsetTarget.offset(buffer, putIndex, offsetSource.offset(buffer, getIndex));
}
offset = (entrySize - desiredEntrySize) * numElements;
@@ -745,19 +745,7 @@ public class BinaryTupleBuilder {
assert elementIndex < numElements : "Element index overflow: " + elementIndex + " >= " + numElements;
int offset = buffer.position() - valueBase;
- switch (entrySize) {
- case Byte.BYTES:
- buffer.put(entryBase + elementIndex, (byte) offset);
- break;
- case Short.BYTES:
- buffer.putShort(entryBase + elementIndex * Short.BYTES, (short) offset);
- break;
- case Integer.BYTES:
- buffer.putInt(entryBase + elementIndex * Integer.BYTES, offset);
- break;
- default:
- assert false;
- }
+ offsetWriteFunc.offset(buffer, entryBase + elementIndex * entrySize, offset);
elementIndex++;
return this;
diff --git a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java
index 9f97c8e16cd..7a25779b0c7 100644
--- a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleCommon.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.binarytuple;
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.nio.ByteBuffer;
import org.apache.ignite.internal.lang.IgniteInternalException;
/**
@@ -123,4 +124,88 @@ public class BinaryTupleCommon {
return value;
}
+
+ /**
+ * Gets a function that reads the field offset.
+ *
+ * @param entrySize Offset table entry size.
+ * @return Offset calculation function.
+ */
+ public static OffsetReadFunction offsetReadFunction(int entrySize) {
+ switch (entrySize) {
+ case Byte.BYTES:
+ return BinaryTupleCommon::readByteOffset;
+ case Short.BYTES:
+ return BinaryTupleCommon::readShortOffset;
+ case Integer.BYTES:
+ return BinaryTupleCommon::readIntOffset;
+ case Long.BYTES:
+ throw new BinaryTupleFormatException("Unsupported offset table size");
+ default:
+ throw new BinaryTupleFormatException("Invalid offset table size");
+ }
+ }
+
+ /**
+ * Gets a function that writes the field offset.
+ *
+ * @param entrySize Offset table entry size.
+ * @return Offset calculation function.
+ */
+ public static OffsetWriteFunction offsetWriteFunction(int entrySize) {
+ switch (entrySize) {
+ case Byte.BYTES:
+ return BinaryTupleCommon::writeByteOffset;
+ case Short.BYTES:
+ return BinaryTupleCommon::writeShortOffset;
+ case Integer.BYTES:
+ return BinaryTupleCommon::writeIntOffset;
+ case Long.BYTES:
+ throw new BinaryTupleFormatException("Unsupported offset table size");
+ default:
+ throw new BinaryTupleFormatException("Invalid offset table size");
+ }
+ }
+
+ private static int readByteOffset(ByteBuffer buffer, int index) {
+ return Byte.toUnsignedInt(buffer.get(index));
+ }
+
+ private static int readShortOffset(ByteBuffer buffer, int index) {
+ return Short.toUnsignedInt(buffer.getShort(index));
+ }
+
+ private static int readIntOffset(ByteBuffer buffer, int index) {
+ int offset = buffer.getInt(index);
+ if (offset < 0) {
+ throw new BinaryTupleFormatException("Unsupported offset table size");
+ }
+ return offset;
+ }
+
+ private static void writeByteOffset(ByteBuffer buffer, int index, int offset) {
+ buffer.put(index, (byte) offset);
+ }
+
+ private static void writeShortOffset(ByteBuffer buffer, int index, int offset) {
+ buffer.putShort(index, (short) offset);
+ }
+
+ private static void writeIntOffset(ByteBuffer buffer, int index, int offset) {
+ buffer.putInt(index, offset);
+ }
+
+ /** Offset read function. */
+ @FunctionalInterface
+ public interface OffsetReadFunction {
+ /** Returns offset of the given column index. */
+ int offset(ByteBuffer buffer, int index);
+ }
+
+ /** Offset write function. */
+ @FunctionalInterface
+ public interface OffsetWriteFunction {
+ /** Writes offset of the given column index. */
+ void offset(ByteBuffer buffer, int index, int offset);
+ }
}
diff --git a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
index cd28909643e..dd45e31cef7 100644
--- a/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
+++ b/modules/binary-tuple/src/main/java/org/apache/ignite/internal/binarytuple/BinaryTupleParser.java
@@ -28,6 +28,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.util.UUID;
+import org.apache.ignite.internal.binarytuple.BinaryTupleCommon.OffsetReadFunction;
import org.apache.ignite.internal.util.ByteUtils;
/**
@@ -69,6 +70,9 @@ public class BinaryTupleParser {
/** Binary tuple. */
private final ByteBuffer buffer;
+ /** Offset calculation function. */
+ private final OffsetReadFunction offsetFunc;
+
/**
* Constructor.
*
@@ -87,13 +91,15 @@ public class BinaryTupleParser {
entryBase = BinaryTupleCommon.HEADER_SIZE;
entrySize = 1 << (flags & BinaryTupleCommon.VARSIZE_MASK);
valueBase = entryBase + entrySize * numElements;
+
+ offsetFunc = BinaryTupleCommon.offsetReadFunction(entrySize);
}
/**
* Returns the binary tuple size in bytes.
*/
public int size() {
- return valueBase + getOffset(valueBase - entrySize);
+ return valueBase + offsetFunc.offset(buffer, valueBase - entrySize);
}
/**
@@ -122,12 +128,9 @@ public class BinaryTupleParser {
int entry = entryBase + index * entrySize;
- int offset = valueBase;
- if (index > 0) {
- offset += getOffset(entry - entrySize);
- }
+ int offset = valueBase + ((index > 0) ? offsetFunc.offset(buffer, entry - entrySize) : 0);
- int nextOffset = valueBase + getOffset(entry);
+ int nextOffset = valueBase + offsetFunc.offset(buffer, entry);
if (nextOffset < offset) {
throw new BinaryTupleFormatException("Corrupted offset table");
}
@@ -145,7 +148,7 @@ public class BinaryTupleParser {
int offset = valueBase;
for (int i = 0; i < numElements; i++) {
- int nextOffset = valueBase + getOffset(entry);
+ int nextOffset = valueBase + offsetFunc.offset(buffer, entry);
if (nextOffset < offset) {
throw new BinaryTupleFormatException("Corrupted offset table");
}
@@ -504,32 +507,6 @@ public class BinaryTupleParser {
}
}
- /**
- * Gets an entry from the value offset table.
- *
- * @param index Byte index of the table entry.
- * @return Entry value.
- */
- private int getOffset(int index) {
- switch (entrySize) {
- case Byte.BYTES:
- return Byte.toUnsignedInt(buffer.get(index));
- case Short.BYTES:
- return Short.toUnsignedInt(buffer.getShort(index));
- case Integer.BYTES: {
- int offset = buffer.getInt(index);
- if (offset < 0) {
- throw new BinaryTupleFormatException("Unsupported offset table size");
- }
- return offset;
- }
- case Long.BYTES:
- throw new BinaryTupleFormatException("Unsupported offset table size");
- default:
- throw new BinaryTupleFormatException("Invalid offset table size");
- }
- }
-
/**
* Gets array of bytes from a given range in the buffer.
*/
@@ -560,17 +537,23 @@ public class BinaryTupleParser {
long time = Integer.toUnsignedLong(buffer.getInt(offset));
int nanos;
- if (length == 4) {
- nanos = ((int) time & ((1 << 10) - 1)) * 1000 * 1000;
- time >>>= 10;
- } else if (length == 5) {
- time |= Byte.toUnsignedLong(buffer.get(offset + 4)) << 32;
- nanos = ((int) time & ((1 << 20) - 1)) * 1000;
- time >>>= 20;
- } else {
- time |= Short.toUnsignedLong(buffer.getShort(offset + 4)) << 32;
- nanos = ((int) time & ((1 << 30) - 1));
- time >>>= 30;
+ switch (length) {
+ case 4: {
+ nanos = ((int) time & ((1 << 10) - 1)) * 1000 * 1000;
+ time >>>= 10;
+ break;
+ }
+ case 5: {
+ time |= Byte.toUnsignedLong(buffer.get(offset + 4)) << 32;
+ nanos = ((int) time & ((1 << 20) - 1)) * 1000;
+ time >>>= 20;
+ break;
+ }
+ default: {
+ time |= Short.toUnsignedLong(buffer.getShort(offset + 4)) << 32;
+ nanos = ((int) time & ((1 << 30) - 1));
+ time >>>= 30;
+ }
}
int second = ((int) time) & 63;
diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuplePrefix.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuplePrefix.java
index 041d46a135a..ea435bf70da 100644
--- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuplePrefix.java
+++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/BinaryTuplePrefix.java
@@ -21,6 +21,7 @@ import static org.apache.ignite.internal.binarytuple.BinaryTupleCommon.PREFIX_FL
import java.nio.ByteBuffer;
import org.apache.ignite.internal.binarytuple.BinaryTupleCommon;
+import org.apache.ignite.internal.binarytuple.BinaryTupleCommon.OffsetWriteFunction;
import org.apache.ignite.internal.binarytuple.BinaryTuplePrefixBuilder;
import org.apache.ignite.internal.binarytuple.BinaryTupleReader;
import org.apache.ignite.internal.lang.InternalTuple;
@@ -127,20 +128,9 @@ public class BinaryTuplePrefix extends BinaryTupleReader implements InternalTupl
.put(tupleBuffer.duplicate().limit(dataBeginOffsetHolder[0])); // header
int payloadEndPosition = dataEndOffsetHolder[0] - dataBeginOffsetHolder[0];
+ OffsetWriteFunction offsetWriteFunction = BinaryTupleCommon.offsetWriteFunction(entrySize);
for (int idx = tuple.elementCount(); idx < numElements; idx++) {
- switch (entrySize) {
- case Byte.BYTES:
- prefixBuffer.put((byte) payloadEndPosition);
- break;
- case Short.BYTES:
- prefixBuffer.putShort((short) payloadEndPosition);
- break;
- case Integer.BYTES:
- prefixBuffer.putInt(payloadEndPosition);
- break;
- default:
- assert false;
- }
+ offsetWriteFunction.offset(prefixBuffer, prefixBuffer.position(), payloadEndPosition);
}
prefixBuffer
@@ -156,14 +146,13 @@ public class BinaryTuplePrefix extends BinaryTupleReader implements InternalTupl
private static BinaryTuplePrefix truncateTuple(int numElements, BinaryTuple tuple) {
assert numElements < tuple.elementCount();
- int[] dataBeginOffsetHolder = new int[1];
- int[] dataEndOffsetHolder = new int[1];
+ int[] dataOffsetHolder = new int[2];
- tuple.fetch(0, (index, begin, end) -> dataBeginOffsetHolder[0] = begin);
- tuple.fetch(numElements - 1, (index, begin, end) -> dataEndOffsetHolder[0] = end);
+ tuple.fetch(0, (index, begin, end) -> dataOffsetHolder[0] = begin);
+ tuple.fetch(numElements - 1, (index, begin, end) -> dataOffsetHolder[1] = end);
BinaryTuplePrefixBuilder builder = new BinaryTuplePrefixBuilder(
- numElements, numElements, dataEndOffsetHolder[0] - dataBeginOffsetHolder[0]
+ numElements, numElements, dataOffsetHolder[1] - dataOffsetHolder[0]
);
for (int i = 0; i < numElements; i++) {