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