bitflicker64 commented on code in PR #3430:
URL: https://github.com/apache/hugegraph/pull/3430#discussion_r4404678188


##########
.github/workflows/graphid-rekey-experiment.yml:
##########
@@ -0,0 +1,78 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+name: GraphID rekey experiment
+on:
+  pull_request:
+    paths:
+      - 
'hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/upgrade/GraphIdMigrationPlan.java'
+      - 
'hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/upgrade/GraphIdRewriter.java'
+      - 'hugegraph-store/hg-store-test/src/test/graphid-rekey/**'
+      - '.github/workflows/graphid-rekey-experiment.yml'
+permissions:
+  contents: read
+jobs:
+  native-rekey:
+    runs-on: ubuntu-24.04
+    timeout-minutes: 12
+    steps:
+      - uses: actions/checkout@v7
+        with:
+          ref: ${{ github.event.pull_request.head.sha }}
+          persist-credentials: false
+      - uses: actions/setup-java@v6
+        with:
+          distribution: zulu
+          java-version: '17'
+      - name: Run bounded native database experiments
+        shell: bash
+        run: |
+          set -euo pipefail
+          WORK="$RUNNER_TEMP/graphid-rekey"
+          mkdir -p "$WORK/classes" "$WORK/deps"
+          exec > >(tee "$WORK/run.log") 2>&1
+          git rev-parse HEAD | tee "$WORK/source-sha.txt"
+          java -version
+          cat > "$WORK/pom.xml" <<'POM'
+          <project xmlns="http://maven.apache.org/POM/4.0.0";>
+            <modelVersion>4.0.0</modelVersion>
+            
<groupId>org.apache.hugegraph</groupId><artifactId>graphid-rekey-probe</artifactId><version>1</version>
+            <dependencies>
+              
<dependency><groupId>org.rocksdb</groupId><artifactId>rocksdbjni</artifactId><version>8.10.2</version></dependency>

Review Comment:
   Minor: the `GraphIdRewriter` probes run only here, against a hard-coded 
`rocksdbjni` 8.10.2 and only when these files change, so a `rocksdb.version` 
bump in the root `pom.xml` changes the native library under the shipped kernel 
without re-running them. Move the probes into `hg-store-test` as JUnit tests so 
`pd_store / store` runs them on the reactor's versions.



