diff --git a/.github/configs/settings.xml b/.github/configs/settings.xml
index 45c87139a9..6cc7dc435c 100644
--- a/.github/configs/settings.xml
+++ b/.github/configs/settings.xml
@@ -27,6 +27,13 @@
staged-releases
https://repository.apache.org/content/groups/staging/
+
+ github
+ https://maven.pkg.github.com/hugegraph/toplingdb
+
+ true
+
+
diff --git a/.github/workflows/check-dependencies.yml b/.github/workflows/check-dependencies.yml
index fa804e260c..75a104c019 100644
--- a/.github/workflows/check-dependencies.yml
+++ b/.github/workflows/check-dependencies.yml
@@ -14,8 +14,10 @@ jobs:
dependency-check:
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
SCRIPT_DEPENDENCY: install-dist/scripts/dependency
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
steps:
- name: Checkout source
uses: actions/checkout@v4
diff --git a/.github/workflows/cluster-test-ci.yml b/.github/workflows/cluster-test-ci.yml
index 3ef269e878..0537f31a6a 100644
--- a/.github/workflows/cluster-test-ci.yml
+++ b/.github/workflows/cluster-test-ci.yml
@@ -12,7 +12,9 @@ jobs:
cluster-test:
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
steps:
- name: Install JDK 11
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index d66dc8cee9..52f3d2a93e 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -12,7 +12,9 @@ on:
jobs:
analyze:
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
name: Analyze
runs-on: ubuntu-latest
permissions:
diff --git a/.github/workflows/commons-ci.yml b/.github/workflows/commons-ci.yml
index 5311ebeee0..c6f9e7c1da 100644
--- a/.github/workflows/commons-ci.yml
+++ b/.github/workflows/commons-ci.yml
@@ -9,16 +9,22 @@ on:
- /^test-.*$/
pull_request:
+permissions:
+ contents: read
+ packages: read
+
jobs:
build-commons:
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
strategy:
fail-fast: false
matrix:
- JAVA_VERSION: ['11']
+ JAVA_VERSION: [ '11' ]
steps:
- name: Install JDK ${{ matrix.JAVA_VERSION }}
diff --git a/.github/workflows/docker-build-ci.yml b/.github/workflows/docker-build-ci.yml
index ada012be80..1c763ca2e3 100644
--- a/.github/workflows/docker-build-ci.yml
+++ b/.github/workflows/docker-build-ci.yml
@@ -35,11 +35,13 @@ jobs:
strategy:
fail-fast: false
matrix:
- dockerfile:
- - hugegraph-pd/Dockerfile
- - hugegraph-store/Dockerfile
- - hugegraph-server/Dockerfile
- - hugegraph-server/Dockerfile-hstore
+ include:
+ - dockerfile: hugegraph-pd/Dockerfile
+ - dockerfile: hugegraph-store/Dockerfile
+ - dockerfile: hugegraph-server/Dockerfile
+ - dockerfile: hugegraph-server/Dockerfile
+ target: topling
+ - dockerfile: hugegraph-server/Dockerfile-hstore
steps:
- name: Checkout
@@ -47,7 +49,12 @@ jobs:
- name: Build ${{ matrix.dockerfile }}
run: |
- IMAGE_ID=$(docker build -q -f ${{ matrix.dockerfile }} .)
+ TARGET_ARGS=()
+ if [[ -n "${{ matrix.target }}" ]]; then
+ TARGET_ARGS+=(--target "${{ matrix.target }}")
+ fi
+ IMAGE_ID=$(docker build -q "${TARGET_ARGS[@]}" \
+ -f ${{ matrix.dockerfile }} .)
echo "Built: $IMAGE_ID"
echo "IMAGE_ID=$IMAGE_ID" >> "$GITHUB_ENV"
HC=$(docker inspect --format='{{json .Config.Healthcheck}}' "$IMAGE_ID")
@@ -55,9 +62,20 @@ jobs:
[[ "$HC" != "null" ]] || { echo "ERROR: HEALTHCHECK missing in ${{ matrix.dockerfile }}"; exit 1; }
- name: Test server entrypoint property mapping
- if: matrix.dockerfile == 'hugegraph-server/Dockerfile'
+ if: matrix.dockerfile == 'hugegraph-server/Dockerfile' && matrix.target != 'topling'
run: bash hugegraph-server/hugegraph-dist/docker/test/test-docker-entrypoint.sh
+ - name: Verify ToplingDB image runtime
+ if: matrix.target == 'topling'
+ run: |
+ docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' \
+ "$IMAGE_ID" | grep -qx 'HG_SERVER_ROCKSDB_PROVIDER=topling'
+ docker run --rm --entrypoint bash "$IMAGE_ID" -c '
+ test -n "$(find lib/topling -maxdepth 1 -name "rocksdbjni*.jar" -print -quit)"
+ test -r library/librocksdbjni-linux64.so
+ ldd library/librocksdbjni-linux64.so | grep -qv "not found"
+ '
+
# The startup preflight needs a socket-table tool, and the base image
# ships none of its own. Without one every start reports "unknown" and
# a duplicate start is no longer refused, so assert the image can
diff --git a/.github/workflows/licence-checker.yml b/.github/workflows/licence-checker.yml
index a6e6990a64..e1b8ee9f93 100644
--- a/.github/workflows/licence-checker.yml
+++ b/.github/workflows/licence-checker.yml
@@ -11,7 +11,9 @@ jobs:
check-license:
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/pd-store-ci.yml b/.github/workflows/pd-store-ci.yml
index 6f670e1cb9..95693e2c43 100644
--- a/.github/workflows/pd-store-ci.yml
+++ b/.github/workflows/pd-store-ci.yml
@@ -8,8 +8,68 @@ on:
- 'test-*'
pull_request:
+permissions:
+ contents: read
+ packages: read
+
# TODO: consider merge to one ci.yml file
jobs:
+ distributed-rocksdb-runtime:
+ runs-on: ubuntu-22.04
+ strategy:
+ fail-fast: false
+ matrix:
+ component: [ pd, store ]
+ provider: [ rocksdb, topling ]
+ env:
+ TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install Java 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'zulu'
+
+ - name: Use staged maven repo settings
+ run: |
+ mkdir -p "$HOME/.m2"
+ cp -vf .github/configs/settings.xml "$HOME/.m2/settings.xml"
+
+ - name: Package distributions
+ run: |
+ mvn clean package -Dmaven.test.skip=true -ntp
+
+ - name: Configure ${{ matrix.component }} ${{ matrix.provider }} provider
+ run: |
+ VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+ SERVER_DIR="hugegraph-server/apache-hugegraph-server-$VERSION"
+ if [ "${{ matrix.component }}" = "pd" ]; then
+ COMPONENT_DIR="hugegraph-pd/apache-hugegraph-pd-$VERSION"
+ CONFIG_FILE="$COMPONENT_DIR/conf/application.yml"
+ sed -i 's/^# rocksdb:/rocksdb:/' "$CONFIG_FILE"
+ sed -i 's/^# provider: rocksdb/ provider: ${{ matrix.provider }}/' \
+ "$CONFIG_FILE"
+ else
+ COMPONENT_DIR="hugegraph-store/apache-hugegraph-store-$VERSION"
+ CONFIG_FILE="$COMPONENT_DIR/conf/application-pd.yml"
+ sed -i 's/^ # provider: topling/ provider: ${{ matrix.provider }}/' \
+ "$CONFIG_FILE"
+ fi
+ echo "SERVER_DIR=$SERVER_DIR" >> "$GITHUB_ENV"
+ echo "COMPONENT_DIR=$COMPONENT_DIR" >> "$GITHUB_ENV"
+
+ - name: Prepare and test real ${{ matrix.provider }} runtime
+ run: |
+ source "$TRAVIS_DIR/install-rocksdb.sh" "${{ matrix.component }}"
+ "$TRAVIS_DIR/test-rocksdb-runtime.sh" \
+ "${{ matrix.provider }}" "$SERVER_DIR" "$COMPONENT_DIR"
+
struct:
runs-on: ubuntu-latest
env:
@@ -62,10 +122,12 @@ jobs:
runs-on: ubuntu-latest
env:
# TODO: avoid duplicated env setup in pd & store
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
steps:
- name: Install JDK 11
@@ -92,6 +154,15 @@ jobs:
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
+ - name: Install deps
+ run: |
+ "${TRAVIS_DIR}/install-deps.sh" || exit 1
+
+ - name: Package
+ # todo remove --fail-at-end after test
+ run: |
+ mvn clean package -U -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -ntp --fail-at-end
+
- name: Run common test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-common-test
@@ -106,6 +177,7 @@ jobs:
# todo remove --fail-at-end after test
run: |
mvn clean package -U -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -ntp --fail-at-end
+ source "${TRAVIS_DIR}/install-rocksdb.sh" pd
- name: Check startup test prerequisites (PD)
id: pd-preflight
@@ -154,10 +226,12 @@ jobs:
needs: struct
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
steps:
- name: Install JDK 11
@@ -184,10 +258,15 @@ jobs:
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
+ - name: Install deps
+ run: |
+ "${TRAVIS_DIR}/install-deps.sh" || exit 1
+
- name: Package
# todo remove --fail-at-end after test
run: |
mvn clean package -U -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -ntp --fail-at-end
+ source "${TRAVIS_DIR}/install-rocksdb.sh" store
- name: Check startup test prerequisites (Store)
id: store-preflight
@@ -259,11 +338,13 @@ jobs:
needs: struct
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: hstore
RELEASE_BRANCH: ${{ startsWith(github.ref_name, 'release-') || startsWith(github.ref_name, 'test-') || startsWith(github.base_ref, 'release-') }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
steps:
- name: Install JDK 11
@@ -284,6 +365,10 @@ jobs:
with:
fetch-depth: 2
+ - name: Install deps
+ run: |
+ "${TRAVIS_DIR}/install-deps.sh" || exit 1
+
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
@@ -294,6 +379,9 @@ jobs:
# todo remove --fail-at-end after test
run: |
mvn clean package -U -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -ntp --fail-at-end
+ source "${TRAVIS_DIR}/install-rocksdb.sh" pd
+ source "${TRAVIS_DIR}/install-rocksdb.sh" store
+ source "${TRAVIS_DIR}/install-rocksdb.sh" hstore
- name: Prepare env and service
run: |
diff --git a/.github/workflows/server-ci.yml b/.github/workflows/server-ci.yml
index 9c4e577d85..4bce60da5e 100644
--- a/.github/workflows/server-ci.yml
+++ b/.github/workflows/server-ci.yml
@@ -9,6 +9,59 @@ on:
pull_request:
jobs:
+ server-rocksdb-runtime:
+ runs-on: ubuntu-22.04
+ permissions:
+ contents: read
+ packages: read
+ strategy:
+ fail-fast: false
+ matrix:
+ provider: [ rocksdb, topling ]
+ env:
+ TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install Java 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'zulu'
+
+ - name: Use staged maven repo settings
+ run: |
+ mkdir -p "$HOME/.m2"
+ cp -vf .github/configs/settings.xml "$HOME/.m2/settings.xml"
+
+ - name: Package Server
+ run: |
+ mvn clean package -pl hugegraph-server/hugegraph-dist -am \
+ -Dmaven.test.skip=true -ntp
+
+ - name: Configure ${{ matrix.provider }} provider
+ run: |
+ VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+ SERVER_DIR="hugegraph-server/apache-hugegraph-server-$VERSION"
+ GRAPH_CONF="$SERVER_DIR/conf/graphs/hugegraph.properties"
+ sed -i '/^[#]*rocksdb\.provider=/d' "$GRAPH_CONF"
+ echo "rocksdb.provider=${{ matrix.provider }}" >> "$GRAPH_CONF"
+ echo "SERVER_DIR=$SERVER_DIR" >> "$GITHUB_ENV"
+
+ - name: Prepare ${{ matrix.provider }} runtime
+ run: |
+ source "$TRAVIS_DIR/install-rocksdb.sh" server
+
+ - name: Select and test real ${{ matrix.provider }} runtime
+ run: |
+ source "$SERVER_DIR/bin/preload-topling.sh"
+ "$TRAVIS_DIR/test-rocksdb-runtime.sh" \
+ "${{ matrix.provider }}" "$SERVER_DIR"
+
wait-storage-shell-test:
permissions:
contents: read
@@ -25,8 +78,11 @@ jobs:
build-server:
# TODO: we need test & replace it to ubuntu-24.04 or ubuntu-latest
runs-on: ubuntu-22.04
+ permissions:
+ contents: read
+ packages: read
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: ${{ matrix.BACKEND }}
@@ -36,6 +92,8 @@ jobs:
TARGET_BRANCH_NAME: ${{ github.base_ref != '' && github.base_ref || github.ref_name }}
RELEASE_BRANCH: ${{ startsWith(github.ref_name, 'release-') || startsWith(github.ref_name, 'test-') }}
RAFT_MODE: ${{ startsWith(github.head_ref, 'test') || startsWith(github.head_ref, 'raft') }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_ACTOR: ${{ github.actor }}
strategy:
fail-fast: false
@@ -56,16 +114,16 @@ jobs:
java-version: '8'
distribution: 'zulu'
- - name: Prepare backend environment
- run: |
- $TRAVIS_DIR/install-backend.sh $BACKEND && jps -l
-
- name: Install Java ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'
+ - name: Install deps
+ run: |
+ ${TRAVIS_DIR}/install-deps.sh
+
- name: Cache Maven packages
uses: actions/cache@v4
with:
@@ -79,9 +137,14 @@ jobs:
cp $HOME/.m2/settings.xml /tmp/settings.xml
cp -vf .github/configs/settings.xml $HOME/.m2/settings.xml && cat $HOME/.m2/settings.xml
- - name: Compile
+ - name: Package
run: |
- mvn clean compile -U -Dmaven.javadoc.skip=true -ntp
+ mvn clean package -Dmaven.test.skip=true -ntp
+ source "$TRAVIS_DIR/install-rocksdb.sh" server
+
+ - name: Prepare backend environment
+ run: |
+ $TRAVIS_DIR/install-backend.sh $BACKEND && jps -l
- name: Validate Docker integration
if: ${{ env.BACKEND == 'rocksdb' }}
@@ -178,6 +241,8 @@ jobs:
- name: Run start-hugegraph.sh foreground mode tests
if: ${{ env.BACKEND == 'rocksdb' && steps.server-preflight.outputs.can_run == 'true' }}
run: |
+ mvn package -Dmaven.test.skip=true -pl hugegraph-server/hugegraph-dist -am -ntp
+ source "$TRAVIS_DIR/install-rocksdb.sh" server
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
SERVER_DIR=hugegraph-server/apache-hugegraph-server-$VERSION/
$TRAVIS_DIR/test-start-hugegraph.sh $SERVER_DIR
diff --git a/.specs/hugegraph-server/ToplingDB/design.md b/.specs/hugegraph-server/ToplingDB/design.md
new file mode 100644
index 0000000000..725418f5a0
--- /dev/null
+++ b/.specs/hugegraph-server/ToplingDB/design.md
@@ -0,0 +1,356 @@
+# Design of ToplingDB
+
+## Overview
+
+HugeGraph ToplingDB aims to enhance compatibility with ToplingDB, providing users with an additional storage engine option that improves performance, functionality, and usability.
+
+## Design Goals
+
+* **Dynamic Configuration**: Support flexible configuration of RocksDB parameters via YAML files, replacing hardcoded values to improve maintainability and adaptability.
+* **API Compatibility**: Maintain compatibility with the RocksDB API. API
+ compatibility does not imply that data written with ToplingDB-specific
+ options can be reopened safely by standard RocksDB.
+* **Visual Monitoring**: Provide a Web Server interface for real-time visibility into storage engine status and configuration, enhancing observability.
+* **Immutable Runtime Selection**: Prepare JARs, native libraries, and static
+ resources during packaging or installation. Service startup only validates
+ and selects the prepared runtime.
+
+## Architecture Diagram
+
+### HugeGraph Startup Script Logic
+
+The diagram below separates mutable runtime preparation from read-only service
+startup. `install-rocksdb.sh` must run after the component distribution is
+assembled and before ToplingDB is selected.
+
+From the user's perspective, startup remains unchanged—simply execute `start-hugegraph.sh`.
+The script reads `rocksdb.provider` before preparing any ToplingDB resources. The
+default value is `rocksdb`; ToplingDB is never selected from `option_path` or from
+classpath detection alone.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User as User
+ participant Install as install-rocksdb.sh
+ participant StartSh as start-hugegraph.sh
+ participant Preload as preload-topling.sh
+ participant JVM as JVM/LD Loader
+ participant Server as HugeGraph Server
+
+ User->>Install: Prepare selected component runtime
+ Install->>Install: Extract native library and static resources
+ Install->>Install: Resolve optional allocator and system compatibility
+ User->>StartSh: Execute startup script
+ StartSh->>Preload: Source preload script
+ Preload->>Preload: Read rocksdb.provider (default: rocksdb)
+ alt provider is rocksdb
+ Preload->>Preload: Validate standard RocksDB runtime
+ alt runtime mismatches rocksdb
+ Preload-->>StartSh: Fail startup with an explicit error
+ else runtime matches rocksdb
+ Preload->>Preload: Keep standard RocksDB classpath
+ end
+ else provider is topling
+ Preload->>Preload: Require and validate ToplingDB runtime
+ alt runtime missing or provider mismatch
+ Preload-->>StartSh: Fail startup with an explicit error
+ else runtime matches topling
+ Preload->>Preload: Select the preinstalled ToplingDB classpath
+ Preload->>Preload: Validate TOP/library and configuration
+ Preload->>JVM: Set LD_LIBRARY_PATH and LD_PRELOAD
+ end
+ else provider value is unsupported
+ Preload-->>StartSh: Fail startup with an explicit error
+ end
+ Preload-->>StartSh: Return
+ StartSh->>Server: Start service
+ Server-->>User: Service running
+```
+
+### RocksDB Startup Logic
+
+Select the storage engine exclusively from `rocksdb.provider`. Reflection is used
+only to validate and invoke the explicitly selected ToplingDB runtime. A missing
+runtime, an unsupported provider, or a provider/runtime mismatch is a startup
+error; HugeGraph does not silently fall back to another engine.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant Store as HugeGraph Store
+ participant Config as HugeConfig
+ participant Sessions as RocksDBStdSessions
+ participant SPR as SidePluginRepo (Reflection)
+ participant Repo as Repo Instance
+ participant Rocks as RocksDB
+
+ Store->>Config: Read PROVIDER / OPTION_PATH / OPEN_HTTP
+ Store->>Sessions: Create Sessions(..., provider, optionPath, openHttp)
+ alt provider is rocksdb or unset
+ Sessions->>Sessions: Validate standard RocksDB runtime
+ Sessions->>Rocks: Standard open()
+ Sessions-->>Store: Return OpenedRocksDB(null, handles)
+ else provider is topling
+ Sessions->>SPR: Require ToplingDB API and validate runtime match
+ alt SPR missing or runtime mismatched
+ Sessions-->>Store: Throw startup error
+ else ToplingDB runtime is valid
+ Sessions->>SPR: Reflectively load/create Repo
+ opt optionPath provided
+ Sessions->>Repo: importAutoFile(optionPath)
+ end
+ Sessions->>Repo: open (with JSON descriptor)
+ opt openHttp is true and instance is GRAPH_STORE
+ Sessions->>Repo: startHttpServer()
+ end
+ Sessions->>Rocks: Get RocksDB instance (with CF handles)
+ Sessions-->>Store: Return OpenedRocksDB(repo, handles)
+ end
+ else provider value is unsupported
+ Sessions-->>Store: Throw configuration error
+ end
+ note over Store,Sessions: On shutdown, if repo exists, call repo.closeAllDB()
+```
+
+## Involved Modules
+
+### ToplingDB JAR and Maven Setup
+
+There are two ways to obtain the JAR package:
+
+1. Pull from GitHub repository
+2. Build manually and install to Maven
+
+#### Pull JAR from GitHub Repository
+
+Since ToplingDB is not published to Maven Central, the JAR can only be obtained from GitHub Actions releases:
+[JAR Package](https://github.com/hugegraph/toplingdb/packages/2550860)
+
+Add GitHub repository configuration to your Maven `settings.xml`:
+
+```xml
+
+
+
+
+ github
+ YOUR_GITHUB_ACTOR
+
+ YOUR_GITHUB_TOKEN
+
+
+
+
+
+ ...
+
+ ...
+
+
+ github
+ https://maven.pkg.github.com/hugegraph/toplingdb
+
+ true
+
+
+
+
+
+```
+
+Also, update the `rocksdbjni` version in `hugegraph-server/hugegraph-rocksdb/pom.xml` from `7.2.2` to `8.10.2-SNAPSHOT` to match the GitHub release:
+
+```xml
+
+ org.rocksdb
+ rocksdbjni
+ 8.10.2-SNAPSHOT
+
+```
+
+#### Build ToplingDB JAR Manually
+
+Clone [ToplingDB](https://github.com/topling/toplingdb) and run the following commands:
+
+```bash
+# Build shared library
+make -j$(nproc) DEBUG_LEVEL=0 shared_lib
+# Install shared library
+sudo make install-shared PREFIX=/opt DEBUG_LEVEL=0
+# Package JAR
+make rocksdbjava -j$(nproc) DEBUG_LEVEL=0 STRIP_DEBUG_INFO=1 ROCKSDB_JAR_WITH_DYNAMIC_LIBS=1
+
+# Set JAVA_HOME (especially for root)
+export JAVA_HOME=/usr/lib/jvm/jre-openjdk-yourpath
+# Install librocksdbjni dynamic library
+sudo make -j install-jni PREFIX=/opt DEBUG_LEVEL=0 STRIP_DEBUG_INFO=1
+# Install JAR to local Maven repository
+cd java/target
+cp rocksdbjni-8.10.2-linux64.jar rocksdbjni-8.10.2-SNAPSHOT-linux64.jar
+mvn install:install-file -Dfile=rocksdbjni-8.10.2-SNAPSHOT-linux64.jar \
+ -DgroupId=org.rocksdb -DartifactId=rocksdbjni \
+ -Dversion=8.10.2-SNAPSHOT -Dpackaging=jar
+```
+
+### Preloading Dynamic Libraries and Static Resources
+
+ToplingDB uses thread-local storage (TLS), requiring dynamic libraries to be preloaded via `LD_PRELOAD`.
+
+Additionally, the Web Server needs static resources to render the visualization interface.
+
+`install-rocksdb.sh` prepares ToplingDB dynamic libraries and Web resources.
+`preload-topling.sh` performs read-only validation and exports the selected
+classpath and library paths.
+
+Installation tasks:
+
+- Extract `.so` libraries and Web resources (HTML/CSS) from `rocksdbjni*.jar`
+- Handle `libaio` compatibility issues on Ubuntu 24.04+
+- Optionally prepare jemalloc
+
+Startup tasks are limited to strict provider parsing, immutable runtime
+selection, dependency validation, and exporting `LD_LIBRARY_PATH`, `LD_PRELOAD`,
+and the Server classpath. Startup never downloads files, extracts archives,
+replaces JARs, invokes `sudo`, or modifies system directories. Missing prepared
+resources are a startup error with an instruction to run the installation step.
+
+### HugeGraph Configuration Options for RocksDB
+
+Three configuration options define engine selection and ToplingDB behavior.
+`rocksdb.provider` is the sole engine selector. `rocksdb.option_path` only points
+to a parameter file and never enables ToplingDB by itself.
+
+```properties
+# rocksdb backend config
+#rocksdb.data_path=/path/to/disk
+#rocksdb.wal_path=/path/to/disk
+#rocksdb.provider=rocksdb
+# To enable ToplingDB explicitly:
+#rocksdb.provider=topling
+#rocksdb.option_path=./conf/graphs/rocksdb_plus.yaml
+#rocksdb.open_http=true
+```
+
+Java-side parsing and default values:
+
+```java
+public static final ConfigOption PROVIDER =
+ new ConfigOption<>(
+ "rocksdb.provider",
+ "The RocksDB runtime provider: rocksdb or topling",
+ allowValues("rocksdb", "topling"),
+ "rocksdb"
+ );
+
+public static final ConfigOption OPTION_PATH =
+ new ConfigOption<>(
+ "rocksdb.option_path",
+ "The ToplingDB YAML parameter file; this does not select a provider",
+ null,
+ ""
+ );
+
+public static final ConfigOption OPEN_HTTP =
+ new ConfigOption<>(
+ "rocksdb.open_http",
+ "Whether to start Topling's HTTP service",
+ disallowEmpty(),
+ false
+ );
+```
+
+### ToplingDB Startup Logic
+
+HugeGraph selects ToplingDB only when `rocksdb.provider=topling`. In that mode,
+the ToplingDB runtime must be present and must match the selected provider or
+initialization fails immediately. When the provider is `rocksdb` or omitted,
+HugeGraph uses standard RocksDB. `option_path` is consulted only after ToplingDB
+has been selected and validated.
+
+To keep port configuration simple, the Web Server is only enabled for the `GRAPH_STORE` instance.
+
+```mermaid
+flowchart LR
+ A[Start Initialization] --> B{rocksdb.provider}
+ B -- rocksdb or unset --> C{Standard runtime matches?}
+ C -- No --> X[Fail startup: provider mismatch]
+ C -- Yes --> Z[Use standard RocksDB to open DB] --> O[Finish standard init]
+ B -- unsupported --> Y[Fail startup: invalid provider]
+ B -- topling --> D{ToplingDB runtime present and matching?}
+ D -- No --> X
+ D -- Yes --> E{Is optionPath provided?}
+ E -- Yes --> F["Load SidePluginRepo and call importAutoFile(optionPath)"]
+ E -- No --> G[Use ToplingDB default parameters]
+ F --> H[Open DB through SidePluginRepo]
+ G --> H
+ H --> K{Is openHttp true?}
+ K -- No --> M[Finish Topling init]
+ K -- Yes --> L{Is dbName GRAPH_STORE?}
+ L -- No --> M
+ L -- Yes --> N["startHttpServer()"] --> M
+```
+
+### Data Compatibility, Backup, and Rollback
+
+Changing `rocksdb.provider` selects the runtime used for the next open; it is
+not a data migration or rollback operation. The shipped ToplingDB option files
+currently enable ToplingDB-specific behavior, including:
+
+```yaml
+convert_to_sst: kFileMmap
+memtable_as_log_index: true
+```
+
+After ToplingDB has opened and written a database with these options, its WAL,
+SST, or related metadata may no longer be safely consumable by standard
+RocksDB. Therefore changing `rocksdb.provider` from `topling` to `rocksdb` and
+restarting is unsupported as a rollback procedure. HugeGraph must not describe
+a successful JAR restoration or provider change as a successful data rollback.
+
+```mermaid
+flowchart LR
+ A[Standard RocksDB data] --> B[Create consistent pre-migration snapshot]
+ B --> C[Open and write with ToplingDB]
+ C --> D{Rollback required?}
+ D -- Yes --> E[Stop all writers]
+ E --> F[Restore the complete pre-migration snapshot]
+ F --> G[Validate RocksDB, JNI, and data-format compatibility]
+ G --> H[Set provider to rocksdb and start]
+ D -- Provider switch only --> X[Unsupported: may fail to open or corrupt data]
+```
+
+The pre-migration snapshot must be a RocksDB-consistent snapshot created with
+RocksDB Checkpoint or BackupEngine, or a complete copy of the data directory
+while the owning process is stopped. It must include every file required for
+recovery, including SST files, `CURRENT`, `MANIFEST-*`, `OPTIONS-*`, column
+family metadata, and the required WAL files. Copying or restoring only SST and
+MANIFEST files is not sufficient and can produce a mixed database state.
+
+Rollback procedure:
+
+1. Before enabling ToplingDB, stop writes and create a complete consistent
+ snapshot for every affected Server, PD, and Store database.
+2. Record and verify the standard RocksDB/JNI versions and snapshot format.
+3. To roll back, stop the component and restore the entire snapshot into an
+ empty data directory; do not merge it with files written by ToplingDB.
+4. Restore the matching standard JNI/runtime, set `rocksdb.provider=rocksdb`,
+ and verify the database before accepting traffic.
+
+Online or in-place gray switching is not supported by this design. It may only
+be documented as supported after an automated compatibility test proves the
+complete sequence below for every supported version and option set:
+
+```text
+standard create/write -> ToplingDB open/write -> restart ToplingDB
+ -> standard reopen/read/write verification
+```
+
+Until that test exists and passes, deployment tooling and documentation must
+require snapshot restoration when returning to standard RocksDB after any
+ToplingDB write.
+
+## Design Decisions and Rationale
+
+1. **Why is the Web Server only started for GRAPH_STORE?**
+ - All graph data is stored in GRAPH_STORE, and performance tuning and observability are primarily focused on this instance.
diff --git a/.specs/hugegraph-server/ToplingDB/requirements.md b/.specs/hugegraph-server/ToplingDB/requirements.md
new file mode 100644
index 0000000000..6530b32cae
--- /dev/null
+++ b/.specs/hugegraph-server/ToplingDB/requirements.md
@@ -0,0 +1,35 @@
+# Requirements of ToplingDB
+
+## Introduction
+
+RocksDB is the primary standalone/distributed backend storage engine planned for HugeGraph.
+However, the current `rocksdb-jni` design makes it difficult for HugeGraph to dynamically modify or adjust RocksDB parameters, resulting in limited flexibility and extensive hard-coding logic.
+
+To improve performance, functionality, and usability, HugeGraph introduces `ToplingDB` as an optional enhancement.
+It allows users to configure RocksDB parameters via external configuration files and visualize storage engine status through a built-in Web Server.
+
+## Requirement List
+
+### 1. Support ToplingDB while maintaining compatibility with RocksDB
+
+**User Story**: As a long-term user, I want the system to support the enhanced features of ToplingDB without affecting existing RocksDB functionality or data compatibility.
+
+**Acceptance Criteria**: Users can choose between RocksDB and ToplingDB via configuration files or startup parameters.
+
+### 2. Support configuring RocksDB parameters via external configuration files
+
+**User Story**: As a user, I want to adjust storage engine parameters based on my business needs and hardware environment to optimize database performance.
+
+**Acceptance Criteria**: The system supports passing configuration files to customize RocksDB parameters.
+
+### 3. Support runtime observability of the RocksDB storage engine
+
+**User Story**: As a system operator, I want clear and intuitive visibility into RocksDB configuration and runtime status.
+
+**Acceptance Criteria**: The system supports enhancing storage engine observability via a Web Server.
+
+## Success Criteria
+
+* The system maintains API compatibility with both RocksDB and ToplingDB.
+* The system supports configuring ToplingDB parameters via external configuration files.
+* The system enhances storage engine observability through a built-in Web Server.
diff --git a/.specs/hugegraph-server/ToplingDB/task.md b/.specs/hugegraph-server/ToplingDB/task.md
new file mode 100644
index 0000000000..7ae83eff1b
--- /dev/null
+++ b/.specs/hugegraph-server/ToplingDB/task.md
@@ -0,0 +1,54 @@
+# Tasks of ToplingDB
+
+This document translates the design of HugeGraph ToplingDB into a series of executable development tasks. Each task follows a test-driven approach to ensure incremental progress and early validation.
+
+## Common Development Commands
+
+### Runtime
+
+ToplingDB (ToplingDB) requires dynamic libraries to be preloaded via `LD_PRELOAD`. The `preload-topling.sh` script parses the JAR package, extracts the necessary libraries, and performs the preload setup.
+
+When using an IDE such as IntelliJ IDEA, you need to configure the following environment variables in Run/Debug Configurations:
+
+```shell
+LD_LIBRARY_PATH=/path/to/your/library:$LD_LIBRARY_PATH
+LD_PRELOAD=libjemalloc.so:librocksdbjni-linux64.so
+```
+
+When running from the terminal, simply use `init-store.sh` and `start-hugegraph.sh`, as `preload-topling.sh` is already embedded in these scripts.
+
+## 1. Project Infrastructure Setup
+
+- [x] **1.1 Build ToplingDB JAR Package**
+ - Publish the package to GitHub Packages via GitHub Actions and update Maven's `settings.xml`
+ - Provide documentation for manually building the ToplingDB JAR package
+
+## 2. Compatibility with ToplingDB and Standard RocksDB
+
+- [x] **2.1 Modify openRocksDB logic in RocksDBStdSession**
+ - Use reflection to detect whether the current JAR contains ToplingDB APIs; if so, start the storage engine using ToplingDB
+ - If not available, fall back to the standard RocksDB API for engine startup
+
+## 3. Add Configuration Options for ToplingDB in HugeGraph
+
+- [x] **3.1 Add `rocksdb.option_path` configuration**
+ - Type: string, used to specify the path to the YAML configuration file
+ - Allow users to pass the YAML file via `hugegraph.properties` using `rocksdb.option_path`
+ - This option is invalid for standard RocksDB JARs, as RocksDB APIs do not support file-based configuration
+
+- [x] **3.2 Add `rocksdb.open_http` configuration**
+ - Type: boolean, used to specify whether to enable the ToplingDB Web Server
+ - Allow users to configure Web Server activation via `rocksdb.open_http` in `hugegraph.properties`
+ - The Web Server port is defined in the YAML file specified by `option_path`, under `http.listening_ports`
+ - For simplicity, the Web Server is only enabled for the `GRAPH_STORE` instance that stores graph data
+
+## 4. End-to-End Performance Testing
+
+- [x] **4.1 Write Performance Testing**
+ - Use `hugegraph-loader` to load the twitter-2010 dataset
+ - Shuffle the twitter-2010 dataset to simulate real-world random insertion patterns and evaluate the write performance of ToplingDB.
+ - ToplingDB improves random write performance by up to 40% and reduces storage overhead by approximately 50%
+
+- [x] **4.2 Read Performance Testing**
+ - Execute edge traversal, vertex traversal, and KOUT queries to evaluate read performance improvements
+ - Under cold start conditions, edge traversal latency is reduced by up to 50%, and KOUT query average latency is reduced by approximately 15%
diff --git a/docker/README.md b/docker/README.md
index 0ee1f586b6..e8e675d145 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -255,6 +255,7 @@ Configuration is injected via environment variables. The old `docker/configs/app
| Variable | Required | Default | Maps To | Description |
|----------|----------|---------|-----------------------------|-------------|
| `HG_SERVER_BACKEND` | Yes | — | `backend` in `hugegraph.properties` | Storage backend (e.g. `hstore`) |
+| `HG_SERVER_ROCKSDB_PROVIDER` | No | Image/config default | `rocksdb.provider` | RocksDB JNI provider (`rocksdb` or `topling`); the Topling image defaults to `topling` |
| `HG_SERVER_PD_PEERS` | Yes | — | `pd.peers` | PD cluster addresses (e.g. `pd0:8686,pd1:8686,pd2:8686`) |
| `HG_SERVER_CLUSTER` | No | — | `cluster` in `rest-server.properties` | PD discovery application name; single-node Compose uses `hg` to match Hubble |
| `HG_SERVER_USE_PD` | No | — | `usePD` in `rest-server.properties` | Enables Server PD registration and discovery |
diff --git a/docs/toplingdb/rocksdb-provider-pattern-reference.md b/docs/toplingdb/rocksdb-provider-pattern-reference.md
new file mode 100644
index 0000000000..748722c70e
--- /dev/null
+++ b/docs/toplingdb/rocksdb-provider-pattern-reference.md
@@ -0,0 +1,163 @@
+# RocksDB Provider Pattern 参考文档
+
+> 本文档记录 `hugegraph-rocksdb-provider` 模块的 SPI 设计模式,供未来参考。
+> 如果后续需要重新引入 Provider 抽象层(例如支持新的存储引擎变体),可基于此设计恢复。
+
+## 设计概述
+
+采用 Java SPI (ServiceLoader) + Strategy Pattern,通过配置项 `rocksdb.provider` 在运行时选择 RocksDB 引擎实现。
+
+```
+RocksDBProvider (接口)
+ └── AbstractRocksDBProvider (模板方法基类)
+ ├── StandardRocksDBProvider ("standard")
+ └── ToplingRocksDBProvider ("topling")
+
+RocksDBProviderLoader (单例注册中心,对外提供静态方法)
+```
+
+## 核心接口
+
+```java
+public interface RocksDBProvider {
+ String getProviderName();
+ boolean isAvailable();
+ void initialize();
+ void shutdown();
+
+ RocksDB openRocksDB(Options options, String dataPath) throws RocksDBException;
+ RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+ List cfDescriptors,
+ List cfHandles) throws RocksDBException;
+ void closeRocksDB(RocksDB db);
+ void closeRocksDB(RocksDB db, List cfHandles);
+}
+```
+
+## 抽象基类(模板方法)
+
+```java
+public abstract class AbstractRocksDBProvider implements RocksDBProvider {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractRocksDBProvider.class);
+
+ @Override
+ public final RocksDB openRocksDB(Options options, String dataPath) throws RocksDBException {
+ LOG.info("Opening RocksDB via [{}] provider at: {}", getProviderName(), dataPath);
+ return doOpenRocksDB(options, dataPath);
+ }
+
+ @Override
+ public final RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+ List cfDescriptors,
+ List cfHandles) throws RocksDBException {
+ LOG.info("Opening RocksDB with {} CFs via [{}] provider at: {}",
+ cfDescriptors.size(), getProviderName(), dataPath);
+ return doOpenRocksDB(dbOptions, dataPath, cfDescriptors, cfHandles);
+ }
+
+ @Override
+ public void closeRocksDB(RocksDB db) {
+ if (db != null) {
+ performProviderSpecificClose(db);
+ db.close();
+ }
+ }
+
+ @Override
+ public void closeRocksDB(RocksDB db, List cfHandles) {
+ if (cfHandles != null) {
+ cfHandles.forEach(ColumnFamilyHandle::close);
+ }
+ closeRocksDB(db);
+ }
+
+ protected abstract RocksDB doOpenRocksDB(Options options, String dataPath) throws RocksDBException;
+ protected abstract RocksDB doOpenRocksDB(DBOptions dbOptions, String dataPath,
+ List cfDescriptors,
+ List cfHandles) throws RocksDBException;
+ protected abstract void performProviderSpecificClose(RocksDB rocksDB);
+}
+```
+
+## ProviderLoader(单例注册中心)
+
+```java
+public class RocksDBProviderLoader {
+
+ private static final RocksDBProviderLoader INSTANCE = new RocksDBProviderLoader();
+ private final Map providers = new ConcurrentHashMap<>();
+ private volatile RocksDBProvider activeProvider;
+
+ public static RocksDBProviderLoader getInstance() { return INSTANCE; }
+
+ public void reload() {
+ providers.clear();
+ ServiceLoader loader = ServiceLoader.load(RocksDBProvider.class);
+ for (RocksDBProvider provider : loader) {
+ providers.put(provider.getProviderName(), provider);
+ }
+ }
+
+ public void selectProvider(String name) {
+ RocksDBProvider provider = providers.get(name);
+ if (provider == null) throw new IllegalArgumentException("Unknown provider: " + name);
+ if (!provider.isAvailable()) throw new IllegalStateException("Provider not available: " + name);
+ provider.initialize();
+ activeProvider = provider;
+ }
+
+ // 静态便捷方法
+ public static RocksDB openRocksDB(Options options, String dataPath) throws RocksDBException {
+ return INSTANCE.activeProvider.openRocksDB(options, dataPath);
+ }
+
+ public static RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+ List cfDescriptors,
+ List cfHandles) throws RocksDBException {
+ return INSTANCE.activeProvider.openRocksDB(dbOptions, dataPath, cfDescriptors, cfHandles);
+ }
+
+ public static void closeRocksDB(RocksDB db) {
+ INSTANCE.activeProvider.closeRocksDB(db);
+ }
+}
+```
+
+## SPI 注册
+
+文件:`META-INF/services/org.apache.hugegraph.rocksdb.provider.RocksDBProvider`
+
+```
+org.apache.hugegraph.rocksdb.provider.StandardRocksDBProvider
+org.apache.hugegraph.rocksdb.provider.ToplingRocksDBProvider
+```
+
+## 调用方使用方式
+
+```java
+// 初始化(在 HugeGraph 启动时调用一次)
+RocksDBProviderLoader loader = RocksDBProviderLoader.getInstance();
+loader.reload();
+loader.selectProvider(config.get("rocksdb.provider")); // "standard" or "topling"
+
+// 使用(在 RocksDBStdSessions / RocksDBSession 中)
+RocksDB db = RocksDBProviderLoader.openRocksDB(options, dataPath);
+RocksDBProviderLoader.closeRocksDB(db);
+```
+
+## 去除原因
+
+Easy Migrate 重构后,`ToplingRocksDBProvider` 和 `StandardRocksDBProvider` 的 `doOpenRocksDB` 实现完全相同(都是 `RocksDB.open()`)。差异化逻辑已移至启动脚本:
+
+- JAR 切换:`preload-topling.sh` 根据配置替换 classpath 中的 JAR
+- 环境变量:启动脚本设置 `TOPLINGDB_EASY_MIGRATE_CONF`
+- Native 库:启动脚本设置 `LD_PRELOAD` / `LD_LIBRARY_PATH`
+
+Provider 抽象层不再承载实质性逻辑,因此可安全移除。
+
+## 何时考虑恢复
+
+- 需要在 Java 层根据不同引擎执行不同的 open/close 逻辑
+- 需要支持第三种 RocksDB 变体(如 SpeeDB、TerarkDB 等)
+- 需要在运行时动态切换引擎(而非启动时确定)
diff --git a/docs/toplingdb/toplingdb-explicit-config-independent-provider-sop.md b/docs/toplingdb/toplingdb-explicit-config-independent-provider-sop.md
new file mode 100644
index 0000000000..e563479da2
--- /dev/null
+++ b/docs/toplingdb/toplingdb-explicit-config-independent-provider-sop.md
@@ -0,0 +1,420 @@
+# ToplingDB 显式配置 + 独立 Provider 重构 SOP
+
+## 一、背景与问题
+
+### 1.1 现状
+
+当前 ToplingDB 集成方案存在以下核心问题:
+
+| 问题 | 具体表现 |
+|------|----------|
+| **隐式激活** | `ToplingRocksDBProvider` 通过 `Class.forName("org.rocksdb.SidePluginRepo")` 自动探测 classpath,只要 ToplingDB JAR 存在就自动接管所有 RocksDB 操作(priority=200 > standard=100),用户无法显式选择 |
+| **共享坐标污染** | ToplingDB 与标准 RocksDB 共用 `org.rocksdb:rocksdbjni` 坐标(仅版本/来源不同),导致 Maven 依赖仲裁不可控 |
+| **影响纯 RocksDB 用户** | 不需要 ToplingDB 的用户也被 SNAPSHOT 依赖、GitHub Packages 仓库配置所困扰 |
+
+### 1.2 目标
+
+1. **显式配置**:用户通过 `rocksdb.provider=standard|topling` 明确选择引擎,不再依赖 classpath 自动探测
+2. **部署时 Drop-in**:运维不需要 Maven 配置,下载 ToplingDB addon 包放入部署目录即可
+3. **模块结构不变**:保留现有 `hugegraph-rocksdb-provider` 单模块,内部简化逻辑
+
+---
+
+## 二、分发模型
+
+### 2.1 构建与部署分离
+
+ToplingDB 本身就需要下载 native `.so` 库和可能的外置二进制文件,因此对终端用户来说是一个 **部署时 addon**,而非编译时依赖。
+
+```
+┌──────────────────────────────────────────────────────────┐
+│ 默认构建产物 │
+│ mvn clean package │
+│ ├── lib/rocksdbjni-8.10.2.jar (标准 RocksDB) │
+│ └── lib/hugegraph-rocksdb-provider.jar │
+└──────────────────────────────────────────────────────────┘
+
+ ↓ 运维选择启用 ToplingDB ↓
+
+┌──────────────────────────────────────────────────────────┐
+│ ToplingDB Addon 包 (独立下载) │
+│ toplingdb-addon-1.0.0-linux-x86_64.tar.gz │
+│ ├── lib/toplingdb-jni-1.0.0.jar (替换 rocksdbjni) │
+│ ├── native/librocksdbjni-linux64.so │
+│ ├── native/libterark-*.so (可选) │
+│ ├── web/ (ToplingDB HTTP 监控 UI) │
+│ └── conf/rocksdb_plus.yaml.template │
+└──────────────────────────────────────────────────────────┘
+```
+
+### 2.2 两种角色
+
+| 角色 | ToplingDB 怎么来 | 需要 Maven 配置? |
+|------|-----------------|-----------------|
+| **运维/部署者** | 下载 addon 包,解压到部署目录,改配置 | 不需要 |
+| **开发者** | POM 中 `-P toplingdb` 引入(仅编译/调试用) | 需要 |
+
+### 2.3 部署流程(运维视角)
+
+```bash
+# 1. 下载 ToplingDB addon 包
+wget https://github.com/hugegraph/toplingdb/releases/download/v1.0.0/toplingdb-addon-1.0.0-linux-x86_64.tar.gz
+
+# 2. 解压到 HugeGraph 安装目录
+tar -xzf toplingdb-addon-1.0.0-linux-x86_64.tar.gz -C /opt/hugegraph/
+
+# 3. 替换标准 RocksDB JAR(互斥)
+rm /opt/hugegraph/lib/rocksdbjni-*.jar
+
+# 4. 修改配置
+vi conf/hugegraph.properties
+# rocksdb.provider=topling
+# rocksdb.option_path=./conf/graphs/rocksdb_plus.yaml
+
+# 5. 启动
+bin/start-hugegraph.sh
+```
+
+---
+
+## 三、模块改造设计
+
+### 3.1 保持单模块结构
+
+`hugegraph-rocksdb-provider` 模块保持不变,内部简化为配置驱动:
+
+```
+hugegraph-rocksdb-provider/
+├── src/main/java/.../rocksdb/provider/
+│ ├── RocksDBProvider.java (接口,移除 getPriority())
+│ ├── AbstractRocksDBProvider.java (模板基类,保持不变)
+│ ├── RocksDBProviderLoader.java (改为配置驱动选择)
+│ ├── StandardRocksDBProvider.java (保持不变)
+│ └── ToplingRocksDBProvider.java (保持不变)
+├── src/main/resources/META-INF/services/ (SPI 注册,保持不变)
+└── pom.xml (依赖改造)
+```
+
+### 3.2 POM 依赖改造
+
+```xml
+
+
+
+
+ org.rocksdb
+ rocksdbjni
+ ${rocksdb.version}
+
+
+
+
+
+
+
+
+
+ standard-rocksdb
+
+ true
+
+
+ org.rocksdb
+ rocksdbjni
+ ${rocksdb.version}
+
+
+
+ toplingdb
+
+ org.apache.hugegraph
+ toplingdb-jni
+ ${toplingdb.version}
+
+
+
+```
+
+`hugegraph-rocksdb-provider/pom.xml` 中依赖改为变量引用:
+
+```xml
+
+ ${rocksdb.engine.groupId}
+ ${rocksdb.engine.artifactId}
+ ${rocksdb.engine.version}
+
+```
+
+### 3.3 RocksDBProviderLoader 改造
+
+从"按 priority 自动选最高"改为"按配置名精确匹配":
+
+```java
+public class RocksDBProviderLoader {
+
+ private final Map providerRegistry = new ConcurrentHashMap<>();
+ private volatile RocksDBProvider activeProvider;
+
+ /**
+ * 加载所有 SPI 注册的 Provider 到 registry
+ */
+ public synchronized void loadProviders() {
+ ServiceLoader loader = ServiceLoader.load(RocksDBProvider.class);
+ for (RocksDBProvider provider : loader) {
+ providerRegistry.put(provider.getProviderName(), provider);
+ LOG.info("Discovered RocksDB provider: {}", provider.getProviderName());
+ }
+ }
+
+ /**
+ * 根据配置值选择并激活 Provider
+ */
+ public synchronized RocksDBProvider selectProvider(String providerName) {
+ if (providerRegistry.isEmpty()) {
+ loadProviders();
+ }
+
+ RocksDBProvider provider = providerRegistry.get(providerName);
+ if (provider == null) {
+ throw new IllegalStateException(String.format(
+ "RocksDB provider '%s' not found. Available: %s. " +
+ "If using ToplingDB, ensure the addon is installed in lib/.",
+ providerName, providerRegistry.keySet()));
+ }
+
+ if (!provider.isAvailable()) {
+ throw new IllegalStateException(String.format(
+ "RocksDB provider '%s' found but not available. " +
+ "Check native libraries and LD_PRELOAD.",
+ providerName));
+ }
+
+ this.activeProvider = provider;
+ provider.initialize();
+ LOG.info("Activated RocksDB provider: {}", providerName);
+ return provider;
+ }
+
+ /**
+ * 获取已激活的 Provider
+ */
+ public RocksDBProvider getActiveProvider() {
+ if (activeProvider == null) {
+ throw new IllegalStateException(
+ "No RocksDB provider activated. Call selectProvider() first.");
+ }
+ return activeProvider;
+ }
+
+ // static 便捷方法内部改为 getActiveProvider()
+ public static RocksDB openRocksDB(Options options, String dataPath,
+ String optionPath, Boolean openHttp) throws RocksDBException {
+ return getInstance().getActiveProvider()
+ .openRocksDB(options, dataPath, optionPath, openHttp);
+ }
+
+ public static void closeRocksDB(RocksDB rocksDB) {
+ getInstance().getActiveProvider().closeRocksDB(rocksDB);
+ }
+}
+```
+
+### 3.4 Provider 接口简化
+
+```java
+public interface RocksDBProvider {
+
+ /** Provider 标识名,与 rocksdb.provider 配置值匹配 */
+ String getProviderName(); // "standard" or "topling"
+
+ /** 当前环境是否可用 */
+ boolean isAvailable();
+
+ // open/close 方法签名保持不变...
+
+ // 移除 getPriority() — 不再需要优先级竞争
+}
+```
+
+### 3.5 新增配置项
+
+在 `RocksDBOptions.java`(server 和 store 两处)新增:
+
+```java
+public static final ConfigOption PROVIDER =
+ new ConfigOption<>(
+ "rocksdb.provider",
+ "The RocksDB engine provider. 'standard' for vanilla RocksDB, " +
+ "'topling' for ToplingDB (requires addon installation).",
+ allowValues("standard", "topling"),
+ "standard"
+ );
+```
+
+### 3.6 调用方改造
+
+在 RocksDB Backend 初始化时读取配置并激活 Provider:
+
+```java
+// RocksDBStdSessions 构造函数 或 RocksDBStoreProvider.open() 中
+String providerName = config.get(RocksDBOptions.PROVIDER);
+RocksDBProviderLoader.getInstance().selectProvider(providerName);
+
+// 后续 open/close 调用方式不变
+RocksDBProviderLoader.openRocksDB(options, dataPath, optionPath, openHttp);
+```
+
+---
+
+## 四、ToplingDB Addon 包
+
+### 4.1 包内容
+
+```
+toplingdb-addon-1.0.0-linux-x86_64.tar.gz
+├── lib/
+│ └── toplingdb-jni-1.0.0.jar ← 替换 rocksdbjni-*.jar
+├── native/
+│ ├── librocksdbjni-linux64.so
+│ ├── libterark-zip-rocksdb-trial.so (可选)
+│ └── libjemalloc.so (可选)
+├── web/
+│ ├── index.html
+│ └── style.css
+├── conf/
+│ └── rocksdb_plus.yaml.template
+└── install.sh (可选安装脚本)
+```
+
+### 4.2 启动脚本适配
+
+`common-topling.sh` 查找逻辑改为优先使用 `native/` 目录:
+
+```bash
+# 优先从 native/ 目录加载(addon 已安装)
+if [ -d "$HUGEGRAPH_HOME/native" ] && ls "$HUGEGRAPH_HOME/native"/librocksdbjni*.so >/dev/null 2>&1; then
+ export LD_PRELOAD="$HUGEGRAPH_HOME/native/librocksdbjni-linux64.so"
+else
+ # 回退:从 JAR 中提取(兼容旧方式)
+ jar_file=$(ls -1 "$lib_dir"/toplingdb-jni*.jar 2>/dev/null | head -1)
+ if [ -z "$jar_file" ]; then
+ jar_file=$(ls -1 "$lib_dir"/rocksdbjni*.jar 2>/dev/null | head -1)
+ fi
+ extract_so_from_jar "$jar_file"
+fi
+```
+
+---
+
+## 五、配置使用
+
+### 5.1 标准 RocksDB(默认)
+
+```properties
+backend=rocksdb
+# rocksdb.provider=standard ← 默认值,可不写
+```
+
+### 5.2 ToplingDB
+
+```properties
+backend=rocksdb
+rocksdb.provider=topling
+rocksdb.option_path=./conf/graphs/rocksdb_plus.yaml
+rocksdb.open_http=true
+```
+
+### 5.3 错误提示
+
+| 场景 | 错误信息 |
+|------|----------|
+| 配置 `topling` 但未安装 addon | `RocksDB provider 'topling' not found. Available: [standard]. Install ToplingDB addon to lib/.` |
+| addon JAR 在但 native lib 缺失 | `RocksDB provider 'topling' found but not available. Check native libraries and LD_PRELOAD.` |
+
+---
+
+## 六、实施步骤
+
+### Phase 1:改造 RocksDBProviderLoader(核心)
+
+1. 移除 `getBestProvider()` 的 priority 竞争逻辑
+2. 新增 `selectProvider(String name)` 按名精确匹配
+3. 新增 `getActiveProvider()` 替代原 `getBestProvider()`
+4. `RocksDBProvider` 接口移除 `getPriority()`
+5. **验证**:编译通过,配置 `standard` 时行为与原来一致
+
+### Phase 2:新增配置项 + 调用方改造
+
+1. `RocksDBOptions.java` (server + store) 新增 `rocksdb.provider`
+2. `RocksDBStdSessions` 初始化时调用 `selectProvider(config.get(PROVIDER))`
+3. `hg-store-rocksdb` 的 `RocksDBSession` 同理
+4. **验证**:`provider=standard` 正常工作
+
+### Phase 3:POM 独立坐标 + Profile
+
+1. Root `pom.xml` 新增 `standard-rocksdb` / `toplingdb` 两个 Profile
+2. `hugegraph-rocksdb-provider/pom.xml` 依赖改为 `${rocksdb.engine.*}` 变量
+3. 移除 `8.10.2-SNAPSHOT` 硬编码,标准 profile 用正式 release
+4. **验证**:`mvn package` 默认无 SNAPSHOT,`mvn package -P toplingdb` 引入 ToplingDB
+
+### Phase 4:Addon 包 + 脚本改造
+
+1. 设计 addon 包打包流程(CI)
+2. 改造 `common-topling.sh` 支持 `native/` 目录
+3. 编写 `install.sh`
+4. **验证**:全新部署环境通过 addon 安装 ToplingDB 正常启动
+
+### Phase 5:清理
+
+1. 移除 `.github/configs/settings.xml` 中 GitHub Packages 仓库(默认构建不再需要)
+2. 更新配置文件模板
+3. 更新文档
+4. **验证**:完整测试矩阵
+
+---
+
+## 七、验证矩阵
+
+| 验证项 | 操作 | 预期 |
+|--------|------|------|
+| 默认构建 | `mvn clean package` | 无 SNAPSHOT,无 GitHub Token,产物仅含标准 RocksDB |
+| 开发者构建 | `mvn clean package -P toplingdb` | 含 ToplingDB JNI |
+| 标准模式启动 | `provider=standard` | 使用原生 RocksDB |
+| ToplingDB 启动 | `provider=topling` + addon 安装 | 使用 ToplingDB |
+| 配置不匹配 | `provider=topling` + 未安装 addon | 明确错误信息 |
+| Addon 安装 | 解压 addon + 改配置 | 无需重新编译 |
+| HStore 模式 | Store 节点同验证 | 一致 |
+
+---
+
+## 八、设计决策
+
+### 为什么保持单模块?
+
+- `hugegraph-rocksdb-provider` 已被 `hugegraph-server/hugegraph-rocksdb` 和 `hugegraph-store/hg-store-rocksdb` 共同依赖,是两者共享 open/close 逻辑的自然位置
+- 拆成 api + standard + topling 三个模块增加了维护成本,但 Provider 实现本身代码量很小,不值得拆
+- 单模块内通过配置驱动切换,足够简洁
+
+### 为什么运维走 Drop-in 而非 Maven?
+
+- ToplingDB 本身就需要 native lib 下载,addon 包是天然的分发单元
+- 运维不需要理解 Maven Profile,下载解压改配置即可
+- 离线环境友好
+- CI/CD 中普通构建不需要 GitHub Token
+
+### 为什么 `rocksdb.provider` 而非 `backend=toplingdb`?
+
+ToplingDB 是 RocksDB 引擎层替换,不是新的存储后端。表结构、序列化、查询全部复用 RocksDB Backend 代码。`rocksdb.provider=topling` 语义精确。
+
+---
+
+## 九、时间估算
+
+| Phase | 工作量 |
+|-------|--------|
+| Phase 1:Loader 改造 | 0.5 天 |
+| Phase 2:配置项 + 调用方 | 0.5 天 |
+| Phase 3:POM + Profile | 0.5 天 |
+| Phase 4:Addon + 脚本 | 1.5 天 |
+| Phase 5:清理 | 0.5 天 |
+| **合计** | **3.5 天** |
diff --git a/docs/toplingdb/toplingdb-hstore-integration.md b/docs/toplingdb/toplingdb-hstore-integration.md
new file mode 100644
index 0000000000..f10cc4acef
--- /dev/null
+++ b/docs/toplingdb/toplingdb-hstore-integration.md
@@ -0,0 +1,637 @@
+# HugeGraph 集成 ToplingDB 与 HStore 技术文档
+
+## 一、整体架构概览
+
+HugeGraph 的存储层采用**可插拔后端架构(Pluggable Backend Architecture)**,通过 `BackendStoreProvider` SPI 支持多种存储引擎。当前支持的后端类型为:`memory`、`rocksdb`、`hbase`、`hstore`。
+
+```
+┌─────────────────────────────────────────────────────────┐
+│ HugeGraph Server │
+│ │
+│ ┌─────────────────────────────────────────────────┐ │
+│ │ BackendProviderFactory │ │
+│ │ (根据配置选择: rocksdb / hstore / hbase / memory) │ │
+│ └──────────┬───────────────────────┬───────────────┘ │
+│ │ │ │
+│ ┌─────────▼──────────┐ ┌────────▼──────────┐ │
+│ │ RocksDBStoreProvider│ │ HstoreProvider │ │
+│ │ (type="rocksdb") │ │ (type="hstore") │ │
+│ └─────────┬──────────┘ └────────┬──────────┘ │
+│ │ │ │
+│ ┌─────────▼──────────┐ ┌────────▼──────────┐ │
+│ │ RocksDBStdSessions │ │HstoreSessionsImpl │ │
+│ └─────────┬──────────┘ └────────┬──────────┘ │
+│ │ │ │
+│ ┌─────────▼──────────┐ ┌────────▼──────────┐ │
+│ │RocksDBProviderLoader│ │ HgStoreClient │ │
+│ │ (SPI: Standard / │ │ (gRPC → Store节点) │ │
+│ │ ToplingDB) │ └────────┬──────────┘ │
+│ └─────────┬──────────┘ │ │
+└─────────────┼───────────────────────┼─────────────────────┘
+ │ │
+ ┌─────────▼──────────┐ ┌────────▼──────────────────┐
+ │ RocksDB / ToplingDB │ │ hugegraph-store 集群 │
+ │ (本地嵌入式) │ │ (Raft + PD + RocksDB/ │
+ │ │ │ ToplingDB 节点) │
+ └─────────────────────┘ └──────────────────────────┘
+```
+
+**关键设计点**:ToplingDB 和 HStore 是**正交的两个维度**:
+
+- **ToplingDB** = 增强版 RocksDB 存储引擎(可替换标准 RocksDB)
+- **HStore** = 分布式存储架构(客户端-服务端 + Raft 共识)
+- 两者可以组合使用:HStore 节点内部也能使用 ToplingDB
+
+---
+
+## 二、ToplingDB 接入详解
+
+### 2.1 设计思路:SPI + 反射,零硬依赖
+
+ToplingDB 的集成采用了 **Java SPI(Service Provider Interface) + 反射** 的方式,核心原则是:
+
+1. **编译时不依赖 ToplingDB 特有 API** —— 通过 `Class.forName("org.rocksdb.SidePluginRepo")` 探测
+2. **运行时自动选择最优 Provider** —— 优先级机制(ToplingDB=200 > Standard=100)
+3. **完全向后兼容** —— 没有 ToplingDB JAR 时自动降级为标准 RocksDB
+
+### 2.2 模块结构
+
+```
+hugegraph-rocksdb-provider/ ← 独立 Maven 模块
+├── pom.xml ← 依赖 rocksdbjni:8.10.2-SNAPSHOT (ToplingDB 增强版)
+└── src/main/java/org/apache/hugegraph/rocksdb/provider/
+ ├── RocksDBProvider.java ← SPI 接口定义
+ ├── AbstractRocksDBProvider.java ← 模板方法基类
+ ├── StandardRocksDBProvider.java ← 标准 RocksDB 实现 (priority=100)
+ ├── ToplingRocksDBProvider.java ← ToplingDB 实现 (priority=200)
+ └── RocksDBProviderLoader.java ← ServiceLoader 加载器 (单例)
+```
+
+SPI 注册文件位于 `META-INF/services/org.apache.hugegraph.rocksdb.provider.RocksDBProvider`:
+
+```
+org.apache.hugegraph.rocksdb.provider.StandardRocksDBProvider
+org.apache.hugegraph.rocksdb.provider.ToplingRocksDBProvider
+```
+
+### 2.3 核心接口 RocksDBProvider
+
+> 源码位置:`hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/RocksDBProvider.java`
+
+```java
+public interface RocksDBProvider {
+ String getProviderName(); // "standard" 或 "topling"
+ int getPriority(); // 数值越大优先级越高
+ boolean isAvailable(); // 运行时环境检测
+
+ // 核心 open 方法 —— 1:1 替换 RocksDB.open()
+ RocksDB openRocksDB(Options options, String dataPath) throws RocksDBException;
+
+ RocksDB openRocksDB(Options options, String dataPath,
+ String optionPath, Boolean openHttp) throws RocksDBException;
+
+ RocksDB openRocksDB(DBOptions dbOptions, String dataPath,
+ List cfDescriptors,
+ List cfHandles,
+ String optionPath, Boolean openHttp) throws RocksDBException;
+
+ // 核心 close 方法
+ void closeRocksDB(RocksDB rocksDB);
+}
+```
+
+### 2.4 ToplingDB Provider 的工作原理
+
+> 源码位置:`hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/ToplingRocksDBProvider.java`
+
+#### Step 1: 可用性检测
+
+```java
+@Override
+public boolean isAvailable() {
+ try {
+ Class.forName("org.rocksdb.SidePluginRepo"); // ToplingDB 特有类
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+}
+```
+
+#### Step 2: 反射初始化 SidePluginRepo
+
+```java
+private Object initializeToplingRepo(Object options, String dataPath, String optionPath) {
+ // 动态加载 SidePluginRepo 类
+ Class> sidePluginRepoClass = Class.forName("org.rocksdb.SidePluginRepo");
+ Object repo = sidePluginRepoClass.getConstructor().newInstance();
+
+ // 将 Options 注入 repo
+ String dbName = getDbName(dataPath);
+ Method putMethod = sidePluginRepoClass.getMethod("put", String.class, Options.class);
+ putMethod.invoke(repo, dbName, options);
+
+ // 加载 YAML 配置文件
+ Method importAutoFileMethod = sidePluginRepoClass.getMethod("importAutoFile", String.class);
+ importAutoFileMethod.invoke(repo, optionPath);
+
+ return repo;
+}
+```
+
+#### Step 3: 通过 SidePluginRepo 打开 DB
+
+```java
+Method openDBMethod = sidePluginRepoClass.getMethod("openDB", String.class);
+Object result = openDBMethod.invoke(repo, converseOptionsToJsonString(dataPath, null));
+```
+
+传递给 `openDB` 的 JSON 格式:
+
+```json
+{
+ "method": "DB::Open",
+ "params": {
+ "db_options": "$dbo",
+ "cf_options": "$default",
+ "column_families": { "default": "$default" },
+ "path": "/data/hugegraph/graph"
+ }
+}
+```
+
+#### Step 4: 启动 HTTP 监控服务器(可选)
+
+```java
+if (Boolean.TRUE.equals(openHttp)) {
+ Method openHttpMethod = sidePluginRepoClass.getMethod("startHttpServer");
+ openHttpMethod.invoke(repo);
+}
+```
+
+#### Step 5: 关闭时清理 SidePluginRepo
+
+```java
+@Override
+protected void performProviderSpecificClose(RocksDB rocksDB) {
+ Object repo = rocksDBToRepoMap.remove(rocksDB);
+ if (repo != null) {
+ Method closeAllDBMethod = repo.getClass().getMethod("closeAllDB");
+ closeAllDBMethod.invoke(repo);
+ }
+}
+```
+
+### 2.5 Provider 加载器
+
+> 源码位置:`hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/RocksDBProviderLoader.java`
+
+```java
+public class RocksDBProviderLoader {
+ private static final RocksDBProviderLoader INSTANCE = new RocksDBProviderLoader();
+
+ public synchronized void loadProviders() {
+ ServiceLoader serviceLoader = ServiceLoader.load(RocksDBProvider.class);
+ for (RocksDBProvider provider : serviceLoader) {
+ if (provider.isAvailable()) {
+ providerCache.put(provider.getProviderName(), provider);
+ }
+ }
+ }
+
+ public RocksDBProvider getBestProvider() {
+ // 选择 priority 最高的可用 Provider
+ RocksDBProvider bestProvider = null;
+ int highestPriority = Integer.MIN_VALUE;
+ for (RocksDBProvider provider : providerCache.values()) {
+ if (provider.isAvailable() && provider.getPriority() > highestPriority) {
+ bestProvider = provider;
+ highestPriority = provider.getPriority();
+ }
+ }
+ return bestProvider;
+ }
+
+ // 静态便捷方法,供消费方直接调用
+ public static RocksDB openRocksDB(Options options, String dataPath,
+ String optionPath, Boolean openHttp) {
+ RocksDBProvider provider = getInstance().getBestProvider();
+ return provider.openRocksDB(options, dataPath, optionPath, openHttp);
+ }
+
+ public static void closeRocksDB(RocksDB rocksDB) {
+ RocksDBProvider provider = getInstance().getBestProvider();
+ provider.closeRocksDB(rocksDB);
+ }
+}
+```
+
+### 2.6 调用链路
+
+以 `hugegraph-server` 单机模式为例:
+
+> 源码位置:`hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStdSessions.java:385-431`
+
+```
+RocksDBStdSessions.openRocksDB(config, dataPath, walPath)
+ │
+ ├─ config.get(RocksDBOptions.OPTION_PATH) → e.g. "conf/topling.yaml"
+ ├─ config.get(RocksDBOptions.OPEN_HTTP) → true/false
+ │
+ └─ RocksDBProviderLoader.openRocksDB(options, dataPath, optionPath, openHttp)
+ │
+ └─ getInstance().getBestProvider()
+ │
+ ├─ [有 ToplingDB JAR] → ToplingRocksDBProvider (priority=200)
+ │ └─ 反射: SidePluginRepo → importAutoFile → openDB → startHttpServer
+ │
+ └─ [无 ToplingDB JAR] → StandardRocksDBProvider (priority=100)
+ └─ 直接 RocksDB.open(options, dataPath)
+```
+
+关键代码(`RocksDBStdSessions.java` 第 385-391 行):
+
+```java
+// Only enable HTTP server for GRAPH_STORE when openHttp is true
+boolean openHttp = Boolean.TRUE.equals(config.get(RocksDBOptions.OPEN_HTTP)) &&
+ BackendStoreProvider.GRAPH_STORE.equals(getDbName(dataPath));
+RocksDB rocksdb = RocksDBProviderLoader.openRocksDB(options, dataPath,
+ config.get(RocksDBOptions.OPTION_PATH),
+ openHttp);
+```
+
+### 2.7 Native Library 预加载
+
+ToplingDB 依赖额外的 `.so` 动态库,通过启动脚本处理。
+
+> 源码位置:`hugegraph-server/hugegraph-dist/src/assembly/static/bin/common-topling.sh`
+
+**`bin/preload-topling.sh`** → 调用 **`bin/common-topling.sh`** 中的 `preload_toplingdb()` 函数:
+
+```bash
+function preload_toplingdb() {
+ local lib_dir="$1"
+ local dest_dir="$2"
+
+ # 1. 从 rocksdbjni*.jar 中解压 .so 文件
+ extract_so_with_jar "$jar_file" "$dest_dir"
+
+ # 2. 处理 Ubuntu 24.04+ 的 libaio 兼容性
+ ensure_libaio_symlink
+
+ # 3. 下载并预加载 jemalloc(优先使用系统已安装的)
+ download_and_setup_jemalloc "$top"
+
+ # 4. 设置 LD_LIBRARY_PATH
+ export LD_LIBRARY_PATH="$dest_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+
+ # 5. 设置 LD_PRELOAD 预加载 librocksdbjni-linux64.so
+ export LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$dest_dir/librocksdbjni-linux64.so"
+
+ # 6. 解压 HTML/CSS(ToplingDB Web 监控界面资源)
+ extract_html_css_from_jar "$jar_file" "$dest_dir"
+}
+```
+
+### 2.8 配置选项
+
+> 源码位置:`hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBOptions.java:89-103`
+
+| 配置项 | 类型 | 说明 |
+|--------|------|------|
+| `rocksdb.option_path` | String | ToplingDB YAML 配置文件路径(如 `conf/topling.yaml`) |
+| `rocksdb.open_http` | Boolean | 是否启动 ToplingDB 内嵌 Web 监控服务器 |
+
+安全验证规则(`ToplingRocksDBProvider.validateOptionPath()`):
+
+- 路径必须匹配正则 `^[a-zA-Z0-9/_.-]+\.yaml$`
+- 不允许包含 `..` 或 `://`
+- 必须位于 `./conf/` 目录下(路径遍历防护)
+- 文件必须存在且可读
+- 文件大小限制 10MB(防止 DoS)
+- YAML 使用 `SafeConstructor` 解析(防止反序列化攻击)
+
+### 2.9 StandardRocksDBProvider(降级方案)
+
+> 源码位置:`hugegraph-rocksdb-provider/src/main/java/org/apache/hugegraph/rocksdb/provider/StandardRocksDBProvider.java`
+
+当 ToplingDB 不可用时,`StandardRocksDBProvider`(priority=100)接管:
+
+```java
+public class StandardRocksDBProvider extends AbstractRocksDBProvider {
+ @Override
+ public boolean isAvailable() {
+ RocksDB.loadLibrary(); // 只要标准 RocksDB 能加载就可用
+ return true;
+ }
+
+ @Override
+ protected RocksDB doOpenRocksDB(Options options, String dataPath) {
+ return RocksDB.open(options, dataPath); // 直接调用标准 API
+ }
+
+ // ToplingDB 专有参数会被忽略并打印 warn 日志
+ @Override
+ protected RocksDB doOpenRocksDB(Options options, String dataPath,
+ String optionPath, Boolean openHttp) {
+ if (optionPath != null) {
+ LOG.warn("Standard RocksDB does not support optionPath, ignoring: {}", optionPath);
+ }
+ return RocksDB.open(options, dataPath);
+ }
+}
+```
+
+---
+
+## 三、HStore 接入详解
+
+### 3.1 设计思路:分布式存储客户端
+
+HStore 是 HugeGraph 的**分布式存储后端**,它将一个独立的 `hugegraph-store` 集群(多节点 Raft + RocksDB)封装为与单机 RocksDB 相同的 `BackendStoreProvider` 接口。对上层查询引擎完全透明。
+
+### 3.2 模块结构
+
+```
+hugegraph-server/hugegraph-hstore/ ← 客户端适配模块
+├── HstoreProvider.java ← BackendStoreProvider 实现 (type="hstore")
+├── HstoreStore.java ← 抽象 Store (HstoreSchemaStore / HstoreGraphStore)
+├── HstoreSessions.java ← 会话抽象层
+├── HstoreSessionsImpl.java ← 具体实现:通过 gRPC 与 Store 集群通信
+├── HstoreTable.java ← 表操作抽象
+├── HstoreTables.java ← 具体表定义 (vertex, edge, index 等)
+├── HstoreFeatures.java ← 后端能力声明
+├── HstoreOptions.java ← 配置项(如 partition_count)
+└── HstoreMetrics.java ← 指标收集
+
+hugegraph-store/ ← 存储节点服务(独立部署)
+├── hg-store-grpc/ ← gRPC 协议定义
+├── hg-store-common/ ← 公共类
+├── hg-store-client/ ← 客户端库 (HgStoreClient)
+├── hg-store-core/ ← 核心逻辑(Raft、分区管理)
+├── hg-store-node/ ← 节点服务主程序
+├── hg-store-rocksdb/ ← 节点层 RocksDB 访问(也支持 ToplingDB)
+├── hg-store-cli/ ← 命令行工具
+├── hg-store-test/ ← 测试
+└── hg-store-dist/ ← 打包分发
+```
+
+### 3.3 HstoreProvider —— 入口
+
+> 源码位置:`hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreProvider.java`
+
+```java
+public class HstoreProvider extends AbstractBackendStoreProvider {
+
+ @Override
+ public String type() {
+ return "hstore";
+ }
+
+ @Override
+ public String driverVersion() {
+ return "1.13";
+ }
+
+ @Override
+ protected BackendStore newSchemaStore(HugeConfig config, String store) {
+ return new HstoreStore.HstoreSchemaStore(this, this.namespace(), store);
+ }
+
+ @Override
+ protected BackendStore newGraphStore(HugeConfig config, String store) {
+ return new HstoreStore.HstoreGraphStore(this, this.namespace(), store);
+ }
+}
+```
+
+### 3.4 HstoreSessionsImpl —— 核心连接层
+
+> 源码位置:`hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreSessionsImpl.java`
+
+这是 HStore 最关键的实现类,负责与分布式存储集群通信:
+
+```java
+public class HstoreSessionsImpl extends HstoreSessions {
+ private static volatile PDClient defaultPdClient; // PD 元数据客户端
+ private static volatile HgStoreClient hgStoreClient; // Store 数据客户端
+
+ // 初始化 Store 节点连接(单例,只执行一次)
+ private void initStoreNode(HugeConfig config) {
+ if (!initializedNode) {
+ synchronized (this) {
+ if (!initializedNode) {
+ // 创建 PD 客户端(Placement Driver,负责元数据和路由)
+ PDConfig pdConfig = PDConfig.of(config.get(CoreOptions.PD_PEERS))
+ .setAuthority(PDAuthConfig.service(),
+ PDAuthConfig.token())
+ .setEnableCache(true);
+ defaultPdClient = PDClient.create(pdConfig);
+
+ // 基于 PD 客户端创建 Store 客户端(负责数据读写)
+ hgStoreClient = HgStoreClient.create(defaultPdClient);
+ initializedNode = Boolean.TRUE;
+ }
+ }
+ }
+ }
+
+ // 打开会话时向 PD 注册图的分区信息
+ @Override
+ public void open() {
+ if (!infoInitializedGraph.contains(this.graphName)) {
+ Integer partitionCount = this.config.get(HstoreOptions.PARTITION_COUNT);
+ defaultPdClient.setGraph(Metapb.Graph.newBuilder()
+ .setGraphName(this.graphName)
+ .setPartitionCount(partitionCount)
+ .build());
+ infoInitializedGraph.add(this.graphName);
+ }
+ this.session.open();
+ }
+
+ // 表操作委托给远程 Store 节点
+ @Override
+ public synchronized void createTable(String... tables) { ... }
+
+ @Override
+ public synchronized void dropTable(String... tables) { ... }
+
+ @Override
+ public boolean existsTable(String table) { ... }
+}
+```
+
+### 3.5 HstoreStore —— 存储抽象
+
+> 源码位置:`hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreStore.java`
+
+```java
+public abstract class HstoreStore extends AbstractBackendStore {
+
+ // 支持的索引类型
+ private static final Set INDEX_TYPES = ImmutableSet.of(
+ HugeType.SECONDARY_INDEX, HugeType.VERTEX_LABEL_INDEX,
+ HugeType.EDGE_LABEL_INDEX, HugeType.RANGE_INT_INDEX,
+ HugeType.RANGE_FLOAT_INDEX, HugeType.RANGE_LONG_INDEX,
+ HugeType.RANGE_DOUBLE_INDEX, HugeType.SEARCH_INDEX,
+ HugeType.SHARD_INDEX, HugeType.UNIQUE_INDEX
+ );
+
+ // 两种具体实现
+ public static class HstoreSchemaStore extends HstoreStore { ... }
+ public static class HstoreGraphStore extends HstoreStore { ... }
+}
+```
+
+### 3.6 HStore 运行时数据流
+
+```
+HugeGraph Server (hugegraph-hstore 客户端)
+ │
+ ├─ HstoreSessionsImpl
+ │ ├─ PDClient ──────────── gRPC ──→ PD (Placement Driver)
+ │ │ • 获取 partition 路由表 │ • 管理分区分配
+ │ │ • 注册图元数据 │ • 调度数据均衡
+ │ │ │
+ │ └─ HgStoreClient ──── gRPC ──→ Store Node (hg-store-node)
+ │ • put / get / scan / delete │ • Raft 共识保证一致性
+ │ • 按 partition 路由到对应节点 │ • RocksDB / ToplingDB 存储
+ │ │ • 数据分片与副本
+ │ │
+ └─ HstoreTable └─→ hg-store-rocksdb
+ • 序列化/反序列化 vertex/edge/index │
+ • 构建 HgScanQuery └─ RocksDBProviderLoader (同样的 SPI)
+ ├─ ToplingRocksDBProvider
+ └─ StandardRocksDBProvider
+```
+
+### 3.7 BackendProviderFactory —— 后端注册与发现
+
+> 源码位置:`hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/BackendProviderFactory.java`
+
+```java
+public class BackendProviderFactory {
+ // 允许的后端类型白名单
+ private static final List ALLOWED_BACKENDS =
+ List.of("memory", "rocksdb", "hbase", "hstore");
+
+ public static BackendStoreProvider open(HugeGraphParams params) {
+ String backend = config.get(CoreOptions.BACKEND).toLowerCase(); // e.g. "hstore"
+ BackendStoreProvider provider = newProvider(config);
+
+ // 如果开启 Raft 模式,包装为 RaftBackendStoreProvider
+ if (raftMode) {
+ provider = new RaftBackendStoreProvider(params, provider);
+ }
+ provider.open(graph);
+ return provider;
+ }
+}
+```
+
+### 3.8 关键配置
+
+HStore 模式配置示例:
+
+```properties
+# hugegraph.properties
+backend=hstore
+pd.peers=127.0.0.1:8686,127.0.0.1:8687,127.0.0.1:8688
+hstore.partition_count=24
+```
+
+Store 节点也支持 ToplingDB(`hugegraph-store/hg-store-dist/src/assembly/static/conf/application-pd.yml`):
+
+```yaml
+rocksdb:
+ option_path: conf/topling-store.yaml
+ open_http: true
+```
+
+---
+
+## 四、两者的关系与对比
+
+| 维度 | ToplingDB | HStore |
+|------|-----------|--------|
+| **是什么** | 增强版存储引擎 | 分布式存储架构 |
+| **替换什么** | 替换标准 RocksDB 的 open/close | 替换单机嵌入式存储模式 |
+| **接入方式** | Java SPI + 反射,运行时探测 | BackendStoreProvider 插件注册 |
+| **影响范围** | 仅引擎层(open/close 两个点) | 全栈(路由、分片、复制、事务) |
+| **能否组合** | ✅ 可用于 HStore 节点内部 | ✅ 节点内部可用 ToplingDB |
+| **侵入性** | 极低,零编译时依赖 | 中等,需要完整实现 Store 接口 |
+| **依赖模块** | `hugegraph-rocksdb-provider` | `hugegraph-hstore` + `hugegraph-store` 集群 |
+| **部署要求** | 只需替换 JAR + 运行启动脚本 | 需要独立部署 PD + Store 节点集群 |
+
+### 组合部署矩阵
+
+| 部署模式 | 配置 | 效果 |
+|----------|------|------|
+| 单机 + 标准 RocksDB | `backend=rocksdb` + 标准 JAR | StandardRocksDBProvider |
+| 单机 + ToplingDB | `backend=rocksdb` + ToplingDB JAR | ToplingRocksDBProvider(自动) |
+| 分布式 + 标准 RocksDB | `backend=hstore` + Store 节点用标准 JAR | HStore + StandardRocksDBProvider |
+| 分布式 + ToplingDB | `backend=hstore` + Store 节点用 ToplingDB JAR | HStore + ToplingRocksDBProvider |
+
+---
+
+## 五、Maven 依赖链
+
+```
+hugegraph (root pom.xml)
+│
+├── hugegraph-rocksdb-provider ← 独立模块
+│ └── rocksdbjni:8.10.2-SNAPSHOT ← ToplingDB 增强版 RocksDB JNI
+│ └── snakeyaml:2.2 ← YAML 配置解析
+│ └── json-smart:2.3 ← JSON 构建(SidePluginRepo 参数)
+│
+├── hugegraph-server/hugegraph-rocksdb ← 单机 RocksDB 后端
+│ └── depends on: hugegraph-rocksdb-provider
+│
+├── hugegraph-server/hugegraph-hstore ← HStore 客户端
+│ └── depends on: hg-store-client ← gRPC 客户端
+│ └── depends on: hg-pd-client ← PD 客户端
+│
+└── hugegraph-store/hg-store-rocksdb ← Store 节点存储层
+ └── depends on: hugegraph-rocksdb-provider ← 同一个 SPI 模块!
+```
+
+ToplingDB Maven artifact 来源(`.github/configs/settings.xml`):
+
+```xml
+
+ github-toplingdb
+ https://maven.pkg.github.com/hugegraph/toplingdb
+
+```
+
+---
+
+## 六、关键源码文件索引
+
+| 文件 | 作用 |
+|------|------|
+| `hugegraph-rocksdb-provider/src/.../RocksDBProvider.java` | SPI 接口定义 |
+| `hugegraph-rocksdb-provider/src/.../ToplingRocksDBProvider.java` | ToplingDB 适配核心 |
+| `hugegraph-rocksdb-provider/src/.../StandardRocksDBProvider.java` | 标准 RocksDB 降级方案 |
+| `hugegraph-rocksdb-provider/src/.../RocksDBProviderLoader.java` | ServiceLoader + Provider 选择 |
+| `hugegraph-server/hugegraph-rocksdb/src/.../RocksDBStdSessions.java` | 单机模式调用入口 |
+| `hugegraph-server/hugegraph-rocksdb/src/.../RocksDBOptions.java` | 配置项定义 |
+| `hugegraph-server/hugegraph-rocksdb/src/.../OpenedRocksDB.java` | close 调用入口 |
+| `hugegraph-server/hugegraph-hstore/src/.../HstoreProvider.java` | HStore 后端入口 |
+| `hugegraph-server/hugegraph-hstore/src/.../HstoreSessionsImpl.java` | HStore gRPC 通信核心 |
+| `hugegraph-server/hugegraph-hstore/src/.../HstoreStore.java` | HStore 存储抽象 |
+| `hugegraph-store/hg-store-rocksdb/src/.../RocksDBSession.java` | Store 节点 RocksDB 层 |
+| `hugegraph-server/hugegraph-core/src/.../BackendProviderFactory.java` | 后端工厂(注册与发现) |
+| `hugegraph-server/hugegraph-dist/src/.../bin/common-topling.sh` | Native 库预加载脚本 |
+| `hugegraph-server/hugegraph-dist/src/.../bin/preload-topling.sh` | 启动时调用入口 |
+
+---
+
+## 七、总结
+
+1. **ToplingDB 接入的精髓**是"最小侵入":只在 `RocksDB.open()` 和 `rocksdb.close()` 两个调用点做替换,通过 Java SPI 机制实现零编译时依赖、运行时自动发现和优雅降级。所有 ToplingDB 特有 API(`SidePluginRepo`)均通过反射调用,确保标准 RocksDB 环境下代码完全正常运行。
+
+2. **HStore 接入的精髓**是"透明分布式":通过实现 `BackendStoreProvider` 接口,将分布式集群(PD + Store 节点 + Raft 共识)封装为与单机 RocksDB 相同的语义。上层查询引擎无需任何修改即可从单机切换到分布式。
+
+3. **两者共享 `hugegraph-rocksdb-provider` 模块**:无论是单机 `hugegraph-server/hugegraph-rocksdb` 路径,还是分布式 `hugegraph-store/hg-store-rocksdb` 路径,都依赖同一个 Provider SPI 模块。这意味着 ToplingDB 的性能优势在两种部署模式下都能获得。
diff --git a/docs/toplingdb/toplingdb-operations.md b/docs/toplingdb/toplingdb-operations.md
new file mode 100644
index 0000000000..b5e3ea9055
--- /dev/null
+++ b/docs/toplingdb/toplingdb-operations.md
@@ -0,0 +1,87 @@
+# ToplingDB Operations Guide
+
+This guide outlines key operational practices for deploying, monitoring, tuning, and upgrading ToplingDB in production environments. It is intended for system administrators, DevOps engineers, and database maintainers seeking to ensure stability, performance, and scalability.
+
+---
+
+## Monitoring Metrics
+
+- **Key Performance Indicators (KPI)**
+ - Write throughput (bytes/sec, ops/sec)
+ - Read latency (P95/P99)
+ - MemTable usage and flush frequency
+ - Block cache hit ratio
+
+- **Alert Thresholds**
+ - L0 file count exceeding `level0_stop_writes_trigger`
+ - Background job saturation (`max_background_jobs`)
+ - WAL size growth beyond expected limits
+ - Cache eviction rate anomalies
+
+- **Monitoring Tool Integration**
+ - Export metrics via HTTP endpoints
+ - Integrate with Prometheus using custom exporters
+ - Visualize trends and thresholds in Grafana dashboards
+ - Use SidePlugin’s web server (`listening_ports`) for live inspection
+
+---
+
+## Performance Tuning
+
+- **Cache Size Optimization**
+ - Adjust `capacity` in `lru_cache` based on workload and memory budget
+ - Tune `high_pri_pool_ratio` to prioritize index/filter caching
+
+- **Compression Algorithm Selection**
+ - Use `kSnappyCompression` for balanced speed and space
+ - Disable compression (`kNoCompression`) for latency-sensitive workloads
+
+- **Compaction Strategy Adjustment**
+ - Set `level0_file_num_compaction_trigger` to control L0 flush frequency
+ - Use `level_compaction_dynamic_file_size: true` to adapt SST sizing
+ - Tune `max_subcompactions` and `max_background_jobs` for parallelism
+
+- **I/O Tuning Parameters**
+ - Evaluate `convert_to_sst: kFileMmap` to bypass traditional flush
+ - Set `sync_sst_file: false` for performance, with caution on durability
+ - Adjust `compaction_readahead_size` for sequential disk access
+
+---
+
+## Capacity Planning
+
+- **Disk Space Estimation**
+ - Base on `write_buffer_size`, `target_file_size_base`, and compaction amplification
+ - Include space for WAL, MANIFEST, and temporary files
+
+- **Memory Requirement Calculation**
+ - Sum of MemTable (`mem_cap`), block cache (`capacity`), and background buffers
+ - Consider `max_write_buffer_number` and `min_write_buffer_number_to_merge`
+
+- **CPU Resource Planning**
+ - Allocate cores for compaction (`max_background_compactions`)
+ - Reserve CPU for Hugegraph query threads and SidePlugin HTTP services
+ - Monitor mutex contention (`use_adaptive_mutex`) and shard parallelism
+
+---
+
+## Upgrade Procedure
+
+- **Version Compatibility Check**
+ - Review changelogs and YAML schema changes
+ - Validate plugin compatibility (e.g., `cspp`, `DispatcherTable`)
+
+- **Data Backup Strategy**
+ - Snapshot SST files and MANIFEST
+ - Backup column family metadata and configuration files
+
+- **Rolling Upgrade Steps**
+ - Drain traffic from target node
+ - Stop ToplingDB process and apply new binary
+ - Validate startup with `create_if_missing: false`
+ - Rejoin cluster and monitor metrics
+
+- **Rollback Plan**
+ - Restore previous binary and configuration
+ - Revert SST and MANIFEST from backup
+ - Disable incompatible plugins if needed
diff --git a/docs/toplingdb/toplingdb-security.md b/docs/toplingdb/toplingdb-security.md
new file mode 100644
index 0000000000..e57b877426
--- /dev/null
+++ b/docs/toplingdb/toplingdb-security.md
@@ -0,0 +1,50 @@
+# ToplingDB Security Hardening Guide
+
+This document provides best practices for securing a ToplingDB deployment. It covers file permissions, network access control, firewall rules, and additional hardening measures to reduce the attack surface and ensure safe operation in production environments.
+
+---
+
+## 1. File Permissions
+
+Restrict file permissions to prevent unauthorized access or modification of scripts and configuration files:
+
+```bash
+chmod 750 $HUGEGRAPH_HOME/bin/*.sh
+chmod 640 $HUGEGRAPH_HOME/conf/graphs/*.yaml
+chown -R hugegraph:hugegraph $HUGEGRAPH_HOME
+```
+
+- `750` ensures only the owner can execute scripts, while group members can read them.
+- `640` ensures configuration files are readable by the owner and group, but not world-readable.
+- Ownership should be assigned to a dedicated service account (e.g., `hugegraph`).
+
+---
+
+## 2. Network Access Control
+
+Restrict network exposure by binding services to localhost or specific interfaces:
+
+```yaml
+# Localhost-only access
+http:
+ listening_ports: '127.0.0.1:2011'
+```
+
+- Avoid binding to `0.0.0.0` unless absolutely necessary.
+- Use reverse proxies (e.g., Nginx) or VPN tunnels if remote access is required.
+
+---
+
+## 3. Firewall Rules
+
+Use firewall rules to limit access to trusted IP ranges:
+
+```bash
+# Allow only specific subnet to access the Web Server
+iptables -A INPUT -p tcp --dport 2011 \
+ -s 192.168.1.0/24 -j ACCEPT
+iptables -A INPUT -p tcp --dport 2011 -j DROP
+```
+
+- Replace `192.168.1.0/24` with your trusted network.
+- Consider using `firewalld` or `ufw` for simplified management.
diff --git a/docs/toplingdb/toplingdb-troubleshooting.md b/docs/toplingdb/toplingdb-troubleshooting.md
new file mode 100644
index 0000000000..68d8072c46
--- /dev/null
+++ b/docs/toplingdb/toplingdb-troubleshooting.md
@@ -0,0 +1,138 @@
+# ToplingDB Troubleshooting
+
+## Issues
+
+### Issue 1: Startup Failure Due to YAML Format Error
+
+Sample log output:
+
+```java
+2025-10-15 01:55:50 [db-open-1] [INFO] o.a.h.b.s.r.RocksDBStdSessions - SidePluginRepo found. Will attempt to open multi CFs RocksDB using Topling plugin.
+21:1: (891B):ERROR:
+sideplugin/rockside/3rdparty/rapidyaml/src/c4/yml/parse.cpp:3310: ERROR parsing yml: parse error: incorrect indentation?
+```
+
+**Solution**:
+
+1. Check that YAML indentation is correct (must use spaces, not tabs).
+2. Validate YAML syntax:
+
+ ```bash
+ python -c "import yaml; yaml.safe_load(open('conf/graphs/rocksdb_plus.yaml'))"
+ ```
+
+3. Review the specific error message in the logs for further clues.
+
+---
+
+### Issue 2: Web Server Port Conflict
+
+Sample log output:
+
+```java
+2025-10-15 01:57:34 [db-open-1] [INFO] o.a.h.b.s.r.RocksDBStdSessions - SidePluginRepo found. Will attempt to open multi CFs RocksDB using Topling plugin.
+2025-10-15 01:57:34 [db-open-1] [ERROR] o.a.h.b.s.r.RocksDBStore - Failed to open RocksDB 'rocksdb-data/data/g'
+org.rocksdb.RocksDBException: rocksdb::Status rocksdb::SidePluginRepo::StartHttpServer(): null context when constructing CivetServer. Possible problem binding to port.
+ at org.rocksdb.SidePluginRepo.startHttpServer(Native Method) ~[rocksdbjni-8.10.2-20250804.074027-4.jar:?]
+```
+
+**Solution**:
+
+1. Check if the port is already in use:
+
+ ```bash
+ lsof -i :2011
+ ```
+
+2. Modify the `listening_ports` setting in the YAML configuration file.
+3. Restart the HugeGraph Server.
+
+---
+
+### Issue 3: Database Initialization Failure
+
+This error indicates the database lock file cannot be acquired, possibly due to insufficient write permissions or another process holding the lock:
+
+```java
+Caused by: org.rocksdb.RocksDBException: While lock file: rocksdb-data/data/m/LOCK: Resource temporarily unavailable
+ at org.rocksdb.SidePluginRepo.nativeOpenDBMultiCF(Native Method)
+ at org.rocksdb.SidePluginRepo.openDB(SidePluginRepo.java:22)
+```
+
+**Solution**:
+
+1. Confirm the configuration file path is correct:
+
+ ```properties
+ rocksdb.option_path=./conf/graphs/rocksdb_plus.yaml
+ ```
+
+2. Check permissions on the data directory to ensure the running user has read/write access.
+3. Review detailed logs:
+
+ ```bash
+ bin/init-store.sh 2>&1 | tee init.log
+ ```
+
+---
+
+## Log Analysis
+
+### Enable Debug Logging
+
+```properties
+# conf/log4j2.xml
+
+```
+
+### Key Log Locations
+
+- Application logs: `logs/hugegraph-server.log`
+- RocksDB logs: `data/rocksdb/LOG`
+- Web Server logs: check the `access_log` setting in the YAML configuration
+
+Additional notes:
+
+- Enable debug logging only during troubleshooting, as it may generate large log files and impact performance.
+- Rotate and archive logs regularly to prevent disk space exhaustion.
+
+---
+
+## Performance Diagnostics
+
+### High CPU Usage
+
+1. Review and tune **compaction** configuration (e.g., compaction style, trigger thresholds).
+2. Adjust **thread pool size** to match available CPU cores and workload characteristics.
+3. Optimize **write batching** to reduce per-operation overhead.
+4. Monitor for **hot keys** or skewed workloads that may cause uneven CPU usage.
+5. Use performance profiling tools (e.g., `perf`, `async-profiler`) to identify hotspots.
+
+---
+
+### Excessive Memory Usage
+
+1. Adjust **block cache size** to balance between read performance and memory footprint.
+2. Review **write buffer** (memtable) configuration, including number and size.
+3. Monitor for **memory leaks** in the application layer or plugins.
+4. Enable **JVM GC logging** to analyze garbage collection behavior.
+
+---
+
+### Disk I/O Bottlenecks
+
+1. Use **SSD storage** for RocksDB data directories to improve latency and throughput.
+2. Tune **WAL (Write-Ahead Log)** configuration, such as enabling `wal_dir` on a separate disk.
+3. Optimize **compaction strategy** (e.g., level-based vs. universal compaction) based on workload.
+4. Monitor **disk utilization** and IOPS using tools like `iostat` or `dstat`.
+5. Separate **data, WAL, and log directories** onto different physical devices if possible.
+
+---
+
+### General Recommendations
+
+- Always benchmark configuration changes in a staging environment before applying them to production.
+- Use monitoring systems (e.g., Prometheus + Grafana) to track CPU, memory, and I/O metrics over time.
+- Regularly review RocksDB’s internal statistics (`rocksdb.stats`) for deeper insights into performance.
+- Automate log collection and alerting to quickly detect anomalies.
diff --git a/docs/toplingdb/toplingdb.md b/docs/toplingdb/toplingdb.md
new file mode 100644
index 0000000000..2a0566fde0
--- /dev/null
+++ b/docs/toplingdb/toplingdb.md
@@ -0,0 +1,179 @@
+# ToplingDB Support and Configuration
+
+- **Status**: Implemented
+- **Pull Request**: [#15](https://github.com/hugegraph/hugegraph/pull/15)
+
+## Background knowledge
+
+[ToplingDB](https://github.com/topling/toplingdb) is a high-performance, cloud-native key-value store built as a fork of RocksDB.
+
+ToplingDB extends RocksDB with several advanced features:
+
+- **Searchable Compression**: ToplingDB introduces compression algorithms that preserve searchability, enabling efficient queries directly on compressed data.
+- **SidePlugin Architecture**: It supports configuration via YAML files through a plugin system, allowing tuning parameters without recompilation.
+- **Built-in Observability**: A lightweight HTTP server exposes internal metrics and configuration states, making it easier to monitor and debug storage behavior.
+- **Distributed Compaction**: Designed for cloud environments, ToplingDB supports distributed compaction strategies to reduce write amplification and improve throughput.
+- **Compatibility**: Drop-in replacement for RocksDB in most use cases.
+
+## Motivation
+
+Introduce a new optional storage component in HugeGraph to support [ToplingDB](https://github.com/topling/toplingdb)), a configurable and observable extension of the RocksDB storage engine.
+
+ToplingDB resolves key limitations in HugeGraph’s current `rocksdbjni` integration, which relies heavily on hard-coding parameters and lacks runtime configurability and observability.
+
+By enabling YAML-based configuration and exposing a Web Server interface, ToplingDB allows users to fine-tune performance and monitor engine behavior without modifying code or restarting services.
+
+This is especially valuable in environments where storage workloads vary across deployments, and where operational transparency is critical for debugging and optimization.
+
+For example, in production clusters with heterogeneous hardware or mixed graph workloads, users can adjust compaction, caching, and I/O settings to match their performance goals.
+
+Additionally, ToplingDB maintains full compatibility with the existing RocksDB API, allowing seamless migration and fallback. Users can opt into ToplingDB via configuration, without impacting legacy data or workflows.
+
+By supporting ToplingDB, HugeGraph empowers users with greater control over storage behavior, simplifies deployment through automated dynamic library loading, and enhances operational insight—all while preserving compatibility and ease of use.
+
+## Goals
+
+**Introduce ToplingDB as a configurable and observable alternative to RocksDB.**
+
+Enable users to select ToplingDB via configuration, allowing tuning parameters through YAML files without recompilation and real-time monitoring via Web Server—without sacrificing compatibility with existing RocksDB APIs.
+
+## Design
+
+### Configuration Parameters
+
+To support ToplingDB in HugeGraph, two new configuration parameters have been introduced: `rocksdb.option_path` and `rocksdb.open_http`. These options allow users to configure RocksDB parameters and enable real-time observability.
+
+#### `rocksdb.option_path`: External YAML Configuration
+
+This parameter allows users to specify a YAML file that defines ToplingDB settings such as compaction strategy, cache size, compression type, and more.
+
+- **Purpose**: Replace hard-coding parameters with flexible, file-based configuration.
+
+- **Usage**: Add the following line to your `hugegraph.properties` file:
+
+ ```properties
+ rocksdb.option_path=./conf/graphs/rocksdb_plus.yaml
+ ```
+
+ The specified YAML file will be automatically loaded during database initialization if ToplingDB is available.
+
+ For security reasons, HugeGraph only allows YAML files to be stored under the `$HUGEGRAPH_HOME/conf/graphs` directory.
+
+ For details on the YAML structure and supported configuration fields, please refer to [SidePlugin](https://github.com/topling/sideplugin-wiki-en/wiki).
+
+- **Implementation**: During initialization, HugeGraph checks whether the configured JAR contains ToplingDB APIs. If so, it uses reflection to load the SidePluginRepo class and calls `importAutoFile(optionPath)` to parse the YAML file. The resulting configuration is applied to the RocksDB instance.
+
+- **Fallback**: If the YAML file is not provided or ToplingDB is unavailable, HugeGraph will fall back to standard RocksDB behavior.
+
+#### `rocksdb.open_http`: Enable Web Server for Observability
+
+This boolean flag controls whether the embedded Web Server in ToplingDB should be started. The server exposes runtime metrics, configuration status, and internal RocksDB statistics via a browser-accessible interface.
+
+- **Purpose**: Provide real-time visibility into the storage engine for debugging and performance tuning.
+
+- **Usage**: Add the following line to your `hugegraph.properties` file:
+
+ ```properties
+ rocksdb.open_http=true
+ ```
+
+ The listening port is defined in the YAML file specified by `option_path`, under the key `http.listening_ports`:
+
+ ```yaml
+ http:
+ document_root: /dev/shm/rocksdb_resource
+ listening_ports: '127.0.0.1:2011' # by default, only local access is allowed
+ ```
+
+ For security reasons, the default configuration only allows local access.
+ When adjusting this setting, users should carefully manage port and network access permissions to avoid potential security incidents.
+ To preview the Web Server interface and its layout, see [Web Server](https://github.com/topling/sideplugin-wiki-en/wiki/WebView).
+
+- **Implementation**: If `open_http` is set to true and the database instance is `GRAPH_STORE`, HugeGraph invokes `startHttpServer()` on the ToplingDB repo object. This exposes a browser-accessible dashboard for monitoring RocksDB internals.
+
+- **Scope**: For simplicity, the Web Server is only enabled for the `GRAPH_STORE` instance, which holds the main graph data.
+
+- **Security**: The Web Server does **not** provide built-in authentication. In production environments, configure firewalls or network access controls carefully to prevent unauthorized access.
+
+### Reflection-Based Loading Mechanism
+
+To support ToplingDB without introducing hard dependencies, HugeGraph uses Java reflection to detect and load enhanced APIs at runtime.
+
+During initialization, HugeGraph checks whether the current JAR contains the class `com.topling.sideplugin.SidePluginRepo`. If present, it assumes ToplingDB is available and proceeds to:
+
+1. **Load the SidePluginRepo class via reflection** This avoids compile-time coupling and allows fallback to standard RocksDB if the class is missing.
+ - If the ToplingDB API cannot be found, HugeGraph silently falls back to the standard RocksDB API for startup.
+2. **Invoke** `importAutoFile(optionPath)` This method parses the YAML configuration file specified by `rocksdb.option_path` to configure storage engine parameters.
+ - If the `option_path` is incorrect or parsing fails, ToplingDB throws an error and terminates the startup process.
+3. **Call** `open()` **with a JSON descriptor** The parsed configuration is converted to a JSON structure and passed to the ToplingDB engine to initialize the database.
+4. **Optionally start the Web Server** If `rocksdb.open_http` is true and the instance is `GRAPH_STORE`, HugeGraph invokes `startHttpServer()` via reflection to enable observability.
+ - If the Web Server cannot be started due to misconfiguration **or if the specified HTTP port is already in use**, ToplingDB throws an error and the startup process is terminated
+
+This design ensures that ToplingDB can be integrated as an optional enhancement, without breaking compatibility or requiring changes to the core HugeGraph codebase.
+
+## Impact
+
+### For Users
+
+The way users operate remains unchanged by default, and adding ToplingDB configuration provides additional functionality.
+The ToplingDB integration is fully embedded into the existing startup scripts (`init-store.sh` and `start-hugegraph.sh`). Users only need to set `rocksdb.option_path` to specify the YAML file path and adjust its contents as needed to tune the storage engine.
+
+### For Developers
+
+Developers need to make two adjustments to enable ToplingDB during development:
+
+1. **Maven Repository Configuration**: since ToplingDB is published via GitHub Packages, developers must add the GitHub repository to their `settings.xml` to fetch the correct JAR:
+
+ ```xml
+
+
+
+
+ github
+ YOUR_GITHUB_ACTOR
+
+ YOUR_GITHUB_TOKEN
+
+
+
+
+
+ ...
+
+ ...
+
+
+ github
+ https://maven.pkg.github.com/hugegraph/toplingdb
+
+ true
+
+
+
+
+
+ ```
+
+2. **IDE Environment Setup**: developers must configure runtime environment variables to preload required native libraries.
+ The `preload-topling.sh` script not only extracts the necessary dynamic libraries and web server static resources into the `library` directory next to the `bin` directory,
+ but also sets the required environment variables in the current process.
+ When executed in a terminal using `source preload-topling.sh`, these variables take effect immediately in that shell session.
+
+ However, when launching HugeGraph from an IDE, the program typically runs in a separate process,
+ so environment variables defined in scripts run from the terminal are not inherited.
+ In this case, developers need to manually configure the IDE's run/debug environment variables to ensure proper preloading of native libraries.
+
+ In your IDE’s Run/Debug Configuration, set:
+
+ ```bash
+ LD_LIBRARY_PATH="/path/to/your/library:${LD_LIBRARY_PATH}"
+ LD_PRELOAD="libjemalloc.so:librocksdbjni.so"
+ ```
+
+These steps ensure that ToplingDB loads correctly in development environments and behaves consistently with production deployments.
+
+## Links
+
+- **ToplingDB**: [https://github.com/topling/toplingdb](https://github.com/topling/toplingdb)
+- **Configuration YAML of ToplingDB**: [https://github.com/topling/sideplugin-wiki-en/wiki](https://github.com/topling/sideplugin-wiki-en/wiki)
+- **Web Server of ToplingDB**: [https://github.com/topling/sideplugin-wiki-en/wiki/WebView](https://github.com/topling/sideplugin-wiki-en/wiki/WebView)
diff --git a/hugegraph-pd/hg-pd-cli/pom.xml b/hugegraph-pd/hg-pd-cli/pom.xml
index 4920174d76..98b5954278 100644
--- a/hugegraph-pd/hg-pd-cli/pom.xml
+++ b/hugegraph-pd/hg-pd-cli/pom.xml
@@ -49,7 +49,7 @@
com.alipay.sofa
jraft-core
- 1.3.13
+ 1.3.14
org.rocksdb
diff --git a/hugegraph-pd/hg-pd-core/pom.xml b/hugegraph-pd/hg-pd-core/pom.xml
index e17570d592..48d43dbd41 100644
--- a/hugegraph-pd/hg-pd-core/pom.xml
+++ b/hugegraph-pd/hg-pd-core/pom.xml
@@ -38,7 +38,7 @@
com.alipay.sofa
jraft-core
- 1.3.13
+ 1.3.14
org.rocksdb
@@ -49,7 +49,7 @@
org.rocksdb
rocksdbjni
- 6.29.5
+ ${rocksdb.version}
org.apache.hugegraph
diff --git a/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/store/HgKVStoreImpl.java b/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/store/HgKVStoreImpl.java
index bd2e7a9e22..6f7ea817b5 100644
--- a/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/store/HgKVStoreImpl.java
+++ b/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/store/HgKVStoreImpl.java
@@ -67,7 +67,7 @@ public void init(PDConfig config) {
final Lock writeLock = this.readWriteLock.writeLock();
writeLock.lock();
try {
- this.dbPath = config.getDataPath() + "/rocksdb/";
+ this.dbPath = config.getDataPath() + "/rocksdb";
File file = new File(this.dbPath);
if (!file.exists()) {
try {
diff --git a/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/start-hugegraph-pd.sh b/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/start-hugegraph-pd.sh
index 1329df2271..d59f27daa6 100755
--- a/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/start-hugegraph-pd.sh
+++ b/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/start-hugegraph-pd.sh
@@ -63,9 +63,21 @@ PID_FILE="$BIN/pid"
. "$BIN"/util.sh
+PARENT_DIR="$(cd "$TOP"/../ && pwd)"
+SERVER_VERSION_DIR="${SERVER_VERSION_DIR:-$(find_hugegraph_server_dir "$PARENT_DIR")}"
+
ensure_path_writable "$LOGS"
ensure_path_writable "$PLUGINS"
+# preload rocksdb/toplingdb
+if [ -n "$SERVER_VERSION_DIR" ] && [ -e "$SERVER_VERSION_DIR/bin/preload-topling.sh" ]; then
+ TOPLINGDB_EASY_MIGRATE_CONF="$CONF/rocksdb_pd.yaml"
+ TOPLING_COMPONENT_TOP="$TOP"
+ TOPLING_USE_SERVER_CLASSPATH=false
+ source "$SERVER_VERSION_DIR/bin/preload-topling.sh"
+ unset TOPLING_COMPONENT_TOP TOPLING_USE_SERVER_CLASSPATH
+fi
+
# The maximum and minimum heap memory that service can use
MAX_MEM=$((32 * 1024))
MIN_MEM=$((1 * 512))
diff --git a/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/util.sh b/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/util.sh
index b476d7935b..b42239d2b7 100644
--- a/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/util.sh
+++ b/hugegraph-pd/hg-pd-dist/src/assembly/static/bin/util.sh
@@ -394,3 +394,21 @@ function kill_process_and_wait() {
kill_process "$process_name" "$pid"
wait_for_shutdown "$process_name" "$pid" "$timeout_s"
}
+
+# Find HugeGraph server directory in parent path using prefix glob.
+# Usage: find_hugegraph_server_dir "/path/to/parent"
+# Returns: first matching directory path or empty string
+function find_hugegraph_server_dir() {
+ local parent_dir="$1"
+ if [ -z "$parent_dir" ]; then
+ parent_dir="$(cd "${TOP:-$(pwd)}"/.. && pwd)"
+ fi
+ local found=""
+ for d in "$parent_dir"/apache-hugegraph-server*; do
+ if [ -d "$d" ]; then
+ found="$d"
+ break
+ fi
+ done
+ echo "$found"
+}
diff --git a/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/application.yml b/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/application.yml
index eb8fda4526..4a03a83c4b 100644
--- a/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/application.yml
+++ b/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/application.yml
@@ -39,6 +39,10 @@ grpc:
port: 8686
# The service address of grpc needs to be changed to the actual local IPv4 address when deploying.
host: 127.0.0.1
+# rocksdb:
+# provider: rocksdb
+# option-path: ./conf/rocksdb_pd.yaml
+# open-http: true
server:
# REST service port number
diff --git a/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/rocksdb_pd.yaml b/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/rocksdb_pd.yaml
new file mode 100644
index 0000000000..917b32ef48
--- /dev/null
+++ b/hugegraph-pd/hg-pd-dist/src/assembly/static/conf/rocksdb_pd.yaml
@@ -0,0 +1,162 @@
+#
+# 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.
+#
+# common parameters
+http:
+ # normally parent path of db path
+ document_root: ./library/rocksdb_resource
+ listening_ports: '127.0.0.1:2012'
+ auto_start_http: true
+setenv:
+ StrSimpleEnvNameNotOverwrite: StringValue
+ IntSimpleEnvNameNotOverwrite: 16384
+ OverwriteThisEnv:
+ #comment: overwrite is default to false
+ overwrite: true
+ value: force overwrite this env by overwrite true
+Cache:
+ lru_cache:
+ class: LRUCache
+ params:
+ capacity: 8G
+ num_shard_bits: -1
+ strict_capacity_limit: false
+ high_pri_pool_ratio: 0.5
+ use_adaptive_mutex: false
+ metadata_charge_policy: kFullChargeCacheMetadata
+Statistics:
+ stat:
+ class: default
+ params:
+ discard_tickers:
+ - rocksdb.block.cache
+ - rocksdb.block.cachecompressed
+ - rocksdb.block
+ - rocksdb.memtable.payload.bytes.at.flush
+ - rocksdb.memtable.garbage.bytes.at.flush
+ - rocksdb.txn
+ - rocksdb.blobdb
+ - rocksdb.row.cache
+ - rocksdb.number.block
+ - rocksdb.bloom.filter
+ - rocksdb.persistent
+ - rocksdb.sim.block.cache
+ discard_histograms:
+ # comment: ....
+ - rocksdb.blobdb
+ - rocksdb.bytes.compressed
+ - rocksdb.bytes.decompressed
+ - rocksdb.num.index.and.filter.blocks.read.per.level
+ - rocksdb.num.data.blocks.read.per.level
+ - rocksdb.compression.times.nanos
+ - rocksdb.decompression.times.nanos
+ - rocksdb.read.block.get.micros
+ - rocksdb.write.raw.block.micros
+ # comment end of array
+ #stats_level: kAll
+ stats_level: kDisableAll
+MemTableRepFactory:
+ cspp:
+ class: cspp
+ params:
+ mem_cap: 16G
+ use_vm: false
+ token_use_idle: true
+ chunk_size: 16K
+ convert_to_sst: kFileMmap
+ sync_sst_file: false
+ skiplist:
+ class: SkipList
+ params:
+ lookahead: 0
+TableFactory:
+ cspp_memtab_sst:
+ class: CSPPMemTabTable
+ params: # empty params
+ bb:
+ class: BlockBasedTable
+ params:
+ checksum: kCRC32c
+ block_size: 4K
+ block_restart_interval: 16
+ index_block_restart_interval: 1
+ metadata_block_size: 4K
+ enable_index_compression: true
+ block_cache: "${lru_cache}"
+ readers:
+ BlockBasedTable: bb
+ CSPPMemTabTable: cspp_memtab_sst
+ block_cache_compressed:
+ persistent_cache:
+ filter_policy:
+ dispatch:
+ class: DispatcherTable
+ params:
+ default: bb
+ readers:
+ BlockBasedTable: bb
+ CSPPMemTabTable: cspp_memtab_sst
+ level_writers: [ bb, bb, bb, bb, bb, bb ]
+CFOptions:
+ default:
+ max_write_buffer_number: 6
+ memtable_factory: "${cspp}"
+ write_buffer_size: 128M
+ # set target_file_size_base as small as 512K is to make many SST files,
+ # thus key prefix cache can present efficiency
+ target_file_size_base: 64M
+ target_file_size_multiplier: 1
+ table_factory: dispatch
+ max_bytes_for_level_base: 512M
+ max_bytes_for_level_multiplier: 10
+ level_compaction_dynamic_level_bytes: false
+ level0_slowdown_writes_trigger: 20
+ level0_stop_writes_trigger: 36
+ level0_file_num_compaction_trigger: 2
+ merge_operator: uint64add # support merge
+ level_compaction_dynamic_file_size: true
+ optimize_filters_for_hits: true
+ allow_merge_memtables: true
+ min_write_buffer_number_to_merge: 2
+ compression_per_level:
+ - kNoCompression
+ - kNoCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+DBOptions:
+ log:
+ create_if_missing: true
+ create_missing_column_families: true
+ default:
+ create_if_missing: true
+ create_missing_column_families: false # this is important, must be false to hugegraph
+ max_background_compactions: -1
+ max_subcompactions: 4
+ max_level1_subcompactions: 0
+ inplace_update_support: false
+ WAL_size_limit_MB: 0
+ statistics: "${stat}"
+ max_manifest_file_size: 100M
+ max_background_jobs: 8
+ # WARNING: This profile enables ToplingDB-specific WAL/SST behavior through
+ # convert_to_sst and memtable_as_log_index. After ToplingDB writes data, changing
+ # rocksdb.provider back to rocksdb is not a safe rollback. Restore a complete,
+ # consistent snapshot created before migration; see the ToplingDB design document.
+ compaction_readahead_size: 0
+ memtable_as_log_index: true
diff --git a/hugegraph-server/Dockerfile b/hugegraph-server/Dockerfile
index 5caadd23cb..cd16800fb8 100644
--- a/hugegraph-server/Dockerfile
+++ b/hugegraph-server/Dockerfile
@@ -1,4 +1,3 @@
-# syntax=docker/dockerfile:1
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
@@ -30,11 +29,29 @@ RUN --mount=type=cache,target=/root/.m2 \
mvn package $MAVEN_ARGS -e -B -ntp -Dmaven.test.skip=true -Dmaven.javadoc.skip=true \
&& rm ./hugegraph-server/*.tar.gz ./hugegraph-pd/*.tar.gz ./hugegraph-store/*.tar.gz
-# 2nd stage: runtime env
+# Prepare the optional ToplingDB runtime in a dedicated build target. The
+# regular Maven distribution intentionally excludes lib/topling/**.
+FROM build AS build-topling
+
+RUN apt-get -q update \
+ && apt-get -q install -y --no-install-recommends --no-install-suggests unzip \
+ && rm -rf /var/lib/apt/lists/* \
+ && SERVER_DIR=$(find /pkg/hugegraph-server -maxdepth 1 -type d \
+ -name 'apache-hugegraph-server-*' -print -quit) \
+ && test -n "$SERVER_DIR" \
+ && mkdir -p "$SERVER_DIR/lib/topling" \
+ && cp /pkg/hugegraph-server/hugegraph-dist/src/assembly/static/lib/topling/rocksdbjni*.jar \
+ "$SERVER_DIR/lib/topling/" \
+ && printf '\nrocksdb.provider=topling\n' \
+ >> "$SERVER_DIR/conf/graphs/hugegraph.properties" \
+ && bash -c 'source hugegraph-server/hugegraph-dist/src/assembly/travis/install-rocksdb.sh server' \
+ && sed -i '/^rocksdb\.provider=topling$/d' \
+ "$SERVER_DIR/conf/graphs/hugegraph.properties"
+
+# Shared runtime environment
# Note: ZGC (The Z Garbage Collector) is only supported on ARM-Mac with java > 13
-FROM eclipse-temurin:11-jre-jammy
+FROM eclipse-temurin:11-jre-noble AS runtime
-COPY --from=build /pkg/hugegraph-server/apache-hugegraph-server-*/ /hugegraph-server/
LABEL maintainer="HugeGraph Docker Maintainers "
# TODO: use g1gc or zgc as default
@@ -58,20 +75,46 @@ RUN apt-get -q update \
iproute2 \
vim \
&& apt-get clean \
- && rm -rf /var/lib/apt/lists/* \
- && sed -i "s/^restserver.url.*$/restserver.url=http:\/\/0.0.0.0:8080/g" ./conf/rest-server.properties
+ && rm -rf /var/lib/apt/lists/*
# 2. Init docker script
-COPY hugegraph-server/hugegraph-dist/docker/scripts/remote-connect.groovy ./scripts
-COPY hugegraph-server/hugegraph-dist/docker/scripts/detect-storage.groovy ./scripts
+COPY hugegraph-server/hugegraph-dist/docker/scripts/remote-connect.groovy /opt/hugegraph-docker/
+COPY hugegraph-server/hugegraph-dist/docker/scripts/detect-storage.groovy /opt/hugegraph-docker/
COPY hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh .
RUN chmod 755 ./docker-entrypoint.sh
EXPOSE 8080
-VOLUME /hugegraph-server
HEALTHCHECK --interval=15s --timeout=10s --start-period=90s --retries=3 \
CMD curl -fsS http://localhost:8080/versions >/dev/null
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["./docker-entrypoint.sh"]
+
+# ToplingDB image: contains both providers and selects ToplingDB by default.
+# Build with: docker build --platform linux/amd64 --target topling ...
+FROM runtime AS topling
+
+COPY --from=build-topling /pkg/hugegraph-server/apache-hugegraph-server-*/ /hugegraph-server/
+RUN apt-get -q update \
+ && apt-get -q install -y --no-install-recommends --no-install-suggests \
+ libbz2-1.0 \
+ liblz4-1 \
+ libsnappy1v5 \
+ zlib1g \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/* \
+ && cp /opt/hugegraph-docker/*.groovy ./scripts/ \
+ && sed -i "s/^restserver.url.*$/restserver.url=http:\/\/0.0.0.0:8080/g" \
+ ./conf/rest-server.properties
+ENV HG_SERVER_ROCKSDB_PROVIDER="topling"
+VOLUME /hugegraph-server
+
+# Keep the standard image as the final/default target for existing builds.
+FROM runtime AS standard
+
+COPY --from=build /pkg/hugegraph-server/apache-hugegraph-server-*/ /hugegraph-server/
+RUN cp /opt/hugegraph-docker/*.groovy ./scripts/ \
+ && sed -i "s/^restserver.url.*$/restserver.url=http:\/\/0.0.0.0:8080/g" \
+ ./conf/rest-server.properties
+VOLUME /hugegraph-server
diff --git a/hugegraph-server/hugegraph-core/pom.xml b/hugegraph-server/hugegraph-core/pom.xml
index b2519633a9..70aafa3278 100644
--- a/hugegraph-server/hugegraph-core/pom.xml
+++ b/hugegraph-server/hugegraph-core/pom.xml
@@ -29,7 +29,7 @@
${basedir}/..
- 1.3.11
+ 1.3.14
0.7.4
5.12.1
1.8.1
diff --git a/hugegraph-server/hugegraph-dist/docker/README.md b/hugegraph-server/hugegraph-dist/docker/README.md
index 9214aa830e..a89b07e9db 100644
--- a/hugegraph-server/hugegraph-dist/docker/README.md
+++ b/hugegraph-server/hugegraph-dist/docker/README.md
@@ -27,6 +27,25 @@ Use Docker to quickly start a standalone HugeGraph Server with RocksDB.
- 8080:8080
```
+### ToplingDB image
+
+The same Server Dockerfile has a `topling` target. It copies the checked-in
+ToplingDB JAR into the Server distribution and prepares its native runtime at
+image build time, so starting a container needs no GitHub token or download.
+
+```bash
+docker build --platform linux/amd64 --target topling \
+ -f hugegraph-server/Dockerfile \
+ -t hugegraph/hugegraph:1.8.0-topling .
+docker run -itd --name=graph -p 8080:8080 \
+ hugegraph/hugegraph:1.8.0-topling
+```
+
+The `-topling` image selects ToplingDB by default. Set
+`HG_SERVER_ROCKSDB_PROVIDER=rocksdb` to use the standard RocksDB provider from
+the same image. ToplingDB currently supports only Linux x86-64. Do not switch
+an existing data volume between providers without a supported migration.
+
## 2. Create Sample Graph on Server Startup
To preload sample data on startup, set `PRELOAD=true`.
diff --git a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh
index 4b5dcf5ba7..6d16d56913 100755
--- a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh
+++ b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint-test.sh
@@ -61,6 +61,7 @@ chmod +x "${TEST_HOME}/bin/"*.sh
(
cd "${TEST_HOME}"
HG_SERVER_BACKEND=hstore \
+ HG_SERVER_ROCKSDB_PROVIDER=topling \
HG_SERVER_PD_PEERS=pd:8686 \
HG_SERVER_CLUSTER=hg \
HG_SERVER_USE_PD=true \
@@ -72,6 +73,8 @@ chmod +x "${TEST_HOME}/bin/"*.sh
[[ "$(wc -l < "${TEST_HOME}/docker/init-store-calls")" -eq 1 ]]
grep -qx 'backend=hstore' "${TEST_HOME}/conf/graphs/hugegraph.properties"
+grep -qx 'rocksdb.provider=topling' \
+ "${TEST_HOME}/conf/graphs/hugegraph.properties"
grep -qx 'pd.peers=pd:8686' "${TEST_HOME}/conf/graphs/hugegraph.properties"
grep -qx 'usePD=true' "${TEST_HOME}/conf/rest-server.properties"
grep -qx 'pd.peers=pd:8686' "${TEST_HOME}/conf/rest-server.properties"
@@ -85,6 +88,18 @@ grep -qx 'auth.token_secret=12345678901234567890123456789012' \
grep -qx 'auth.token_secret=12345678901234567890123456789012' \
"${TEST_HOME}/conf/graphs/hugegraph.properties"
+cp "${TEST_HOME}/conf/graphs/hugegraph.properties" \
+ "${TEST_HOME}/conf/graphs/hugegraph.properties.before-invalid-provider"
+if (
+ cd "${TEST_HOME}"
+ HG_SERVER_ROCKSDB_PROVIDER=invalid bash ./docker-entrypoint.sh
+); then
+ echo "invalid RocksDB provider unexpectedly succeeded" >&2
+ exit 1
+fi
+cmp "${TEST_HOME}/conf/graphs/hugegraph.properties.before-invalid-provider" \
+ "${TEST_HOME}/conf/graphs/hugegraph.properties"
+
cp "${TEST_HOME}/conf/rest-server.properties" \
"${TEST_HOME}/conf/rest-server.properties.before-short-secret"
cp "${TEST_HOME}/conf/graphs/hugegraph.properties" \
diff --git a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh
index 295fe1e2eb..138a698e47 100755
--- a/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh
+++ b/hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh
@@ -90,6 +90,13 @@ migrate_env() {
migrate_env "BACKEND" "HG_SERVER_BACKEND"
migrate_env "PD_PEERS" "HG_SERVER_PD_PEERS"
+ROCKSDB_PROVIDER="${HG_SERVER_ROCKSDB_PROVIDER:-}"
+case "${ROCKSDB_PROVIDER}" in
+ "" | rocksdb | topling) ;;
+ *) log "ERROR: HG_SERVER_ROCKSDB_PROVIDER must be rocksdb or topling"
+ exit 1 ;;
+esac
+
if [[ -n "${HG_SERVER_AUTH_TOKEN_SECRET:-}" ]]; then
LC_ALL=C
if (( ${#HG_SERVER_AUTH_TOKEN_SECRET} < 32 )); then
@@ -117,6 +124,8 @@ fi
# ── Map env → properties file ─────────────────────────────────────────
[[ -n "${HG_SERVER_BACKEND:-}" ]] && set_prop "backend" "${HG_SERVER_BACKEND}" "${GRAPH_CONF}"
+[[ -n "${ROCKSDB_PROVIDER}" ]] && \
+ set_prop "rocksdb.provider" "${ROCKSDB_PROVIDER}" "${GRAPH_CONF}"
[[ -n "${HG_SERVER_PD_PEERS:-}" ]] && set_prop "pd.peers" "${HG_SERVER_PD_PEERS}" "${GRAPH_CONF}"
[[ -n "${HG_SERVER_USE_PD:-}" ]] && \
set_prop "usePD" "${HG_SERVER_USE_PD}" "${REST_SERVER_CONF}"
diff --git a/hugegraph-server/hugegraph-dist/pom.xml b/hugegraph-server/hugegraph-dist/pom.xml
index c4575bc877..5c88a931f8 100644
--- a/hugegraph-server/hugegraph-dist/pom.xml
+++ b/hugegraph-server/hugegraph-dist/pom.xml
@@ -112,6 +112,9 @@
${basedir}/src/assembly/static
true
+
+ lib/topling/**
+
${basedir}/src/main/resources
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/bin/common-topling.sh b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/common-topling.sh
new file mode 100644
index 0000000000..4c25725a3d
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/common-topling.sh
@@ -0,0 +1,294 @@
+#!/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.
+#
+set -Eeuo pipefail
+IFS=$'\n\t'
+trap 'echo "[common-topling] error at line ${LINENO}: ${BASH_COMMAND}" >&2' ERR
+
+GITHUB="https://github.com"
+
+function abs_path() {
+ local SOURCE
+ SOURCE="${BASH_SOURCE[0]}"
+ while [[ -h "$SOURCE" ]]; do
+ local DIR
+ DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
+ SOURCE="$(readlink "$SOURCE")"
+ [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
+ done
+ cd -P "$(dirname "$SOURCE")" && pwd
+}
+
+function extract_so_with_jar() {
+ local jar_file="$1"
+ local dest_dir="$2"
+ local abs_jar_path
+
+ if [ ! -f "$jar_file" ]; then
+ echo "'$jar_file' Not Exist" >&2
+ return 1
+ fi
+
+ mkdir -p "$dest_dir" || {
+ echo "Cannot mkdir '$dest_dir'" >&2
+ return 1
+ }
+
+ if command -v realpath >/dev/null 2>&1; then
+ abs_jar_path="$(realpath "$jar_file")"
+ else
+ abs_jar_path="$(readlink -f "$jar_file")"
+ fi
+ if ! command -v unzip >/dev/null 2>&1; then
+ echo "Error: 'unzip' command not found. Please install unzip." >&2
+ return 1
+ fi
+ unzip -j -o "$abs_jar_path" "*.so" -d "$dest_dir" > /dev/null 2>&1 || {
+ local code=$?
+ if [ $code -eq 11 ]; then
+ echo "Error: No .so files found in '$abs_jar_path' (unzip exit 11)" >&2
+ else
+ echo "Error: unzip failed (exit $code) for '$abs_jar_path'" >&2
+ fi
+ return $code
+ }
+}
+
+function extract_html_css_from_jar() {
+ local jar_file="$1"
+ local dest_dir="$2"
+ local abs_jar_path
+ local resource_target="$dest_dir/rocksdb_resource"
+
+ if [ ! -f "$jar_file" ]; then
+ echo "Error: JAR file '$jar_file' does not exist." >&2
+ return 1
+ fi
+
+ mkdir -p "$resource_target" || {
+ echo "Error: Cannot create resource directory '$resource_target'." >&2
+ return 1
+ }
+
+ if command -v realpath >/dev/null 2>&1; then
+ abs_jar_path="$(realpath "$jar_file")"
+ else
+ abs_jar_path="$(readlink -f "$jar_file")"
+ fi
+ if ! command -v unzip >/dev/null 2>&1; then
+ echo "Error: 'unzip' command not found. Please install unzip." >&2
+ return 1
+ fi
+ unzip -j -o "$abs_jar_path" "*.html" "*.css" -d "$resource_target" > /dev/null || {
+ local code=$?
+ if [ $code -eq 11 ]; then
+ echo "Notice: No .html or .css files found in '$jar_file'." >&2
+ return 0
+ else
+ echo "Error: unzip failed with exit code $code" >&2
+ return $code
+ fi
+ }
+
+}
+
+function ensure_libaio_symlink() {
+ local dest_dir="$1"
+ # Keep the Ubuntu 24.04 compatibility link inside the component runtime.
+ # Installation must never require sudo or modify /usr/lib.
+ if [ -f /etc/os-release ]; then
+ . /etc/os-release
+ if [ "${ID:-}" = "ubuntu" ] &&
+ command -v dpkg >/dev/null 2>&1 &&
+ dpkg --compare-versions "${VERSION_ID:-0}" "ge" "24.04" &&
+ [ ! -e /usr/lib/x86_64-linux-gnu/libaio.so.1 ] &&
+ [ -e /usr/lib/x86_64-linux-gnu/libaio.so.1t64 ]; then
+ mkdir -p "$dest_dir"
+ ln -sfn /usr/lib/x86_64-linux-gnu/libaio.so.1t64 \
+ "$dest_dir/libaio.so.1"
+ echo "Prepared component-local libaio.so.1 compatibility link"
+ fi
+ fi
+}
+
+function download_and_verify() {
+ local url=$1
+ local filepath=$2
+ local expected_sha256=$3
+ local actual_sha256
+
+ if [[ -f $filepath ]]; then
+ echo "File $filepath exists. Verifying SHA-256 checksum..."
+ actual_sha256=$(sha256sum "$filepath" | awk '{ print $1 }')
+ if [[ $actual_sha256 != $expected_sha256 ]]; then
+ echo "SHA-256 checksum verification failed for $filepath. Expected: $expected_sha256, but got: $actual_sha256"
+ echo "Deleting $filepath..."
+ rm -f "$filepath"
+ else
+ echo "SHA-256 checksum verification succeeded for $filepath."
+ return 0
+ fi
+ fi
+
+ echo "Downloading $filepath..."
+ curl -fL -o "$filepath" "$url"
+
+ actual_sha256=$(sha256sum "$filepath" | awk '{ print $1 }')
+ if [[ $actual_sha256 != $expected_sha256 ]]; then
+ echo "SHA-256 checksum verification failed for $filepath after download. Expected: $expected_sha256, but got: $actual_sha256"
+ return 1
+ fi
+
+ return 0
+}
+
+function download_and_setup_jemalloc() {
+ local arch lib_file download_url expected_sha256 system_lib top
+ top=$1
+
+ if [[ "${LD_PRELOAD:-}" == *"libjemalloc"* ]]; then
+ return 0
+ fi
+
+ # Prefer system-installed jemalloc if available
+ # Try ldconfig first to locate the shared object
+ if command -v ldconfig >/dev/null 2>&1; then
+ system_lib=$(ldconfig -p 2>/dev/null | awk '/jemalloc/{print $4}' | head -n1)
+ fi
+ # Fallback to common library paths if ldconfig is not available or found nothing
+ if [[ -z "$system_lib" ]]; then
+ for p in \
+ /usr/lib/libjemalloc.so \
+ /usr/lib/libjemalloc.so.2 \
+ /usr/lib64/libjemalloc.so \
+ /usr/lib64/libjemalloc.so.2 \
+ /usr/local/lib/libjemalloc.so \
+ /usr/local/lib/libjemalloc.so.2 \
+ /usr/lib/x86_64-linux-gnu/libjemalloc.so \
+ /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 \
+ /usr/lib/aarch64-linux-gnu/libjemalloc.so \
+ /usr/lib/aarch64-linux-gnu/libjemalloc.so.2; do
+ if [[ -f "$p" ]]; then
+ system_lib="$p"
+ break
+ fi
+ done
+ fi
+
+ # If found, set LD_PRELOAD and return immediately
+ if [[ -n "$system_lib" ]]; then
+ export LD_PRELOAD="${system_lib}${LD_PRELOAD:+:$LD_PRELOAD}"
+ return 0
+ fi
+
+ # Detect system architecture
+ arch=$(uname -m)
+
+ # System jemalloc not found, try to download the correct library for the architecture
+ # Checksums match apache/hugegraph-doc@567625c6ec66907fc60f1864146fbec91b5f6204.
+ if [[ $arch == "aarch64" || $arch == "arm64" ]]; then
+ lib_file="$top/bin/libjemalloc_aarch64.so"
+ download_url="${GITHUB}/apache/hugegraph-doc/raw/binary-1.5/dist/server/libjemalloc_aarch64.so"
+ expected_sha256="6b7e6099b6da798829c6ce6fcb55a787508841edd52446332a73300889dcd1dc"
+ elif [[ $arch == "x86_64" ]]; then
+ lib_file="$top/bin/libjemalloc.so"
+ download_url="${GITHUB}/apache/hugegraph-doc/raw/binary-1.5/dist/server/libjemalloc.so"
+ expected_sha256="53b25e8626e1605cbd8b60befb3431cabc1b8851a54285e0dda412796feab67d"
+ else
+ echo "Unsupported architecture: $arch"
+ return 1
+ fi
+
+ # Download and verify jemalloc library (fallback when system lib not found)
+ if download_and_verify "$download_url" "$lib_file" "$expected_sha256"; then
+ export LD_PRELOAD="${lib_file}${LD_PRELOAD:+:$LD_PRELOAD}"
+ else
+ echo "Failed to verify or download jemalloc for $arch, skipping"
+ return 1
+ fi
+}
+
+function require_topling_platform() {
+ local os_name machine_arch
+
+ os_name="$(uname -s)"
+ machine_arch="$(uname -m)"
+ if [ "$os_name" != "Linux" ] ||
+ [[ "$machine_arch" != "x86_64" ]]; then
+ printf 'Error: ToplingDB native runtime supports Linux x86_64 only; ' >&2
+ printf 'current platform is %s/%s\n' "$os_name" "$machine_arch" >&2
+ return 1
+ fi
+}
+
+function prepare_toplingdb() {
+ local lib_dir="$1"
+ local dest_dir="$2"
+ local top_override="${3:-}"
+
+ require_topling_platform || return 1
+
+ local top
+ if [ -n "$top_override" ]; then
+ top="$top_override"
+ else
+ top="$(cd "$lib_dir"/../ && pwd)" || {
+ echo "Error: failed to resolve the ToplingDB installation directory" >&2
+ return 1
+ }
+ fi
+
+ local jar_file
+ jar_file=$(ls -1 "$lib_dir"/rocksdbjni*.jar 2>/dev/null | sort -V | tail -n1 || true)
+ if [ -z "${jar_file:-}" ]; then
+ echo "Error: No rocksdbjni*.jar found under '$lib_dir'" >&2
+ return 1
+ fi
+
+ ensure_libaio_symlink "$dest_dir"
+ if ! download_and_setup_jemalloc "$top"; then
+ echo "Warning: jemalloc is unavailable; continuing without it" >&2
+ fi
+ extract_so_with_jar "$jar_file" "$dest_dir"
+ if [ -d "$dest_dir" ]; then
+ if [[ ":${LD_LIBRARY_PATH:-}:" != *":$dest_dir:"* ]]; then
+ export LD_LIBRARY_PATH="$dest_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+ fi
+
+ if [ -f "$dest_dir/librocksdbjni-linux64.so" ] && [[ ":${LD_PRELOAD:-}:" != *"librocksdbjni-linux64.so:"* ]]; then
+ export LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$dest_dir/librocksdbjni-linux64.so"
+ fi
+
+ # Persist environment for subsequent GitHub Actions steps
+ # so LD_* variables survive across separate run blocks.
+ if [ -n "${GITHUB_ENV:-}" ] && [ -w "$GITHUB_ENV" ]; then
+ {
+ echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
+ echo "LD_PRELOAD=$LD_PRELOAD"
+ if [ -n "${SERVER_VERSION_DIR:-}" ]; then
+ echo "SERVER_VERSION_DIR=$SERVER_VERSION_DIR"
+ fi
+ } >> "$GITHUB_ENV" || true
+ echo "[common-topling] Exported LD_LIBRARY_PATH and LD_PRELOAD to GITHUB_ENV" >&2 || true
+ fi
+ else
+ echo "Warn: LD paths skipped, directory '$dest_dir' does not exist." >&2
+ fi
+ if ! extract_html_css_from_jar "$jar_file" "$dest_dir"; then
+ echo "Warning: failed to extract optional ToplingDB web resources; continuing" >&2
+ fi
+}
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/bin/init-store.sh b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/init-store.sh
index 74ec0bb731..d2f4e398e6 100755
--- a/hugegraph-server/hugegraph-dist/src/assembly/static/bin/init-store.sh
+++ b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/init-store.sh
@@ -48,10 +48,15 @@ cd "${TOP}" || exit
DEFAULT_JAVA_OPTIONS="--add-exports=java.base/jdk.internal.reflect=ALL-UNNAMED"
+source "$BIN/preload-topling.sh"
+
echo "Initializing HugeGraph Store..."
# Build classpath with hugegraph*.jar first to avoid class loading conflicts
CP=$(find -L "${LIB}" -name 'hugegraph*.jar' | sort | tr '\n' ':')
+if [ -n "${TOPLING_RUNTIME_CLASSPATH:-}" ]; then
+ CP="$TOPLING_RUNTIME_CLASSPATH:$CP"
+fi
CP="$CP":$(find -L "${LIB}" -name '*.jar' \! -name 'hugegraph*' | sort | tr '\n' ':')
CP="$CP":$(find -L "${PLUGINS}" -name '*.jar' | sort | tr '\n' ':')
$JAVA -cp $CP ${DEFAULT_JAVA_OPTIONS} \
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/bin/preload-topling.sh b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/preload-topling.sh
new file mode 100644
index 0000000000..5b0b0735b6
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/preload-topling.sh
@@ -0,0 +1,222 @@
+#!/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.
+#
+
+ORIG_SHELL_FLAGS="$-"
+ORIG_PIPEFAIL="$(set -o | awk '$1 == "pipefail" { print $2 }')"
+ORIG_ERR_TRAP="$(trap -p ERR)"
+# Save original IFS to avoid leaking into parent shell when sourced
+ORIG_IFS="${IFS}"
+set -Eeuo pipefail
+IFS=$'\n\t'
+# Unified error capture for easy positioning
+trap 'echo "[preload-topling] error at line ${LINENO}: ${BASH_COMMAND}" >&2' ERR
+
+SERVER_BIN="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+SERVER_TOP="$(cd "$SERVER_BIN"/../ && pwd)"
+SERVER_LIB="$SERVER_TOP/lib"
+COMPONENT_TOP="${TOPLING_COMPONENT_TOP:-$SERVER_TOP}"
+USE_SERVER_CLASSPATH="${TOPLING_USE_SERVER_CLASSPATH:-true}"
+DEST_DIR="$COMPONENT_TOP/library"
+
+case "$USE_SERVER_CLASSPATH" in
+ true | false) ;;
+ *)
+ echo "Error: TOPLING_USE_SERVER_CLASSPATH must be true or false" >&2
+ exit 1
+ ;;
+esac
+
+detect_rocksdb_provider() {
+ local conf_dir="$1"
+ local file
+ local -a values=()
+ local -a unique_values=()
+ local value key conflicts
+ local -A seen=()
+
+ for file in "$conf_dir"/graphs/*.properties; do
+ [ -f "$file" ] || continue
+ mapfile -t -O "${#values[@]}" values < <(
+ awk '
+ /^[[:space:]]*#/ { next }
+ /^[[:space:]]*rocksdb\.provider[[:space:]]*=/ {
+ value = $0
+ sub(/^[^=]*=[[:space:]]*/, "", value)
+ sub(/[[:space:]]+#.*/, "", value)
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
+ print value
+ }
+ ' "$file"
+ )
+ done
+ for file in "$conf_dir"/application*.yml; do
+ [ -f "$file" ] || continue
+ mapfile -t -O "${#values[@]}" values < <(
+ awk '
+ /^[[:space:]]*#/ || /^[[:space:]]*$/ { next }
+ /^[^[:space:]#][^:]*:/ {
+ in_rocksdb = ($0 ~ /^rocksdb[[:space:]]*:/)
+ }
+ in_rocksdb && /^[[:space:]]+provider[[:space:]]*:/ {
+ value = $0
+ sub(/^[^:]*:[[:space:]]*/, "", value)
+ sub(/[[:space:]]+#.*/, "", value)
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
+ if (value ~ /^"[^"]*"$/ || value ~ /^'\''[^'\'']*'\''$/) {
+ value = substr(value, 2, length(value) - 2)
+ }
+ print value
+ }
+ ' "$file"
+ )
+ done
+
+ for value in "${values[@]}"; do
+ key="provider:$value"
+ if [ -z "${seen[$key]:-}" ]; then
+ unique_values+=("$value")
+ seen[$key]=true
+ fi
+ done
+
+ if [ "${#unique_values[@]}" -gt 1 ]; then
+ conflicts=$(IFS=,; echo "${unique_values[*]}")
+ echo "Error: conflicting rocksdb.provider values: $conflicts" >&2
+ return 1
+ fi
+ local provider="${unique_values[0]:-rocksdb}"
+ case "$provider" in
+ rocksdb | topling)
+ echo "$provider"
+ ;;
+ *)
+ echo "Error: invalid rocksdb.provider '$provider'; expected rocksdb or topling" >&2
+ return 1
+ ;;
+ esac
+}
+
+PROVIDER=$(detect_rocksdb_provider "$COMPONENT_TOP/conf") || exit 1
+
+remove_path_entry() {
+ local value="${1:-}"
+ local remove="${2:-}"
+ local entry result=""
+ local path_ifs="$IFS"
+ IFS=:
+ for entry in $value; do
+ [ -n "$entry" ] && [ "$entry" != "$remove" ] || continue
+ result="${result:+$result:}$entry"
+ done
+ IFS="$path_ifs"
+ echo "$result"
+}
+
+# A parent launcher may start multiple components from one shell. Remove only
+# the runtime entry previously selected by this helper before selecting ours.
+if [ -n "${TOPLING_ACTIVE_NATIVE:-}" ]; then
+ LD_PRELOAD=$(remove_path_entry "${LD_PRELOAD:-}" "$TOPLING_ACTIVE_NATIVE")
+ LD_LIBRARY_PATH=$(remove_path_entry "${LD_LIBRARY_PATH:-}" \
+ "$(dirname "$TOPLING_ACTIVE_NATIVE")")
+ export LD_PRELOAD LD_LIBRARY_PATH
+fi
+if [ -n "${TOPLING_ACTIVE_JAR:-}" ]; then
+ CLASSPATH=$(remove_path_entry "${CLASSPATH:-}" "$TOPLING_ACTIVE_JAR")
+ export CLASSPATH
+fi
+unset TOPLING_ACTIVE_NATIVE TOPLING_ACTIVE_JAR TOPLING_RUNTIME_CLASSPATH
+
+if [ "$PROVIDER" = "topling" ]; then
+ # Runtime selection is read-only. Installation prepares all files beforehand.
+ if [ "$(uname -s)" != "Linux" ] || [ "$(uname -m)" != "x86_64" ]; then
+ echo "Error: ToplingDB runtime supports Linux x86_64 only" >&2
+ exit 1
+ fi
+ TOPLING_JAR=""
+ if [ "$USE_SERVER_CLASSPATH" = "true" ]; then
+ TOPLING_JAR=$(ls -1 "$SERVER_LIB"/topling/rocksdbjni*.jar 2>/dev/null |
+ sort -V | tail -1 || true)
+ if [ -z "$TOPLING_JAR" ]; then
+ echo "Error: no prepared ToplingDB JAR found in $SERVER_LIB/topling/" >&2
+ exit 1
+ fi
+ fi
+
+ CONF_FILE="${TOPLINGDB_EASY_MIGRATE_CONF:-}"
+ if [ -z "$CONF_FILE" ]; then
+ CONF_FILE="$COMPONENT_TOP/conf/toplingdb.yaml"
+ if [ ! -f "$CONF_FILE" ]; then
+ CONF_FILE="$COMPONENT_TOP/conf/rocksdb_store.yaml"
+ fi
+ if [ ! -f "$CONF_FILE" ]; then
+ CONF_FILE="$COMPONENT_TOP/conf/rocksdb_pd.yaml"
+ fi
+ fi
+ if [ ! -f "$CONF_FILE" ]; then
+ echo "Error: required ToplingDB Easy Migrate config not found: $CONF_FILE" >&2
+ exit 1
+ fi
+ if [ ! -r "$CONF_FILE" ]; then
+ echo "Error: ToplingDB Easy Migrate config is not readable: $CONF_FILE" >&2
+ exit 1
+ fi
+ export TOPLINGDB_EASY_MIGRATE_CONF="$CONF_FILE"
+ echo "[preload-topling] TOPLINGDB_EASY_MIGRATE_CONF=$CONF_FILE"
+ NATIVE_LIBRARY="$DEST_DIR/librocksdbjni-linux64.so"
+ if [ ! -r "$NATIVE_LIBRARY" ]; then
+ echo "Error: prepared ToplingDB native library not found: $NATIVE_LIBRARY" >&2
+ echo " Run install-rocksdb.sh for this component before startup." >&2
+ exit 1
+ fi
+ export LD_LIBRARY_PATH="$DEST_DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+ if command -v ldd >/dev/null 2>&1 &&
+ ldd "$NATIVE_LIBRARY" 2>/dev/null | grep -q 'not found'; then
+ echo "Error: ToplingDB native library has unresolved system dependencies" >&2
+ echo " Install them during package/deployment preparation." >&2
+ exit 1
+ fi
+
+ export LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$NATIVE_LIBRARY"
+ export TOPLING_ACTIVE_NATIVE="$NATIVE_LIBRARY"
+ if [ "$USE_SERVER_CLASSPATH" = "true" ]; then
+ export TOPLING_RUNTIME_CLASSPATH="$TOPLING_JAR"
+ export CLASSPATH="$TOPLING_JAR${CLASSPATH:+:$CLASSPATH}"
+ export TOPLING_ACTIVE_JAR="$TOPLING_JAR"
+ fi
+else
+ echo "[preload-topling] Component uses rocksdb provider"
+fi
+
+unset -f detect_rocksdb_provider remove_path_entry
+
+# Restore original IFS
+IFS="$ORIG_IFS"
+if [ -n "$ORIG_ERR_TRAP" ]; then
+ eval "$ORIG_ERR_TRAP"
+else
+ trap - ERR
+fi
+# Restore shell options to their state before this script was sourced
+case "$ORIG_SHELL_FLAGS" in *e*) set -e ;; *) set +e ;; esac
+case "$ORIG_SHELL_FLAGS" in *u*) set -u ;; *) set +u ;; esac
+case "$ORIG_SHELL_FLAGS" in *E*) set -E ;; *) set +E ;; esac
+if [ "$ORIG_PIPEFAIL" = "on" ]; then
+ set -o pipefail
+else
+ set +o pipefail
+fi
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/bin/start-hugegraph.sh b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/start-hugegraph.sh
index 2c99238327..56986ee5a9 100644
--- a/hugegraph-server/hugegraph-dist/src/assembly/static/bin/start-hugegraph.sh
+++ b/hugegraph-server/hugegraph-dist/src/assembly/static/bin/start-hugegraph.sh
@@ -99,6 +99,8 @@ if [[ $PRELOAD == "true" ]]; then
sed -i -e '/registerBackends/d; /serverStarted/d' "${SCRIPTS}/${EXAMPLE_SCRIPT}"
fi
+source "$BIN/preload-topling.sh"
+
if [[ $DAEMON == "true" ]]; then
echo "Starting HugeGraphServer in daemon mode..."
"${BIN}"/hugegraph-server.sh "${CONF}/${GREMLIN_SERVER_CONF}" "${CONF}"/rest-server.properties \
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
index 26adfe0183..f424cdb1f8 100644
--- a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
+++ b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
@@ -43,6 +43,10 @@ search.text_analyzer_mode=INDEX
# rocksdb backend config
#rocksdb.data_path=/path/to/disk
#rocksdb.wal_path=/path/to/disk
+# To enable ToplingDB: uncomment the line below (requires ToplingDB JAR in lib/topling/)
+# The startup script detects this setting and handles JAR swap + env var setup automatically.
+# ToplingDB config: conf/toplingdb.yaml (auto-loaded via TOPLINGDB_EASY_MIGRATE_CONF env var)
+#rocksdb.provider=topling
# hbase backend config
#hbase.hosts=localhost
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/toplingdb.yaml b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/toplingdb.yaml
new file mode 100644
index 0000000000..1bf56910c6
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/toplingdb.yaml
@@ -0,0 +1,162 @@
+#
+# 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.
+#
+# common parameters
+http:
+ # normally parent path of db path
+ document_root: ./library/rocksdb_resource
+ listening_ports: '127.0.0.1:2011'
+ auto_start_http: true
+setenv:
+ StrSimpleEnvNameNotOverwrite: StringValue
+ IntSimpleEnvNameNotOverwrite: 16384
+ OverwriteThisEnv:
+ #comment: overwrite is default to false
+ overwrite: true
+ value: force overwrite this env by overwrite true
+Cache:
+ lru_cache:
+ class: LRUCache
+ params:
+ capacity: 8G
+ num_shard_bits: -1
+ strict_capacity_limit: false
+ high_pri_pool_ratio: 0.5
+ use_adaptive_mutex: false
+ metadata_charge_policy: kFullChargeCacheMetadata
+Statistics:
+ stat:
+ class: default
+ params:
+ discard_tickers:
+ - rocksdb.block.cache
+ - rocksdb.block.cachecompressed
+ - rocksdb.block
+ - rocksdb.memtable.payload.bytes.at.flush
+ - rocksdb.memtable.garbage.bytes.at.flush
+ - rocksdb.txn
+ - rocksdb.blobdb
+ - rocksdb.row.cache
+ - rocksdb.number.block
+ - rocksdb.bloom.filter
+ - rocksdb.persistent
+ - rocksdb.sim.block.cache
+ discard_histograms:
+ # comment: ....
+ - rocksdb.blobdb
+ - rocksdb.bytes.compressed
+ - rocksdb.bytes.decompressed
+ - rocksdb.num.index.and.filter.blocks.read.per.level
+ - rocksdb.num.data.blocks.read.per.level
+ - rocksdb.compression.times.nanos
+ - rocksdb.decompression.times.nanos
+ - rocksdb.read.block.get.micros
+ - rocksdb.write.raw.block.micros
+ # comment end of array
+ #stats_level: kAll
+ stats_level: kDisableAll
+MemTableRepFactory:
+ cspp:
+ class: cspp
+ params:
+ mem_cap: 16G
+ use_vm: false
+ token_use_idle: true
+ chunk_size: 16K
+ convert_to_sst: kFileMmap
+ sync_sst_file: false
+ skiplist:
+ class: SkipList
+ params:
+ lookahead: 0
+TableFactory:
+ cspp_memtab_sst:
+ class: CSPPMemTabTable
+ params: # empty params
+ bb:
+ class: BlockBasedTable
+ params:
+ checksum: kCRC32c
+ block_size: 4K
+ block_restart_interval: 16
+ index_block_restart_interval: 1
+ metadata_block_size: 4K
+ enable_index_compression: true
+ block_cache: "${lru_cache}"
+ readers:
+ BlockBasedTable: bb
+ CSPPMemTabTable: cspp_memtab_sst
+ block_cache_compressed:
+ persistent_cache:
+ filter_policy:
+ dispatch:
+ class: DispatcherTable
+ params:
+ default: bb
+ readers:
+ BlockBasedTable: bb
+ CSPPMemTabTable: cspp_memtab_sst
+ level_writers: [ bb, bb, bb, bb, bb, bb ]
+CFOptions:
+ default:
+ max_write_buffer_number: 6
+ memtable_factory: "${cspp}"
+ write_buffer_size: 128M
+ # set target_file_size_base as small as 512K is to make many SST files,
+ # thus key prefix cache can present efficiency
+ target_file_size_base: 64M
+ target_file_size_multiplier: 1
+ table_factory: dispatch
+ max_bytes_for_level_base: 512M
+ max_bytes_for_level_multiplier: 10
+ level_compaction_dynamic_level_bytes: false
+ level0_slowdown_writes_trigger: 20
+ level0_stop_writes_trigger: 36
+ level0_file_num_compaction_trigger: 2
+ merge_operator: uint64add # support merge
+ level_compaction_dynamic_file_size: true
+ optimize_filters_for_hits: true
+ allow_merge_memtables: true
+ min_write_buffer_number_to_merge: 2
+ compression_per_level:
+ - kNoCompression
+ - kNoCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+DBOptions:
+ log:
+ create_if_missing: true
+ create_missing_column_families: true
+ default:
+ create_if_missing: true
+ create_missing_column_families: false # this is important, must be false to hugegraph
+ max_background_compactions: -1
+ max_subcompactions: 4
+ max_level1_subcompactions: 0
+ inplace_update_support: false
+ WAL_size_limit_MB: 0
+ statistics: "${stat}"
+ max_manifest_file_size: 100M
+ max_background_jobs: 8
+ # WARNING: This profile enables ToplingDB-specific WAL/SST behavior through
+ # convert_to_sst and memtable_as_log_index. After ToplingDB writes data, changing
+ # rocksdb.provider back to rocksdb is not a safe rollback. Restore a complete,
+ # consistent snapshot created before migration; see the ToplingDB design document.
+ compaction_readahead_size: 0
+ memtable_as_log_index: true
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/static/lib/topling/rocksdbjni-8.10.2-20260725.141011-1.jar b/hugegraph-server/hugegraph-dist/src/assembly/static/lib/topling/rocksdbjni-8.10.2-20260725.141011-1.jar
new file mode 100644
index 0000000000..61c401bb01
Binary files /dev/null and b/hugegraph-server/hugegraph-dist/src/assembly/static/lib/topling/rocksdbjni-8.10.2-20260725.141011-1.jar differ
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/RocksDBRuntimeSmokeTest.java b/hugegraph-server/hugegraph-dist/src/assembly/travis/RocksDBRuntimeSmokeTest.java
new file mode 100644
index 0000000000..a381b5513e
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/RocksDBRuntimeSmokeTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.rocksdb.ColumnFamilyDescriptor;
+import org.rocksdb.ColumnFamilyHandle;
+import org.rocksdb.ColumnFamilyOptions;
+import org.rocksdb.DBOptions;
+import org.rocksdb.Options;
+import org.rocksdb.RocksDB;
+
+public final class RocksDBRuntimeSmokeTest {
+
+ private static final byte[] CF = bytes("runtime-smoke");
+ private static final byte[] KEY = bytes("key");
+ private static final byte[] VALUE = bytes("value-before-restart");
+ private static final byte[] RECREATED_VALUE = bytes("value-after-recreate");
+
+ public static void main(String[] args) throws Exception {
+ if (args.length != 3) {
+ throw new IllegalArgumentException(
+ "Usage: ");
+ }
+
+ String provider = args[0];
+ String dbPath = args[1];
+ String expectedNativePath = args[2];
+ verifyProvider(provider);
+ RocksDB.loadLibrary();
+ verifyNativeLibrary(expectedNativePath);
+
+ createAndWrite(dbPath);
+ reopenDropAndRecreate(dbPath);
+ System.out.printf("Runtime smoke test passed: provider=%s, version=%s%n",
+ provider, RocksDB.rocksdbVersion());
+ }
+
+ private static void verifyProvider(String provider) {
+ boolean hasToplingApi;
+ try {
+ Class.forName("org.rocksdb.SidePluginRepo");
+ hasToplingApi = true;
+ } catch (ClassNotFoundException ignored) {
+ hasToplingApi = false;
+ }
+
+ if (!"rocksdb".equals(provider) && !"topling".equals(provider)) {
+ throw new IllegalArgumentException("Unsupported provider: " + provider);
+ }
+ if ("rocksdb".equals(provider) && hasToplingApi) {
+ throw new IllegalStateException("Standard provider loaded a Topling JAR");
+ }
+ if ("topling".equals(provider) && !hasToplingApi) {
+ throw new IllegalStateException("Topling provider loaded no Topling API");
+ }
+ }
+
+ private static void verifyNativeLibrary(String expectedNativePath)
+ throws Exception {
+ if ("none".equals(expectedNativePath)) {
+ return;
+ }
+ String maps = new String(Files.readAllBytes(Paths.get("/proc/self/maps")),
+ StandardCharsets.UTF_8);
+ String absolutePath = Paths.get(expectedNativePath).toAbsolutePath()
+ .normalize().toString();
+ if (!maps.contains(absolutePath)) {
+ throw new IllegalStateException("Expected native library is not mapped: " +
+ absolutePath);
+ }
+ for (String line : maps.split("\\R")) {
+ if (line.contains("librocksdbjni") && !line.contains(absolutePath)) {
+ throw new IllegalStateException(
+ "An unexpected RocksDB JNI library is also mapped: " + line);
+ }
+ }
+ System.out.println("Verified native library: " + absolutePath);
+ }
+
+ private static void createAndWrite(String dbPath) throws Exception {
+ try (Options options = new Options().setCreateIfMissing(true);
+ RocksDB db = RocksDB.open(options, dbPath);
+ ColumnFamilyOptions cfOptions = new ColumnFamilyOptions();
+ ColumnFamilyHandle handle = db.createColumnFamily(
+ new ColumnFamilyDescriptor(CF, cfOptions))) {
+ db.put(handle, KEY, VALUE);
+ assertBytes(VALUE, db.get(handle, KEY), "initial read");
+ }
+ }
+
+ private static void reopenDropAndRecreate(String dbPath) throws Exception {
+ List descriptors = new ArrayList<>();
+ try (Options options = new Options()) {
+ for (byte[] name : RocksDB.listColumnFamilies(options, dbPath)) {
+ descriptors.add(new ColumnFamilyDescriptor(name));
+ }
+ }
+
+ List handles = new ArrayList<>();
+ RocksDB db = null;
+ try (DBOptions options = new DBOptions().setCreateIfMissing(false)) {
+ db = RocksDB.open(options, dbPath, descriptors, handles);
+ ColumnFamilyHandle smoke = findHandle(descriptors, handles, CF);
+ assertBytes(VALUE, db.get(smoke, KEY), "read after reopen");
+ db.dropColumnFamily(smoke);
+ handles.remove(smoke);
+ smoke.close();
+
+ try (ColumnFamilyOptions cfOptions = new ColumnFamilyOptions();
+ ColumnFamilyHandle recreated = db.createColumnFamily(
+ new ColumnFamilyDescriptor(CF, cfOptions))) {
+ db.put(recreated, KEY, RECREATED_VALUE);
+ assertBytes(RECREATED_VALUE, db.get(recreated, KEY),
+ "read after CF recreation");
+ }
+ } finally {
+ for (ColumnFamilyHandle handle : handles) {
+ handle.close();
+ }
+ if (db != null) {
+ db.close();
+ }
+ }
+ }
+
+ private static ColumnFamilyHandle findHandle(
+ List descriptors,
+ List handles,
+ byte[] name) {
+ for (int i = 0; i < descriptors.size(); i++) {
+ if (Arrays.equals(name, descriptors.get(i).getName())) {
+ return handles.get(i);
+ }
+ }
+ throw new IllegalStateException("Column family was not reopened");
+ }
+
+ private static void assertBytes(byte[] expected, byte[] actual,
+ String operation) {
+ if (!Arrays.equals(expected, actual)) {
+ throw new AssertionError(operation + " returned unexpected data");
+ }
+ }
+
+ private static byte[] bytes(String value) {
+ return value.getBytes(StandardCharsets.UTF_8);
+ }
+
+ private RocksDBRuntimeSmokeTest() {
+ }
+}
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/install-deps.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/install-deps.sh
new file mode 100755
index 0000000000..c5719254a4
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/install-deps.sh
@@ -0,0 +1,24 @@
+#!/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.
+#
+set -ev
+
+if [ -f /etc/debian_version ]; then
+ sudo apt-get update && sudo apt-get install -y liburing-dev libaio-dev libjemalloc-dev
+elif [ -f /etc/redhat-release ]; then
+ sudo yum install -y liburing-devel libaio-devel jemalloc-devel
+fi
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/install-rocksdb.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/install-rocksdb.sh
new file mode 100755
index 0000000000..d57f379ad6
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/install-rocksdb.sh
@@ -0,0 +1,195 @@
+#!/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.
+#
+
+if [ "$(uname -s)" != "Linux" ]; then
+ echo "[install-rocksdb] Skip native preload on non-Linux platform: $(uname -s)"
+ return 0 2>/dev/null || exit 0
+fi
+
+ORIG_SHELL_FLAGS="$-"
+ORIG_PIPEFAIL="$(set -o | awk '$1 == "pipefail" { print $2 }')"
+ORIG_ERR_TRAP="$(trap -p ERR)"
+ORIG_EXIT_TRAP="$(trap -p EXIT)"
+# Save original IFS to avoid leaking into parent shell when sourced
+ORIG_IFS="${IFS}"
+set -Eeuo pipefail
+IFS=$'\n\t'
+
+install_rocksdb_restore_state() {
+ local exit_status=$?
+
+ # Prevent recursive execution while restoring the caller's EXIT trap.
+ trap - EXIT
+ IFS="$ORIG_IFS"
+ if [ -n "$ORIG_ERR_TRAP" ]; then
+ eval "$ORIG_ERR_TRAP"
+ else
+ trap - ERR
+ fi
+ if [ -n "$ORIG_EXIT_TRAP" ]; then
+ eval "$ORIG_EXIT_TRAP"
+ else
+ trap - EXIT
+ fi
+ case "$ORIG_SHELL_FLAGS" in *e*) set -e ;; *) set +e ;; esac
+ case "$ORIG_SHELL_FLAGS" in *u*) set -u ;; *) set +u ;; esac
+ case "$ORIG_SHELL_FLAGS" in *E*) set -E ;; *) set +E ;; esac
+ if [ "$ORIG_PIPEFAIL" = "on" ]; then
+ set -o pipefail
+ else
+ set +o pipefail
+ fi
+ return "$exit_status"
+}
+trap install_rocksdb_restore_state EXIT
+
+# Unified error capture for easy positioning
+trap 'echo "[install-rocksdb] error at line ${LINENO}: ${BASH_COMMAND}" >&2' ERR
+
+VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+COMPONENT="${1:-server}"
+SERVER_VERSION_DIR="$(pwd)/hugegraph-server/apache-hugegraph-server-$VERSION"
+SERVER_BIN="$SERVER_VERSION_DIR/bin"
+SERVER_LIB="$SERVER_VERSION_DIR/lib"
+
+case "$COMPONENT" in
+ server | hstore)
+ COMPONENT_VERSION_DIR="$SERVER_VERSION_DIR"
+ ;;
+ pd)
+ COMPONENT_VERSION_DIR="$(pwd)/hugegraph-pd/apache-hugegraph-pd-$VERSION"
+ ;;
+ store)
+ COMPONENT_VERSION_DIR="$(pwd)/hugegraph-store/apache-hugegraph-store-$VERSION"
+ ;;
+ *)
+ echo "Error: unsupported component '$COMPONENT' (expected server, pd, store, or hstore)" >&2
+ exit 1
+ ;;
+esac
+INSTALL_DEST_DIR="$COMPONENT_VERSION_DIR/library"
+
+if [ ! -d "$SERVER_VERSION_DIR" ]; then
+ echo "Error: SERVER_VERSION_DIR not found: $SERVER_VERSION_DIR" >&2
+ exit 1
+fi
+if [ ! -d "$SERVER_LIB" ]; then
+ echo "Error: SERVER_LIB dir not found: $SERVER_LIB" >&2
+ exit 1
+fi
+if [ ! -d "$COMPONENT_VERSION_DIR" ]; then
+ echo "Error: component dir not found: $COMPONENT_VERSION_DIR" >&2
+ exit 1
+fi
+
+detect_rocksdb_provider() {
+ local conf_dir="$1"
+ local file
+ local -a values=()
+ local -a unique_values=()
+ local value key conflicts
+ local -A seen=()
+
+ for file in "$conf_dir"/graphs/*.properties; do
+ [ -f "$file" ] || continue
+ mapfile -t -O "${#values[@]}" values < <(
+ awk '
+ /^[[:space:]]*#/ { next }
+ /^[[:space:]]*rocksdb\.provider[[:space:]]*=/ {
+ value = $0
+ sub(/^[^=]*=[[:space:]]*/, "", value)
+ sub(/[[:space:]]+#.*/, "", value)
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
+ print value
+ }
+ ' "$file"
+ )
+ done
+ for file in "$conf_dir"/application*.yml; do
+ [ -f "$file" ] || continue
+ mapfile -t -O "${#values[@]}" values < <(
+ awk '
+ /^[[:space:]]*#/ || /^[[:space:]]*$/ { next }
+ /^[^[:space:]#][^:]*:/ {
+ in_rocksdb = ($0 ~ /^rocksdb[[:space:]]*:/)
+ }
+ in_rocksdb && /^[[:space:]]+provider[[:space:]]*:/ {
+ value = $0
+ sub(/^[^:]*:[[:space:]]*/, "", value)
+ sub(/[[:space:]]+#.*/, "", value)
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
+ if (value ~ /^"[^"]*"$/ || value ~ /^'\''[^'\'']*'\''$/) {
+ value = substr(value, 2, length(value) - 2)
+ }
+ print value
+ }
+ ' "$file"
+ )
+ done
+
+ for value in "${values[@]}"; do
+ key="provider:$value"
+ if [ -z "${seen[$key]:-}" ]; then
+ unique_values+=("$value")
+ seen[$key]=true
+ fi
+ done
+
+ if [ "${#unique_values[@]}" -gt 1 ]; then
+ conflicts=$(IFS=,; echo "${unique_values[*]}")
+ echo "Error: conflicting rocksdb.provider values: $conflicts" >&2
+ return 1
+ fi
+ local provider="${unique_values[0]:-rocksdb}"
+ case "$provider" in
+ rocksdb | topling)
+ echo "$provider"
+ ;;
+ *)
+ echo "Error: invalid rocksdb.provider '$provider'; expected rocksdb or topling" >&2
+ return 1
+ ;;
+ esac
+}
+
+PROVIDER=$(detect_rocksdb_provider "$COMPONENT_VERSION_DIR/conf") || exit 1
+
+if [ "$PROVIDER" = "topling" ]; then
+ if [ ! -f "$SERVER_BIN/common-topling.sh" ]; then
+ echo "Error: common-topling.sh not found under: $SERVER_BIN" >&2
+ exit 1
+ fi
+
+ source "$SERVER_BIN/common-topling.sh"
+ type prepare_toplingdb >/dev/null 2>&1 || {
+ echo "Error: function prepare_toplingdb not found" >&2
+ exit 1
+ }
+ prepare_toplingdb "$SERVER_LIB/topling" "$INSTALL_DEST_DIR" \
+ "$COMPONENT_VERSION_DIR"
+else
+ echo "[install-rocksdb] $COMPONENT uses rocksdb provider (or unset)," \
+ "skipping native preload"
+fi
+
+unset -f detect_rocksdb_provider
+
+# A sourced script does not trigger EXIT on normal return, so restore explicitly.
+# The EXIT trap above covers exit and errexit failure paths.
+install_rocksdb_restore_state
+unset -f install_rocksdb_restore_state
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/run-api-test.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/run-api-test.sh
index 7ffa6b8685..c9bca1e10a 100755
--- a/hugegraph-server/hugegraph-dist/src/assembly/travis/run-api-test.sh
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/run-api-test.sh
@@ -67,6 +67,9 @@ JACOCO_PORT=36320
mvn package -Dmaven.test.skip=true -ntp
+# install rocksdb
+source $TRAVIS_DIR/install-rocksdb.sh
+
if [[ ! -e "$SERVER_DIR/lib/ikanalyzer-2012_u6.jar" ]]; then
download_to_dir "$SERVER_DIR/lib/" \
"https://raw.githubusercontent.com/apache/hugegraph-doc/ik_binary/dist/server/ikanalyzer-2012_u6.jar"
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/run-core-test.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/run-core-test.sh
index a95d2f0806..6ced5d93b0 100755
--- a/hugegraph-server/hugegraph-dist/src/assembly/travis/run-core-test.sh
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/run-core-test.sh
@@ -18,5 +18,9 @@
set -ev
BACKEND=$1
+TRAVIS_DIR=$(dirname $0)
+
+# install rocksdb
+source $TRAVIS_DIR/install-rocksdb.sh
mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,$BACKEND
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/run-unit-test.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/run-unit-test.sh
index 5fe9b476b3..6b1b22225a 100755
--- a/hugegraph-server/hugegraph-dist/src/assembly/travis/run-unit-test.sh
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/run-unit-test.sh
@@ -19,6 +19,9 @@ set -ev
BACKEND=$1
+# install rocksdb
+source $TRAVIS_DIR/install-rocksdb.sh
+
if [[ "$BACKEND" == "memory" ]]; then
mvn test -pl hugegraph-server/hugegraph-test -am -P unit-test
fi
diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/test-rocksdb-runtime.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/test-rocksdb-runtime.sh
new file mode 100755
index 0000000000..d0952ea339
--- /dev/null
+++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/test-rocksdb-runtime.sh
@@ -0,0 +1,78 @@
+#!/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.
+#
+
+set -Eeuo pipefail
+
+PROVIDER="${1:?Usage: $0 [component-dir]}"
+SERVER_DIR="${2:?Usage: $0 [component-dir]}"
+COMPONENT_DIR="${3:-$SERVER_DIR}"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+TEST_ROOT=$(mktemp -d /tmp/hugegraph-rocksdb-runtime.XXXXXX)
+cleanup() {
+ rm -rf "$TEST_ROOT"
+}
+trap cleanup EXIT
+
+case "$PROVIDER" in
+ rocksdb)
+ EXPECTED_NATIVE_PATH=none
+ ;;
+ topling)
+ EXPECTED_NATIVE_PATH="$COMPONENT_DIR/library/librocksdbjni-linux64.so"
+ if [ ! -f "$EXPECTED_NATIVE_PATH" ]; then
+ echo "Error: Topling native library was not installed for the component" >&2
+ exit 1
+ fi
+ ;;
+ *)
+ echo "Error: unsupported provider '$PROVIDER'" >&2
+ exit 1
+ ;;
+esac
+
+if [ "$COMPONENT_DIR" = "$SERVER_DIR" ]; then
+ if [ "$PROVIDER" = "topling" ]; then
+ JAR="${TOPLING_RUNTIME_CLASSPATH:-}"
+ else
+ JAR=$(ls -1 "$SERVER_DIR"/lib/rocksdbjni*.jar 2>/dev/null |
+ sort -V | tail -1 || true)
+ fi
+else
+ BOOT_JAR=$(ls -1 "$COMPONENT_DIR"/lib/*.jar 2>/dev/null |
+ sort -V | tail -1 || true)
+ NESTED_JAR=$(unzip -Z1 "$BOOT_JAR" 'BOOT-INF/lib/rocksdbjni*.jar' |
+ sort -V | tail -1 || true)
+ if [ -z "$NESTED_JAR" ]; then
+ echo "Error: no embedded rocksdbjni JAR found in $BOOT_JAR" >&2
+ exit 1
+ fi
+ JAR="$TEST_ROOT/rocksdbjni.jar"
+ unzip -p "$BOOT_JAR" "$NESTED_JAR" > "$JAR"
+fi
+if [ -z "$JAR" ]; then
+ echo "Error: no rocksdbjni JAR found for provider '$PROVIDER'" >&2
+ exit 1
+fi
+
+# This test exercises the RocksDB JNI API directly. Do not let Easy Migrate
+# auto-import a SidePluginRepo configuration, whose DB/CF ownership contract
+# requires opening the database through SidePluginRepo instead of RocksDB.open().
+env -u TOPLINGDB_EASY_MIGRATE_CONF \
+ java -cp "$JAR" "$SCRIPT_DIR/RocksDBRuntimeSmokeTest.java" \
+ "$PROVIDER" "$TEST_ROOT/db" "$EXPECTED_NATIVE_PATH"
diff --git a/hugegraph-server/hugegraph-rocksdb/pom.xml b/hugegraph-server/hugegraph-rocksdb/pom.xml
index 845cf40f9c..276f8163cd 100644
--- a/hugegraph-server/hugegraph-rocksdb/pom.xml
+++ b/hugegraph-server/hugegraph-rocksdb/pom.xml
@@ -37,7 +37,7 @@
org.rocksdb
rocksdbjni
- 8.10.2
+ ${rocksdb.version}
diff --git a/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStdSessions.java b/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStdSessions.java
index c1cc1c5075..8a624fba41 100644
--- a/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStdSessions.java
+++ b/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStdSessions.java
@@ -83,23 +83,28 @@ public class RocksDBStdSessions extends RocksDBSessions {
private final AtomicInteger refCount;
public RocksDBStdSessions(HugeConfig config, String database, String store,
- String dataPath, String walPath) throws RocksDBException {
+ String dataPath, String walPath) throws
+ RocksDBException {
super(config, database, store);
this.config = config;
this.dataPath = dataPath;
this.walPath = walPath;
+
this.rocksdb = RocksDBStdSessions.openRocksDB(config, dataPath, walPath);
this.refCount = new AtomicInteger(1);
}
public RocksDBStdSessions(HugeConfig config, String database, String store,
String dataPath, String walPath,
- List cfNames) throws RocksDBException {
+ List cfNames) throws
+ RocksDBException {
super(config, database, store);
this.config = config;
this.dataPath = dataPath;
this.walPath = walPath;
- this.rocksdb = RocksDBStdSessions.openRocksDB(config, cfNames, dataPath, walPath);
+
+ this.rocksdb =
+ RocksDBStdSessions.openRocksDB(config, cfNames, dataPath, walPath);
this.refCount = new AtomicInteger(1);
this.ingestExternalFile();
@@ -366,25 +371,25 @@ private void ingestExternalFile() throws RocksDBException {
}
private static OpenedRocksDB openRocksDB(HugeConfig config, String dataPath,
- String walPath) throws RocksDBException {
+ String walPath) throws
+ RocksDBException {
// Init options
Options options = new Options();
RocksDBStdSessions.initOptions(config, options, options, options, options);
options.setWalDir(walPath);
SstFileManager sstFileManager = new SstFileManager(Env.getDefault());
options.setSstFileManager(sstFileManager);
- /*
- * Open RocksDB at the first time
- * Don't merge old CFs, we expect a clear DB when using this one
- */
+
RocksDB rocksdb = RocksDB.open(options, dataPath);
+
Map cfs = new ConcurrentHashMap<>();
return new OpenedRocksDB(rocksdb, cfs, sstFileManager);
}
private static OpenedRocksDB openRocksDB(HugeConfig config,
List cfNames, String dataPath,
- String walPath) throws RocksDBException {
+ String walPath) throws
+ RocksDBException {
// Old CFs should always be opened
Set mergedCFs = RocksDBStdSessions.mergeOldCFs(dataPath,
cfNames);
@@ -407,9 +412,9 @@ private static OpenedRocksDB openRocksDB(HugeConfig config,
}
SstFileManager sstFileManager = new SstFileManager(Env.getDefault());
options.setSstFileManager(sstFileManager);
-
// Open RocksDB with CFs
List cfhs = new ArrayList<>();
+
RocksDB rocksdb = RocksDB.open(options, dataPath, cfds, cfhs);
E.checkState(cfhs.size() == cfs.size(),
diff --git a/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStore.java b/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStore.java
index 3b6b54eadb..2117e1c24f 100644
--- a/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStore.java
+++ b/hugegraph-server/hugegraph-rocksdb/src/main/java/org/apache/hugegraph/backend/store/rocksdb/RocksDBStore.java
@@ -372,7 +372,8 @@ protected RocksDBSessions open(HugeConfig config, String dataPath,
protected RocksDBSessions openSessionPool(HugeConfig config,
String dataPath, String walPath,
- List tableNames) throws RocksDBException {
+ List tableNames) throws
+ RocksDBException {
if (tableNames == null) {
return new RocksDBStdSessions(config, this.database, this.store, dataPath, walPath);
} else {
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/rocksdb/RocksDBSessionsTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/rocksdb/RocksDBSessionsTest.java
index 5dbc96c5c6..accc5e7f6b 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/rocksdb/RocksDBSessionsTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/rocksdb/RocksDBSessionsTest.java
@@ -190,7 +190,8 @@ public void testIngestSst() throws RocksDBException {
Assert.assertFalse(sstSessions.existsTable(TABLE1));
Assert.assertFalse(sstSessions.existsTable(TABLE2));
- RocksDBSessions rocks = new RocksDBStdSessions(config, "db", "store", sstPath, sstPath);
+ RocksDBSessions rocks =
+ new RocksDBStdSessions(config, "db", "store", sstPath, sstPath);
// Will ingest sst file of TABLE1
rocks.createTable(TABLE1);
Assert.assertEquals(ImmutableList.of("1000"),
diff --git a/hugegraph-store/hg-store-core/pom.xml b/hugegraph-store/hg-store-core/pom.xml
index 0ecf723280..84e23e8b88 100644
--- a/hugegraph-store/hg-store-core/pom.xml
+++ b/hugegraph-store/hg-store-core/pom.xml
@@ -55,7 +55,7 @@
com.alipay.sofa
jraft-core
- 1.3.13
+ 1.3.14
org.rocksdb
diff --git a/hugegraph-store/hg-store-dist/src/assembly/static/bin/start-hugegraph-store.sh b/hugegraph-store/hg-store-dist/src/assembly/static/bin/start-hugegraph-store.sh
index 88165e47b6..2287792bba 100755
--- a/hugegraph-store/hg-store-dist/src/assembly/static/bin/start-hugegraph-store.sh
+++ b/hugegraph-store/hg-store-dist/src/assembly/static/bin/start-hugegraph-store.sh
@@ -38,6 +38,8 @@ GITHUB="https://github.com"
PID_FILE="$BIN/pid"
. "$BIN"/util.sh
+PARENT_DIR="$(cd "$TOP"/../ && pwd)"
+SERVER_VERSION_DIR="${SERVER_VERSION_DIR:-$(find_hugegraph_server_dir "$PARENT_DIR")}"
arch=$(uname -m)
echo "Current arch: $arch"
@@ -64,6 +66,15 @@ else
echo "Unsupported architecture: $arch"
fi
+# preload rocksdb/toplingdb
+if [ -n "$SERVER_VERSION_DIR" ] && [ -e "$SERVER_VERSION_DIR/bin/preload-topling.sh" ]; then
+ TOPLINGDB_EASY_MIGRATE_CONF="$CONF/rocksdb_store.yaml"
+ TOPLING_COMPONENT_TOP="$TOP"
+ TOPLING_USE_SERVER_CLASSPATH=false
+ source "$SERVER_VERSION_DIR/bin/preload-topling.sh"
+ unset TOPLING_COMPONENT_TOP TOPLING_USE_SERVER_CLASSPATH
+fi
+
##pd/store max user processes, ulimit -u
# Reduce the maximum number of processes that can be opened by a normal dev/user
export PROC_LIMITN=1024
diff --git a/hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh b/hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh
index e45249a04b..579cc12c49 100644
--- a/hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh
+++ b/hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh
@@ -434,3 +434,21 @@ function kill_process_and_wait() {
kill_process "$process_name" "$pid"
wait_for_shutdown "$process_name" "$pid" "$timeout_s"
}
+
+# Find HugeGraph server directory in parent path using prefix glob.
+# Usage: find_hugegraph_server_dir "/path/to/parent"
+# Returns: first matching directory path or empty string
+function find_hugegraph_server_dir() {
+ local parent_dir="$1"
+ if [ -z "$parent_dir" ]; then
+ parent_dir="$(cd "${TOP:-$(pwd)}"/.. && pwd)"
+ fi
+ local found=""
+ for d in "$parent_dir"/apache-hugegraph-server*; do
+ if [ -d "$d" ]; then
+ found="$d"
+ break
+ fi
+ done
+ echo "$found"
+}
diff --git a/hugegraph-store/hg-store-dist/src/assembly/static/conf/application-pd.yml b/hugegraph-store/hg-store-dist/src/assembly/static/conf/application-pd.yml
index 0315c4b4fe..2d667afdb1 100644
--- a/hugegraph-store/hg-store-dist/src/assembly/static/conf/application-pd.yml
+++ b/hugegraph-store/hg-store-dist/src/assembly/static/conf/application-pd.yml
@@ -32,3 +32,6 @@ rocksdb:
write_buffer_size: 32000000
# For each rocksdb, the number of memtables reaches this value for writing to disk.
min_write_buffer_number_to_merge: 16
+ # To enable ToplingDB: set provider to 'topling' (requires the shared ToplingDB runtime)
+ # ToplingDB config is loaded from conf/rocksdb_store.yaml
+ # provider: topling
diff --git a/hugegraph-store/hg-store-dist/src/assembly/static/conf/rocksdb_store.yaml b/hugegraph-store/hg-store-dist/src/assembly/static/conf/rocksdb_store.yaml
new file mode 100644
index 0000000000..a807b11483
--- /dev/null
+++ b/hugegraph-store/hg-store-dist/src/assembly/static/conf/rocksdb_store.yaml
@@ -0,0 +1,162 @@
+#
+# 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.
+#
+# common parameters
+http:
+ # normally parent path of db path
+ document_root: ./library/rocksdb_resource
+ listening_ports: '127.0.0.1:2013'
+ auto_start_http: true
+setenv:
+ StrSimpleEnvNameNotOverwrite: StringValue
+ IntSimpleEnvNameNotOverwrite: 16384
+ OverwriteThisEnv:
+ #comment: overwrite is default to false
+ overwrite: true
+ value: force overwrite this env by overwrite true
+Cache:
+ lru_cache:
+ class: LRUCache
+ params:
+ capacity: 8G
+ num_shard_bits: -1
+ strict_capacity_limit: false
+ high_pri_pool_ratio: 0.5
+ use_adaptive_mutex: false
+ metadata_charge_policy: kFullChargeCacheMetadata
+Statistics:
+ stat:
+ class: default
+ params:
+ discard_tickers:
+ - rocksdb.block.cache
+ - rocksdb.block.cachecompressed
+ - rocksdb.block
+ - rocksdb.memtable.payload.bytes.at.flush
+ - rocksdb.memtable.garbage.bytes.at.flush
+ - rocksdb.txn
+ - rocksdb.blobdb
+ - rocksdb.row.cache
+ - rocksdb.number.block
+ - rocksdb.bloom.filter
+ - rocksdb.persistent
+ - rocksdb.sim.block.cache
+ discard_histograms:
+ # comment: ....
+ - rocksdb.blobdb
+ - rocksdb.bytes.compressed
+ - rocksdb.bytes.decompressed
+ - rocksdb.num.index.and.filter.blocks.read.per.level
+ - rocksdb.num.data.blocks.read.per.level
+ - rocksdb.compression.times.nanos
+ - rocksdb.decompression.times.nanos
+ - rocksdb.read.block.get.micros
+ - rocksdb.write.raw.block.micros
+ # comment end of array
+ #stats_level: kAll
+ stats_level: kDisableAll
+MemTableRepFactory:
+ cspp:
+ class: cspp
+ params:
+ mem_cap: 16G
+ use_vm: false
+ token_use_idle: true
+ chunk_size: 16K
+ convert_to_sst: kFileMmap
+ sync_sst_file: false
+ skiplist:
+ class: SkipList
+ params:
+ lookahead: 0
+TableFactory:
+ cspp_memtab_sst:
+ class: CSPPMemTabTable
+ params: # empty params
+ bb:
+ class: BlockBasedTable
+ params:
+ checksum: kCRC32c
+ block_size: 4K
+ block_restart_interval: 16
+ index_block_restart_interval: 1
+ metadata_block_size: 4K
+ enable_index_compression: true
+ block_cache: "${lru_cache}"
+ readers:
+ BlockBasedTable: bb
+ CSPPMemTabTable: cspp_memtab_sst
+ block_cache_compressed:
+ persistent_cache:
+ filter_policy:
+ dispatch:
+ class: DispatcherTable
+ params:
+ default: bb
+ readers:
+ BlockBasedTable: bb
+ CSPPMemTabTable: cspp_memtab_sst
+ level_writers: [ bb, bb, bb, bb, bb, bb ]
+CFOptions:
+ default:
+ max_write_buffer_number: 6
+ memtable_factory: "${cspp}"
+ write_buffer_size: 128M
+ # set target_file_size_base as small as 512K is to make many SST files,
+ # thus key prefix cache can present efficiency
+ target_file_size_base: 64M
+ target_file_size_multiplier: 1
+ table_factory: dispatch
+ max_bytes_for_level_base: 512M
+ max_bytes_for_level_multiplier: 10
+ level_compaction_dynamic_level_bytes: false
+ level0_slowdown_writes_trigger: 20
+ level0_stop_writes_trigger: 36
+ level0_file_num_compaction_trigger: 2
+ merge_operator: uint64add # support merge
+ level_compaction_dynamic_file_size: true
+ optimize_filters_for_hits: true
+ allow_merge_memtables: true
+ min_write_buffer_number_to_merge: 2
+ compression_per_level:
+ - kNoCompression
+ - kNoCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+ - kSnappyCompression
+DBOptions:
+ log:
+ create_if_missing: true
+ create_missing_column_families: true
+ default:
+ create_if_missing: true
+ create_missing_column_families: false # this is important, must be false to hugegraph
+ max_background_compactions: -1
+ max_subcompactions: 4
+ max_level1_subcompactions: 0
+ inplace_update_support: false
+ WAL_size_limit_MB: 0
+ statistics: "${stat}"
+ max_manifest_file_size: 100M
+ max_background_jobs: 8
+ # WARNING: This profile enables ToplingDB-specific WAL/SST behavior through
+ # convert_to_sst and memtable_as_log_index. After ToplingDB writes data, changing
+ # rocksdb.provider back to rocksdb is not a safe rollback. Restore a complete,
+ # consistent snapshot created before migration; see the ToplingDB design document.
+ compaction_readahead_size: 0
+ memtable_as_log_index: true
diff --git a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java
index 94bdc4c6bc..ceecc43399 100644
--- a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java
+++ b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java
@@ -54,12 +54,12 @@ public final class RocksDBMetricsConst {
TickerType.BLOCK_CACHE_INDEX_HIT, // Index cache hits.
TickerType.BLOCK_CACHE_INDEX_ADD, // Index blocks added to cache.
TickerType.BLOCK_CACHE_INDEX_BYTES_INSERT, // Bytes inserted into index cache.
- TickerType.BLOCK_CACHE_INDEX_BYTES_EVICT, // Bytes evicted from index cache.
+ // BLOCK_CACHE_INDEX_BYTES_EVICT removed in RocksDB 8.x
TickerType.BLOCK_CACHE_FILTER_MISS, // Filter cache misses.
TickerType.BLOCK_CACHE_FILTER_HIT, // Filter cache hits.
TickerType.BLOCK_CACHE_FILTER_ADD, // Filter blocks added to cache.
TickerType.BLOCK_CACHE_FILTER_BYTES_INSERT, // Bytes inserted in filter cache.
- TickerType.BLOCK_CACHE_FILTER_BYTES_EVICT, // Bytes evicted from filter cache.
+ // BLOCK_CACHE_FILTER_BYTES_EVICT removed in RocksDB 8.x
TickerType.BLOCK_CACHE_DATA_MISS, // Data cache misses.
TickerType.BLOCK_CACHE_DATA_HIT, // Data cache hits.
TickerType.BLOCK_CACHE_DATA_ADD, // Data blocks added to cache.
@@ -95,31 +95,31 @@ public final class RocksDBMetricsConst {
TickerType.NUMBER_DB_NEXT_FOUND, // Number of successful next operations.
TickerType.NUMBER_DB_PREV_FOUND, // Number of successful previous operations.
TickerType.ITER_BYTES_READ, // Bytes read by iterators.
- TickerType.NO_FILE_CLOSES, // Number of file close operations.
+ // NO_FILE_CLOSES removed in RocksDB 8.x
TickerType.NO_FILE_OPENS, // Number of file open operations.
TickerType.NO_FILE_ERRORS, // Number of file errors.
TickerType.STALL_MICROS, // Time spent in a stall micro.
TickerType.DB_MUTEX_WAIT_MICROS, // Time spent waiting on a mutex.
- TickerType.RATE_LIMIT_DELAY_MILLIS, // Rate limiting delay in milliseconds.
- TickerType.NO_ITERATORS, // Number of iterators created.
+ // RATE_LIMIT_DELAY_MILLIS removed in RocksDB 8.x
+ // NO_ITERATORS removed in RocksDB 8.x
TickerType.NUMBER_MULTIGET_BYTES_READ, // Bytes read by multi-get operations.
TickerType.NUMBER_MULTIGET_KEYS_READ, // Keys read in multi-get operations.
TickerType.NUMBER_MULTIGET_CALLS, // Number of multi-get operations.
- TickerType.NUMBER_FILTERED_DELETES, // Number of deletes filtered.
+ // NUMBER_FILTERED_DELETES removed in RocksDB 8.x
TickerType.NUMBER_MERGE_FAILURES, // Number of merge failures.
TickerType.BLOOM_FILTER_PREFIX_CHECKED, // Number of prefix bloom filter checks.
TickerType.BLOOM_FILTER_PREFIX_USEFUL, // Number of useful prefix bloom filter checks.
TickerType.NUMBER_OF_RESEEKS_IN_ITERATION, // Number of reseeks in iteration.
TickerType.GET_UPDATES_SINCE_CALLS, // Number of get updates since calls.
- TickerType.BLOCK_CACHE_COMPRESSED_MISS, // Misses in compressed block cache.
- TickerType.BLOCK_CACHE_COMPRESSED_HIT, // Hits in compressed block cache.
- TickerType.BLOCK_CACHE_COMPRESSED_ADD, // Compressed blocks added to cache.
- TickerType.BLOCK_CACHE_COMPRESSED_ADD_FAILURES, // Failures adding compressed blocks.
+ // BLOCK_CACHE_COMPRESSED_MISS removed in RocksDB 8.x
+ // BLOCK_CACHE_COMPRESSED_HIT removed in RocksDB 8.x
+ // BLOCK_CACHE_COMPRESSED_ADD removed in RocksDB 8.x
+ // BLOCK_CACHE_COMPRESSED_ADD_FAILURES removed in RocksDB 8.x
TickerType.WAL_FILE_SYNCED, // Number of synced WAL files.
TickerType.WAL_FILE_BYTES, // Bytes written to WAL files.
TickerType.WRITE_DONE_BY_SELF, // Writes completed by self.
TickerType.WRITE_DONE_BY_OTHER, // Writes completed by others.
- TickerType.WRITE_TIMEDOUT, // Number of write timeouts.
+ // WRITE_TIMEDOUT removed in RocksDB 8.x
TickerType.WRITE_WITH_WAL, // Writes involving WAL.
TickerType.COMPACT_READ_BYTES, // Bytes read during compaction.
TickerType.COMPACT_WRITE_BYTES, // Bytes written during compaction.
@@ -167,12 +167,10 @@ public final class RocksDBMetricsConst {
// Time spent reading blocks during compaction.
HistogramType.READ_BLOCK_GET_MICROS, // Time spent reading blocks during get.
HistogramType.WRITE_RAW_BLOCK_MICROS, // Time spent writing raw blocks.
- HistogramType.STALL_L0_SLOWDOWN_COUNT, // Count of stalls due to L0 slowdown.
- HistogramType.STALL_MEMTABLE_COMPACTION_COUNT,
- // Count of stalls due to memtable compaction.
- HistogramType.STALL_L0_NUM_FILES_COUNT, // Count of stalls due to number of files at L0.
- HistogramType.HARD_RATE_LIMIT_DELAY_COUNT, // Count of delays due to hard rate limits.
- HistogramType.SOFT_RATE_LIMIT_DELAY_COUNT, // Count of delays due to soft rate limits.
+ // STALL_L0_SLOWDOWN_COUNT removed in RocksDB 8.x
+ // Note: The following constants were removed in RocksDB 8.10.2:
+ // STALL_MEMTABLE_COMPACTION_COUNT, STALL_L0_NUM_FILES_COUNT,
+ // HARD_RATE_LIMIT_DELAY_COUNT, SOFT_RATE_LIMIT_DELAY_COUNT
HistogramType.NUM_FILES_IN_SINGLE_COMPACTION, // Number of files in a single compaction.
HistogramType.DB_SEEK, // Latency of database seek operations.
HistogramType.WRITE_STALL, // Time spent in write stalls.
diff --git a/hugegraph-store/hg-store-rocksdb/pom.xml b/hugegraph-store/hg-store-rocksdb/pom.xml
index cd9cf28c6d..232aecffa1 100644
--- a/hugegraph-store/hg-store-rocksdb/pom.xml
+++ b/hugegraph-store/hg-store-rocksdb/pom.xml
@@ -57,7 +57,7 @@
org.rocksdb
rocksdbjni
- 7.7.3
+ ${rocksdb.version}
org.projectlombok
diff --git a/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBOptions.java b/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBOptions.java
index 7fcd07f3b8..374778d9e2 100644
--- a/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBOptions.java
+++ b/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBOptions.java
@@ -56,7 +56,6 @@ public class RocksDBOptions extends OptionHolder {
disallowEmpty(),
false
);
-
// public static final ConfigListOption DATA_DISKS =
// new ConfigListOption<>(
// "rocksdb.data_disks",
diff --git a/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBSession.java b/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBSession.java
index f4e7605a7f..bfd3240ba7 100644
--- a/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBSession.java
+++ b/hugegraph-store/hg-store-rocksdb/src/main/java/org/apache/hugegraph/rocksdb/access/RocksDBSession.java
@@ -450,8 +450,9 @@ private void openRocksDB(String dbDataPath, long version) {
new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOptions));
}
List columnFamilyHandleList = new ArrayList<>();
- this.rocksDB = RocksDB.open(dbOptions, dbPath, columnFamilyDescriptorList,
- columnFamilyHandleList);
+ this.rocksDB =
+ RocksDB.open(dbOptions, dbPath, columnFamilyDescriptorList,
+ columnFamilyHandleList);
Asserts.isTrue(columnFamilyHandleList.size() > 0, "must have column family");
for (ColumnFamilyHandle handle : columnFamilyHandleList) {
diff --git a/install-dist/release-docs/LICENSE b/install-dist/release-docs/LICENSE
index 06a31044eb..fdbff8fd3d 100644
--- a/install-dist/release-docs/LICENSE
+++ b/install-dist/release-docs/LICENSE
@@ -481,6 +481,12 @@ non-Apache-2.0 license text is required for a bundled component.
https://central.sonatype.com/artifact/net.java.dev.jna/jna/5.12.1 -> Apache 2.0
https://central.sonatype.com/artifact/net.java.dev.jna/jna/5.5.0 -> Apache 2.0
https://central.sonatype.com/artifact/net.java.dev.jna/jna/5.7.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.github.jnr/jnr-ffi/2.1.7 -> Apache 2.0
+ https://central.sonatype.com/artifact/joda-time/joda-time/2.10.8 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.alipay.sofa/jraft-core/1.3.14 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.skyscreamer/jsonassert/1.5.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.jayway.jsonpath/json-path/2.5.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.googlecode.json-simple/json-simple/1.1 -> Apache 2.0
https://central.sonatype.com/artifact/net.jodah/failsafe/2.4.1 -> Apache 2.0
https://central.sonatype.com/artifact/net.minidev/accessors-smart/1.2 -> Apache 2.0
https://central.sonatype.com/artifact/net.minidev/json-smart/2.3 -> Apache 2.0
@@ -655,10 +661,48 @@ non-Apache-2.0 license text is required for a bundled component.
https://central.sonatype.com/artifact/org.powermock/powermock-module-junit4-rule/2.0.0-RC.3 -> Apache 2.0
https://central.sonatype.com/artifact/org.powermock/powermock-module-junit4/2.0.0-RC.3 -> Apache 2.0
https://central.sonatype.com/artifact/org.powermock/powermock-reflect/2.0.0-RC.3 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.google.api.grpc/proto-google-common-protos/1.17.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.google.api.grpc/proto-google-common-protos/2.0.1 -> Apache 2.0
+ https://central.sonatype.com/artifact/io.protostuff/protostuff-api/1.6.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/io.protostuff/protostuff-collectionschema/1.6.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/io.protostuff/protostuff-core/1.6.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/io.protostuff/protostuff-runtime/1.6.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.addthis.metrics/reporter-config3/3.0.3 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.addthis.metrics/reporter-config-base/3.0.3 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.opencypher/rewriting-9.0/9.0.20190305 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.rocksdb/rocksdbjni/8.10.2 -> Apache 2.0
+ https://github.com/hugegraph/toplingdb/packages/3151853 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.fusesource/sigar/1.6.4 -> Apache 2.0
+ https://central.sonatype.com/artifact/io.prometheus/simpleclient/0.10.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/io.prometheus/simpleclient_common/0.10.0 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-agent/0.22 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-cli/0.14 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-cli/0.22 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-core/0.14 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-core/0.22 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-hflame/0.22 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.perfkit.sjk.parsers/sjk-jfr5/0.5 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.perfkit.sjk.parsers/sjk-jfr6/0.7 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.perfkit.sjk.parsers/sjk-jfr-standalone/0.7 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-json/0.14 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-json/0.22 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.perfkit.sjk.parsers/sjk-nps/0.9 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-stacktrace/0.14 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.gridkit.jvmtool/sjk-stacktrace/0.22 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.yaml/snakeyaml/1.18 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.yaml/snakeyaml/1.26 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.yaml/snakeyaml/1.27 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.yaml/snakeyaml/1.28 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.yaml/snakeyaml/2.2 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.xerial.snappy/snappy-java/1.1.2.6 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.alipay.sofa.common/sofa-common-tools/1.0.12 -> Apache 2.0
+ https://central.sonatype.com/artifact/com.alipay.sofa/sofa-rpc-all/5.7.6 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.springframework/spring-aop/5.3.20 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.springframework/spring-beans/5.3.20 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.springframework.boot/spring-boot/2.5.14 -> Apache 2.0
+ https://central.sonatype.com/artifact/org.springframework.boot/spring-boot-actuator/2.5.14 -> Apache 2.0
https://central.sonatype.com/artifact/org.roaringbitmap/RoaringBitmap/0.9.38 -> Apache 2.0
https://central.sonatype.com/artifact/org.roaringbitmap/shims/0.9.38 -> Apache 2.0
- https://central.sonatype.com/artifact/org.rocksdb/rocksdbjni/6.29.5 -> Apache 2.0
- https://central.sonatype.com/artifact/org.rocksdb/rocksdbjni/7.7.3 -> Apache 2.0
https://central.sonatype.com/artifact/org.rocksdb/rocksdbjni/8.10.2 -> Apache 2.0
https://central.sonatype.com/artifact/org.skyscreamer/jsonassert/1.5.0 -> Apache 2.0
https://central.sonatype.com/artifact/org.springframework.boot/spring-boot-actuator-autoconfigure/2.5.14 -> Apache 2.0
diff --git a/install-dist/release-docs/licenses/LICENSE-rocksdbjni-8.10.2-SNAPSHOT.txt b/install-dist/release-docs/licenses/LICENSE-rocksdbjni-8.10.2-SNAPSHOT.txt
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/install-dist/release-docs/licenses/LICENSE-rocksdbjni-8.10.2-SNAPSHOT.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/install-dist/scripts/dependency/known-dependencies.txt b/install-dist/scripts/dependency/known-dependencies.txt
index 157da1c064..708fda7b87 100644
--- a/install-dist/scripts/dependency/known-dependencies.txt
+++ b/install-dist/scripts/dependency/known-dependencies.txt
@@ -282,8 +282,7 @@ jna-5.5.0.jar
jna-5.7.0.jar
joda-time-2.10.8.jar
joni-2.2.1.jar
-jraft-core-1.3.11.jar
-jraft-core-1.3.13.jar
+jraft-core-1.3.14.jar
jraft-core-1.3.9.jar
jsonassert-1.5.0.jar
json-path-2.5.0.jar
diff --git a/pom.xml b/pom.xml
index 3581d0346f..3cadf89ea0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -95,6 +95,7 @@
UTF-8
bash
1.5.0
+ 8.10.2
@@ -218,6 +219,9 @@
**/src/main/java/org/apache/hugegraph/pd/grpc/**
**/src/main/java/org/apache/hugegraph/store/grpc/**
+
+ **/library/*.html
+ **/library/*.css
true