You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by ji...@apache.org on 2026/10/06 14:28:01 UTC

(hugegraph) 13/14: fix(server): complete remaining upgrade contracts

This is an automated email from the ASF dual-hosted git repository.

imbajin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hugegraph.git

commit 28bb37455f3bb11ddaa76100ef375cef9b0b4f82
Author: imbajin <ji...@apache.org>
AuthorDate: Tue Oct 6 21:48:46 2026 +0800

    fix(server): complete remaining upgrade contracts
    
    - encode Shard results as standard GraphBinary maps
    - mirror OffsetDateTime conversion in the shared graph model
    - regenerate the exact runtime dependency inventory
    - retain TP report gates in the new reusable CI layout
---
 .github/workflows/server-ci.yml                    |  3 ++
 .github/workflows/server-tests.yml                 | 29 ++++++++++---
 docs/upgrade-tinkerpop-3.8.md                      |  3 ++
 .../io/HugeGraphTypeSerializerRegistryBuilder.java | 15 +++++++
 .../config/GraphBinarySchemaCompatibilityTest.java | 30 ++++++++++++++
 .../org/apache/hugegraph/type/define/DataType.java |  3 ++
 .../hugegraph/struct/schema/PropertyKeyTest.java   | 48 ++++++++++++++++++++++
 .../scripts/dependency/known-dependencies.txt      | 16 --------
 8 files changed, 125 insertions(+), 22 deletions(-)

diff --git a/.github/workflows/server-ci.yml b/.github/workflows/server-ci.yml
index ab2432805..ffff8c587 100644
--- a/.github/workflows/server-ci.yml
+++ b/.github/workflows/server-ci.yml
@@ -81,6 +81,9 @@ jobs:
       - name: Run RISC-V Java runtime contract tests
         run: hugegraph-server/hugegraph-dist/src/assembly/travis/test-riscv64-java-runtime.sh
 
+      - name: Check TinkerPop report execution gates
+        run: bash hugegraph-server/hugegraph-dist/src/assembly/travis/test-tinkerpop-reports.sh
+
   # Required coverage: memory on the project runtime and any additional test JDKs.
   # The shared runtime comes from .github/workflows/.java-version, independent of bytecode targets.
   # Keep the job ID for the Codecov configuration validator.
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 96400e926..5161c168f 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -26,7 +26,20 @@ jobs:
       HEAD_BRANCH_NAME: ${{ github.head_ref }}
       BASE_BRANCH_NAME: ${{ github.base_ref }}
       TARGET_BRANCH_NAME: ${{ github.base_ref != '' && github.base_ref || github.ref_name }}
-      RELEASE_BRANCH: ${{ startsWith(github.ref_name, 'release-') || startsWith(github.ref_name, 'test-') }}
+      RUN_TINKERPOP_TESTS: >-
+        ${{
+          startsWith(github.ref_name, 'release-') ||
+          startsWith(github.ref_name, 'test-') ||
+          startsWith(github.head_ref, 'release-') ||
+          startsWith(github.head_ref, 'test-') ||
+          startsWith(github.head_ref, 'task/tp381-3-') ||
+          startsWith(github.ref_name, 'task/tp381-3-') ||
+          startsWith(github.base_ref, 'task/tp381-3-') ||
+          github.base_ref == 'task/tinkerpop-3.7-upgrade' ||
+          github.head_ref == 'task/tinkerpop-3.7-upgrade' ||
+          github.base_ref == 'task/gsoc-phase2-java17' ||
+          github.head_ref == 'task/gsoc-phase2-java17'
+        }}
       RAFT_MODE: ${{ startsWith(github.ref_name, 'raft-') || startsWith(github.head_ref, 'raft-') }}
 
     strategy:
@@ -168,11 +181,15 @@ jobs:
         run: |
           $TRAVIS_DIR/run-api-test-for-raft.sh $BACKEND $REPORT_DIR
 
-      - name: Run TinkerPop test
-        if: ${{ env.RELEASE_BRANCH == 'true' }}
-        run: |
-          echo "[WARNING] Enter Tinkerpop Test, current 'github.ref_name' is ${{ github.ref_name }}"
-          $TRAVIS_DIR/run-tinkerpop-test.sh $BACKEND tinkerpop
+      - name: Run TinkerPop structure test
+        if: ${{ env.RUN_TINKERPOP_TESTS == 'true' && (env.BACKEND == 'memory' || env.BACKEND == 'rocksdb') }}
+        timeout-minutes: 60
+        run: $TRAVIS_DIR/run-tinkerpop-test.sh $BACKEND structure
+
+      - name: Run TinkerPop process test
+        if: ${{ env.RUN_TINKERPOP_TESTS == 'true' && (env.BACKEND == 'memory' || env.BACKEND == 'rocksdb') }}
+        timeout-minutes: 180
+        run: $TRAVIS_DIR/run-tinkerpop-test.sh $BACKEND process
 
       - name: Upload coverage to Codecov
         uses: codecov/codecov-action@v7
