yugaaank commented on code in PR #3104: URL: https://github.com/apache/hugegraph/pull/3104#discussion_r3635689319
########## hugegraph-server/hugegraph-dist/src/assembly/travis/run-riscv64-smoke.sh: ########## @@ -0,0 +1,474 @@ +#!/bin/bash +# +# 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. +# +# run-riscv64-smoke.sh — Disposable RISC-V (linux/riscv64) end-to-end smoke test. +# +# Builds the HugeGraph Server distribution on the contributor's native host +# (x86-64 / arm64), then runs it inside an emulated linux/riscv64 container to +# verify the RocksDB backend + Gremlin stack actually work on RISC-V via QEMU. +# +# This is a CORRECTNESS gate, not a performance benchmark. QEMU user-mode +# emulation is several times slower than native; expect the full run (build + +# init + REST + Gremlin + restart) to take many minutes the first time. +# +# It requires Docker with QEMU/binfmt_misc multi-platform support (Docker +# Desktop ships this; on Linux install it with: +# docker run --privileged --rm tonistiigi/binfmt --install all +# No host RISC-V packages are installed by this script. +# +# It removes ONLY what it creates: a uniquely-named container, volume, and +# locally-built image. The QEMU emulator registration is left untouched +# (remove it with: docker run --privileged --rm tonistiigi/binfmt --uninstall all). +# +# Usage: +# ./run-riscv64-smoke.sh [path-to-server-dist.tar.gz] +# ./run-riscv64-smoke.sh # builds the dist under hugegraph-server/ +# +set -euo pipefail + +ARCH=riscv64 +PLATFORM="linux/${ARCH}" +# Ubuntu 24.04 publishes openjdk-11-jre-headless for linux/riscv64 (glibc). +BASE_IMAGE="ubuntu:24.04" + +REPO_ROOT=$(cd "$(dirname "$0")/../../../../.." && pwd) + +# Use disk-backed temp: the extracted server (~1GB) blows out a small RAM tmpfs +# /tmp. Default to a work dir on the same (large) filesystem as the repo. +: "${TMPDIR:=$REPO_ROOT/.riscv64-smoke-tmp}" +mkdir -p "$TMPDIR" +export TMPDIR + +# Unique, traceable names so cleanup removes only our own resources. +STAMP=$(date +%Y%m%d%H%M%S) +TAG="hugegraph-riscv64-smoke:${STAMP}" +# KEEP: don't auto-cleanup so a failed/finished run stays pokeable. +VOL="hugegraph-riscv64-data-${STAMP}" +CONTAINER="hugegraph-riscv64-smoke-${STAMP}" + +DIST_ARG="${1:-}" +DIST_TAR="" +SERVER_DIR="" +BUILD_CTX="" +ROCKS_BUILD="" + +GREEN=$'\033[0;32m'; RED=$'\033[0;31m'; NC=$'\033[0m' +pass() { echo "${GREEN}PASS${NC} $*"; } +fail() { echo "${RED}FAIL${NC} $*" >&2; } + +# Check if the container is still alive (returns 0 if running). +container_alive() { + $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qx "$CONTAINER" +} + +# Run docker exec with container-liveness guard + exit-code logging. +# Usage: safe_exec $DOCKER exec <container> <cmd> [args...] +# Handles multi-word DOCKER values (e.g. "sudo docker") via eval. +# Returns the command's output on stdout; logs failures to stderr. +safe_exec() { + local rc + if ! container_alive; then + fail "container '$CONTAINER' is no longer running (before: $*)" + dump_health_diagnostics + return 1 + fi + set +e + eval "$@" + rc=$? + set -e + if [[ $rc -ne 0 ]]; then + fail "command failed (exit $rc): $*" + dump_health_diagnostics + return 1 + fi +} + +# DOCKER: allow callers to override (e.g. "sudo docker"). Defaults to plain docker. +DOCKER=${DOCKER:-docker} + +# Dump container diagnostics to stderr. Defined early so the EXIT trap can +# call it even if the script fails before the main body. +dump_health_diagnostics() { + echo "----- health-check diagnostics ($CONTAINER) -----" >&2 + $DOCKER inspect --format \ + 'state={{.State.Status}} exit={{.State.ExitCode}} error={{.State.Error}}' \ + "$CONTAINER" >&2 || true + + if $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qx "$CONTAINER"; then + echo "----- listening processes -----" >&2 + $DOCKER exec "$CONTAINER" sh -c \ + 'lsof -nP -iTCP:8080 -sTCP:LISTEN || true' >&2 || true + for endpoint in versions graphs; do + echo "----- GET /$endpoint -----" >&2 + $DOCKER exec "$CONTAINER" curl -i -sS --connect-timeout 5 --max-time 15 \ + "http://127.0.0.1:8080/$endpoint" >&2 || true + done + fi + + echo "----- recent container logs -----" >&2 + $DOCKER logs --tail 100 "$CONTAINER" >&2 || true + echo "----- end health-check diagnostics -----" >&2 +} + +_EXIT_CODE=0 +_exit_handler() { + local rc=$? + # If the script failed, log the exit code so the root cause isn't lost. + if [[ $rc -ne 0 ]]; then + echo "" >&2 + echo "==> Script failed with exit code $rc" >&2 + if container_alive; then + dump_health_diagnostics + else + echo "==> container '$CONTAINER' is not running (may have been OOM-killed or crashed)" >&2 + # Best-effort: check docker inspect for OOMKilled + dump any surviving logs + $DOCKER inspect --format \ + 'OOMKilled={{.State.OOMKilled}} ExitCode={{.State.ExitCode}} Status={{.State.Status}}' \ + "$CONTAINER" >&2 2>/dev/null || true + $DOCKER logs --tail 80 "$CONTAINER" >&2 2>/dev/null || true + fi + fi + _cleanup +} + +_cleanup() { + # KEEP=1: leave everything standing for live poking. Still dump logs so a + # failure's root cause is visible; skip all teardown. + if [[ -n "${KEEP:-}" ]]; then + echo "==> KEEP=1 set — skipping cleanup. Resources left standing:" >&2 + echo " container: $CONTAINER" >&2 + echo " volume: $VOL" >&2 + echo " image: $TAG" >&2 + return 0 + fi + # Dump container logs first so a failure's root cause isn't destroyed by cleanup. + if $DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qx "$CONTAINER"; then + echo "----- container logs ($CONTAINER) -----" >&2 + $DOCKER logs --tail 60 "$CONTAINER" >&2 || true + echo "----- end logs -----" >&2 + # The startup wrapper hides the real error in the server log file; dump it + # from the stopped container (docker cp works on exited containers). + echo "----- hugegraph-server.log -----" >&2 + $DOCKER cp "$CONTAINER:/server/logs/hugegraph-server.log" - 2>/dev/null \ + | tar -xO 2>/dev/null | tail -n 80 >&2 || true + echo "----- end hugegraph-server.log -----" >&2 + fi + $DOCKER rm -f "$CONTAINER" >/dev/null 2>&1 || true + # Only remove the volume we created. + $DOCKER volume rm "$VOL" >/dev/null 2>&1 || true + # Only remove the image we tagged; never prune the host's image store. + $DOCKER rmi "$TAG" >/dev/null 2>&1 || true + # Remove disk-backed temp work dirs (build context holds the ~1GB extract). + [[ -n "$BUILD_CTX" && -d "$BUILD_CTX" ]] && rm -rf "$BUILD_CTX" + [[ -n "$ROCKS_BUILD" && -d "$ROCKS_BUILD" ]] && rm -rf "$ROCKS_BUILD" +} +trap _exit_handler EXIT + +need() { command -v "$1" >/dev/null 2>&1 || { fail "missing required command: $1"; exit 1; }; } +need docker +# buildx is required: the legacy builder ignores --platform. +$DOCKER buildx version >/dev/null 2>&1 || { fail "docker buildx is required (pacman -S docker-buildx)"; exit 1; } + +# Register QEMU user-mode emulation for riscv64 if the kernel can't already run +# it (otherwise the build/run fails with 'exec format error'). binfmt handlers +# do NOT survive reboots, so a fresh checkout needs this — makes the smoke test +# self-contained on any x86 host. Pinned tag: :latest 403s on Docker Hub. +if ! ls /proc/sys/fs/binfmt_misc/qemu-riscv64 >/dev/null 2>&1; then + echo "==> Registering QEMU riscv64 emulation (binfmt)" + $DOCKER run --privileged --rm tonistiigi/binfmt:qemu-v8.1.5 --install riscv64 >/dev/null +fi + +# 1. Resolve the Server distribution tarball (build on host if not supplied). +# Build from the ROOT pom (not hugegraph-server/): the root parent pom +# `hugegraph` and the root sibling `hugegraph-struct` must be installed +# into ~/.m2 first, or module resolution fails on the ${revision} parent. +if [[ -n "$DIST_ARG" ]]; then + DIST_TAR="$DIST_ARG" +else + echo "==> Building HugeGraph Server distribution on host (native platform)" + mvn -f "$REPO_ROOT/pom.xml" package -e -B -ntp \ + -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Drat.skip=true \ + -pl hugegraph-server/hugegraph-dist -am + DIST_TAR=$(ls -t "$REPO_ROOT"/hugegraph-server/apache-hugegraph-server-*.tar.gz 2>/dev/null | head -n1 || true) +fi +[[ -f "$DIST_TAR" ]] || { fail "server distribution tarball not found"; exit 1; } +echo "==> Using distribution: $DIST_TAR" + +# Extract straight into the build context's server/ dir — no second copy +# (the extracted tree is ~1GB; copying it twice doubled the temp footprint). +BUILD_CTX=$(mktemp -d "hugegraph-riscv64-ctx.XXXXXX") +SERVER_DIR="$BUILD_CTX/server" +mkdir -p "$SERVER_DIR" +tar -xzf "$DIST_TAR" -C "$SERVER_DIR" --strip-components=1 + +# Force the RocksDB backend for the smoke run. +CONF="$SERVER_DIR/conf/graphs/hugegraph.properties" +grep -qE '^[[:space:]]*backend[[:space:]]*=' "$CONF" \ + && sed -i 's/^[[:space:]]*backend[[:space:]]*=.*/backend=rocksdb/' "$CONF" \ Review Comment: Fixed. Added a portable sedi() helper that uses temp-file-rename instead of sed -i. Covers the macOS/Docker Desktop path. The two sed -i calls inside the heredoc were left unchanged since they run inside the Ubuntu container where GNU sed is guaranteed. -- 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]