##########
hugegraph-store/hg-store-test/src/test/graphid-rekey/official-17-source.py:
##########
@@ -0,0 +1,251 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Generate a bounded, fresh official 1.7 HStore source; NOT an upgrade 
test."""
+import hashlib
+import json
+import os
+from pathlib import Path
+import shutil
+import socket
+import subprocess
+import sys
+import tarfile
+import time
+import urllib.request
+import zipfile
+
+RELEASE = 
"https://github.com/apache/hugegraph/releases/download/1.7.0/apache-hugegraph-incubating-1.7.0.tar.gz";
+RELEASE_SHA = 
"e9b95b5afac156f251a12134a03a27579cca9ed7cca7e42ad0529e639b1cde1e"
+FIXTURE_SHA = "52c52778263e4ba81686a86de8eac2cf4b0df7ae"
+FIXTURE = 
f"https://raw.githubusercontent.com/SebastianGruza/hugegraph-validation/{FIXTURE_SHA}/results/upgrade-170-to-master/scripts/hg_data.py";
+
+
+def http(path, body=None):
+    payload = None if body is None else json.dumps(body).encode()
+    request = urllib.request.Request(path, data=payload, 
headers={"Content-Type": "application/json"})
+    with urllib.request.urlopen(request, timeout=60) as reply:
+        raw = reply.read()
+        try:
+            return json.loads(raw)
+        except json.JSONDecodeError:
+            return raw.decode()
+
+
+def download(url, target, expected=None):
+    h = hashlib.sha256()
+    with urllib.request.urlopen(url, timeout=120) as response, 
target.open("xb") as output:
+        while chunk := response.read(1024 * 1024):
+            h.update(chunk)
+            output.write(chunk)
+    digest = h.hexdigest()
+    if expected and digest != expected:
+        raise RuntimeError(f"Checksum mismatch for {url}: {digest}")
+    return digest
+
+
+def property_file(path, updates):
+    lines = path.read_text().splitlines()
+    lines = [line for line in lines if line.partition("=")[0].strip() not in 
updates]
+    path.write_text("\n".join(lines + [f"{k}={v}" for k, v in 
updates.items()]) + "\n")
+
+
+def main():
+    root = Path(sys.argv[1]).resolve()
+    root.mkdir(parents=True, exist_ok=False)
+    evidence = root / "evidence"
+    evidence.mkdir()
+    processes = []
+    handles = []
+    components = {}
+    forced_stops = []
+
+    def launch(name, command, cwd):
+        log = (evidence / f"{name}.log").open("wb")
+        handles.append(log)
+        process = subprocess.Popen(command, cwd=cwd, stdin=subprocess.DEVNULL, 
stdout=log,
+                                   stderr=subprocess.STDOUT)
+        processes.append((name, process))
+        return process
+
+    def wait_port(process, port):
+        deadline = time.monotonic() + 150
+        while time.monotonic() < deadline and process.poll() is None:
+            try:
+                with socket.create_connection(("127.0.0.1", port), timeout=1):
+                    return
+            except OSError:
+                time.sleep(1)
+        raise RuntimeError(f"Service did not listen on {port}; 
exit={process.poll()}")
+
+    def stop(process):
+        if process.poll() is not None:
+            return
+        process.terminate()
+        try:
+            process.wait(timeout=35)
+        except subprocess.TimeoutExpired:
+            process.kill()
+            process.wait(timeout=10)
+            forced_stops.append(process.pid)
+            print("Stopped a stuck old-version process with SIGKILL; retain 
Raft for validation", flush=True)
+
+    try:
+        archive = root / "release.tar.gz"
+        download(RELEASE, archive, RELEASE_SHA)
+        with tarfile.open(archive) as tar:
+            members = [entry for entry in tar.getmembers() if not 
Path(entry.name).name.startswith("._")]
+            (evidence / "excluded-appledouble.txt").write_text("\n".join(
+                entry.name for entry in tar.getmembers() if 
Path(entry.name).name.startswith("._")))
+            tar.extractall(root / "release", members=members, filter="data")
+        for name in ("pd", "store", "server"):
+            matches = list((root / 
"release").glob(f"**/apache-hugegraph-{name}-incubating-1.7.0"))
+            if len(matches) != 1:
+                raise RuntimeError(f"Expected one {name} distribution, found 
{matches}")
+            components[name] = matches[0]
+        pd, store, server = (components[name] for name in ("pd", "store", 
"server"))
+        config = pd / "conf/application.yml"
+        config.write_text(config.read_text().replace("store-max-shard-count: 
12", "store-max-shard-count: 2"))
+        property_file(server / "conf/rest-server.properties", {
+            "usePD": "true", "pd.peers": "127.0.0.1:8686", 
"memory_monitor.threshold": "1",
+            "batch.max_write_threads": "2"})
+        property_file(server / "conf/graphs/hugegraph.properties", {
+            "backend": "hstore", "pd.peers": "127.0.0.1:8686", 
"vertex.cache_capacity": "1000",
+            "edge.cache_capacity": "1000"})
+        java17 = str(Path(os.environ["JAVA_HOME_17_X64"]) / "bin/java")
+        java11 = str(Path(os.environ["JAVA_HOME_11_X64"]) / "bin/java")
+        jvm = ["-Xms128m", "-Xmx768m", "-XX:ActiveProcessorCount=2",
+               "--add-opens=java.base/java.lang=ALL-UNNAMED",
+               "--add-opens=java.base/java.nio=ALL-UNNAMED",
+               "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
+               "--add-exports=java.base/jdk.internal.reflect=ALL-UNNAMED"]
+        for name, component, pattern, port in (("pd", pd, 
"hg-pd-service-*.jar", 8686),
+                                               ("store", store, 
"hg-store-node-*.jar", 8500)):
+            jars = list((component / "lib").glob(pattern))
+            if len(jars) != 1:
+                raise RuntimeError(f"Ambiguous {name} executable: {jars}")
+            process = launch(name, [java17, *jvm, 
f"-Dspring.config.location={component}/conf/application.yml",
+                                    "-jar", str(jars[0])], component)
+            wait_port(process, port)
+        store_process = processes[-1][1]
+        jars = sorted((server / "lib").rglob("*.jar"))
+        # Prefer released modular Netty classes over an older bundled fat 
netty-all.
+        modular_netty = [p for p in jars if p.name.startswith("netty-") and 
not p.name.startswith("netty-all-")]
+        hugegraph = [p for p in jars if p.name.startswith("hugegraph")]
+        ordered = list(dict.fromkeys(modular_netty + hugegraph + jars))
+        ordered += sorted((server / "ext").rglob("*.jar")) + sorted((server / 
"plugins").rglob("*.jar"))
+        classpath = os.pathsep.join(map(str, ordered))
+        (evidence / "server-classpath.txt").write_text("\n".join(p.name for p 
in ordered))
+        for attempt in range(3):
+            with (evidence / f"init-{attempt}.log").open("wb") as output:
+                result = subprocess.run([java11, *jvm, "-cp", classpath, 
"org.apache.hugegraph.cmd.InitStore",
+                                         "conf/rest-server.properties"], 
cwd=server, input=b"\n",
+                                        stdout=output, 
stderr=subprocess.STDOUT, timeout=120)
+            if result.returncode == 0:
+                break
+            time.sleep(3)
+        else:
+            raise RuntimeError("Official 1.7 InitStore failed")
+        sv = launch("server", [java11, *jvm, 
"-Dlog4j.configurationFile=conf/log4j2.xml", "-cp", classpath,
+                               "org.apache.hugegraph.dist.HugeGraphServer", 
"conf/gremlin-server.yaml",
+                               "conf/rest-server.properties"], server)
+        wait_port(sv, 8080)
+        deadline = time.monotonic() + 90
+        while True:
+            try:
+                http("http://127.0.0.1:8080/graphs";)
+                break
+            except Exception:
+                if sv.poll() is not None or time.monotonic() > deadline:
+                    raise
+                time.sleep(1)
+        fixture = root / "hg_data.py"
+        fixture_digest = download(FIXTURE, fixture)
+        for mode in ("write", "read"):
+            with (evidence / f"fixture-{mode}.log").open("wb") as output:
+                subprocess.run([sys.executable, str(fixture), mode, 
"http://127.0.0.1:8080";,
+                                str(evidence / f"fixture-{mode}.json")], 
stdout=output, stderr=subprocess.STDOUT,
+                               check=True, timeout=180)
+        baseline = json.loads((evidence / "fixture-read.json").read_text())
+        checks = [entry for entry in baseline if 
entry["step"].startswith("gremlin ")]
+        if len(checks) != 16 or any(entry["status"] != 200 for entry in 
checks):
+            raise RuntimeError("The official source did not pass all 16 
fixture requests")

Review Comment:
   Important: the `official-source` job in 
`.github/workflows/graphid-official-source.yml` fails at this head on this 
check, so the PR adds a workflow that is red on every run and never produces 
the 1.7 source it exists for. Fix the fixture run so all 16 Gremlin requests 
pass, or drop the workflow and script from this PR until they do.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to