This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 65b64d8667 [core] Add version in BlobDescriptor (#6333)
65b64d8667 is described below
commit 65b64d8667927ac52f2bbd554c17c366c0d1de14
Author: Yonghao Fang <[email protected]>
AuthorDate: Thu Sep 25 16:10:21 2025 +0800
[core] Add version in BlobDescriptor (#6333)
---
.../org/apache/paimon/data/BlobDescriptor.java | 52 +++++++++++++++++++---
.../org/apache/paimon/data/BlobDescriptorTest.java | 28 +++++++++++-
2 files changed, 71 insertions(+), 9 deletions(-)
diff --git
a/paimon-common/src/main/java/org/apache/paimon/data/BlobDescriptor.java
b/paimon-common/src/main/java/org/apache/paimon/data/BlobDescriptor.java
index 52e9667cbf..3e60ea3486 100644
--- a/paimon-common/src/main/java/org/apache/paimon/data/BlobDescriptor.java
+++ b/paimon-common/src/main/java/org/apache/paimon/data/BlobDescriptor.java
@@ -26,16 +26,39 @@ import java.util.Objects;
import static java.nio.charset.StandardCharsets.UTF_8;
-/** Blob descriptor to describe a blob reference. */
+/**
+ * Blob descriptor to describe a blob reference.
+ *
+ * <p>Memory Layout Description: All multi-byte numerical values (int/long)
are stored using Little
+ * Endian byte order.
+ *
+ * <pre>
+ * | Offset (Bytes) | Field Name | Type | Size (Bytes) | Description
|
+ *
|----------------|---------------|-----------|--------------|-----------------------------------------------------|
+ * | 0 | version | byte | 1 | Serialization
structure version |
+ * | 1 | uriLength | int | 4 | Length (N) of
the URI string in UTF-8 bytes |
+ * | 5 | uriBytes | byte[N] | N | UTF-8 encoded
bytes of the URI string |
+ * | 5 + N | offset | long | 8 | Starting
offset of the Blob within the URI resource |
+ * | 13 + N | length | long | 8 | Length of the
Blob data |
+ * </pre>
+ */
public class BlobDescriptor implements Serializable {
private static final long serialVersionUID = 1L;
+ private static final byte CURRENT_VERSION = 1;
+
+ private final byte version;
private final String uri;
private final long offset;
private final long length;
public BlobDescriptor(String uri, long offset, long length) {
+ this(CURRENT_VERSION, uri, offset, length);
+ }
+
+ private BlobDescriptor(byte version, String uri, long offset, long length)
{
+ this.version = version;
this.uri = uri;
this.offset = offset;
this.length = length;
@@ -59,18 +82,24 @@ public class BlobDescriptor implements Serializable {
return false;
}
BlobDescriptor that = (BlobDescriptor) o;
- return offset == that.offset && length == that.length &&
Objects.equals(uri, that.uri);
+ return version == that.version
+ && offset == that.offset
+ && length == that.length
+ && Objects.equals(uri, that.uri);
}
@Override
public int hashCode() {
- return Objects.hash(uri, offset, length);
+ return Objects.hash(version, uri, offset, length);
}
@Override
public String toString() {
return "BlobDescriptor{"
- + "uri='"
+ + "version="
+ + version
+ + '\''
+ + ", uri='"
+ uri
+ '\''
+ ", offset="
@@ -84,10 +113,11 @@ public class BlobDescriptor implements Serializable {
byte[] uriBytes = uri.getBytes(UTF_8);
int uriLength = uriBytes.length;
- int totalSize = 4 + uriLength + 8 + 8;
+ int totalSize = 1 + 4 + uriLength + 8 + 8;
ByteBuffer buffer = ByteBuffer.allocate(totalSize);
buffer.order(ByteOrder.LITTLE_ENDIAN);
+ buffer.put(version);
buffer.putInt(uriLength);
buffer.put(uriBytes);
@@ -101,6 +131,15 @@ public class BlobDescriptor implements Serializable {
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
+ byte version = buffer.get();
+ if (version != CURRENT_VERSION) {
+ throw new UnsupportedOperationException(
+ "Expecting BlobDescriptor version to be "
+ + CURRENT_VERSION
+ + ", but found "
+ + version
+ + ".");
+ }
int uriLength = buffer.getInt();
byte[] uriBytes = new byte[uriLength];
buffer.get(uriBytes);
@@ -108,7 +147,6 @@ public class BlobDescriptor implements Serializable {
long offset = buffer.getLong();
long length = buffer.getLong();
-
- return new BlobDescriptor(uri, offset, length);
+ return new BlobDescriptor(version, uri, offset, length);
}
}
diff --git
a/paimon-common/src/test/java/org/apache/paimon/data/BlobDescriptorTest.java
b/paimon-common/src/test/java/org/apache/paimon/data/BlobDescriptorTest.java
index 5cd3a06f55..ef860e8c55 100644
--- a/paimon-common/src/test/java/org/apache/paimon/data/BlobDescriptorTest.java
+++ b/paimon-common/src/test/java/org/apache/paimon/data/BlobDescriptorTest.java
@@ -20,13 +20,16 @@ package org.apache.paimon.data;
import org.junit.jupiter.api.Test;
+import java.lang.reflect.Constructor;
+
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
/** Test for {@link BlobDescriptor}. */
public class BlobDescriptorTest {
@Test
- public void testEquals() {
+ public void testEquals() throws Exception {
String uri1 = "/test/path1";
String uri2 = "/test/path2";
@@ -35,11 +38,12 @@ public class BlobDescriptorTest {
BlobDescriptor descriptor3 = new BlobDescriptor(uri2, 100L, 200L);
BlobDescriptor descriptor4 = new BlobDescriptor(uri1, 150L, 200L);
BlobDescriptor descriptor5 = new BlobDescriptor(uri1, 100L, 250L);
-
+ BlobDescriptor descriptor6 = createDescriptorWithVersion((byte) 2,
uri1, 100L, 200L);
assertThat(descriptor1).isEqualTo(descriptor2);
assertThat(descriptor1).isNotEqualTo(descriptor3);
assertThat(descriptor1).isNotEqualTo(descriptor4);
assertThat(descriptor1).isNotEqualTo(descriptor5);
+ assertThat(descriptor1).isNotEqualTo(descriptor6);
assertThat(descriptor1).isNotEqualTo(null);
assertThat(descriptor1).isNotEqualTo(new Object());
}
@@ -60,6 +64,7 @@ public class BlobDescriptorTest {
BlobDescriptor descriptor = new BlobDescriptor(uri, 100L, 200L);
String toString = descriptor.toString();
+ assertThat(toString).contains("version=1");
assertThat(toString).contains("uri='/test/path'");
assertThat(toString).contains("offset=100");
assertThat(toString).contains("length=200");
@@ -80,4 +85,23 @@ public class BlobDescriptorTest {
assertThat(deserialized.length()).isEqualTo(original.length());
assertThat(deserialized).isEqualTo(original);
}
+
+ @Test
+ public void testDeserializeWithUnsupportedVersion() {
+ String uri = "/test/path";
+ byte[] serialized = new BlobDescriptor(uri, 1, 1).serialize();
+ serialized[0] = 2;
+ assertThatThrownBy(() -> BlobDescriptor.deserialize(serialized))
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("Expecting BlobDescriptor version to be
1, but found 2.");
+ }
+
+ private BlobDescriptor createDescriptorWithVersion(
+ byte version, String uri, long offset, long length) throws
Exception {
+ Constructor<BlobDescriptor> constructor =
+ BlobDescriptor.class.getDeclaredConstructor(
+ byte.class, String.class, long.class, long.class);
+ constructor.setAccessible(true);
+ return constructor.newInstance(version, uri, offset, length);
+ }
}