Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/scripts/check-docker-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ for pair in \
case "$dockerfile" in
hugegraph-pd/*) OWNED_DIRS=". logs pd_data" ;;
hugegraph-store/*) OWNED_DIRS=". logs storage" ;;
hugegraph-server/Dockerfile) OWNED_DIRS=". logs rocksdb-data" ;;
*) OWNED_DIRS=". logs" ;;
hugegraph-server/*) OWNED_DIRS=". logs rocksdb-data" ;;
esac
IMAGE_USER=$(docker image inspect --format '{{.Config.User}}' "$IMAGE_ID")
RUNTIME_IDS=$(docker run --rm --pull never --entrypoint sh "$IMAGE_ID" -c \
Expand All @@ -47,6 +46,20 @@ for pair in \
exit 1
}

if [[ "$dockerfile" == hugegraph-server/* ]]; then
(
volume=$(docker volume create)
trap 'docker volume rm "$volume" >/dev/null' EXIT
# A new named volume must inherit writable ownership, including
# when the HStore image is explicitly used with local RocksDB.
docker run --rm --pull never --entrypoint sh \
-v "$volume:/hugegraph-server/rocksdb-data" "$IMAGE_ID" -ec '
test "$(stat -c %u:%g rocksdb-data)" = 10001:10001
touch rocksdb-data/ownership-probe
'
)
fi

# Helm reuses these images for tool containers instead of pulling curlimages/curl.
# Check the same non-root/read-only tool environment as the Server test hook.
if [[ "$dockerfile" == hugegraph-store/* || "$dockerfile" == hugegraph-server/* ]]; then
Expand Down
13 changes: 13 additions & 0 deletions .github/scripts/test_ci_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ def test_ordinary_server_changes_only_run_mainline_server_and_arm_smoke(self):
self.assertFalse(plan["macos_full"])
self.assertFalse(plan["pd_store"])

def test_topling_assets_run_server_native_contracts(self):
scripts = ("test-topling-prepare.sh", "test-topling-selection.sh")
workflow = (Path(__file__).resolve().parents[1] / "workflows/server-tests.yml").read_text()
for script in scripts:
step = next(step for step in workflow.split("\n - ") if script in step)
self.assertIn("if: inputs.backend == 'rocksdb'", step)
paths = [policy.TRAVIS + script for script in scripts]
paths += ["hugegraph-server/hugegraph-dist/src/assembly/static/" + path for path in
("bin/prepare-topling.sh", "bin/preload-topling.sh", "conf/toplingdb.yaml")]
for path in paths:
with self.subTest(path=path):
self.assertIn("server-rocksdb", self.coordinator_jobs(self.plan_for([path])))

def test_distributed_server_contracts_keep_hstore_cluster_without_pd_store_units(self):
for path in [policy.SERVER_CORE + "backend/store/BackendStore.java",
policy.SERVER_CORE + "meta/MetaManager.java", policy.SERVER_CORE + "StandardHugeGraph.java",
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pd-store-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ jobs:
- name: Check explicit Topling launcher selection
run: |
bash $TRAVIS_DIR/test-topling-selection.sh
bash $TRAVIS_DIR/test-topling-prepare.sh
bash hugegraph-store/hg-store-dist/src/assembly/travis/test-store-preloads.sh

- name: Run PD docker entrypoint secret override tests
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/server-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ jobs:
"$TRAVIS_DIR/test-wait-storage.sh"
"$TRAVIS_DIR/test-start-server.sh"
"$TRAVIS_DIR/test-riscv64-java-runtime.sh"
bash "$TRAVIS_DIR/test-topling-selection.sh"
bash "$TRAVIS_DIR/test-topling-prepare.sh"
bash "$TRAVIS_DIR/test-tinkerpop-reports.sh"

- name: Validate Docker integration
Expand Down
5 changes: 5 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ an explicit `-Xmx` that exceeds the container's limit.

This is the recommended quickstart.

For a single Server without Hubble, or an unpacked binary distribution, see
[Standalone Server deployment](../docs/deployment-standalone.md). The standard
image is `hugegraph/hugegraph`; `hugegraph/server` selects HStore defaults and
requires PD/Store unless its backend configuration is explicitly replaced.

Start:

```bash
Expand Down
107 changes: 107 additions & 0 deletions docs/deployment-standalone.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Standalone Server with local RocksDB

Standalone Server needs no PD or Store. The standard distribution ships
`backend=rocksdb` and `serializer=binary`; `pd.peers` is commented out. The
HStore image deliberately replaces this graph configuration. Select the image
or distribution before diagnosing a wait for distributed storage.

| Deployment | Artifact | Default backend |
| --- | --- | --- |
| Single Server container | `hugegraph/hugegraph:<tag>` | Local RocksDB |
| Binary distribution | `apache-hugegraph-server-<version>` | Local RocksDB |
| Distributed Server container | `hugegraph/server:<tag>` | HStore; requires PD and Store |
| Current Helm chart | `helm/hugegraph` | HStore only |

The chart's `values-single.yaml` means one PD, one Store and one Server. It does
not mean a standalone RocksDB Server. Vermeer and SeaTunnel each have their own
standalone topology setting, independent of the Server storage backend.

## One Server container

Pin a tag built from the revision you want to run; `latest` is mutable. A
published image may not yet contain the corresponding source fixes.

```bash
docker volume create hugegraph-rocksdb
docker run -d --name hugegraph-standalone \
-p 127.0.0.1:8080:8080 \
-e PASSWORD='replace-with-your-password' \
-v hugegraph-rocksdb:/hugegraph-server/rocksdb-data \
hugegraph/hugegraph:latest
docker logs -f hugegraph-standalone
```

The image initializes authentication from `PASSWORD` on the first startup.
Changing this variable does not rotate an existing account's password. The
named data volume retains its contents when the container is removed. The
default data path is `/hugegraph-server/rocksdb-data`; mounting a volume at
`/hugegraph-server/data` does not persist the default RocksDB database.

If you need to reuse the HStore Server image for a new, empty standalone
installation, set both `HG_SERVER_BACKEND=rocksdb` and
`HG_SERVER_USE_PD=false`. Its template already uses `serializer=binary`.
The entrypoint then configures local storage before the storage-wait step;
non-HStore backends skip PD/Store polling even if the template retains
`pd.peers`. Backend selection accepts spaces around `=` as well as the ordinary
colon/whitespace property separators, without requiring a backend environment
override. Only recognized local backends bypass the wait; an unread or unknown
backend cannot silently take that path.
Images containing this fix pre-create `rocksdb-data` owned by
10001:10001 so a fresh named volume inherits writable ownership.
No graph configuration bind mount is needed. Older HStore images need a
corrected writable graph configuration and data-directory ownership instead.
Do not switch an existing
HStore installation's backend or reuse its initialization marker this way.

Custom configuration bind mounts must be writable by UID/GID 10001. Mount a
whole writable configuration directory rather than a single properties file:
the entrypoint edits files with atomic rename. Prefer a named data volume to
changing host-directory permissions recursively. See the
[Docker guide](../docker/README.md) for authentication keys, volume ownership
and a Server plus Hubble Compose quickstart.

## Binary distribution

Use Java 17. Server 1.8 bytecode does not run on Java 11. Run these commands
inside a fresh unpacked Server distribution:

```bash
java -version
# Confirm backend=rocksdb, serializer=binary and no active pd.peers in this file.
cat conf/graphs/hugegraph.properties
bin/init-store.sh
bin/start-hugegraph.sh
```

To enable authentication on a fresh distribution instead, set
`auth.admin_pa` in `conf/rest-server.properties`, run `bin/enable-auth.sh`,
and provide the same password on stdin when running `bin/init-store.sh`.
The initializer does not read the container entrypoint's `PASSWORD` variable.
Then start Server normally. Configuration files containing passwords must be
readable only by the service account and its administrators.

## Verify the graph

```bash
curl -fsS http://localhost:8080/versions
curl -fsS -u 'admin:replace-with-your-password' \
http://localhost:8080/graphspaces/DEFAULT/graphs
curl -fsS -u 'admin:replace-with-your-password' \
-H 'Content-Type: application/json' \
-d '{"gremlin":"g.V().count()","aliases":{"g":"__g_DEFAULT-hugegraph"}}' \
http://localhost:8080/gremlin
```

Omit `-u` if authentication is disabled. Server 1.8 still uses the `DEFAULT`
GraphSpace in standalone mode; it does not register the legacy
`__g_hugegraph` traversal source. GraphSpace management itself requires PD.
See [REST requests](rest-api-usage.md) for aliases, shard pagination and tasks.

## Optional Topling runtime

Keep `backend=rocksdb` and select the native provider separately, following
[Storage provider selection](storage-lifecycle.md#storage-provider-selection-and-toplingdb).
The standard image includes a Java 17 JDK and `unzip` for preparing a compatible
JNI supplied by the operator; it does not bundle or download optional JNI.
The JNI's glibc, libaio and CPU requirements must match the image or host.
Do not assume that a mutable image tag proves which native library is loaded.
44 changes: 40 additions & 4 deletions docs/rest-api-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,46 @@ are query variables; they do not create graph bindings. An alias target must be
an existing graph or traversal-source binding, rather than a Gremlin expression
such as `graph.traversal()`.

For a standalone legacy graph with no GraphSpace, use `<graph>` and
`__g_<graph>` instead. The Java client builds the appropriate aliases from its
configured GraphSpace and graph. Verify the configured names before treating a
`Could not rebind` response as a graph-registration failure.
Server 1.8 uses these GraphSpace-scoped bindings in standalone RocksDB mode too:
the default graph is `DEFAULT-hugegraph`, and its traversal source is
`__g_DEFAULT-hugegraph`. Disabling PD does not select legacy aliases. Only older
Servers without GraphSpace bindings use `<graph>` and `__g_<graph>`. Select the
Java client's GraphSpace to match the Server, and verify the configured names
before treating a `Could not rebind` response as a graph-registration failure.

## Export a shard with bounded pages

Both `GET .../traversers/vertices/scan` and `GET .../traversers/edges/scan`
require `start` and `end`. Missing either parameter returns HTTP 400 with its
name on every backend. This also changes HStore and in-memory requests that
previously interpreted missing bounds as zero; callers must now supply both.
See the [upgrade notes](upgrade-notes.md#required-shard-scan-bounds).

Empty strings represent open bounds in RocksDB and HBase. They do **not**
represent a whole-graph range in HStore or the in-memory backend. The following
example is for **RocksDB**:

```bash
curl -G 'http://localhost:8080/graphspaces/DEFAULT/graphs/hugegraph/traversers/vertices/scan' \
--data-urlencode 'start=' --data-urlencode 'end=' \
--data-urlencode 'page=' --data-urlencode 'page_limit=1000'
```

Pass `page=` explicitly for the first page, then URL-encode the returned `page`
token on subsequent requests, keeping the same bounds. Stop when the returned
token is null or empty. Edge scans use the same pagination contract.

For HStore and in-memory exports, first request the corresponding
`.../vertices/shards?split_size=1048576` or `.../edges/shards?split_size=1048576`.
Iterate **every** returned shard, using its exact `start` and `end` and a fresh
`page=` for each shard. Preserve the backend's boundary encoding; do not reuse
vertex bounds for edges. An empty HStore range can stop after the partition
containing hash zero, and an empty in-memory end can produce no results.
A terminal page token finishes only that shard, not the entire graph.

Omitting `page` retains the existing unpaged scan behavior: `page_limit` does
not bound that response and the result has no continuation token. Exporters
must pass the empty initial page to avoid reading an entire shard at once.

## Run long queries as tasks

Expand Down
39 changes: 36 additions & 3 deletions docs/storage-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,30 @@ Use a stopped Server distribution on Linux x86_64 with a Java 17 JDK. If your
distribution lacks these scripts, [build it from this source](#build-and-prepare) first.
Prepare the runtime once, select it, then initialize and start the Server. The graph
APIs and normal start/stop commands stay the same; Topling's native options are
configured in `conf/toplingdb.yaml`. Use new, empty, service-writable data and WAL
configured in `conf/toplingdb.yaml`. The shipped native profile uses community-compatible SkipList
memtables and BlockBasedTable files; it does not require CSPP, DispatcherTable
or private compression plugins. Its 64 MiB cache and 16 MiB write buffers are
individual native budgets, not a process memory limit. Budget for every database
and column family and tune the profile for the deployment.

With the tested community JNI, EasyMigrate applies these YAML values when the
database opens, overriding the corresponding Java RocksDBOptions values.
The observed settings are a 64 MiB block cache, 16 MiB write buffers and three
write buffers; Java initializes the latter two to 128 MiB and six beforehand.
Other JNI builds must be checked against their persisted OPTIONS files and
`rocksdb.block-cache-capacity`; Java option getters before open do not establish
the effective native settings.

Custom profiles can require additional plugins in the chosen JNI. Preparation
imports the selected profile to verify its plugins before installing the
runtime. Existing data written with other table formats still requires those
formats' readers; changing this default does not convert existing SST files.
For existing CSPP installations, preserve the matching JNI and native options;
`conf/toplingdb-legacy-cspp.yaml` retains the prior configuration and readers in
Server, PD and Store distributions. Read the [Topling upgrade notes](upgrade-notes.md#topling-native-profiles)
before applying the new profile or its smaller memory and compaction defaults.

Use new, empty, service-writable data and WAL
directories outside the distribution for this example.

**1. Prepare the runtime.** Supply your ToplingDB JNI JAR and its trusted SHA-256:
Expand Down Expand Up @@ -569,8 +592,18 @@ entry, the ELF architecture and native dependencies. Before installation, it ope
closes a disposable database with the selected JNI and checks that a probe configuration
changes the persisted write-buffer size. A marker or matching hash alone is
insufficient: builds without the EasyMigrate configuration entry point are rejected. The
probe validates the configuration entry point, not existing-data compatibility or every
setting in your production profile. Its checksum receipt binds the probe to the
probe validates the configuration entry point. A second native import validates
`TOPLINGDB_EASY_MIGRATE_CONF` when set, otherwise the component's
`conf/toplingdb.yaml`; unavailable plugins fail preparation before publication.
It does not open databases using production WAL/log paths.
Relative profile overrides are converted to absolute paths against the caller's
working directory by both preparation and runtime selection, before the launcher
changes directories. Resolution ignores `CDPATH` and follows physical directory
semantics for symlinks combined with `..`, matching the file checked for readability.
Use the same file for preparation and service startup.
This is not an existing-data compatibility test or validation of every production
column family. Keep an explicit profile override in the service environment too.
The checksum receipt binds the capability probe to the
installed JAR and native library. Launchers reject missing or stale receipts; prepare a
fresh distribution when upgrading from an older preparation script. It installs
`topling/rocksdbjni.jar`, its matching native library and optional web resources outside
Expand Down
52 changes: 52 additions & 0 deletions docs/upgrade-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Storage and scan upgrade notes

These notes describe development storage changes. A published image can lag the
source revision; check that the deployed build contains the corresponding fixes.

## Required shard scan bounds

`traversers/vertices/scan` and `traversers/edges/scan` now reject a missing
`start` or `end` with HTTP 400 on **all backends**. Previously RocksDB could
throw an NPE and return 500, while HStore and in-memory implementations could
interpret omitted values as zero and run an incomplete scan. Both parameters
are now mandatory even when that older behavior appeared to succeed.

For an export, obtain all ranges from the matching `vertices/shards` or
`edges/shards` endpoint. Keep each range's exact boundary strings and paginate
it independently with an explicit initial `page=`. Only RocksDB and HBase
interpret empty bounds as an open range. Do not use `start=&end=` for a
whole-graph HStore or in-memory export. See [REST usage](rest-api-usage.md#export-a-shard-with-bounded-pages).

## Topling native profiles

The new default `conf/toplingdb.yaml` supports the tested community JNI without
CSPP plugins. It changes native formats and tuning from the previous default:

| Setting | Previous CSPP profile | New community profile |
| --- | --- | --- |
| Memtable/table factories | CSPP with DispatcherTable and CSPPMemTabTable readers | SkipList and BlockBasedTable |
| Block cache | 8 GiB | 64 MiB |
| Write buffer / maximum buffers | 128 MiB / 6 | 16 MiB / 3 |
| Maximum background jobs | 8 | 2 |

Other prior compaction tuning is also absent from the smaller community profile.
This is a configuration and performance change, not a transparent optimization
or an existing-data format conversion. With the tested community JNI, native
EasyMigrate options override corresponding Java options when opening a database.
Inspect effective OPTIONS and cache capacity when using a different JNI build.

For an existing Topling installation, stop the component and retain its previous
JNI, configuration and a recoverable data backup. The Server, PD and Store
distributions also ship `conf/toplingdb-legacy-cspp.yaml`, preserving the old
profile unchanged. Select that profile, or the deployment's previous tuned
profile, through an absolute `TOPLINGDB_EASY_MIGRATE_CONF` path during preparation
and startup. Keep the native library that provides the required CSPP readers.
The community JNI used for validation lacks those readers and cannot validate
old CSPP SST data; such an upgrade needs a matching JNI and old-format dataset
before deployment. Do not replace its options with the new community profile.

The prepare script verifies JNI capabilities with a disposable database and
imports the selected profile before publication. This import checks plugin
availability; it does not read existing business SSTs or certify their
compatibility. Relative profile paths are normalized before a launcher changes
its working directory; absolute service configuration is recommended.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
<outputDirectory>conf</outputDirectory>
<fileMode>644</fileMode>
</file>
<file>
<source>${project.basedir}/../../hugegraph-server/hugegraph-dist/src/assembly/static/conf/toplingdb-legacy-cspp.yaml</source>
<outputDirectory>conf</outputDirectory>
<fileMode>644</fileMode>
</file>
</files>

<dependencySets>
Expand Down
1 change: 1 addition & 0 deletions hugegraph-server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ RUN apt-get -q update \
procps \
curl \
iproute2 \
unzip \
vim \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
Expand Down
Loading
Loading