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);
+    }
 }

Reply via email to