diff --git a/docs/upgrade-tinkerpop-3.8.md b/docs/upgrade-tinkerpop-3.8.md
index ce13a0ab9..0cb692f0a 100644
--- a/docs/upgrade-tinkerpop-3.8.md
+++ b/docs/upgrade-tinkerpop-3.8.md
@@ -82,6 +82,9 @@ HugeGraph enums such as `DataType.TEXT` and `Directions.OUT` return their names
 over GraphBinary, including in maps and lists. `graph.schema()` returns a map
 with `propertykeys`, `vertexlabels`, `edgelabels` and `indexlabels` lists, using
 the same schema conversion. TinkerPop enums retain their native wire types.
+Backend `Shard` values, including `graph.metadata(HugeType.VERTEX, 'splits', size)`,
+return standard maps with `start`, `end` and an exact 64-bit `length`, including
+inside lists and maps. The default Driver does not need a private Shard serializer.
 
 Local edge ID filters accept both serialized strings and native edge IDs in
 mixed collections: `hasId(not(without(ids)))` and `hasId(within(ids))` agree on
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/HugeGraphTypeSerializerRegistryBuilder.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/HugeGraphTypeSerializerRegistryBuilder.java
index 422932e46..28cb79bd7 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/HugeGraphTypeSerializerRegistryBuilder.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/HugeGraphTypeSerializerRegistryBuilder.java
@@ -29,6 +29,7 @@ import java.util.Optional;
 import java.util.function.Function;
 
 import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.backend.store.Shard;
 import org.apache.hugegraph.schema.EdgeLabel;
 import org.apache.hugegraph.schema.IndexLabel;
 import org.apache.hugegraph.schema.PropertyKey;
@@ -54,6 +55,8 @@ public final class HugeGraphTypeSerializerRegistryBuilder
             new WireTransformSerializer<>(Id::asObject);
     private static final TypeSerializer<Blob> BLOB_TRANSFORM_SERIALIZER =
             new WireTransformSerializer<>(blob -> ByteBuffer.wrap(blob.bytes()));
+    private static final TypeSerializer<Shard> SHARD_TRANSFORM_SERIALIZER =
+            new WireTransformSerializer<>(HugeGraphTypeSerializerRegistryBuilder::shardMap);
     private static final TypeSerializer<SchemaElement> SCHEMA_TRANSFORM_SERIALIZER =
             new WireTransformSerializer<>(HugeGraphTypeSerializerRegistryBuilder::schemaMap);
     private static final TypeSerializer<SchemaManager> SCHEMA_MANAGER_TRANSFORM_SERIALIZER =
@@ -77,6 +80,9 @@ public final class HugeGraphTypeSerializerRegistryBuilder
             if (Blob.class.isAssignableFrom(type)) {
                 return BLOB_TRANSFORM_SERIALIZER;
             }
+            if (Shard.class.isAssignableFrom(type)) {
+                return SHARD_TRANSFORM_SERIALIZER;
+            }
             if (SchemaElement.class.isAssignableFrom(type)) {
                 return SCHEMA_TRANSFORM_SERIALIZER;
             }
@@ -105,6 +111,15 @@ public final class HugeGraphTypeSerializerRegistryBuilder
                type.getName().startsWith("org.apache.hugegraph.");
     }
 
+    private static Map<String, Object> shardMap(Shard shard) {
+        // Match the existing GraphSON contract, including open range boundaries.
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("start", shard.start());
+        result.put("end", shard.end());
+        result.put("length", shard.length());
+        return result;
+    }
+
     private static Map<String, Object> schemaManagerMap(SchemaManager schema) {
         Map<String, Object> result = new LinkedHashMap<>();
         result.put("propertykeys", schemaValue(schema.getPropertyKeys()));
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/config/GraphBinarySchemaCompatibilityTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/config/GraphBinarySchemaCompatibilityTest.java
index 9c5a84df0..60fd0cfe9 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/config/GraphBinarySchemaCompatibilityTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/config/GraphBinarySchemaCompatibilityTest.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.UUID;
 
 import org.apache.hugegraph.backend.id.IdGenerator;
+import org.apache.hugegraph.backend.store.Shard;
 import org.apache.hugegraph.backend.tx.ISchemaTransaction;
 import org.apache.hugegraph.io.HugeGraphTypeSerializerRegistryBuilder;
 import org.apache.hugegraph.schema.EdgeLabel;
@@ -54,6 +55,35 @@ import io.netty.buffer.ByteBufAllocator;
 
 public class GraphBinarySchemaCompatibilityTest extends BaseUnitTest {
 
+    @Test
+    public void testShardUsesExistingGraphSONFieldsWithStandardClient() throws Exception {
+        Shard shard = new Shard("start", "end", Long.MAX_VALUE);
+        Assert.assertEquals(Map.of("start", "start", "end", "end", "length", Long.MAX_VALUE),
+                            roundTrip(shard));
+    }
+
+    @Test
+    public void testShardsInsideListsAndMapsWithStandardClient() throws Exception {
+        Shard shard = new Shard("a", "z", 1048576L);
+        Map<String, Object> expected = Map.of("start", "a", "end", "z", "length", 1048576L);
+        Assert.assertEquals(List.of(expected), roundTrip(List.of(shard)));
+        Assert.assertEquals(Map.of("splits", List.of(expected)),
+                            roundTrip(Map.of("splits", List.of(shard))));
+    }
+
+    @Test
+    public void testShardPreservesEmptyAndNullBoundaries() throws Exception {
+        Assert.assertEquals(Map.of("start", "", "end", "", "length", 0L),
+                            roundTrip(new Shard("", "", 0L)));
+        Map<?, ?> result = (Map<?, ?>) roundTrip(new Shard(null, null, Long.MAX_VALUE));
+        Assert.assertEquals(3, result.size());
+        Assert.assertTrue(result.containsKey("start"));
+        Assert.assertTrue(result.containsKey("end"));
+        Assert.assertNull(result.get("start"));
+        Assert.assertNull(result.get("end"));
+        Assert.assertEquals(Long.MAX_VALUE, result.get("length"));
+    }
+
     @Test
     public void testHugeGraphEnumsUseNamesWithStandardClient() throws Exception {
         Assert.assertEquals("OUT", roundTrip(Directions.OUT));
diff --git a/hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/DataType.java b/hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/DataType.java
index 6a04a8303..c5c6c3536 100644
--- a/hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/DataType.java
+++ b/hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/DataType.java
@@ -20,6 +20,7 @@
 package org.apache.hugegraph.type.define;
 
 import java.nio.ByteBuffer;
+import java.time.OffsetDateTime;
 import java.util.Date;
 import java.util.List;
 import java.util.UUID;
@@ -155,6 +156,8 @@ public enum DataType implements SerialEnum {
         }
         if (value instanceof Date) {
             return (Date) value;
+        } else if (value instanceof OffsetDateTime) {
+            return Date.from(((OffsetDateTime) value).toInstant());
         } else if (value instanceof Integer) {
             return new Date(((Number) value).intValue());
         } else if (value instanceof Long) {
diff --git a/hugegraph-struct/src/test/java/org/apache/hugegraph/struct/schema/PropertyKeyTest.java b/hugegraph-struct/src/test/java/org/apache/hugegraph/struct/schema/PropertyKeyTest.java
index d8441144f..077594148 100644
--- a/hugegraph-struct/src/test/java/org/apache/hugegraph/struct/schema/PropertyKeyTest.java
+++ b/hugegraph-struct/src/test/java/org/apache/hugegraph/struct/schema/PropertyKeyTest.java
@@ -17,19 +17,67 @@
 
 package org.apache.hugegraph.struct.schema;
 
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Set;
 
 import org.apache.hugegraph.id.IdGenerator;
+import org.apache.hugegraph.structure.BaseEdge;
+import org.apache.hugegraph.structure.BaseVertex;
 import org.apache.hugegraph.type.define.Cardinality;
 import org.apache.hugegraph.type.define.DataType;
+import org.apache.hugegraph.type.define.IdStrategy;
 import org.apache.hugegraph.util.DateUtil;
+import org.apache.hugegraph.util.LongEncoding;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class PropertyKeyTest {
 
+    @Test
+    public void testOffsetDateTimeNormalizedToDate() {
+        OffsetDateTime value = OffsetDateTime.parse("2026-05-14T10:11:12.345678+08:00");
+        OffsetDateTime utc = value.withOffsetSameInstant(ZoneOffset.UTC);
+        Date expected = new Date(value.toInstant().toEpochMilli());
+        PropertyKey propertyKey = new PropertyKey(null, IdGenerator.of(1), "joinDate");
+        propertyKey.dataType(DataType.DATE);
+
+        Object normalized = propertyKey.validValue(value);
+        Assert.assertEquals(expected, normalized);
+        Assert.assertEquals(expected, propertyKey.validValue(utc));
+        Assert.assertEquals(345L, ((Date) normalized).getTime() % 1000L);
+        Assert.assertNull(DataType.TEXT.valueToDate(value));
+        Assert.assertNull(DataType.DATE.valueToDate(value.toLocalDateTime()));
+    }
+
+    @Test
+    public void testOffsetDateTimeSerializedAsDateNavigationKeys() {
+        OffsetDateTime value = OffsetDateTime.parse("2026-05-14T10:11:12.345678+08:00");
+        Date expected = new Date(value.toInstant().toEpochMilli());
+        PropertyKey propertyKey = new PropertyKey(null, IdGenerator.of(1), "joinDate");
+        propertyKey.dataType(DataType.DATE);
+        Object encoded = LongEncoding.encodeNumber(expected);
+
+        Assert.assertEquals(encoded, propertyKey.serialValue(value, true));
+        Assert.assertEquals(expected.toString(), propertyKey.serialValue(value, false));
+
+        VertexLabel vertexLabel = new VertexLabel(null, IdGenerator.of(2), "person");
+        vertexLabel.idStrategy(IdStrategy.PRIMARY_KEY);
+        vertexLabel.primaryKey(propertyKey.id());
+        BaseVertex vertex = new BaseVertex(null, vertexLabel);
+        vertex.addProperty(propertyKey, value);
+        Assert.assertEquals(Collections.singletonList(encoded), vertex.primaryValues());
+
+        EdgeLabel edgeLabel = new EdgeLabel(null, IdGenerator.of(3), "joined");
+        edgeLabel.sortKey(propertyKey.id());
+        BaseEdge edge = new BaseEdge(null, edgeLabel);
+        edge.addProperty(propertyKey, value.withOffsetSameInstant(ZoneOffset.UTC));
+        Assert.assertEquals(Collections.singletonList(encoded), edge.sortValues());
+    }
+
     @Test
     public void testDefaultValueNormalizedToDate() {
         // Userdata reloaded from JSON keeps ~default_value as a String;
diff --git a/install-dist/scripts/dependency/known-dependencies.txt b/install-dist/scripts/dependency/known-dependencies.txt
index a38179ed4..567cf670a 100644
--- a/install-dist/scripts/dependency/known-dependencies.txt
+++ b/install-dist/scripts/dependency/known-dependencies.txt
@@ -196,34 +196,18 @@ ivy-2.6.0.jar
 j2objc-annotations-1.1.jar
 j2objc-annotations-1.3.jar
 j2objc-annotations-2.8.jar
-jackson-annotations-2.13.0.jar
-jackson-annotations-2.14.0-rc1.jar
 jackson-annotations-2.15.2.jar
-jackson-core-2.13.0.jar
-jackson-core-2.13.2.jar
-jackson-core-2.14.0-rc1.jar
 jackson-core-2.15.2.jar
-jackson-databind-2.12.7.1.jar
-jackson-databind-2.13.0.jar
-jackson-databind-2.13.2.jar
-jackson-databind-2.14.0-rc1.jar
 jackson-databind-2.15.2.jar
 jackson-dataformat-yaml-2.15.2.jar
-jackson-datatype-jdk8-2.12.7.jar
 jackson-datatype-jdk8-2.15.2.jar
-jackson-datatype-jsr310-2.11.2.jar
-jackson-datatype-jsr310-2.12.7.jar
 jackson-datatype-jsr310-2.15.2.jar
 jackson-jakarta-rs-base-2.15.2.jar
 jackson-jakarta-rs-json-provider-2.15.2.jar
-jackson-jaxrs-base-2.14.0-rc1.jar
 jackson-jaxrs-base-2.15.2.jar
-jackson-jaxrs-json-provider-2.14.0-rc1.jar
 jackson-jaxrs-json-provider-2.15.2.jar
 jackson-module-jakarta-xmlbind-annotations-2.15.2.jar
-jackson-module-jaxb-annotations-2.14.0-rc1.jar
 jackson-module-jaxb-annotations-2.15.2.jar
-jackson-module-parameter-names-2.12.7.jar
 jackson-module-parameter-names-2.15.2.jar
 jakarta.activation-2.0.0.jar
 jakarta.activation-2.0.1.jar