Compare commits

...

624 Commits
tmp ... master

Author SHA1 Message Date
KAI 39f4f8565a
fix(dist): gate init-store on a dedicated init_store.enabled option (#3119)
TODO: we need handle `usePD` in future

---------

Co-authored-by: imbajin <jin@apache.org>
2026-08-05 21:57:33 +08:00
KAI de62d97f34
fix(server): configure finite DNS cache TTL (#3126)
1. A Store pod is replaced in Kubernetes and comes back on a new IP behind the
   same stable DNS name.
2. HugeGraph Server runs with `HugeSecurityManager` installed by default.
3. With a `SecurityManager` present and no explicit policy, Java 11 falls back to
   `networkaddress.cache.ttl = -1`, so `InetAddressCachePolicy` is `FOREVER`.
4. The Server therefore keeps resolving the Store name to the old pod IP, and
   HStore writes keep going to an address that no longer exists.
5. Nothing recovers this until the Server process is restarted.

The setting is only honoured as a **security** property. The ordinary
`-Dnetworkaddress.cache.ttl` system property has no effect here, which is why
that form is deliberately not used.

---------

Co-authored-by: imbajin <jin@apache.org>
2026-08-04 21:24:18 +08:00
KAI 1716c77486
refactor: replace lsof port preflight with ss/netstat (#3105)
Fix a startup hang in kind/Kubernetes environments — the case that surfaced while bringing up the Helm chart. In a pod where `ulimit -n` is very large, `lsof -i :PORT` walks an enormous file descriptor table and `start-hugegraph.sh` stalls before the server ever binds.

The fix replaces that `lsof` call in the server's `check_port`, and removes the dead `check_port` copies from PD/Store.
- retain a bounded real-clock startup smoke test

---------

Co-authored-by: imbajin <jin@apache.org>
2026-08-03 17:25:00 +08:00
KAI 8b2932c764
fix(server): retry all PD peers while waiting for storage (#3129)
- cap each PD connection attempt at 2 seconds
- cap each PD request at 3 seconds
- cover failover after a hanging first peer

---------

Co-authored-by: imbajin <jin@apache.org>
2026-07-31 21:52:47 +08:00
KAI b026a90a0c
fix(store): bind each gRPC stub to its own channel (#3128)
AbstractGrpcClient opens concurrency (32) ManagedChannels per target, but
both stub-pool initializers used one precomputed channel index inside their
loops. Every pool entry therefore pointed at the same channel while the other
31 channels remained idle.

- use channels[i] in the blocking and async pool initializers
- add self-contained tests that verify every pool channel is bound
- add ClientSuiteTest so the store-client-test profile runs the tests

Fixes #3125
2026-07-31 21:47:22 +08:00
legendpei b9710a7b03
fix(server): handle repeated range predicates correctly (#3122) 2026-07-28 21:12:26 +08:00
legendpei f8e7abf9b1
chore(server): remove outdated backends code (#3116)
Remove the backend implementations that have been unsupported since 1.7.0, and
clean up their related build, distribution, test, release, and documentation
artifacts.

- retain the server and backend component boxes in the ASCII diagram
- show HugeGraph-PD and HStore as separate distributed components
- keep removed legacy backends out of the current topology

---------

Co-authored-by: imbajin <jin@apache.org>
2026-07-27 17:39:54 +08:00
Sean c10779dc6d
feat(server): support build & use(RocksDB) on RISC-V (#3102)
- Address the HugeGraph Server + RocksDB `linux/riscv64` build and minimum runtime
  support tracked by #3099.
- Keep the change isolated from the existing Docker image design and from the JDK,
  build, and test paths used by other architectures.

---------

Co-authored-by: Sean <sean@SeandeMacBook-Pro.local>
2026-07-25 13:45:19 +08:00
lokidundun e960cc5ec2
fix(server): skip unsafe count optm for nested predicates (#3100) 2026-07-23 11:21:24 +08:00
imbajin 89b648a7f9
feat: support secure Hubble monitoring targets (#3096)
Provide the minimum Server/PD compatibility and security boundary needed by Hubble native
monitoring and GraphSpace administration. Matching Hubble work:
https://github.com/apache/hugegraph-toolchain/pull/743
2026-07-21 14:37:33 +08:00
imbajin a80291223c
perf(docker): build Java artifacts natively (#3092)
- bind Maven build stages to BUILDPLATFORM
- keep all runtime stages target-platform specific
- avoid emulated Maven builds for ARM images
- cover PD, Store, standalone, and HStore images
2026-07-12 21:36:10 +08:00
Dev Hingu 74e439fbbc
chore(commons): remove redundant version property (#3089)
* fix(deps): remove redundant hugegraph-commons.version property

* fix(deps): update stale reference of hugegraph-commons.version
2026-07-12 20:27:09 +08:00
Yeaury 99936be5f4
feat(server): adapt Hubble 2.0 & add graph/role management (#3008)
Main Changes
Graph management (GraphsAPI.java)
GraphSpace and default-role APIs (GraphSpaceAPI.java)
GraphSpace managers (ManagerAPI.java)
Schema templates (SchemaTemplateAPI.java)
Authentication and graph metadata support

---------

Co-authored-by: imbajin <jin@apache.org>
2026-07-11 02:52:37 +08:00
Tsukilc 2d63804206
refactor(server): disable legacy master-worker scheduler logic (#3082)
This PR soft-disables the pre-PD master-worker task scheduling path while keeping old configs and task data upgrade-safe. Scheduler selection is now backend-driven: `hstore` uses `DistributedTaskScheduler`, and other backends use the local `StandardTaskScheduler`.

---------

Co-authored-by: Himanshu Verma <himnshuverma10152006@gmail.com>
Co-authored-by: imbajin <jin@apache.org>
2026-07-08 13:03:56 +08:00
legendpei 03e6b8e9ef
fix(core): keep unsafe range filters local (#3068) 2026-06-29 12:56:27 +08:00
contrueCT 86e0a66fd9
chore(ci): add gremlin-console smoke test (#3040) 2026-06-23 19:44:53 +08:00
Davide Polato 398a5edc95
fix(core): self-heal etcd meta watch on transport reconnect (#3062)
EtcdMetaDriver.listen/listenPrefix handed jetcd a bare Consumer<WatchResponse>,
so a terminal watch error (e.g. after a transport reconnect) was swallowed and
the JVM-global schema-cache-clear listener died silently: a node stopped
receiving cross-node cache-clear events with no error or warning.

Switch to the Watch.Listener overload and re-subscribe on onError/onCompleted
via a daemon-backed backoff, mirroring the self-heal PdMetaDriver already gets
from KvClient. The driver watch now stays live across reconnects, so
CachedSchemaTransactionV2's register-once flag staying true is correct; the
unused resetMetaListenerForReconnect stopgap and its TODO are removed.
2026-06-23 19:43:04 +08:00
contrueCT 63c97ff93f
fix(server): avoid loading huge task results for metadata queries (#3060) 2026-06-21 20:27:45 +08:00
Davide Polato c3f56b5e9f
fix(core): ref-count store event listener to fix owner-first close leak (#3058)
storeEventListenStatus had the same owner-first-close bug #3017 fixed for
graph cache listeners: non-owner close() dropped the entry and skipped
unlisten() as a no-op, leaking the owner's listener.

Apply CacheListenerHolder ref-count pattern: StoreListenerHolder +
STORE_EVENT_LISTENERS in CachedGraphTransaction, acquire/release via
compute() with provider-identity guard for close/reopen.

Removes storeEventListenStatus from GraphTransaction and
restoreStoreListenerStatusForKnownTeardownBug workaround from tests.
CachedSchemaTransaction* unaffected (per-instance, balanced 1:1).
2026-06-17 12:39:35 +08:00
legendpei 5ddeb0331c
feat(server) : make buffer max capacity configurable (#3049)
Move BytesBuffer.initMaxBufferCapacity() and other process-wide static
config initializations before LockUtil.init() so that validation failures
(e.g. invalid or conflicting serializer.buffer_max_capacity) cannot leave
orphaned lock groups in LockManager, which would block subsequent graph
load attempts without a process restart.

🤖 Generated with [Qoder][https://qoder.com]
2026-06-15 14:01:10 +08:00
KAI ef5d4e0b45
docs: document -d flag and Docker process supervision model (#3056)
- Add -d true|false option to PD and Store startup options sections
  (default: true = daemon; false = foreground for Docker/supervisors)
- Add section to docker/README.md explaining HEALTHCHECK endpoints
  and the Java process supervision model (replaces old cron monitor)

Chunk 10 of #3043.
2026-06-09 18:24:21 +08:00
KAI 0ecd844d9e
chore(ci): exit 77 when tools missing to distinguish skip from pass (#3055)
All three startup test scripts previously exited 0 when required tools
(lsof, curl, java) were not found. This is indistinguishable from a
passing test run — CI shows green even though no tests ran.

Change skip exits to 77 (conventional skip code) and update the CI
workflow steps to treat exit 77 as a visible skip notice rather than
a failure.

Flagged as non-blocking follow-up in reviews of #3044 and #3047.
Related to: #3043
2026-06-09 17:13:02 +08:00
Vaibhav Joshi 39dfb2da5c
fix: gremlin-console.sh fails on Mac M/ARM CPU #3050
* fix [Bug]: gremlin-console.sh fails on Mac M4 (Apple Silicon)#3031

Added org.fusesource.jansi:jansi:2.4.0 as a runtime dependency in
`hugegraph-server/hugegraph-dist/pom.xml` to prevent
NoClassDefFoundError: org/fusesource/jansi/AnsiConsole when launching gremlin-console.
2026-06-08 14:20:48 +08:00
contrueCT 42c039d695
fix(core): align count strategy connective steps (#3037) 2026-06-08 12:38:15 +08:00
KAI fc226637e9
chore(docker): add HEALTHCHECK & clean Dockerfiles (#3052)
Without HEALTHCHECK, docker ps always shows 'Up' even when Java has
crashed inside the container. Add HEALTHCHECK to all three Dockerfiles:
- Server: curl http://localhost:8080/versions
- PD:     curl http://localhost:8620/v1/health
- Store:  curl http://localhost:8520/v1/health

Fallback: if HTTP is not yet up but Java is alive (kill -0 on pid file),
report healthy. Avoids false unhealthy during startup.

Remove cron: Docker containers use foreground mode (-d false) after the
entrypoint fix. The cron-based monitor is for VM/bare-metal only and is
never started in Docker — removing it shrinks the image and reduces
attack surface.

Endpoints match what is already used in docker/docker-compose.yml.

Related to: #3043
2026-06-08 11:16:30 +08:00
KAI 817887dcce
fix(docker): supervise Java process in entrypoints instead of tail -f /dev/null (#3051)
Problem: all three docker-entrypoint.sh files used tail -f /dev/null to
keep the container alive. When Java crashed, tail kept running and the
container stayed up with no Java inside — Docker restart policy never fired.

Verified locally: kill -9 Java inside running container -> container
exits -> Docker restarts it automatically (tested 3 times for server,
PD restart loop confirmed for pd).
2026-06-08 11:14:19 +08:00
lokidundun 1f61c4839a
refactor(server): optimize rockdb batch query perf (#2982)
* optimize: Optimize RocksDB batch query performance

* Refactor getByIds to queryByIds in RocksDBTable

* Modify queryByIds to use super method temporarily

Temporarily use super.queryByIds() instead of getByIds() for batch version support.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-05 11:13:49 +08:00
KAI 16382ccfbd
fix(pd,store): fg mode exit code propagation in startup scripts (#3047)
In foreground mode (-d false), start-hugegraph-pd.sh had no foreground
branch — the script always backgrounded Java with exec ... &, wrote $!
to the pid file, and exited 0, losing Java's exit code entirely.

Fix: add DAEMON="true" default and -d flag to getopts. In the daemon
branch, keep the existing exec ... & pattern. In the foreground branch,
write $$ to the pid file before exec (exec replaces the shell with Java,
so $$ == Java's PID after exec), then exec java without & so the process
blocks and Java's exit code propagates out directly.

No trap needed in the foreground branch — exec replaces the shell
process with Java, so signals from Docker/systemd go directly to Java
without a wrapper to forward through.

Add test-start-hugegraph-pd.sh with 4 tests (daemon regression,
foreground blocking, exit code propagation on SIGKILL, SIGTERM
forwarding via exec) — 12 assertions, all pass after the fix.

Baseline on unmodified code: 3 passed, 9 failed.
After fix: 12 passed, 0 failed.

Wire test into pd-store-ci.yml for the RocksDB backend.

Related to: #3043
2026-06-04 21:25:42 +08:00
legendpei 7f0a44adc0
fix(server): handle match() in no index case (#3039) 2026-06-04 17:50:07 +08:00
KAI d6e6216222
fix(server): fix foreground mode exit code propagation in startup scripts (#3044)
The previous implementation captured $! after the daemon/foreground
if/else block. The script blocked at hugegraph-server.sh until Java
exited, then $! was empty, the pid file got an empty string, and the
script exited 0, losing Java's exit code entirely.
2026-06-03 21:42:36 +08:00
Davide Polato 3405832800
fix(server): normalize typed DEFAULT_VALUE after JSON reload (#3035)
Normalizes PropertyKey default values to their declared data type upon retrieval. Previously, values stored in userdata could lose their original type during serialization and deserialization (e.g., Date becoming String), leading to type mismatches.

The `defaultValue()` method now converts deserialized string representations back to their expected runtime types. This change is verified with extensive tests covering schema parsing, vertex property assignment, and both binary and text serializers.
2026-06-03 21:31:26 +08:00
Vaibhav Joshi a49bf667a9
docs(server): add Docker with HBase validation runbook 2026-06-03 21:18:24 +08:00
legendpei beb30eee62
fix(server): avoid extracting text range filters (#3034) 2026-06-02 12:40:49 +08:00
contrueCT b9a3dd9d99
chore(ci): enable hugegraph-struct tests (#3038) 2026-05-27 18:25:19 +08:00
Vaibhav Joshi 31e8268760
docs: update "Build from Source" instructions in README (#3022)
- Replace exploratory README steps with the actual packaged archive path
- Use the version placeholder instead of hard-coded 1.7.0
- Keep the PR focused on the source-build documentation fix

---------

Co-authored-by: imbajin <jin@apache.org>
2026-05-27 18:20:00 +08:00
Vaibhav Joshi f56462a14d
feat(server): use HBase 2.6 to replace hbase-shaded & support docker-compose way (#3021)
-Added hbase-shaded-client and hbase-endpoint dependencies instead of custom hbase-shaded-endpoint library.
-Added docker files and HBASE.md containing instructions for HBase backend
- Updated known-dependencies.txt to reflect the minimal allowlist.
Improved pom.xml comments to document exclusion rationales and
addressed automated review feedback regarding dependency management.
2026-05-22 11:27:05 +08:00
Davide Polato 454dd3d799
fix(server): keep schema ~create_time as Date after reload (#3026)
Normalize server-side schema ~create_time userdata in SchemaElement so serializer reloads and fromMap paths keep the Date contract.

Add SchemaElement, TextSerializer, and BinarySerializer coverage.

The builder accumulates userdata via Userdata.put() before eliminate()
runs, so `.userdata(CREATE_TIME, "").eliminate()` parsed "" as a date
and threw before the key-only removal path. Pass a blank ~create_time
through unchanged; non-empty malformed values still throw on the add
path, so the existing contract is unchanged.
2026-05-19 17:35:51 +08:00
KAI 8d095e1d99
perf(docker): improve all images build cache efficiency (#3025)
- Fix .gitattribut -> .gitattributes typo in .dockerignore
- Fix **/*.tar.gz* -> **/*.tar.gz (remove unintended trailing wildcard)
- Remove **/target/dist/ (redundant, already covered by **/target/)
- Restore cron to apt-get install in all 4 Dockerfiles to keep the
  existing start-hugegraph.sh -m true monitor path working
2026-05-18 12:47:20 +08:00
Soyaazz 66e5339e3a
fix(server): different graph name share the same backend (#3027)
## Main Changes

Change `ServerInfoManager.selfNodeId()` which returns "server-1" previously to "{graphname}/server-1"

## Upgrade impact

This change namespaces the server id by graph name, so old unfinished tasks in the non-PD local scheduler may still reference the previous bare server id, for example `server-1`.

Those historical tasks can remain visible, but they may not be restored or cancelled by the new namespaced server id after upgrade. The impact is limited to unfinished local-scheduler tasks that already existed before upgrading; newly scheduled tasks use the new namespaced id. To avoid this compatibility edge case, finish or cancel pending local tasks before upgrading.
2026-05-17 11:54:28 +08:00
Davide Polato f69ca66cd6
fix(server): align cache event actions in legacy EventHub path (#3017)
- Align legacy cache invalidation producers and listeners on ACTION_INVALID and
  ACTION_CLEAR, removing the obsolete ACTION_INVALIDED/ACTION_CLEARED constants.
- Add EventHub.notifyExcept(...) so cache transactions and the cache notifier
  bridge can avoid re-processing their own local listener while still delivering
  events to other listeners.
- Track registered graph/schema cache listeners per graph so notifyExcept(...)
  uses the listener instance actually registered on the EventHub, including
  multi-transaction cases where later transactions reuse the first listener.
- Update cache notifier forwarding to prevent local RPC bridge loops after action
  names are unified.
- Add regression coverage for notifyExcept semantics, graph/schema action names,
  listener teardown/re-registration, and notifier no-loop behavior.

- The holder keeps the EventHub listener registered while any transaction for the
  graph is alive, and unregisters/removes it only when the last transaction
  releases it. The registry update, ref-count decrement, and hub unlisten now run
  inside ConcurrentMap.compute() to avoid owner-closes-first invalidation gaps.

  Also add graph/schema regression coverage for owner-first close and last-close
  cleanup, including graph close/reopen handling for stale EventHub holders.
2026-05-15 11:25:33 +08:00
contrueCT e108076aca
fix(server): normalize bool range predicates in gremlin filters (#2991) 2026-05-09 15:23:52 +08:00
contrueCT de8781e182
chore(ci): optimize rerun workflow and add macOS RocksDB coverage (#3010)
- Resolve Travis helper directory to an absolute path
- Use the script directory directly for JaCoCo agent lookup
- Avoid nesting absolute paths under the repository root

---------

Co-authored-by: imbajin <jin@apache.org>
2026-05-08 15:46:33 +08:00
imbajin 06c52e48d4
chore: update project memories with latest codebase state(1.8.0) (#2998)
- Refresh all 8 memories to reflect current code (v1.7.0)
- Remove all PR number references (derivable from git history)
- Remove "Key Recent Changes" changelog section
- Remove CI implementation details (rerun delay/count)
- Describe current behavior as facts, not change events
- Mark legacy backends as excluded from Serena context
- Add GraphSpace, Swagger UI, TTL update, bridge networking info
2026-05-07 16:32:45 +08:00
Davide Polato ee177a0f70
fix(server): sync hstore schema cache clears (#3011)
Register a JVM-wide MetaManager listener on CachedSchemaTransactionV2 so
remote nodes clear their V2 schema-id/schema-name caches and the array
attachment on schema add/remove. Events carry a per-JVM source id to skip
self-echo; 

legacy plain-string payloads still accepted for safe rolling
upgrades. Status transitions no longer broadcast to avoid notify storms
from background rebuild/remove jobs.
2026-05-06 20:59:36 +08:00
Davide Polato 836b34832b
fix(server): auto-recover session after Cassandra restart (#2997)
- Reset driver session after each transient failure in executeWithRetry()
  so retries reopen cleanly via lazy open()
- Remove redundant finally block in reconnectIfNeeded(); null session
  directly on DriverException
- Store retryBaseDelay as field, reuse in open() (removes double-read)
- One-time LOG.warn via AtomicBoolean for commitAsync() retry gap
- Tighten defaults: max_delay 60s→10s, max_retries 10→3, interval 5s→1s
- Wire retry config via HugeConfig in tests; add cross-validator tests
2026-04-26 04:13:06 +08:00
contrueCT 68dd29b29b
refactor(server): add logs for load-based request rejection (#2972)
* fix(filter): enhance load detection logging and memory management
* fix(api): refine low-memory rejection handling
2026-04-25 16:02:49 +08:00
Himanshu Verma bcaa5f1ae5
fix(server): fix check_port port extraction for schemeless URLs (#3005) 2026-04-25 15:14:03 +08:00
Çağlar Eker 7afce9daa2
fix(pd): populate memberSize in GET / endpoint response (#3003)
* fix(pd): complete GET / stats fix and add test coverage

- Use pdService.getMembers() for memberSize (consistent with cluster())
  instead of RaftEngine directly, as suggested in issue #3002 discussion
- Add dataState field to BriefStatistics: exposes worst partition health
  state across all graphs, the most useful missing operational indicator
- Align graphSize to count only user-facing graphs (endsWith("/g")),
  matching the semantics of cluster() to avoid silent count discrepancy
- Add testQueryIndexInfo() to both RestApiTest classes to assert state,
  leader, memberSize > 0, and storeSize > 0 — catches this class of bug

* fix(pd): relax storeSize assertion in PD-only test environment

---------

Co-authored-by: imbajin <jin@apache.org>
2026-04-21 15:27:08 +08:00
imbajin a8ae76b617
fix(docker): skip partition wait for standalone rocksdb mode (#3000)
* fix(docker): skip partition wait for standalone rocksdb mode (#2999)

The `wait-partition.sh` script was called unconditionally in
`docker-entrypoint.sh`, causing standalone containers (rocksdb backend)
to hang for 120s printing "Waiting for partition assignment..." since
there is no Store service to respond.

Now reads the actual backend from `hugegraph.properties` and only runs
the partition wait when `backend=hstore`.
2026-04-20 15:09:52 +08:00
lokidundun 6a983f97e6
fix: enable CI badges displaying normally (#2996)
* fix: fix wrong image address

---------

Co-authored-by: imbajin <jin@apache.org>
2026-04-19 04:38:48 +08:00
contrueCT 9336b5e298
fix(server): guard count strategy on negative bounds (#2993)
* fix(traversal): guard count strategy on negative bounds

* test(traversal): cover repeat count on negative bounds

* test(traversal): cover collection count on negative bounds
2026-04-17 15:51:02 +08:00
contrueCT 470435457d
fix(query): handle conflicting edge label conditions safely (#2990)
HugeGraph may read LABEL from a ConditionQuery before the query is flattened when optimizing edge traversals. In contradictory label combinations such as inE('created').hasLabel('created', 'look').hasLabel('authored'), the previous intersection logic reused an empty set to mean both 'not initialized yet' and 'already intersected to empty'. That allowed later IN conditions to repopulate the candidate set and raised an Illegal key 'LABEL' with more than one value error instead of returning an empty result.

Track whether the intersection has been initialized independently so an empty intersection remains empty. This keeps the existing protection for true multi-value results, while allowing conflicting label predicates to fall back safely and produce no matches.

Add regression coverage for the low-level ConditionQuery behavior and for the edge traversal scenario from issue #2933, including a match()-based equivalent query to assert consistent zero-count results.
2026-04-13 16:12:31 +08:00
contrueCT 28c39b65d2
chore(ci): add automatic rerun controller for flaky workflows (#2984)
* ci: increase retry delay for rerun jobs from 60 to 180 seconds
2026-04-11 23:22:29 +08:00
Uğur Tafralı 06097c8a20
refactor(server): allow TinkerPop exceptions in Gremlin resp (#2987)
* fix(api/gremlin): allow TinkerPop exceptions in Gremlin responses

* Address review feedback
2026-04-10 17:57:05 +08:00
Himanshu Verma c0a2b93e45
fix(docker): enable docker logs for pd/store/server containers (#2980)
* fix(docker): wire console appender to AsyncLogger for hugegraph server
2026-04-05 10:22:48 +08:00
Himanshu Verma 9126c80e41
docs: update Docker deployment docs for bridge networking migration (#2963)
- Create docker/README.md with full setup guide, env var reference,
  port table, health checks, and troubleshooting
- Fix hugegraph-store/docs/deployment-guide.md: replace wrong env vars
  (GRPC_HOST, RAFT_ADDRESS etc.) with correct HG_* names
- Update K8s manifest in deployment-guide.md to use HG_* env vars
- Fix 7 files pointing to dead docker/example/ directory
- Add Docker bridge network notes to PD configuration docs
- Add distributed cluster section to server Docker README

Relates to: #2952

* docs: clarify temporary entrypoint mount workaround in docker/README.md

The 3-node and single-node quickstart compose files currently mount
entrypoint scripts from source as a workaround until updated Docker
images are published with the new entrypoints baked in.

Add a clear note explaining this temporary requirement so users are
not confused about needing a full source clone to run the cluster.

---------

Co-authored-by: imbajin <jin@apache.org>
2026-03-23 20:57:55 +08:00
Himanshu Verma 8d758d5446
chore(docker): remove tmp volume mounts after image update (#2976) 2026-03-22 10:56:17 +08:00
contrueCT 5f91d8b5c6
refactor(server): disable GraphSpaceAPI and ManagerAPI in standalone mode (#2966)
* feat(api): disable GraphSpaceAPI and ManagerAPI in standalone mode

- Add public isUsePD() accessor to GraphManager to expose PD status
- Add checkPdModeEnabled() helper in API base class
- Call checkPdModeEnabled() in all public methods of GraphSpaceAPI (list/get/create/manage/delete)
- Call checkPdModeEnabled() in all public methods of ManagerAPI (createManager/delete/list/checkRole/getRolesInGs)
- Returns HTTP 400 with message 'GraphSpace management is not supported in standalone mode'
- Add standalone-mode rejection tests in GraphSpaceApiTest and ManagerApiTest

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: imbajin <jin@apache.org>
2026-03-20 16:27:15 +08:00
Himanshu Verma 0154c06422
refactor(docker): migrate single-node compose from host to bridge networking (#2952)
* docker: migrate from host to bridge networking

Replace network_mode: host with explicit port mappings and add configuration
volumes for PD, Store, and Server services to support macOS/Windows Docker.

- Remove host network mode from all services
- Add explicit port mappings (8620, 8520, 8080)
- Add configuration directories with volume mounts
- Update healthcheck endpoints
- Add PD peers environment variable
2026-03-20 16:21:59 +08:00
PJ Fanning 62bcdc5d78
fix(dist): use HTTPS for Travis download URLs (#2973)
* Update HBase/Cassandra download address to HTTPS
2026-03-20 16:18:50 +08:00
Himanshu Verma ab12b35b6a
fix(pd): add timeout and null-safety to getLeaderGrpcAddress() (#2961)
* fix(pd): add timeout and null-safety to getLeaderGrpcAddress()

The bolt RPC call in getLeaderGrpcAddress() returns null in Docker
bridge network mode, causing NPE when a follower PD node attempts
to discover the leader's gRPC address. This breaks store registration
and partition distribution when any node other than pd0 wins the
raft leader election.

Add a bounded timeout using the configured rpc-timeout, null-check
the RPC response, and fall back to deriving the address from the
raft endpoint IP when the RPC fails.

Closes apache/hugegraph#2959
2026-03-20 16:17:42 +08:00
Himanshu Verma 5adf14cb24
fix(pd): resolve hostname entries in IpAuthHandler allowlist (#2962)
- Resolve allowlist hostnames to IPs using InetAddress.getAllByName
- Add refresh() to update resolved IPs when Raft peer list changes
- Wire refresh into RaftEngine.changePeerList()
- Add IpAuthHandlerTest covering hostname resolution, refresh behavior, and failure cases
2026-03-17 14:16:34 +08:00
imbajin 1f40f055ae
doc: add comment for historical package names (#2970) 2026-03-17 00:53:28 +08:00
lokidundun 5578b79648
refactor: add the desc of the vars in swagger-ui (#2969) 2026-03-16 15:31:14 +08:00
imbajin 94c03a9aec
refactor: remove 'incubating' branding, update docs & packaging (#2965)
* chore: remove 'incubating' branding, update docs & packaging

Replace references to 'incubator'/'incubating' across the repo to the final 'hugegraph' branding and packaging names. Updates include: removal of DISCLAIMER, NOTICE year bump, README and docs link/badge fixes, pom final.name changes (remove -incubating suffix),

Dockerfile and assembly scripts adjusted to new package paths, numerous docs and tests updated to new URLs/paths, mailing list/contact updates, and minor serena project.yml additions.

---------

Co-authored-by: contrueCT <contrue_CT@outlook.com>
2026-03-14 17:41:12 +08:00
Himanshu Verma 050581067a
docs: remove references to removed hugegraph-style.xml (#2949) 2026-02-14 14:32:16 +08:00
Tsukilc ef2db2c9c0
feat(server): add gs profile api (#2950) 2026-02-14 14:29:59 +08:00
Himanshu Verma 6ffdd9ccbf
refactor(server): unify URL configs when scheme is missing (#2944)
- Add URL normalization support for config options
- Automatically prefix missing schemes (http://, https://)
- Log warnings when auto-correcting user-provided values
- Add comprehensive test coverage for normalization logic
- Update config files to demonstrate the feature

Changes:
- ConfigOption: Add withUrlNormalization() builder method
- ServerOptions: Apply normalization to REST, Gremlin, K8s URLs
- HugeConfig: Implement lazy cache and normalization logic
- Add ServerOptionsTest with 5 test cases
- Simplify URLs in main and Docker config

* repair

---------

Co-authored-by: imbajin <jin@apache.org>
2026-02-03 15:11:32 +08:00
imbajin 88ad859d3e
doc: update Quick Start & Architecture in README (#2947)
* doc: TOC, Quick Start, Architecture

Overhaul README to improve developer onboarding and documentation. Adds a Table of Contents, Quick Start (TL;DR + detailed Docker, binary, and build-from-source instructions), verification steps, and a Module Map. Expands Features into bullet points and introduces detailed Architecture sections including ASCII and Mermaid diagrams, a deployment comparison table, and module overview. Adds contributor guidance, community/contact info, and ecosystem links. Also updates .serena/project.yml to set project_name and include placeholders for base/default modes, included optional tools, and fixed_tools to enable per-project Serena configuration.
2026-02-02 17:31:17 +08:00
Soyaazz 9babe49391
test(server): enable run single unit test (#2940)
* test(server-test): enable run single unit test

* fix: thread-safe graph() method

* fix: more clear error handling in graph() method
2026-01-29 16:06:08 +08:00
Himanshu Verma fc391a7c66
fix(server): prevent await deadlock on ContextCallable failure (#2941)
Add a unit test that explicitly covers the failure scenario described in the PR,
where ContextCallable fails before entering runAndDone().

The test verifies that Consumers.await() does not hang when the worker task
fails during ContextCallable execution, relying on safeRun() to always
decrement the latch in its finally block.

This test would deadlock on the previous implementation and passes with the
current fix, ensuring the issue cannot regress.
2026-01-26 14:59:18 +08:00
slightsharp 99baf2bde2
docs: fix some typos in comments (#2943)
Signed-off-by: slightsharp <slightsharp@outlook.com>
2026-01-23 18:55:03 +08:00
imbajin e0f572b54c
refactor(server): support update TTL in labels & enhance configs (#2938) 2026-01-22 16:38:44 +08:00
Soyaazz 37be6cdde3
test(cluster-test): bump ct to version 1.7.0 (#2921) 2026-01-06 16:17:35 +08:00
ChoHee a93cc218d9
chore(server): remove outdated ConfigAuthenticator (#2927) 2026-01-04 16:28:51 +08:00
Himanshu Verma d641fdb606
docs: fix Cypher documentation link in README (#2925) 2026-01-04 16:28:30 +08:00
Ken 423ede0746
fix: optimize code and update risky deps (#2918) 2026-01-04 16:27:32 +08:00
Tsukilc 2432603d31
fix(server): fix npe in non-auth mode (#2912) 2026-01-04 16:27:09 +08:00
imbajin eec38719d8
chore: update the status of distributed modules (#2916)
* chore: update the status of distributed modules

Eliminated mentions of BETA status from AGENTS.md, README.md, and configuration files for HugeGraph PD and Store. This clarifies the current development status and streamlines documentation for production use.

* docs: update README with requirements and architecture info

Added sections for Requirements and Architecture, specifying Java and Maven versions and deployment options. Updated Docker command to use version 1.7.0. Included build from source instructions with Maven command.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update run-api-test.sh

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: VGalaxies <vgalaxies@apache.org>
2025-12-26 10:07:51 -06:00
Soyaazz d28526e141
fix(pd): pd raft-follower failed to get leader address due to npe (#2919) 2025-12-17 16:26:39 +08:00
vaughn c6d94b47cc
feat: add slack channel (#2920)
Co-authored-by: imbajin <jin@apache.org>
2025-12-17 09:57:23 +08:00
Peng Junzhi 534c81e5fc
fix: use slim docker image (#2903) 2025-12-15 13:35:13 +08:00
Peng Junzhi 18569c49cc
docs: migrate 1.5.0 in readme to 1.7.0 (#2914) 2025-11-28 22:10:12 +08:00
contrueCT 9a3daf824b
refactor(store): fix reflection parameter error and extract duplicate methods to RaftReflectionUtil (#2906) 2025-11-27 13:54:11 +08:00
Peng Junzhi b12425c203
fix: add missing license and remove binary license.txt & fix tinkerpop ci & remove duplicate module (#2910)
* add missing license and remove binary license.txt

* remove dist in commons

* fix tinkerpop test open graph panic and other bugs

* empty commit to trigger ci
2025-11-16 02:07:01 -06:00
Tsukilc 41d0dbcd3a
fix(server): fix reflect bug in init-store.sh (#2905) 2025-11-12 19:58:52 +08:00
imbajin 496b15048a
feat: init serena memory system & add memories (#2902) 2025-11-06 14:22:40 +08:00
Peng Junzhi de0360b118
fix: migrate to LTS jdk11 in all Dockerfile (#2901) 2025-11-04 06:50:42 -06:00
Tsukilc b7998c1c31
refactor(server): remove graph param in auth api path (#2899) 2025-11-04 19:34:12 +08:00
Tsukilc ca5fc0cb29
fix(server): support GraphAPI for rocksdb & add tests (#2900) 2025-11-04 19:33:25 +08:00
Tsukilc 2e0cffe7c4
feat(server): add path filter for graphspace (#2898) 2025-11-04 19:32:28 +08:00
Soyan 00e040be14
fix(store): handle NPE in getVersion for file (#2897)
* fix(store): fix duplicated definition log root
2025-11-03 15:23:30 +08:00
Guangyang Deng d7697f4718
chore(server): bump rocksdb version from 7.2.2 to 8.10.2 (#2896) 2025-11-01 04:10:08 +08:00
Soyan e66acccfda
fix(store): improve some potential lock & type cast issues (#2895)
* update(store): fix some problem and clean up code

- chore(store): clean some comments
- chore(store): using Slf4j instead of System.out to print log
- update(store): update more reasonable timeout setting
- update(store): add close method for CopyOnWriteCache to avoid potential memory leak
- update(store): delete duplicated beginTx() statement
- update(store): extract parameter for compaction thread pool(move to configuration file in the future)
- update(store): add default logic in AggregationFunctions
- update(store): fix potential concurrency problem in QueryExecutor

* Update hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/query/func/AggregationFunctions.java

---------

Co-authored-by: Peng Junzhi <78788603+Pengzna@users.noreply.github.com>
2025-11-01 04:08:14 +08:00
koi f92c5a44ee
docs(pd): update test commands and improve documentation clarity (#2893)
* docs(pd): update test commands and improve documentation clarity

* Update README.md

---------

Co-authored-by: imbajin <jin@apache.org>
2025-10-31 09:01:51 -05:00
Soyan 126885d86f
docs(store): update guidance for store module (#2894) 2025-10-31 19:03:59 +08:00
imbajin 5b3d295d93 docs(store): add deployment/practices/development docs
Introduces three new documentation files: best-practices.md, deployment-guide.md, and development-guide.md for HugeGraph Store. These guides cover production best practices, deployment topologies and steps, and developer environment setup and architecture, improving onboarding and operational clarity.
2025-10-29 15:58:32 +08:00
imbajin 21ef0bf755 docs(store): add comprehensive store design doc
Expanded README.md with detailed overview, architecture, configuration, deployment, integration, and operational guidance for HugeGraph Store.

Added new documentation files covering distributed architecture, integration guide, operations guide, and query engine to provide in-depth technical reference for users and developers.
2025-10-29 15:58:32 +08:00
koi b7758ef178 fix(server): handle graph data sync inconsistent problem (#74)
* feat(server): implement dynamic monitoring and management of graph instance

* refactor(server): consolidate authority setting in PdMetaDriver and HugeGraphServer

* refactor(service): enhance comments for clarity and synchronize graph start method
2025-10-29 15:58:32 +08:00
imbajin 062771fa56 docs(pd): add configuration & development guides for PD
Introduces comprehensive documentation for HugeGraph PD, including a configuration guide covering deployment scenarios, parameter tuning, and monitoring, as well as a development guide detailing environment setup, build/test workflows, code style, debugging, and contribution processes.
2025-10-29 15:58:32 +08:00
imbajin 66ff6682dd docs(pd): add PD API reference documentation
Introduces a comprehensive API reference for HugeGraph PD, detailing gRPC services, Protocol Buffers definitions, Java client usage, REST API endpoints, error handling, and best practices for integration and cluster management.
2025-10-29 15:58:32 +08:00
imbajin 053f562e0f docs(pd): add PD architecture documentation
Introduces a comprehensive architecture overview for HugeGraph PD, detailing system responsibilities, module structure, core components, Raft consensus integration, data flows, and inter-service communication. This document serves as a technical reference for developers and maintainers.
2025-10-29 15:58:32 +08:00
imbajin af1453402c docs(pd): init HugeGraph-PD README file
Added WARP.md to .gitignore.

The HugeGraph PD README was significantly expanded with detailed overview, architecture, quick start instructions, configuration examples, API documentation, testing, Docker usage, production notes, and community resources.
2025-10-29 15:58:32 +08:00
imbajin 2fb3ced8cc docs: add AGENTS.md with project guidance
Introduced AGENTS.md files to the root and all major modules to provide AI coding tool guidance, including architecture, build, test, and development workflows for each component.

Updated .gitignore to exclude various AI prompt files, ensuring only AGENTS.md is kept and others can be soft-linked as needed.
2025-10-29 15:58:32 +08:00
koi 5eeeb9a612 refactor(auth): simplify rpc-auth logic and clean legacy code (#73)
Enhanced internal authentication logic and documentation in Authentication.java, emphasizing production security best practices. Refactored TokenUtil for clarity and immutability. Improved code formatting in PDPulseTest and SampleRegister, and updated ServiceConstant with stricter external exposure warnings.

---------

Co-authored-by: imbajin <jin@apache.org>
2025-10-29 15:58:32 +08:00
imbajin 3c1dd5202c chore: update CodeQL workflow and cleanup dist.sh file
Upgraded CodeQL GitHub Actions to v3 for improved security and features. Enhanced .gitignore and pom.xml to exclude and clean up dist.sh files during build and packaging.

Removed unused hugegraph-struct dependency from hugegraph-store. Updated NOTICE copyright year to 2025.
2025-10-29 15:58:32 +08:00
Tsukilc dc4677673b chore: bump project version from 1.5.0 to 1.7.0 (#72)
* chore(server): improve log clarity and add null checks in api

* chore: bump version from 1.5.0 to 1.7.0

* chore: add todo in common pom.xml
2025-10-29 15:58:32 +08:00
imbajin da244812c4 fix(server): improve label matching and code clarity in HugeAuthenticator
1. Introduced a safe wildcard-based label matching method to prevent ReDoS attacks, replacing direct regex usage.

2. Refactored code for better readability, reordered admin checks, and made minor comment and formatting improvements throughout HugeAuthenticator.java.

3. Enhance zip extraction security with path validation
2025-10-29 15:58:32 +08:00
Tsukilc 7b20a9142d fix(struct): Fix the classpath conflict between struct and server (#65)
* fix(server): add META in HugeType

* fix(server): Add enumerations to the struct

* fix(struct): remove hugegraph-struct/schema to hugegraph-struct/struct/schema

* fix(struct): Change the loading order of classes

* fix(struct): Change the loading order of classes
2025-10-29 15:58:32 +08:00
Tsukilc a00e470f1b fix(server): fix auth test (#64)
* fix(server): Delete the redundant storage during the test

* fix(server): fix auth test
2025-10-29 15:58:32 +08:00
koi 33d8cee592 refactor(license): remove license management-related code and dependencies (#61)
* refactor(license): remove license management-related code and dependencies

* refactor(license): remove unused imports and redundant code

* feat(dependency): update the dependency list and add new dependencies

* refactor(license): mark initialization and validation methods as obsolete
2025-10-29 15:58:32 +08:00
Soyan 33740f519a fix: fix NPE in CI (#60) 2025-10-29 15:58:32 +08:00
Soyan 6184183734 refactor(store): integrate store client module (#47)
* refactor(store): Added query pushdown support for Server & PD

- Add StreamObserver implementation for server side
- Modified the visibility of member variables to support query pushdown
- Add HgSessionConfig.java

* refactor(store): Support get partition from pd based on graph name & code & start key

* chore(store): reformat code & code cleanup

* fix(store): fix problems in code review

fix(store): fix unused sessionConfig in HgStoreClient.java

fix(store): fix potential NPE exception

fix(store): Fix incorrect spelling

fix(store): Fix the unit inconsistency in the time comparison

Update hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/query/QueryExecutor.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Update hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/query/StreamSortedIterator.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Update hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/query/MultiStreamIterator.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Update hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/query/StreamFinalAggregationIterator.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore(store): remove unused code & modify import path

* fix(store): fix bug in ut

* fix(store): add missing table statement

* fix(store): fix ci problem

* Trigger ci

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-29 15:58:32 +08:00
Tsukilc f8cdff781c feat(server): change time fomat to yyyy-MM-dd HH:mm:ss.SSS 2025-10-29 15:58:32 +08:00
koi df58ed3af9 fix(pd): fix the NPE error in AbstractClient's constructor and remove unnecessary assert statements (#58)
* fix(pd): fix the NPE error in AbstractClient's constructor and remove createStub-related tests

* fix(test): Remove unnecessary assert statements
2025-10-29 15:58:32 +08:00
Soyan a2de993063 fix: fix problems found in ci (#51) 2025-10-29 15:58:32 +08:00
Soyan c78aece72a refactor(store): integrate store cli module 2025-10-29 15:58:32 +08:00
Tsukilc 98dcfaf995 fix(server): add ServerOptions: usePD to know whether user use 2025-10-29 15:58:32 +08:00
Tsukilc d5b1e8e0b2 chore(license): add dependencies in known-dependencies.txt 2025-10-29 15:58:32 +08:00
Tsukilc 4235a416dc fix(server): change graphspace/graph to graphspace_graph in hbase 2025-10-29 15:58:32 +08:00
Tsukilc 8e66ccf189 fix(test): fix test to support graphSpace 2025-10-29 15:58:32 +08:00
Tsukilc f1d08f8ae0 feat(server): Add graphSpace CRUD API, service API and registerAPI 2025-10-29 15:58:32 +08:00
Tsukilc 069b6e673f feat(server-test): add graphspace in test 2025-10-29 15:58:32 +08:00
Tsukilc 6a97d93608 feat(server): add graphSpace in HugeGraph.class 2025-10-29 15:58:32 +08:00
Tsukilc a35739b55f feat(server): add k8s api for graphSpace 2025-10-29 15:58:32 +08:00
Tsukilc c92d5f6ea6 feat(server): add kv store 2025-10-29 15:58:32 +08:00
JisoLya 95042946d2 fix(store): optimize options API parameter check & error handling 2025-10-29 15:58:32 +08:00
JisoLya c64429a29f chore(store): reformat code 2025-10-29 15:58:32 +08:00
JisoLya 649acf902f feat(store): add FixGraphIdController and RaftAPI; enhance status and test controllers 2025-10-29 15:58:32 +08:00
JisoLya 4ba1c96caf chore(store): remove deprecated request/response code 2025-10-29 15:58:32 +08:00
JisoLya c6d152cb3b fix(store): fix potential NPE and concurrency problem 2025-10-29 15:58:32 +08:00
JisoLya b3ef56078d chore(store): reformat code 2025-10-29 15:58:32 +08:00
JisoLya 4294b2415a refactor(store): replace DefaultDataMover with DataManagerImpl and update flush method visibility
- Change PartitionMetaStore.flush() from protected to public for broader access
- Replace usage of DefaultDataMover with DataManagerImpl in HgStoreNodeService
- Update Import and instantiation accordingly in StoreEngineTestBase
- Enhance JavaDoc formatting in StoreEngineTestBase for better readability
2025-10-29 15:58:32 +08:00
JisoLya 5a36a9cea3 feat(store): add raft closure and raft operation and SnapshotHandler 2025-10-29 15:58:32 +08:00
JisoLya ac7dd6c2bf feat(store): add async task processors and corresponding metadata 2025-10-29 15:58:32 +08:00
JisoLya dd46167402 refactor(store): update utils 2025-10-29 15:58:32 +08:00
JisoLya 7e0062c0ad feat(store): modify iterator & businessHandler to support computation push down 2025-10-29 15:58:32 +08:00
JisoLya 9a083e068d chore(store): add struct dependency in store-core 2025-10-29 15:58:32 +08:00
koi2000 91aa759baa refactor(pd): refactor pd test cli module 2025-10-29 15:58:32 +08:00
koi2000 42b99479b5 fix(cli): improve command error handling and input validation 2025-10-29 15:58:32 +08:00
koi2000 adfc8ddd0c feat(cli): add CLI commands for changing Raft and checking peers 2025-10-29 15:58:32 +08:00
koi2000 6edb46cad7 refactor(pd): improve error handling for shard address assignment in PartitionAPI 2025-10-29 15:58:32 +08:00
koi2000 d926ec1af4 refactor: enhance graph name validation and logging in GraphStatistics and Partition classes 2025-10-29 15:58:32 +08:00
koi2000 bbc27c5285 refactor(pd): improve thread safety and optimize channel management in service classes 2025-10-29 15:58:32 +08:00
koi2000 867f91793c refactor: optimize JSON conversion and improve date formatting in multiple services 2025-10-29 15:58:32 +08:00
koi2000 c1663b1d1b refactor(pd): simplify variable declarations and improve error handling across multiple classes 2025-10-29 15:58:32 +08:00
koi2000 e948ec96fe feat(auth): implement authentication mechanism for REST and gRPC services 2025-10-29 15:58:32 +08:00
koi2000 37e618c7cb refactor(pd): refactor the pd client 2025-10-29 15:58:32 +08:00
koi2000 bd70159204 refactor(test): rewrite the test code and add new test cases 2025-10-29 15:58:32 +08:00
koi2000 eaf00190be refactor(pd): refactor pd client connection management 2025-10-29 15:58:32 +08:00
koi2000 aebfdb90a7 feat(client): add basic authentication and optimize client configuration 2025-10-29 15:58:32 +08:00
koi 1918a7a6f6 feat(pd): add MetadataService in pd
feat(pd): add MetadataService in pd
2025-10-29 15:58:32 +08:00
Soyan ced7e368c1 refactor(store): integrate store-common module (#26)
* refactor: integrate store-common module

* update: add dependency statement in pom

* fix: Correct spelling errors

* update: simplify TABLES_MAP

* fix: More robust type check

* update: modify to en comments

* update: modify to en comments & Fix some problem

* fix: fix the error logic in AggregationFunctions.MinFunction

* Trigger CI/CD
2025-10-29 15:58:32 +08:00
koi 5c9902ce84 refactor(pd): refactor common module (#24)
* fix(pd): resolving type inference issues
2025-10-29 15:58:32 +08:00
Soyan 0de3210053 refactor(store): integrate store rocksDb module (#34)
* refactor: integrate store-rocksdb module

* update: change comments to en

* fix: fix error logic

* update: add tag
2025-10-29 15:58:32 +08:00
koi fcfa3e55c1 feat(pd): add build index task in pd (#23)
* refactor(pd): added validation and refactor code
2025-10-29 15:58:32 +08:00
Soyan ccec8d8cd7 chore: update workflow for 🚧 stage (#32)
* update: update workflow

* fix: update workflow

* update: change USE_STAGE param & add maven package param

* update: add todo tag

* Update check-dependencies.yml

---------

Co-authored-by: imbajin <jin@apache.org>
2025-10-29 15:58:32 +08:00
koi 1b6ffad6b1 feat(pd): add methods to query graph status and cluster status (#22) 2025-10-29 15:58:32 +08:00
Soyan beaa0a8846 refactor(store): integrate store grpc module (#27)
* refactor: integrate store-grpc module

* ref: change comments to en

* reformat&add comments

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-29 15:58:32 +08:00
Tsukilc 12466fb0bc chore: refresh known-dependencies.txt 2025-10-29 15:58:32 +08:00
Tsukilc 3f2edb0d9a feat(hugegraph-struct): initialize module with core type interfaces and project configuration 2025-10-29 15:58:32 +08:00
imbajin 8bdafb5f3a chore: add auto pr review workflow 2025-10-29 15:58:32 +08:00
imbajin 58c1a58797
docs: add DeepWiki badge to README (#2883)
* feat: add switch for role election

* feat: classNotCass

* Update role election default and refactor TaskManager

Changed the default value of the role election option to false in ServerOptions. Refactored TaskManager for improved readability, updated comments, removed unnecessary protected modifiers, and streamlined thread pool initialization and shutdown logic. Added deprecation notice for local master-worker mechanism.

* docs: add DeepWiki badge to README

- Add DeepWiki badge for interactive documentation access
- Badge enables users to easily access AI-powered documentation assistant
- Positioned with other project badges for consistency

---------

Co-authored-by: vaughn <vaughn@apache.org>
2025-10-05 11:25:41 -05:00
imbajin 7646d488b2
docs: revise Docker usage instructions in README (#2882)
Updated Docker instructions for HugeGraph server.
2025-09-30 17:11:36 +08:00
Tsukilc da6b123606
refactor: remove the package existing in java8 (#2792)
* refactor: Delete the package existing in java8

* chore(format): remove custom line breaks
2025-09-28 12:24:20 +08:00
Tsukilc c0220c78b4
docs: enhance docker instruction with auth opened graph (#2881) 2025-09-25 16:59:34 +08:00
Hervé Boutemy bc7fb1f43e
chore: improve maven Reproducible Builds (#2874) 2025-09-20 14:27:24 +08:00
Jermy Li fe2d215518
perf(rocksdb): RocksDBStore remove redundant checkOpened() call (#2863) 2025-09-16 10:26:20 +08:00
Jermy Li b642b5a4fa
perf(example): add PerfExample5 and PerfExample6 (#2860) 2025-09-16 10:25:11 +08:00
Jermy Li 3d8be7fe76
perf(core): StringId hold bytes to avoid decode/encode (#2862) 2025-09-16 10:24:22 +08:00
Jermy Li f296a20b27
perf(core): optimize perf by avoid boxing long (#2861)
* Query: E.checkArgument avoid boxing long

Change-Id: I6e08bd07b7c20c4025ed2a4fc91aaa3cbbd059e0

* BytesBuffer: E.checkArgument avoid Bytes.toHex and boxing long

Change-Id: Ib92f99f7a24480f44b8b400f49baefd21735fd20

* define const RANGE_TYPES to avoid construct every time

Change-Id: Idb95ad9136c3ce7b1ff2729b712b315a052ac441
2025-09-16 10:22:56 +08:00
vaughn 0946d5dd0c
feat(server): add option for task role election (#2843) 2025-07-31 10:13:23 +08:00
Zhangjian He 3900cc3671
chore: update notice year (#2826)
Signed-off-by: Zhangjian He <hezhangjian97@gmail.com>
2025-07-09 11:59:53 +08:00
橡皮膏 a53af864b3
fix(server): ensure backend is initialized in gremlin script (#2824) 2025-07-03 10:42:12 +08:00
koi e139465335
refactor: centralize version management in project (#2797) 2025-06-25 19:51:50 +08:00
LingXiao Qi 58f2d22048
docs: fix typo in README (#2806) 2025-06-17 21:37:25 +08:00
benny066567 dce7995d9a
fix(server): tx leak when stopping the graph server (#2791) 2025-06-16 14:46:40 +08:00
MingzhenHan 337dc86567
chore(server): remove some outdated configuration
Co-authored-by: imbajin <jin@apache.org>
2025-05-14 18:51:55 +08:00
John 8c1ee710d6
feat(server): LoginAPI support token_expire field (#2754)
Co-authored-by: imbajin <jin@apache.org>
2025-05-05 11:49:12 +08:00
Peng Junzhi 1badd931e2
BREAKING CHANGE(server): disable legacy backends include `MySQL/PG/c*`(.etc) (#2746)
* disable Cassandra、MySQL、Postgre、scyllaDB、palo backend
2025-04-28 15:20:37 +08:00
imbajin e2c08f16d5
Update .asf.yaml (#2751) 2025-04-14 16:29:55 +08:00
haohao0103 42f9a7638b
refactor: adjust the related filters of sofa-bolt (#2735)
* 优化调整sofa-bolt相关filter

* 优化调整sofa-bolt相关filter

* 优化调整sofa-bolt相关filter

* Update hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/raft/auth/IpAuthHandler.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/raft/auth/IpAuthHandler.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* tiny improve

* fix wrong usage in log

---------

Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-02 17:25:46 +08:00
haohao0103 c99cfcddc9
fix(server):fix graph server cache notifier mechanism (#2729)
* #2728

* fix some typo & tiny improve

---------

Co-authored-by: imbajin <jin@apache.org>
2025-04-02 09:53:22 +08:00
VGalaxies a4cb44ea8f
fix(docker): fix build pd-store arm image 2025-03-10 16:53:04 +08:00
VGalaxies 21a8d61050
setup (#2741) 2025-03-06 09:06:46 +08:00
Bobby Warner ca501a202c
doc: enhance words in README (#2734)
Co-authored-by: imbajin <jin@apache.org>
2025-02-20 16:29:53 +08:00
VGalaxies 57e9f56e14
fix(dist): add license for swagger-ui & reset use stage to false in ci yml (#2706)
* setup

* disable use stage

* improve ci

---------

Co-authored-by: imbajin <jin@apache.org>
2024-12-30 23:05:24 +08:00
imbajin f1474609e9
chore: add debug info for tp test (#2688) 2024-12-21 19:58:31 +08:00
LiJie20190102 a369ef1f4a
fix(server): kneigbor-api has unmatched edge type with server (#2699)
Co-authored-by: lijie0203 <lijie@qishudi.com>
Co-authored-by: imbajin <jin@apache.org>
2024-12-20 16:09:53 +08:00
VGalaxies f838897e6b
fix(docker): update server image desc (#2702) 2024-12-09 17:01:01 +08:00
V_Galaxy f0b13952aa
chore(dist): fix the JSON license issue (#2697)
* setup

* chore: change json scope to 'test' in pd.pom

* update license

---------

Co-authored-by: imbajin <jin@apache.org>
2024-11-25 17:20:43 +08:00
Peng Junzhi 3ab8b28914
chore(deps): adjust release fury version (#2698) 2024-11-25 15:32:11 +08:00
Emmanuel Ferdman 5dc3f9062f
docs: update repo artifacts references (#2695) 2024-11-19 00:09:25 +08:00
V_Galaxy d142d91cb8
chore(dist): fix licenses and remove empty files (#2692) 2024-11-12 16:09:55 +08:00
V_Galaxy afe343bd13
chore(dist): update outdated docs for release 1.5.0 (#2690)
* improve

* Update README.md

---------

Co-authored-by: imbajin <jin@apache.org>
2024-11-06 18:49:42 +08:00
YangJiaqi 2294d2abc2
fix(hstore): JRaft Histogram Metrics Value NaN (#2631)
Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: yangjiaqi <jiaqi.yang@veriti@xyz>
2024-11-06 14:55:33 +08:00
YangJiaqi 392dffc495
fix(server): Filter dynamice path(PUT/GET/DELETE) with params cause OOM (#2569)
Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: yangjiaqi <jiaqi.yang@veriti@xyz>
2024-11-06 13:43:49 +08:00
Peng Junzhi 35e5a8c04a
feat(server): support MemoryManagement for graph query framework (#2649)
Users can use **following new options** to configure memory management:

_\# The memory management switch in HugeGraph. Options: off-heap, on-heap, disable._
**memory.mode=off-heap** 
_\# The maximum memory capacity that can be managed for all queries in HugeGraph._
**memory.max_capacity=1073741824** 
_\# The maximum memory capacity that can be managed for a query in HugeGraph._
**memory.one_query_max_capacity=104857600** 
_\# The alignment used for round memory size._
**memory.alignment=8** 

**Detailed docs**: https://github.com/apache/incubator-hugegraph/wiki/%5BMemory-Management%5D-GSoC-2024-Final-Report

![image](https://github.com/user-attachments/assets/411968f8-cbf5-4ea1-8c1f-10c572ecedf2)

---------

Co-authored-by: imbajin <jin@apache.org>
2024-11-05 15:16:48 +08:00
V_Galaxy 96315aa197
chore(dist): update licenses for 1.5 (#2687) 2024-11-04 19:37:30 +08:00
imbajin 21855c67a3
refactor(commons): handle sofa-rpc desc type & mark TODO (#2666)
* chore: upgrade sofa-rpc to latest version (2024.8)

* fix conflicts

* downgrade sofa-rpc to 5.12.

* fix: replace the wrong dep usage for sofa-rpc

* feat: support multi RPC desc type for users

* chore: disable sofa-rpc server by default
2024-10-25 11:16:38 +08:00
V_Galaxy 7b16f4c0f4
fix(server): serialize source and target label for non-father edge label (#2682)
* fix up and  UT
2024-10-24 23:30:41 +08:00
HaoJin Yang 0aeabe06da
refactor(pd/store): remove useless files & clean code (#2681)
* chore(pd&server): remove useless files

* minor improve

---------

Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: V_Galaxy <vgalaxies@apache.org>
2024-10-24 20:40:13 +08:00
MingzhenHan 0cb6115fdc
feat(server): support in-heap memory JVM monitor (#2650) 2024-10-15 19:53:31 +08:00
HaoJin Yang 1a82d83117
feat(clustertest): add basic MiniCluster module for distributed system (#2615)
Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: V_Galaxy <dyc1904821183@gmail.com>
2024-10-15 11:05:43 +08:00
MingzhenHan 29ecc0492e
chore(dist): replace G1 config & handle other gc options (#2664) 2024-10-10 20:29:13 +08:00
vaughn 861a10083c
refactor(server): optimize the server-node info (#2671)
Co-authored-by: imbajin <jin@apache.org>
2024-10-10 20:17:43 +08:00
V_Galaxy f6f3708197
BREAKING CHANGE(server): support "parent & child" EdgeLabel type (#2662)
HugeGraph supports the parent-child edge feature, meaning that an Edgelabel can have a subordinate type. Using the bank transfer graph as an example, transfers may include person-to-person transfers (person-to-person), person-to-company transfers (person-to-company), and company-to-company transfers (company-to-company). These three different types of transfers share a common operation, transfer.

In actual business scenarios, it is often necessary to retrieve all transfer edges with a single query. Currently, competitors can only manually split the transfer edge types, perform multiple queries, and then aggregate the results. With HugeGraph's parent-child edge feature, it is possible to query the corresponding person-to-person transfers, person-to-company transfers, and other sub-edge types, and also conveniently and efficiently retrieve all transfer-related edges at once.

PS: The parent-child edge feature for the cassandra and scylladb backends has been temporarily disabled through the store feature. 

> Code formatting will be done separately in the next PR.

Related to:
- https://github.com/apache/incubator-hugegraph/issues/745
- https://github.com/apache/incubator-hugegraph/issues/447
2024-10-10 00:15:32 +08:00
vaughn 4274b724a8
chore: fix lombok compiling error and error for list cast to string (#2592)
Co-authored-by: imbajin <jin@apache.org>
2024-09-28 22:45:22 +08:00
haohao0103 a657ce5012
fix(pd): Ensure range attribute thread safety (#2641) 2024-09-25 15:26:58 +08:00
haohao0103 d2906a6db8
fix(pd):PartitionCache lockGraph Logic error (#2640) 2024-09-24 16:34:36 +08:00
Shirley c88963c34b
chore(server): mark old raft configs as deprecated (#2661)
---------

Signed-off-by: shirley <shirley.d.storage@gmail.com>
2024-09-08 22:25:43 +08:00
V_Galaxy a529c02577
chore: set the `skipCommonsTests` property to `true` by default (#2651) 2024-09-01 20:35:02 +08:00
YangJiaqi 355483f1b2
chore(ci): fix postgresql unit test failed (#2643)
- close #2648
2024-08-28 12:35:21 +08:00
V_Galaxy 7be8e6b1dd
feat(common): add a tool method encode (common #146, #2647)
Co-authored-by: John <thespica@qq.com>
2024-08-24 16:07:26 +08:00
V_Galaxy 0b24aca3cd
chore(store): translate CJK comments to English for store-dist, store-grpc, store-node, store-rocksdb, store-test (#2645)
Co-authored-by: Peng Junzhi <78788603+Pengzna@users.noreply.github.com>
2024-08-23 14:35:16 +08:00
imbajin f88fad4711
Merge pull request #2646 from apache/fixup-commons
chore(ci): disable merge button & rename ci job name
2024-08-23 11:00:23 +08:00
VGalaxies a767d73182 setup 2024-08-22 20:09:42 +08:00
imbajin 0a0f2c3bfa
Merge pull request #2628 from apache/intro-commons-v2
**TODO:**
After this PR merged, change the README in commons & pin a [issue](https://github.com/hugegraph/hugegraph-hubble/issues/371) to notify all users/devs to know the context (also update the repo description...)

Finally, we may need start a discussion for marking commons repo in achieved status
2024-08-22 19:07:20 +08:00
V_Galaxy 7dc6a86a7d
chore(dist): intro additional Dockerfile to build the server image & skip init-hstore backend (#2642) 2024-08-22 14:04:06 +08:00
VGalaxies b087f085c1 chore(commons): basic adapt for commons migration 2024-08-21 16:09:00 +08:00
YangJiaqi 58f58ee094
fix(hstore): enable JRaft MaxBodySize config (#2633)
* enable JRaft MaxBodySize config
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.apache.hugegraph.store.node.AppConfig$Raft': Unsatisfied dependency expressed through field 'maxBodySize'; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "512*1024"

---------

Co-authored-by: V_Galaxy <vgalaxies@apache.org>
2024-08-18 14:47:11 +08:00
YangJiaqi ba5b89e374
fix(hstore): print time for hstore gc log #2636 2024-08-17 11:39:30 +08:00
V_Galaxy 1c577de9ba
chore(api): support ignore graphspaces segment in url (#2612)
For forwards compatibility with the "graphspace" mode

---------

Co-authored-by: imbajin <jin@apache.org>
2024-08-13 20:56:53 +08:00
V_Galaxy 4f0e4442ab
fix: correct server docker copy source path (#2637) 2024-08-13 20:53:20 +08:00
YangJiaqi a038d2341c
fix(hstore): JRaft maxEntriesSize configuration parameters do not take effect (#2630)
Co-authored-by: imbajin <jin@apache.org>
2024-08-11 13:04:34 +08:00
V_Galaxy df921e915d
refact(server): enlarge bytes write limit & remove param `big` when encode/decode string id length (#2622)
As title, change limit:
- vid max to 16KB
- eid max to 64kb (128k as backup)
- property max to 10MB (keep consistent)

fix #1593 #2291

---------

Co-authored-by: imbajin <jin@apache.org>
2024-08-10 17:02:30 +08:00
V_Galaxy 7df736a77c
chore(hstore): translate CJK comments to English (#2616)
* trans server-core
2024-08-10 15:31:25 +08:00
V_Galaxy c231a6fddb
chore(store): translate CJK comments to English for store-cli, store-client, store-common, store-core (#2623)
* fixup Chinese punctuation
2024-08-10 12:47:09 +08:00
V_Galaxy 2e27c583b4
chore(pd): translate CJK punctuations to English (#2625) 2024-08-10 12:16:51 +08:00
VGalaxies 459d4413b4 Merge remote-tracking branch 'commons/migrate-commons' into intro-commons-v2 2024-08-10 12:14:58 +08:00
V_Galaxy dc3070f45b
chore(dist): tar source and binary package for hugegraph with pd-store (#2594)
tar source and binary package for hugegraph with pd-store
2024-08-06 21:21:14 +08:00
VGalaxies 162a104ebd git mv to hugegraph-commons 2024-08-03 20:34:23 +08:00
YangJiaqi 91f5b33bac
fix(hstore): JRaft Timer Metrics BUG (#2602) 2024-08-02 23:47:56 +08:00
John 53f0e18216
doc(server): enhance rest-server.properties comment (#2610)
---------

Co-authored-by: imbajin <jin@apache.org>
2024-08-02 19:14:25 +08:00
haohao0103 3427f42b81
refact(pd): remove redundant property in LogMeta & PartitionMeta (#2598)
Co-authored-by: V_Galaxy <vgalaxies@apache.org>
2024-08-02 18:37:06 +08:00
haohao0103 24ebe9da26
fix(pd/store): log files do not scroll with the process (#2589)
close #2581 GRPC Java defaults to using java. til.rogging (JUL) as its logging framework,

---------

Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-08-02 17:58:12 +08:00
imbajin 7b9fd21d2a
chore: enable up-to-date for UI(CI) (#2609) 2024-08-02 11:21:54 +08:00
V_Galaxy d36e05ece8
chore: temporarily ignore failure core tests for hstore & simplify ci name (#2599)
* ignore tests for hstore rename ci
2024-07-31 16:40:53 +08:00
haohao0103 9baef8b255
fix(commons):fixed memory leaks occur in HugeGraph Server during data writing (#144)
* #2578
fixed memory leaks occur in HugeGraph Server during data writing
2024-07-30 17:46:59 +08:00
haohao0103 86e1003c16
fix(pd): partition IDs always empty in Shards List (#2596) 2024-07-22 15:15:00 +08:00
Peng Junzhi edb59ebaeb
feat(store): integrate rest of store-test submodule (#2563)
Co-authored-by: imbajin <jin@apache.org>
2024-07-20 18:10:38 +08:00
V_Galaxy 73a4c9d028
chore: intro `editorconfig-maven-plugin` for verifying code style defined in `.editorconfig` (#2591)
* exclude .flattened-pom.xml
2024-07-17 16:03:27 +08:00
V_Galaxy d6bc24e0f2
fix(dist): update build artifact path for docker deployment (#2590)
* fix path
2024-07-16 20:25:02 +08:00
haohao0103 5dfcc3f694
feat: support disable RocksDB auto-compaction by configuration (#2586) 2024-07-16 16:40:44 +08:00
haohao0103 899dc8e0f0
doc(pd): add `initial-store-count` comments in `application.yml` (#2587)
PD cluster will assess the overall health of the cluster. If the number of store nodes is less than the initial-store-count, the cluster will be unavailable
2024-07-16 16:33:58 +08:00
haohao0103 85e096698a
refact: enhance cache invalidation of the partition -> leader shard in ClientCache (#2588) 2024-07-15 23:07:30 +08:00
V_Galaxy bd83741f24
chore: minor improve for pom properties (#2574) 2024-07-15 14:59:10 +08:00
V_Galaxy 882f3b7d65
feat(dist): support docker deployment for PD and Store (#2573)
Co-authored-by: imbajin <jin@apache.org>
2024-07-15 11:12:25 +08:00
HaoJin Yang 03b40a5244
fix(server): random generate default value (#2568)
Co-authored-by: imbajin <jin@apache.org>
2024-07-14 17:05:35 +08:00
V_Galaxy cedc000215
chore: upgrade revision to 1.5.0 (#2585)
* set revision to 1.5.0
2024-07-13 17:00:43 +08:00
V_Galaxy 9f89afc39a
feat(server): support new backend Hstore (#2560)
subtask of #2483
2024-07-10 16:35:44 +08:00
Frosky Lrupotkin 37e71c4858
chore: migrate the `hg-style.xml` to `.editorconfig` (#2561) 2024-06-28 22:34:07 +08:00
Peng Junzhi e82a91ca1a
feat(store): integrate store-dist and store-cli submodule (#2562)
* refact: prepare for integrating rest of store module

* feat(store): integrate store-dist and store-cli submodule

* fix(store): support and fix for store-dist and store-cli submodule

* fix(store): update deps

* fix(store): update deps

* reformat hg-store-cli

---------

Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-06-25 00:07:02 +08:00
V_Galaxy 1e9752109e
chore: intro `install-dist` module in root (#2552)
* init dist in root

* adapt path & regenerate deps

* add comment

* add comment

* fix pd dir

* fix server dir

* improve hugegraph-pd/.gitignore

* improve

* rename dist -> install-dist

* fix path

* regenerate known dependencies
2024-06-13 17:06:37 +08:00
V_Galaxy 506850caea
chore: reset license header for file declared in LICENSE (#2550) 2024-06-11 10:08:23 +08:00
sheli00 1a8959575c
feat(store): integrate `store-node` submodule (#2537) 2024-06-11 00:19:07 +08:00
Peng Junzhi ac93deebc6
feat(store): integrate `store-core` submodule (#2548)
* feat(store): integrate store-core submodule
2024-06-07 17:25:42 +08:00
Zee Huang 93c2e08780
Update 'How to Contribute' link and remove duplicate 'Guidelines' link in README (#143)
* Update 'How to Contribute' link and remove duplicate 'Guidelines' link in README

This PR makes the following changes to the README file to streamline the contribution guidelines and avoid redundancy:

- Updated the 'How to Contribute' link to ensure it directs contributors to the correct resource.
- Removed the 'Guidelines' link as it duplicated the information provided in 'How to Contribute'.

* Update contribution link from markdown to website

- Changed the contribution guide link in the README.md from the markdown file to the corresponding section on the official website.
- This change ensures that the link remains stable and is not impacted by the frequent changes to Markdown files.
2024-05-28 15:22:43 +08:00
V_Galaxy b056c5facd
chore(pd): translate CJK comments to English (#2536) 2024-05-13 16:16:02 +08:00
V_Galaxy c1e8ea5aba
feat(server): integrate `server-hstore` into hugegraph (#2534)
subtask of #2265

When introducing hstore, server-core needs corresponding modifications. Except for BytesBuffer.java in hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/, other files should be consistent with the pd-store branch.

---------

Co-authored-by: imbajin <jin@apache.org>
2024-05-06 20:09:12 +08:00
V_Galaxy 253b8d38b8
feat(pd): integrate `pd-dist` into hugegraph & add core tests, client tests, and REST tests for PD (#2532)
subtask of #2265

---------

Co-authored-by: imbajin <jin@apache.org>
2024-05-06 20:08:48 +08:00
V_Galaxy 2b3bc4f28b
feat(pd): integrate `pd-service` into hugegraph (#2528)
subtask of #2265

For detailed module analysis documentation, please refer to fs doc/link/wiki

TODO: Update the getPomVersion implement in the common-module

---------

Co-authored-by: imbajin <jin@apache.org>
2024-04-22 14:53:45 +08:00
V_Galaxy 43cae1d2e3
feat(pd): integrate `pd-core` into hugegraph (#2478)
The corresponding tests will be merged after pd-service

subtask of https://github.com/apache/incubator-hugegraph/issues/2265

---

During the code review, I found the following issues:

1. Similar functionality appears multiple times, such as stub connection-related code, with redundancy between `PDClient.StubProxy` and `AbstractClientStubProxy`.
2. Package partitioning:
    1. `PDPulse`, `PDPulseImpl` should in `pulse`
    2. `PDWatch`, `PDWatchImpl` should in `watch`
3. Unused code, see below

---------

Co-authored-by: imbajin <jin@apache.org>
2024-04-19 23:27:46 +08:00
Peng Junzhi b4bc1f066a
feat(store): integrate `store-rocksdb` submodule (#2513)
TODO: delete "hugegraph-store/hg-store-rocksdb/src/main/java/place-holder.txt" later

---------

Co-authored-by: imbajin <jin@apache.org>
2024-04-19 11:11:44 +08:00
Hongjun Li 7d335b2c72
chore: config *.md max length (#2525) 2024-04-16 21:15:39 +08:00
Emmanuel Ferdman 543bbfeb74
fix: update resource references (#2522) 2024-04-16 15:10:49 +08:00
Liu Xiao 906112c080
chore: make IDEA support IssueNavigationLink and add icon (#2521) 2024-04-15 15:31:12 +08:00
V_Galaxy 6be756919b
fix(server): avoid overriding backend config in gremlin example script (#2519) 2024-04-14 23:57:07 +08:00
V_Galaxy 3783247c74
fix(server): switch rocksdb backend to memory when executing gremlin example (#2518) 2024-04-12 16:32:08 +08:00
imbajin 1228dec04d fix: maven rat plugin exist partial failure
fix: maven rat plugin exist partial failure
2024-04-05 23:53:09 +08:00
Peng Junzhi d0a3ccc045 feat(store): integrate `store-test` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi 6c72ca5f63 feat(store): integrate `store-client` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi f0d9d12ca7 feat(store): integrate `store-grpc` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi e605f732e2 feat(store): integrate `store-common` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi 52f3d64b6a refact: prepare for integrating store modules 2024-04-05 23:53:09 +08:00
VGalaxies 3a1618faa2 feat(pd): integrate `pd-client` submodule 2024-04-04 17:37:15 +08:00
VGalaxies bd1d9db77b feat(pd): integrate `pd-test` submodule
prepare tests for `pd-common`
2024-04-04 17:37:15 +08:00
VGalaxies b5d9dd2f02 feat(pd): integrate `pd-common` submodule 2024-04-04 17:37:15 +08:00
VGalaxies a560a6efee feat(pd): integrate `pd-grpc` submodule 2024-04-04 17:37:15 +08:00
VGalaxies 37e4405c04 refact: prepare for integrating pd modules
1. prepare pom and CI for pd-client, pd-common, pd-grpc and pd-test
2. drop support for java8
2024-04-04 17:37:15 +08:00
Peng Junzhi 483bca52ef
chore: remove required ci with java8 (#2503) 2024-04-03 23:17:30 +08:00
Simon Cheung 27cf52b007
chore: add swagger-ui LICENSE relative files (#2495)
* Create LICENSE-swagger-ui.txt
* Update NOTICE
2024-03-30 14:17:17 +08:00
imbajin 6a4041e21c chore: upgrade to 1.3.0 (last major version support Java8)
fix
2024-03-22 10:51:57 +08:00
imbajin 713d88d1fd refact: enhance auth logic
fix
2024-03-22 10:51:57 +08:00
imbajin ef8f6128a3 fix: multi graph error in rocksdb with same path/fd 2024-03-22 10:51:57 +08:00
SunnyBoy-WYH 277f76ef03
chore(server): clear context after req done (#2470)
Co-authored-by: vaughn.zhang <vaughn.zhang@zoom.us>
Co-authored-by: imbajin <jin@apache.org>
2024-03-19 17:43:33 +08:00
Bond 7b33574fd0
feat: added the OpenTelemetry trace support (#2477)
TODO: we need enhance our shell experience
---------

Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-03-15 17:30:16 +08:00
imbajin c883f56a4e
chore: disable clean flatten for deploy (#141) 2024-03-13 20:27:00 +08:00
小宇 0cfd8daed3
feat: support user defined RestClientConfig/HTTPClient params (#140)
- add builderCallback param for client to add custom config
- add params connectTimeout and readTimeout to instead the param time
- update version to 1.3.0

---------

Co-authored-by: imbajin <jin@apache.org>
2024-03-13 20:13:01 +08:00
vaughn c09982b0df
fix(auth): enhance the URL check (#2422)
Co-authored-by: imbajin <jin@apache.org>
2024-03-09 21:04:30 +08:00
V_Galaxy eb6570c992
fix(server): 'serverStarted' error when execute gremlin example (#2473) 2024-03-05 15:21:42 +08:00
SunnyBoy-WYH 6861ed5e94
fix(server): fix the bug which promtheus cant collect hg metric (#2462) 2024-03-03 13:05:10 +08:00
SunnyBoy-WYH 3f127f01f1
fix(server): add tip for gremlin api NPE with empty query (#2467)
fix #2426
2024-03-02 01:23:01 +08:00
Hongjun Li 2e3adcde02
chore: Add a newline formatting configuration and a comment for warning (#2464)
- Add a newline formatting configuration
- Add a comment for the IDEA unsupported warning about `continuation_indent_size`
2024-02-29 20:35:52 +08:00
Hongjun Li 47a68f098a
chore: refine the hg-style.xml specification (#2457)
- Change the maximum wrap text length for XML to 120 (via `hg-style.xml`)
- Add a blank line between method definitions, inner class definitions, and static code blocks (via `hg-style.xml`)
- Add `<p>` tags to Javadoc blank lines (via `hg-style.xml`)
- `.xml` file leaves a blank line at the end (via `.editorconfig`)
- Class declaration requires a blank line before and after each line (via `hg-style.xml`)
- Javadoc line comment not in line (via `hg-style.xml`)
- `.properties` file leaves empty lines (via `hg-style.xml`)
- `.yaml` file braces `{}`, brackets `[]` remove spaces (via `hg-style.xml`)
2024-02-27 12:53:29 +08:00
Z-HUANT d0f63c8ac3
feat(api): optimize adjacent-edges query (#2408)
Relevant issue: #2255

Gremlin Query: For adjacency edge queries, if a vertex does not belong to the adjacent vertices of this edge, filter out that vertex.

---------

Co-authored-by: imbajin <jin@apache.org>
2024-02-26 12:29:13 +08:00
M dfee5bf6aa
fix(server): remove extra blank lines (#2459)
* remove extra blank lines in api

* remove extra blank lines in core

* remove extra blank lines in scylladb
2024-02-25 11:45:00 +08:00
Jermy Li eef3b355f6
chore: unify to call SchemaLabel.getLabelId() (#2458)
Change-Id: I31bcc0d1ee99f3c443f8f4f0d458e06ca89977ef
2024-02-24 22:45:23 +08:00
V_Galaxy bc421bb197
chore: improve license header checker confs and pre-check header when validating (#2445)
* improve license header checker confs

* typo

* verify -> validate

* update rat exclude files

* empty commit

* update rat exclude files

* update rat exclude files
2024-02-23 16:42:01 +08:00
V_Galaxy f6da2ee6cb
fix: protobuf file header (#2448) 2024-02-23 16:39:30 +08:00
M e79f1a5e73
fix(server): clean up the code (#2456)
- replace `size() == 0` with `isEmpty()`
- remove unnecessary unboxing
- remove unnecessary boxing
- replace for loop with enhanced for loop
- replace lambda with method reference
2024-02-22 17:26:15 +08:00
M 5cb9aad6ee
fix: format and clean code in modules (#2439)
Format & clean code in submodels:

1. API
2. Scylladb
3. Postgresql
4. Rocksdb
5. Palo
6. Mysql
7. Hbase
8. Cassandra
9. Test

---------

Co-authored-by: imbajin <jin@apache.org>
2024-02-20 17:22:54 +08:00
M 0b70e897f0
fix: format and clean code in core module (#2440) 2024-02-20 17:22:28 +08:00
M 0ee9a9b788
fix: format and clean code in dist and example modules (#2441) 2024-02-20 17:22:07 +08:00
M 75867796b7
fix(server): unify the license headers (#2438)
subtask of #2435

---------

Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-02-07 12:53:57 +08:00
Peng Junzhi 3f7dc2a8b2
fix(server): make CacheManager constructor private to satisfy the singleton pattern (#2432) 2024-02-01 23:58:44 +08:00
SunnyBoy-WYH 1d4532cd62
chore(server): update swagger info for default server profile (#2423) 2024-01-28 14:03:38 +08:00
Dandelion b980df8697
fix(chore): remove zgc in dockerfile for ARM env (#2421)
* remove zgc

* Apply suggestions from code review

Co-authored-by: imbajin <jin@apache.org>

* add comment for hugegraph-server.sh

* fix enable-auth.sh

* init store in entrypoint

* use flag file to skip re-init

* delete tar.gz

* simply dockerfile

* mvn optimize

* simply dockerfile

* add init log in docker

---------

Co-authored-by: imbajin <jin@apache.org>
2024-01-26 16:48:41 +08:00
Z-HUANT 1dd0580d30
fix(server): reinitialize the progress to set up graph auth friendly (#2411) 2024-01-17 20:56:25 +08:00
Dandelion de5904a600
feat: support docker use the auth when starting (#2403)
- allow user to set env for docker to set auth mode
- download keystore when package
- fix a curl error (also use curl first in `function` download)

---------

Co-authored-by: imbajin <jin@apache.org>
2024-01-15 20:50:24 +08:00
imbajin 57cd0e8dd7
doc: enhance NOTICE info to keep it clear (#2409) 2024-01-09 18:44:08 +08:00
Caican Cai 7965aac70d
chore: add license link (#2398) 2024-01-04 12:50:24 +08:00
xiaoleizi2016 cf9ba8b310
fix(core): task restore interrupt problem on restart server (#2401)
* Update StandardTaskScheduler.java
2023-12-29 12:04:54 +08:00
SunnyBoy-WYH 7635c67865
chore(server): update license for 1.2.0 (#2391)
---------

Co-authored-by: liuxiao <liuxiao2103@qq.com>
Co-authored-by: Simon Cheung <ming@apache.org>
2023-12-19 15:22:35 +08:00
V_Galaxy 965d6c137a
fix: incorrect path in hugegraph assembly scripts (#2392)
* fix: typo

* fix: assembly hugegraph path

* reset
2023-12-18 12:33:33 +08:00
Dandelion cb4427d9f1
doc: adjust docker desc in readme (#2390)
* fix(dist): update relative path for the 1.2.0

* add docker policy and run server in daemon

* fix: use tail to avoid container exit

* adjuest the order of quick start

* Update hugegraph-server/hugegraph-dist/docker/scripts/detect-storage.groovy

* adjust desc

* Update README.md

* Update pom.xml

---------

Co-authored-by: imbajin <jin@apache.org>
2023-12-17 15:59:28 +08:00
小宇 33fa9ed45d
update licence (#139) 2023-12-17 15:35:03 +08:00
vaughn 4346b44f80
fix: TinkerPop unit test lack some lables (#2387) 2023-12-14 17:59:31 +08:00
Dandelion 2c6fcdc719
add maven args for stage or other args (#2386) 2023-12-13 16:00:50 +08:00
imbajin 44f99e968c
doc: update README for release (#138) 2023-12-12 17:21:28 +08:00
conghuhu b52517cc47
feat(core): add IntMapByDynamicHash V1 implement (#2377)
* feat(WIP): add IntMapByDynamicHash (#2294)

* feat: add values & keys in IntMapByDynamicHash

* add some basic comment & fix some style

* feat: fix pr review

* fix: fix some review

---------

Co-authored-by: imbajin <jin@apache.org>
2023-12-12 12:25:51 +08:00
imbajin bd5d68f0f2
refact(rocksdb): clean & reformat some code (#2200)
* chore: merge master to clean-rocksdb for synchronization (#2383)

---------

Co-authored-by: V_Galaxy <dyc1904821183@gmail.com>
2023-12-11 22:21:08 +08:00
V_Galaxy bfe9fae150
chore: reset hugegraph version to 1.2.0 (#2382)
* chore: reset version to 1.2.0

* chore: add README for three submodules

* fix: README.md

* fix: README.md

* fix: README.md

* fix: README.md
2023-12-09 22:02:49 +08:00
M c997f35b04
fix(api): correct the vertex id in the edge-existence api (#2380) 2023-12-08 15:59:28 +08:00
小宇 47aa8be850
refact(api): update common 1.2 & fix jersey client code problem (#2365)
* update common version and fix rest client problem

* use stage

* fix dependency issue

* test

* test

* test

* test

* fix

* chore:  improve the ci logic

* fix core-version

* Empty test

* fix code issue

* fix: 3rd party changes

* code optimize

* refactor the AbsJerseyRestClient

* fix code issue

---------

Co-authored-by: imbajin <jin@apache.org>
2023-12-07 12:26:22 +08:00
Simon Cheung e8fb2696d6
chore: fix curl failed to request https urls (#2378) 2023-12-05 21:50:02 +08:00
小宇 dcf3752515
fix the json param convert (#137) 2023-12-05 10:56:12 +08:00
imbajin 10f0a87c7b
refact(common): rename jsonutil to avoid conflicts with server (#136)
fix https://github.com/apache/incubator-hugegraph/actions/runs/7082354080/job/19273001614?pr=2365

Also add some comment for it
2023-12-04 14:55:56 +08:00
Jermy Li 20d1e5228e
chore: move server info into GlobalMasterInfo (#2370)
* chore: move server info into GlobalMasterInfo

Change-Id: Id854892333115fd45d7c8b9799d255627541b2ad

* fix testClearAndInit() and export GlobalMasterInfo

Change-Id: Ic2878c5359e7f55fcd11986aa0bf79241c7ee9ab

* enhence ServerInfoManager.heartbeat()

Change-Id: I6932893c4be8331547f3b721083ca00430f85e58

* move RoleElectionStateMachineTest to UnitTestSuite

Change-Id: I7b3e8e2867dcf1063a726c8005f1c34dbd218f7c
2023-12-04 12:43:32 +08:00
Jermy Li 8c93652de7
fix: Assert.assertThrows() should check result of exceptionConsumer (#135)
* fix: Assert.assertThrows() should check result of exceptionConsumer

* fix some warnings

* remove assertThrowsFuture() from Assert
2023-11-30 16:25:31 +08:00
M ed493f3093
feat: optimize perf for adjacency-edges query (#2242) 2023-11-29 21:44:29 +08:00
haohao0103 d376b02dc5
fix HBase PrefixFilter bug (#2364)
* #2177

* #2177

* #2177

* #2177

* #2177

* #2177
2023-11-29 19:11:28 +08:00
lzyxx 197e8a00ed
chore(ci): add stage profile settings (#2361)
* Update LICENSE

* Update install-cassandra.sh

* add stage profile settings

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Update licence-checker.yml

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-28 17:33:56 +08:00
SunnyBoy-WYH 0c01475843
feat(server):swagger support auth for standardAuth mode (#2360)
* feat(server):swagger support auth for standardAuth mode and try to fix arthas odd test

* chore(api): update api version & swagger token auth mode
2023-11-28 17:01:54 +08:00
imbajin c0ea21eed6
chore: disable raft test in normal PR due to timeout problem (#2349)
And replace it in pd/store module
2023-11-24 19:59:24 +08:00
小宇 5ad55fb82f
feat(common): replace jersey dependencies with OkHttp (Breaking Change) (#133)
* remove jersey

* Update ci.yml

* refact: replace params okhttp3.Headers to internal RestHeaders

* fix: licence dependency

* fix: test error

* fix: code format issue

* fix: unit test error


---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-22 09:37:02 +08:00
Chong Shen 12b4940563
fix(api): remove redirect-to-master from synchronous Gremlin (#2356)
* fix: remove redirect master role to align with behaviour of VertexApi and EdgeApi

* chore: add back necessary annotation
2023-11-22 09:33:04 +08:00
Dandelion 25301f6228
feat: adapt Dockerfile for new project structure (#2344)
* feat: dockerfile adapt the project structure

* change the version

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-13 19:30:24 +08:00
imbajin a6e1f232c2
fix(api): refactor/downgrade record logic for slow log (#2347)
* fix(api): refactor/downgrade record logic for slow log

add some TODOs & assign @SunnyBoy-WYH to address it

* fix typo

* enhance the perf
2023-11-13 18:03:21 +08:00
imbajin a7ad7ea100 Update PerfExampleBase.java 2023-11-13 12:50:49 +08:00
imbajin a9445ca3c3 fix(api): clean some code for release
separate from slow log
2023-11-13 12:50:49 +08:00
V_Galaxy bce6d058f5
refact: adjust project structure for merge PD & Store[Breaking Change] (#2338)
## Purpose of the PR

Subtask of #2265.

Adjust the project structure of this repository to include three sub-modules: hugegraph-server, hugegraph-pd, hugegraph-store at the root level.

## Main Changes

Roll back to the moment when https://github.com/apache/incubator-hugegraph/pull/2266 was merged on `pd-store` and incorporate the latest changes in `master`.

For more detailed information, please refer to https://github.com/apache/incubator-hugegraph/pull/2266#issue-1834369489.


---------

Co-authored-by: M <87920097+msgui@users.noreply.github.com>
2023-11-08 18:08:08 +08:00
SunnyBoy-WYH 69e6b461ad
feat(api): support recording slow query log (#2327)
* chore(api): code style for cr

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-06 14:34:12 +08:00
SunnyBoy-WYH 4d5f4195db
chore(api): add swagger desc for Arthas & Metric & Cypher & White API (#2337)
add swagger belong for arthas API

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-06 14:15:32 +08:00
lzyxx 70ab14e3e6
feat(cassandra): adapt cassandra from 3.11.12 to 4.0.10 (#2300) 2023-10-28 23:58:17 +08:00
conghuhu e90489f361
fix(core): handle schema Cache expandCapacity concurrent problem (#2332) 2023-10-25 17:25:07 +08:00
Wu Chencan 8db0a9b195
feat(core): support batch+parallel edges traverse (#2312)
## Main Changes

- Enhance Consumers.java, supporting ExceptionHandle and `Future` to handle InterruptedException when awaiting
- Add Nested Iterator Edge and support batch execution
- Support batch execution & thread parallel in KoutTraverser and Kneighbor
2023-10-24 19:33:24 +08:00
Dandelion b43526da60
fix: always wait for storage if rocksdb is selected (#2333) 2023-10-24 17:24:43 +08:00
Dandelion d4b95ca323
feat: support Cassandra with docker-compose in server (#2307)
## Main Changes

1. change the dockerfile, adding the shell to wait for storage backend and use a docker-entrypoint.sh to manage the starting process.
2. delete a deprecated class in  gremlin-console.sh (reference: [doc of ScriptExecutor](https://tinkerpop.apache.org/javadocs/3.2.3/full/org/apache/tinkerpop/gremlin/groovy/jsr223/ScriptExecutor.html))
3. add a healthy check in docker-compose
4. add an example folder where we can put all the template docker-compose.yml here
5. add `*swagger-ui*` in gitignore, which appears after you compile the source code locally.

---------

Co-authored-by: imbajin <jin@apache.org>
2023-10-23 16:29:42 +08:00
Dandelion 73329ce4f5
doc: README.md tiny improve (#2331) 2023-10-23 16:17:36 +08:00
SunnyBoy-WYH 869fc81811
feat(api): support embedded arthas agent in hugegraph-server (#2278) 2023-10-20 10:15:51 +08:00
Jermy Li 45636a0489
README.md tiny improve (#2320) 2023-10-13 13:47:01 +08:00
SunnyBoy-WYH fc9bc2866e
feat(api): support metric API Prometheus format & add statistic metric api (#2286) 2023-10-08 20:21:09 +08:00
SunnyBoy-WYH 30ef2f7c6b
feat: support White IP List (#2299)
tips:
- this feat works when auth mode was set.
- this feat works when white ip status was enabled.

because now PD is unavailable,just use java list; when pd ready , we can checkout pd.
2023-10-02 13:25:45 +08:00
Dandelion d7c1c2149c
doc: update README about start server with example graph (#2315) 2023-10-02 13:14:01 +08:00
M b49be05171
add: dependency-review (#134)
* add: dependency-review

* tiny improve

* fix

Co-authored-by: imbajin <jin@apache.org>

---------

Co-authored-by: imbajin <jin@apache.org>
2023-09-20 17:47:01 +08:00
M 4ceef1ab0c
fix: base-ref/head-ref missed in dependency-review on master (#2308) 2023-09-11 10:48:37 +08:00
Wu Chencan 8e99d85d33
feat(api-core): support label & property filtering for both edge and vertex & support kout dfs mode (#2295)
- Support label & property filtering for both edge and vertex and the filtering is implemented in Kout Post and Kneighbor - Post Apis, reducing unnecessary graph searches through pruning
- Support Kout dfs mode in Kout Post Api

Originally only edge label filtering was supported, now label and property filtering for edge and vertex is supported.
- add classes VEStepEntity and VEStep to support serialization in request
- add class Steps to support filtering of edge and vertex in runtime(core)
- add new method edgesOfVertex(Id source, Steps steps) to support label and property filtering for both edge and vertex in HugeTraverser.java

---------

Co-authored-by: imbajin <jin@apache.org>
2023-09-10 16:47:45 +08:00
Dandelion 1d0969dede
fix(dist): avoid var PRELOAD cover environmnet vars (#2302)
Update hugegraph-dist/src/assembly/static/bin/start-hugegraph.sh

---------

Co-authored-by: imbajin <jin@apache.org>
2023-09-08 22:07:57 +08:00
Chong Shen aaf67cf81c
fix(core): close flat mapper iterator after usage (#2281)
close [Bug] FlatMapperIterator should be closed after usage #2280
2023-08-29 16:09:31 +08:00
Dandelion 8a515f20db
feat(dist): support pre-load test graph data in docker container (#2241)
- Provide the related conf and groovy for user to pre load some data.
- Change the start-hugegraph.sh to get the environment variables to decide to pre-load or not.

---------

Co-authored-by: imbajin <jin@apache.org>
2023-08-28 15:36:21 +08:00
V_Galaxy 77c76124af
chore(dist): replace wget to curl to download swagger-ui (#2277)
Main Changes:
1. replace `wget` by `curl` when downloading `swagger-ui`
2. silence the output of `curl` and `tar` commands
3. reuse the existing `v4.15.5.tar.gz` before downloading
4. avoid downloading `swagger-ui` in non-Linux platforms to prevent build failures (there might be a cross-platform build approach available 🤔)
5. wrapp the script content within `<![CDATA[ ... ]]>` blocks ensures that the script retains its original format when generating the `dist.sh` script (also suppresses automatic indentation)
6. remove intermediate files at the end of the script

**An alternative approach**, during the generation of the `dist.sh` script, only the `${final.name}` property from the build process is utilized. It might be possible to separately store a `dist.sh` script within hugegraph-dist, then use `sed` during the build process to replace the value of `${final.name}`, **thereby avoiding the need to embed script content within the pom file**.

---------

Co-authored-by: imbajin <jin@apache.org>
2023-08-25 15:20:44 +08:00
lzyxx 4d7ad86776
fix checkstyle: Update StandardStateMachineCallback.java (#2290)
During the compilation of your code, an informational message was displayed indicating an issue with the file /home/lzy/hugegraph/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardStateMachineCallback.java at line 36. The specific problem was that the length of this line exceeded 100 characters, with a total of 101 characters.

To address this issue, I have made modifications to this class. I have split the originally long line into multiple lines to ensure that each line's length adheres to the coding standards' specified limits. This action not only aligns with the requirements of the code style, but also improves the readability and maintainability of the code.
2023-08-22 14:07:34 +08:00
DanGuge d12f5734e6
feat(api&core): in oltp apis, add statistics info and support full info about vertices and edges (#2262)
* chore: improve gitignore file

* feat: add ApiMeasure to collect runtime data

ApiMeasure will count the number of vertices and edges traversed at runtime, and the time the api takes to execute

* feat: Add ApiMeasure to JsonSerializer and Modify the Serializer interface

* JsonSerializer: return measure information in api response

* Serializer: fit the feature that returns complete information about vertices and edges

* refactor: format code based on hugegraph-style.xml

* feat: Add statistics information in all oltp restful apis response and Support full information about vertices and edges

Statistics information:

* add vertexIterCounter and edgeIterCounter in HugeTraverser.java to track traversed vertices and edges at run time

* modify all oltp restful apis to add statistics information in response

Full information about vertices and edges:

* add 'with_vertex' and 'with_edge' parameter option in apis

* modify oltp apis to support vertex and edge information in api response

* add EdgeRecord in HugeTraverser.java to record edges at run time and generate the edge information returned in api response

* modify Path and PathSet in HugeTraverser.java to support full edge information storage

* modify all traversers to support track of edge information at run time

* fix: numeric cast

* fix: Jaccard Similarity api test

* fix: adjust the code style and naming convention

* Empty commit

* Empty commit

* fix:
1. change System.currentTimeMillis() to System.nanoTime();
2. modify addCount()

* fix: rollback change in .gitignore

* fix: rollback ServerOptions.java code style

* fix: rollback API.java code style and add exception in else branch

* fix: fix code style

* fix: name style & code style
* rename edgeRecord to edgeResults
* fix Request class code style in SameNeighborsAPI.java
2023-08-19 13:41:08 +08:00
DanGuge b02c2bdaa7
fix(api): incorrect use of 'NO_LIMIT' variable (#2253)
* replace Query.NO_LIMIT with HugeTraverser.NO_LIMIT
2023-07-23 10:51:58 +08:00
Z-HUANT 7927335303
fix: asf invalid notification scheme 'discussions_comment' (#2250)
* fix:asf invalid notification scheme 'discussions_status'

---------

Co-authored-by: zhuangpengtao <zhuangpengtao@joyy.com>
Co-authored-by: imbajin <jin@apache.org>
2023-07-20 18:08:53 +08:00
Z-HUANT c922b10c31
fix:asf invalid notification scheme 'discussions_status' (#2247) 2023-07-20 10:32:56 +08:00
ustcer c31a53641f
add some construction methods for more convenient use (#132)
Co-authored-by: chengxin05 <chengxin05@baidu.com>
2023-07-19 21:06:52 +08:00
conghuhu 5df28fa2ca
feat(perf): support JMH benchmark in HG-test module (#2238)
* chore: add param to max cap

* chore: add non argument constructor to IntMapByEcSegment

---------

Co-authored-by: shiyi <congguoqing.cgq@alibaba-inc.com>
2023-07-17 16:50:35 +08:00
Z-HUANT 23776a7686
fix: optimizing ClassNotFoundException error message for MYSQL (#2246) 2023-07-17 16:49:37 +08:00
KeeProMise 8ee3d32b4f
doc: modify ASF and remove meaningless CLA (#2237) 2023-07-01 18:44:49 +08:00
Liu Xiao 5227248799
fix(core): support order by id (#2233)
* revert sslmode
2023-06-21 18:12:02 +08:00
Liu Xiao 80a4cd6877
chore: add pr template (#2234)
* update close/fix synx

* uniform case

---------

Co-authored-by: imbajin <jin@apache.org>
2023-06-21 18:11:18 +08:00
Liu Xiao 324cbb2c1f
collect option ssl_mode for hugegraph-test (#2235) 2023-06-21 17:46:21 +08:00
KeeProMise 258d1812ff
add com.janeluo.ikkanalyzer dependency to core model (#2206)
* put the third-party dependency license file and Declare the dependency in LICENSE info
2023-06-20 21:45:04 +08:00
Lionztt b836426db0
chore: improve the UI & content in README (#2227)
* feat: change contributor img size to normal size

---------

Co-authored-by: imbajin <jin@apache.org>
2023-06-13 00:04:28 +08:00
V_Galaxy b4e67e1dfb
fix: error when start gremlin-console with sample script (#2231)
* fix: add `-i` parameter in `gremlin-console.sh`, add `serverStarted` in `example.groovy`

* fix: modify hugegraph conf path

* fix: remove unnecessary index on properties on [name]
2023-06-12 16:25:47 +08:00
Liu Xiao b8c7743616
fix: jdbc ssl mode parameter (#2224) 2023-06-06 19:58:58 +08:00
M bcf2a395cf
doc: update README & add QR code (#2218)
Co-authored-by: imbajin <jin@apache.org>
2023-06-05 13:54:38 +08:00
imbajin a946ad1de4
chore: update .asf.yaml for mail rule (#2221) 2023-05-31 22:56:58 +08:00
vaughn e1d9607410
refact(core): optimized batch removal of remaining indices consumed by a single consumer (#2203) 2023-05-31 12:36:52 +08:00
starry-sky_down-to-earth f23c648937
refact(core): early stop unnecessary loops in edge cache (#2211) 2023-05-17 00:23:45 +08:00
KeeProMise 0f2faf48dc
fix: remove dup 'From' in filterExpiredResultFromFromBackend (#2207) 2023-05-08 20:55:02 +08:00
zoulei 297e491232
fix commons dependency conflict (#131)
* fix commons dependency conflict
* upgrade commons version to 1.0.1
* upgrade grpc-core version to 1.28.1

Co-authored-by: imbajin <jin@apache.org>
2023-04-21 00:07:05 +08:00
vaughn 267ff6d3a8
chore: async remove left index shouldn't effect query (#2199) 2023-04-19 21:19:01 +08:00
Simon Cheung 7b6a4bd136
fix exception of vertex-drop with index (#2181)
note only the vertex with index data needs forceLoad
2023-03-29 22:35:58 +08:00
zoulei 6997a87d0c
move validate release to hugegraph-doc (#2109) 2023-03-27 16:32:06 +08:00
zoulei 9e4fb9647e
chore: remove stage-repo in pom due to release done & update mail rule (#2128)
* add new issues mailbox and move some mails to it

---------

Co-authored-by: imbajin <jin@apache.org>
2023-03-16 13:16:38 +08:00
Bond 4b74ab6cec
feat: use an enhanced CypherAPI to refactor it (#2143)
Co-authored-by: lynn.bond <liyan75@baidu.com>
Co-authored-by: imbajin <jin@apache.org>
2023-03-15 22:36:13 +08:00
vaughn 6409d9277d
optimize: remove lock of globalMasterInfo (#2151) 2023-03-14 18:55:29 +08:00
Rocky 82c7e78a8c
feat: support parallel compress snapshot (#2136)
* add raft default config

* delete useless final

* fix import style

---------

Co-authored-by: imbajin <jin@apache.org>
2023-03-14 18:50:35 +08:00
Jermy Li 901da45e59
fix query dirty edges of a vertex with cache (#2166)
fix #2163
Change-Id: I58b26f8a791885800e42821a3d4b2724f4e647a0
2023-03-14 17:59:11 +08:00
vaughn 31c6c6df13
feat: support task auto manage by server role state machine (#2130) 2023-03-08 23:20:36 +08:00
Jermy Li a0f34d5973
chore: disable up-to-date in PR (#2150) 2023-03-08 22:53:52 +08:00
imbajin d968deb124
refact: use a slim way to build docker image on latest code & support zgc (#2118)
* also modify shell
2023-03-08 12:14:37 +08:00
imbajin 6c0d596eac
refact: use standard UTF-8 charset & enhance CI configs (#2095) 2023-03-07 23:10:31 +08:00
YangJiaqi 76fa64498a
add github token for license check comment (#2139) 2023-03-02 21:22:16 +08:00
vaughn 1d524760eb
chore: cmn algorithm optimization (#2134) 2023-03-01 08:19:04 +08:00
imbajin 271d72c9f3
doc: update issue template & README file (#2131)
* doc: update issue template & README file
* replace outdated url
2023-02-28 00:16:32 +08:00
Simon Cheung 614d47159d
fix: transfer add_peer/remove_peer command to leader (#2112) 2023-02-20 19:04:15 +08:00
imbajin 82f2a6539f Update license-checker.yml 2023-02-10 14:46:48 +08:00
imbajin f9593d494b chore: refactor the license check CI 2023-02-10 14:46:48 +08:00
vaughn c8e0f0c3e1
chore(license): add ProcessBasicSuite and SturctureBasicSuite license (#2106)
* chore(license): add ProcessBasicSuite and SturctureBasicSuite license

* chore: add snowflake license to binary release

* Update LICENSE-jna.txt
---------

Co-authored-by: imbajin <jin@apache.org>
2023-02-10 14:45:48 +08:00
Simon Cheung 6aa01af49e Update NOTICE 2023-02-09 19:19:11 +08:00
Simon 6f9493a517 1 2023-02-09 19:19:11 +08:00
Simon Cheung effedb0c23
chore: fix snowflake license (#2093) 2023-02-09 19:18:47 +08:00
vaughn eed6103359
fix: some reference url and 3rd-party file license (#2100) 2023-02-07 23:44:05 +08:00
imbajin e1cb3eb16c
chore(license): fix 3rd party refer code (#127)
* fix 3rd party refer in LICENSE
* add sky-walking action to check license header
* Update pom.xml
2023-02-04 01:52:42 +08:00
Simon Cheung e4633e1cdb
chore: choose proper license & remove GPL/CC in multiple licenses (#2099) 2023-02-03 18:41:18 +08:00
imbajin fc6e3702da
refact: update with release branch (#2091)
* fix: add style file back for building

* fix: script no permission

* chore: add NOTICE and LICENSE to binary package and add DISCLAIMER file

Co-authored-by: Simon Cheung <ming@apache.org>
Co-authored-by: vaughn <vaughn@apache.org>
Co-authored-by: 青年 <1043706593@qq.com>
2023-01-17 01:51:26 +08:00
青年 91a616bb38
fix: support null value for gremlin test (#2061)
* fix(core): adapt HugeVertex.property() with null values

Co-authored-by: imbajin <jin@apache.org>
2023-01-16 22:53:24 +08:00
vaughn f49b2b808d
chore: remove hugegraph-server.store & jacoco jar & LicenseVerify (#2092) 2023-01-16 14:10:59 +08:00
imbajin f6018d1071
chore: remove unnecessary binary files & add rat check in ci (#2086) 2023-01-14 23:50:01 +08:00
imbajin 958193d797
chore: support validate apache release automatically (#2076) 2023-01-14 17:50:40 +08:00
Simon Cheung 3427625379
chore: modify NOTICE & LICENSE path (#2084)
Co-authored-by: imbajin <jin@apache.org>
2023-01-14 13:51:36 +08:00
imbajin 8724b12032 chore: fix copyright year and format 2023-01-14 02:07:18 +08:00
imbajin 1f64e8afb0 chore: remove copyright in file header & fix some files 2023-01-14 02:07:18 +08:00
imbajin c28f8c8977 chore: add DISCLAIMER & NOTICE & LICENSE file to binary package 2023-01-14 02:07:18 +08:00
imbajin e339fed6c9 fix(dist): generate doc & exit script when upload files failed 2023-01-14 02:07:18 +08:00
Simon Cheung 04112774d4
remove swagger-ui source (#2089) 2023-01-14 01:51:08 +08:00
imbajin e400e4d22b
refact(test): download binary file for https test (#126) 2023-01-13 23:44:21 +08:00
青年 b385c45c35
chore:remove copyright in license header (#2090)
Co-authored-by: imbajin <jin@apache.org>
2023-01-13 23:26:52 +08:00
vaughn c37556919b
fix: parent dir on project be deleted (#2085) 2023-01-11 23:33:38 +08:00
Jermy Li 62d52a20ba
fix: shutdown exception overrides the original exception (#2072)
Change-Id: I8398ae50197cab7ffe06fa17781300303e385dc9
2023-01-11 22:52:31 +08:00
vaughn 52807b0aa0
chore: remove unknown license and fix source name (#2073) 2023-01-11 19:21:06 +08:00
vaughn b3949997fd
chore: add DISCLAIMER & NOTICE & LICENSE file to binary package (#2071)
* chore: add NOTICE and LICENSE to binary package and add DISCLAIMER file

* Update DISCLAIMER

* Update .licenserc.yaml

Co-authored-by: imbajin <jin@apache.org>
2023-01-06 22:44:43 +08:00
Jermy Li 7efcf879c1
fix: check uncommit due gremlin partition test silently fails (#2065) 2023-01-04 23:18:55 +08:00
vaughn 93614cf29d
fix: scripts no permission (#2069) 2023-01-04 19:54:06 +08:00
Simon Cheung 80bd82bde1
chore: add NOTICE file (#2066) 2023-01-04 02:08:43 +08:00
青年 0239a1e174
fix: add style files back (#125)
* add style
* Update .gitattributes

Co-authored-by: imbajin <jin@apache.org>
2023-01-01 13:18:07 +08:00
seagle fb48e831f7
fix: empty label exception should be labelCanNotBeNull() (#2063) 2022-12-30 11:57:37 +08:00
imbajin 9463119a67
chore: update release script & add mailing lists (#123) 2022-12-15 16:14:29 +08:00
imbajin a40774e484
chore: prepare for release v1.0.0 (#122) 2022-12-06 15:41:56 +08:00
imbajin c86e38a8ac
chore: enable rebase option (#121) 2022-12-05 00:05:14 +08:00
seagle 37e221a712
delete blankspace of licenses filename (#120)
Co-authored-by: yuanbingze <yuanbingze@yy.com>
2022-11-30 15:45:16 +08:00
青年 5bc993fe79
manifest version use project.version (#119) 2022-11-23 21:17:02 +08:00
Simon Cheung 4dbe157ecb
Add thrid-party dependency licenses (#117)
* add dep licenses

* Update LICENSE-JavaHamcrest.txt

Co-authored-by: imbajin <jin@apache.org>
2022-11-09 21:58:18 +08:00
imbajin caa4b26a98
refact: address some code alert (#115) 2022-11-09 17:50:27 +08:00
Simon Cheung 952975a3c7
add dep check ci (#116) 2022-11-08 21:13:45 +08:00
青年 7347b17a47
fix apache revision (#114) 2022-11-04 20:56:00 +08:00
青年 16602cc839
support custom content-type (#113)
* support custom content-type

* support custom content-type v2
2022-11-01 18:16:44 +08:00
imbajin 4361a51d9d
chore: fix missing mail address & other configs (#112) 2022-10-27 00:39:09 +08:00
imbajin dc3e9e2bbd
chore: enable ci in all prs (#111) 2022-10-26 19:38:51 +08:00
imbajin ae54f28308
refact: upgrade a string of dependencies to address CVEs report & clean code (#110)
Note: after use junit-2.13, some assert-api's error messages has changed, check it in other repos (and avoid use long & fixed error message)
2022-10-26 19:02:36 +08:00
imbajin b783da5bde
feat(apache): support check license header with RAT (#108)
use "mvn apache-rat:check" to see the report, and use find ./ -name rat.txt -print0 | xargs -0 -I file cat file > merged-rat.txt
2022-10-20 12:18:49 +08:00
imbajin be72d20f8a
chore: setup for apache maven release (#107) 2022-10-19 23:42:31 +08:00
imbajin e85ab38c6b
refact: clean code & typo & update the name of getTimeZone (#105)
* refact:  clean code & typo & update the name of getTimeZone

Typo: getTimeZome() -> getTimeZone()

And we need check/update the class used it later

* Update RestClient.java
2022-09-15 16:36:13 +08:00
ShouJing 3b1bcb1a99
rename package name `com.baidu` to `org.apache` (#104) 2022-09-08 17:28:03 +08:00
DamonXue(Fibonacci) 42ef9c4d95
chore: upgrade CodeQL version to v2 (#106) 2022-09-06 19:14:59 +08:00
seagle 09b18191ed
update checkstyle (#97)
Co-authored-by: yuanbingze <yuanbingze@yy.com>
Co-authored-by: imbajin <jin@apache.org>
2022-06-13 20:37:54 +08:00
imbajin 745bd861af
chore: use .asf.yaml for apache workflow rule (#98)
* add asf.yaml file

* Update .asf.yaml

* add required
2022-06-07 09:54:42 +08:00
Jermy Li 4af14a9998
add Cnm and Anm to CollectionUtil (#101)
* add Cmn to CollectionUtil

Change-Id: I873e5c41229a8743ca5753d11c3b5e608b2e9298

* add Anm function

Change-Id: Idcb24ba80c61fb53c9744d7ab5d2a379e16a4ad3
2022-05-27 14:21:09 +08:00
Jermy Li 589ee2ca10
support assert-throws return future (#102)
Change-Id: I8fe115a7518dd84e22c9e28f777515e74e48d5d2
2022-05-27 14:19:10 +08:00
imbajin db84121d5d
refact: unify pom & remove useless file (#100) 2022-04-29 12:33:19 +08:00
Jermy Li deac513c43
improve Whitebox.setInternalState() (#99)
* add Whitebox.setInternalFinalState()

* delete Whitebox.setInternalFinalState() method since ineffective
2022-04-27 10:27:59 +08:00
zyxxoo f2e838443d
version 2.1.2 (#96) 2022-04-11 16:11:14 +08:00
zyxxoo d0e5971c7e
fix: can't delete conf file when drop graph (#93) 2022-03-21 19:47:40 +08:00
imbajin 88d2f897ed
chore: support code security check with codeQL (#94) 2022-03-21 17:24:35 +08:00
imbajin 05fe7a4c92
chore: use cla assistant to support robot pr (#92)
Co-authored-by: imbajin <imbajin@users.noreply.github.com>
2022-03-03 19:27:08 +08:00
zyxxoo 4b21e94ad2
chore: support java 11 (#83)
* chore: support java 17

* fix: unitest

* fix: server JAX-B API not found warning

* chore: improve code

* fix: hugeconfig test

* chore: resolve conflict

* fix: version unit test

* chore: improve code

* chore: improve impl version

* chore: improve code

* refactor: hugeconfig get

* chore: improve code
2022-01-14 10:55:34 +08:00
Jermy Li d695bd494d
fix some test cases naming (#90)
Change-Id: I89eaf2b7ff13e6909e057970542fff60ab552785
2021-12-21 20:59:44 +08:00
zhoney 922a4f6334
upgrade log4j to version 2.17.0 (#89) 2021-12-21 17:51:38 +08:00
coderzc 8f0f2ba012
release maven package by actions (#88) 2021-12-21 14:12:35 +08:00
zhoney 4a1926fe40
improve java doc (#87) 2021-12-17 17:43:29 +08:00
Jermy Li fbb743afeb
bump up version to 2.0.0 (#86)
* refactor license module

Change-Id: Ia4041f88994490c1bc0519e0f8ff01d27577bafb
2021-12-17 10:57:40 +08:00
zhoney 3b8933c3d3
fix log4j error (#85) 2021-12-15 20:30:27 +08:00
Jermy Li f5383d5541
Merge pull request #84 (merge rpc module into commons)
refact(rpc): merge rpc module into commons
2021-12-07 16:26:18 +08:00
imbajin ee08712120 chore: new pom & README for module 2021-12-07 14:38:05 +08:00
imbajin 24c3390379 chore: merge license & checkstyle & ci
1. root pom.xml, license, checkstyle, ci,
2021-12-01 20:38:09 +08:00
imbajin 0789b1c8c1 merge rpc module into commons 2021-11-30 15:48:37 +08:00
imbajin c572c2bedd first rename 2021-11-30 15:29:35 +08:00
guoygang 1d27452994
add bearer token support (#81) 2021-11-02 19:43:38 +08:00
imbajin 53c6503cde
chore: update ubuntu version for ci actions (#79) 2021-10-09 11:40:54 +08:00
coderzc 3881b86697
fix: unable to close the rpc thread pool at destroy (#3) 2021-07-28 11:23:55 +08:00
imbajin 49e8599d8f
chore: add issue template & auto stale issues and pr (#78) 2021-07-02 16:35:24 +08:00
ShouJing 535ae072f4
add Auth Context to store request header(Authorization) (#76) 2021-06-24 16:00:29 +08:00
Linary efa8e97c4f
chore: use github action to run ci (#77) 2021-06-23 16:57:12 +08:00
dependabot[bot] 9101842200
Bump jackson.version from 2.10.2 to 2.12.1 (#63)
Bumps `jackson.version` from 2.10.2 to 2.12.1.

Updates `jackson-annotations` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `jackson-core` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson-core/releases)
- [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.10.2...jackson-core-2.12.1)

Updates `jackson-databind` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `jackson-module-jaxb-annotations` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson-modules-base/releases)
- [Commits](https://github.com/FasterXML/jackson-modules-base/compare/jackson-modules-base-2.10.2...jackson-modules-base-2.12.1)

Updates `jackson-jaxrs-base` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson-jaxrs-providers/releases)
- [Commits](https://github.com/FasterXML/jackson-jaxrs-providers/compare/jackson-jaxrs-providers-2.10.2...jackson-jaxrs-providers-2.12.1)

Updates `jackson-jaxrs-json-provider` from 2.10.2 to 2.12.1

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-03 16:06:27 +08:00
dependabot[bot] 27dfd9d5a2
Bump commons-io from 2.4 to 2.7 (#75)
Bumps commons-io from 2.4 to 2.7.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-03 15:50:56 +08:00
houzhizhen 74b954acf2
disable delimiter parsing when construct from MapConfiguration (#74) 2021-04-26 16:16:31 +08:00
Linary f72fac400f
Improve some license params (#73) 2021-04-16 14:58:22 +08:00
Linary 185a926a94
Fix senstive mail address (#71) 2021-04-15 18:05:21 +08:00
shzcore aecaf4e86a
remove inner hostname from cacerts.jks (#72) 2021-04-15 16:54:02 +08:00
Jermy Li fe190141cc
improve profile performance (#69)
* improve profile performance
* support profile nested class
* support total_wasted time
* calculate totalChildrenWasted time for echarts
* only profile super class in the same package
* improve perf through local-tree,local-timer,local-stack
* improve test case
* add Stopwatch remove-child test
* fix can't profile parent class with 2 class not in the same package
* add totalChildrenTimes
* improve LocalTimer perf
* add PerfUtil.useLightStopwatch(true)
* define behavior of switching light-stopwatch process
* ignore other threads if profileSingleThread(true) with multi-threads
* improve the empty judgment the first call in useLightStopwatch()

Change-Id: Id1ae075ddffec77b95b31142d7ebcdae87371943
2021-04-13 14:53:42 +08:00
Jermy Li d51efb6120
add some test cases for util package (#70)
* add check for CollectionUtil.subSet from > to

Change-Id: I32d83f5738250eca23ae16c2ccbf52059a874bf6
2021-04-12 16:28:18 +08:00
Jermy Li 6c800388a1
support random port to start rpc server (#2)
* add rpc.server_adaptive_port option
* use bolt v1.6.2 instead of v1.5.6 to get RemotingServer.port()
2021-03-25 14:06:05 +08:00
Jermy Li 159143c04d
add rpc framework based on sofa-rpc (#1)
* add rpc framework based on sofa-rpc
* allowed to start server or client separately
* add destroy() method for rpc client
* complete the supplement of test cases
* remove sleep in destroy-server and improve comments of test block
* add fanout exception test case
* travis use oraclejdk8
* fix log4j config and remove test/resources from pom to avoid including log4j2.xml in tar

Co-authored-by: Jermy Li <lizhangmei@baidu.com>
Co-authored-by: xuliguov5 <xuliguo@baidu.com>
2021-03-23 18:59:43 +08:00
Linary 265f74bb5f
Add checkstyle plugin (#67) 2021-03-19 21:21:25 +08:00
Jermy Li 98844d8c2a
add UnitUtil class (#66)
* upgrede version to 1.8.6

Change-Id: I67c7b38979b2c0603878d48929247ec0282d10d9
2021-03-19 20:44:46 +08:00
liningrui 3914813fb8 Add checkstyle plugin 2021-03-17 15:21:59 +08:00
liningrui 1114e94924 First commit 2021-03-16 18:56:15 +08:00
Linary 42e5260ba5
Add Class.class as an accept data type in TypedOption (#65) 2021-03-07 16:42:38 +08:00
Jermy Li ccc4d3bd6a
add LimitIterator class (#62)
* bump up version 1.8.4

Change-Id: I5d150e0c30f83200880cf8dd95e6e4b3678137b0
2021-03-01 21:46:06 +08:00
Jermy Li cde7763cc2
fix BatchMapperIterator stopped when fetched none in the middle batch (#64)
Change-Id: I658d8e95a68c8a9494efa98e88f350cf6d65b021
2021-02-25 20:05:39 +08:00
Linary c80f959579
Implement PausableScheduledThreadPool (#61) 2021-02-03 22:03:37 +08:00
houzhizhen f4e861b3a8
add BarrierEvent (#60) 2021-01-11 18:01:35 +08:00
Linary 37de7be0ee
Improve SafeDateFormat by joda DateTimeFormatter (#59)
Fix #58
2020-12-14 15:14:50 +08:00
zhoney 9962e0c9c9
fix https+auth bug (#57)
Change-Id: Ic791c21271c9c9ca60b0ff4294feb5fe2165452a
2020-11-17 17:19:23 +08:00
Linary 2d4a8eebf8
Upgrade version to 1.8.0 for release (#55) 2020-11-05 17:35:59 +08:00
Jermy Li 630e19f8bc
fix LockManager get/create race condition (#53)
* fix LockManager get/create race condition

Change-Id: I524a2d4d13a99f3943bfa0e4a44aa0ccf9c573a1

* add unit test

Change-Id: I17abf10b3c4e7f41fdd82ce9a9423b9ffc5a07fd

* fix not clear test license

Change-Id: I41f463a7e42a9b205c251ebc906cc850cdd4b7af
2020-07-24 08:50:03 +08:00
dependabot[bot] 9f329f5f3a
Bump log4j2.version from 2.8.2 to 2.13.3 (#52)
Bumps `log4j2.version` from 2.8.2 to 2.13.3.

Updates `log4j-api` from 2.8.2 to 2.13.3

Updates `log4j-core` from 2.8.2 to 2.13.3

Updates `log4j-slf4j-impl` from 2.8.2 to 2.13.3

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-02 12:05:58 +08:00
Linary 544599e316
Fix HugeConfig save to file is empty (#51) 2020-07-01 20:53:47 +08:00
Jermy Li b4fb1f7443
refactor RestClient as interface (#49)
Change-Id: Ib7153dc7b8d3bf3df9d19662b54cb05ff14c032b
2020-06-19 20:07:27 +08:00
zhoney 034e1a2513
Add dateutil (#48)
Change-Id: I783d4ba2af19114dafd921c4468d4dbb640964c1
2020-06-15 14:01:07 +08:00
shzcore c2c5ba4689
add https support (#47) 2020-06-11 21:46:38 +08:00
Jermy Li 0d90ae4331
add encodeSignedB64() method (#46)
Change-Id: I771dfaeb923b6f13c14ec1a66df6142eaf2e42ae
2020-03-19 16:06:19 +08:00
Linary fffccf1b2f
Upgrade jackson version to 2.10.2 (#45) 2020-02-23 20:37:09 +08:00
Linary 0a71d120f9
Add nodes and data size to extra param (#44) 2020-02-04 17:45:01 +08:00
Jermy Li 4bd64ce8b5 fix iterators may not be closed (#43)
Change-Id: I3709d96fd2114fa782d6f28f8853b32d65fbd22b
2020-01-08 15:13:38 +08:00
Jermy Li 24b8a33e9c support assert range conditions (#41)
add methods to Assert class:
  assertGt()
  assertGte()
  assertLt()
  assertLte()
  assertContains()

Change-Id: If4c5df19c937a8bb06fcdd60122ac54ab04f501b
2020-01-01 01:17:03 +08:00
Jermy Li 8268b755ef add generic parameter for RowLock (#42)
Change-Id: I309b89846ca15d58ea39095d406a0b0b5de510e7
2019-12-31 15:06:33 +08:00
Jermy Li d78b728aa2 Split ConfigOption read into two steps: parse() and convert() (#40)
also fix ConfigConvOption/ConfigListConvOption read bug

fix: github.com/hugegraph/hugegraph/issues/774
Change-Id: I716c9f187128be9b0d173f152da05e5bdc2208a3
2019-12-31 14:17:25 +08:00
zhoney 49bff5eadc Support RowLock in LockGroup (#39)
Change-Id: Ic25b7d81b5dd5ddc9d85b057e5f00a00763460c7
2019-10-11 20:07:27 +08:00
zhoney 4eda6313eb Support keyLock in LockGroup (#38)
Change-Id: I43360da8b4c701bf02d635a7270af96a433ca5c7
2019-09-25 21:17:19 +08:00
Linary 0ff4b0e234
Extract license common structures (#36) 2019-09-06 10:14:23 +08:00
Jermy Li 41bc25ce85 support calling superclass method for Whitebox.invoke() (#37)
Change-Id: I36b460d1a95b4f063ccd329d2058e4e80ebb71c0
2019-09-05 14:41:19 +08:00
Jermy Li f8e65f83bd add Bytes.toHex() method (#35)
Change-Id: I613cf44728b347634bda726c3376a6fe1f4d4b2f
2019-08-15 17:20:24 +08:00
zhoney cc463411ea improve LongEncoding.decodeSortable() (#34)
Change-Id: I7962ffe9f55a2ef33752a414262e89d5a7918cc1
2019-07-22 11:17:53 +08:00
Jermy Li 0436a14591 add methods Bytes.contains() & Bytes.indexOf() (#33)
Change-Id: I2ddca3eb233a9f9f9610850ceff3a7fadd1bb784
2019-07-17 21:46:50 +08:00
Linary ce75fb96e0 Enhance split in StringUtil (#32) 2019-07-09 21:12:56 +08:00
Linary 88d8838209 Support show time in readable format (#31) 2019-07-01 17:39:53 +08:00
zhoney b525aef026 add maxValueOf() for NumericUtil (#30)
Change-Id: Ie34be6a9aa187691b004391f956891b8c55554fb
2019-06-26 17:56:27 +08:00
Linary 85a6b7e24d Enhance ExecutorUtil to create ScheduledThreadPool (#29) 2019-06-24 15:18:21 +08:00
Jermy Li 48a39fcef8 improve exception message for InvocationTargetException (#28)
Change-Id: Id2bb1d4b90d1f091f4949d7ba4cb6d7df9efb8b0
2019-06-24 15:07:56 +08:00
Jermy Li 2f453c0af9 support typed option (#27)
Change-Id: I845d3e0f59b3de4eb086a57f206a02fae0aae549
2019-06-17 15:13:07 +08:00
Linary 64bd1543e8 RestClient support to close idle connection periodically (#26) 2019-06-11 18:43:20 +08:00
Linary 1a66a60897 Enhance toList and add toSet in CollectionUtil (#25) 2019-05-29 20:07:59 +08:00
Jermy Li 0822dd93f6 let subclass of ConfigOption be able to override parent options (#24)
also implement ConfigOption.toString()

Change-Id: I1f1fd5eeaa80252fc093e7cba5af525a32a23c99
2019-05-28 16:40:43 +08:00
Jermy Li 5ea077f13e add support of sortable negative number for NumericUtil (#23)
Change-Id: I93290d3c1f9f89913d31ec2e5b4293d4a1d1ce1f
2019-05-21 12:06:42 +08:00
Jermy Li 194ed53b85 add Whitebox.invoke() method (#22)
Change-Id: If246e9193a4c61621c942f4b88a703c28c9d2846
2019-05-07 14:35:33 +08:00
liningrui 1eb2414134 Add OrderLimitMap
Change-Id: I66956a0098373a9e8999a335c1d158b6aa482bb6
2019-04-17 19:26:42 +08:00
liningrui 87c5826480 Let RestClient can reuse connections
Implement #14

Change-Id: I49c0675566145e233e40f25fe0c30c9614bf2c14
2019-04-17 19:25:35 +08:00
Zhangmei Li 306b4f1829 fix NPE in EventHub.destroy()
fix: #18
Change-Id: I30f12a583c8168045a2b240995c5277b0efbaa4c
2019-04-08 16:17:59 +08:00
Zhangmei Li 95530cc4b3 add PerfUtil.clear()/Bytes.concat()/CollectionUtil.randomSet()
also add some unit tests: HugeConfigTest, PerfUtilTest,
NumericUtilTest, ReflectionUtilTest and TimeUtilTest.

Change-Id: Ida64154a0bdee62e281585836c5e7ccfc6061c06
2019-03-01 20:02:21 +08:00
zhangyi51 5bac575b29 Set origin iterator last one if all iterators of extendable iterator are empty
implemented: #360

Change-Id: I5586ea3626816c085af788830917759f653ed0c4
2019-02-28 21:54:48 +08:00
Zhangmei Li 5f6012cbe4 Support for sortable base64 encoding
implement #11

Change-Id: I39b8f26d025e095d9d654f655657df6d6dc2543f
2018-12-25 19:56:32 +08:00
liningrui bbbc8e70f5 Add CollectionUtil.sortByValue()
Change-Id: I9152cc7d8fc5a23e3407118ed09c9b6ac116eed9
2018-12-25 16:09:44 +08:00
liningrui 6f20cb8bdc Fix dependency conflict "InjectionManagerFactory not found"
Fix #9

Change-Id: I83f2074c431994f72a62e37ab4a6086c3142a1b5
2018-12-24 15:19:33 +08:00
liningrui 476bb78315 Add CollectionUtilTest to UnitTestSuite
Change-Id: I36f632f0e0b8e6680d4fe16b30cf54e87ef01780
2018-12-17 17:17:26 +08:00
Zhangmei Li 146e4bc362 add api for setting thread pool name
Change-Id: I93aeddc6783e6b03d2aa31aa8ca42059e253ba81
2018-10-23 10:39:25 +08:00
zhangyi51 904f4260b9 README improve
Change-Id: I4550093fb02a0156bc353ef33eaad97f3e63fb12
2018-10-15 10:20:42 +08:00
liningrui 16fbcb354d Optimize intersect action
improve #2

Change-Id: I9c4daeaf812ffdae84a83b2bc94bb114461bda45
2018-10-11 22:33:40 +08:00
Zhangmei Li 591d3f3834 HugeGraph-1399: let EventHub.notify() return Future to sync
Change-Id: If7412da120c9652946a9aff41b0df5571fac3145
2018-10-10 09:46:11 +08:00
zhangyi51 07793f9971 HugeGraph-622: Bump up to version 1.5.0
Change-Id: Id1a905adf907370a5e8c30ba0ae7a8327c519daf
2018-08-09 09:56:11 +08:00
zhangyi51 1c7c839d45 hugegraph-1364 add LICENSE for hugegraph-common
Change-Id: I1e494152aeef3c4ff2bd9a09aeb3ab64303eec29
2018-08-09 09:56:11 +08:00
liningrui a4121451ce HugeGraph-1349: Add some badges(licence, build, coverage and maven) in README
Change-Id: I4d8498adbcf4289ecc897ffe629080cd524d5004
2018-08-09 09:56:11 +08:00
zhangyi51 553cd60b8f hugegraph-889 add ACCEPTED to POST, PUT and DELETE for async
Change-Id: If0acdc33acb4ac1e50295d920e0b77b35d11b12f
2018-08-09 09:56:10 +08:00
liningrui 1db56cfd86 HugeGraph-1341: Upgrade version to 1.4.8(1.4.7 failed deploying to maven respority)
Change-Id: I7fedf79f96607a3e07cceba4bfa263ce56f36f71
2018-08-09 09:56:10 +08:00
Zhangmei Li 9db431015a HugeGraph-1336: move common tests from hugegraph-test to hugegraph-common
Change-Id: Id6698c6fa83a0a9338e6dba02180bd8ce0e73c4d
2018-08-09 09:56:10 +08:00
zhangyi51 eed956d931 hugegraph-81 add github link to README
Change-Id: I16f47975372a5cb88b3890407a6e9d5fd79e19f9
2018-08-09 09:56:10 +08:00
liningrui 50c7738056 HugeGraph-1312: Add config to deploy to sonatype maven respority
Change-Id: I981ecc2486b8091b6c1b039d79da9c05ee3aaa14
2018-08-09 09:56:10 +08:00
Zhangmei Li 92ad62a9fb HugeGraph-1330: add support for 128bits hash
Change-Id: I51b46d3a88e472757e4ca45e73e7d6011150ef2f
2018-08-09 09:56:09 +08:00
liningrui 4aae65cd4d HugeGraph-81: Small optimization of package structure
Change-Id: I84109719a0064ea0d53c26843fbe435b84655912
2018-08-09 09:56:09 +08:00
Zhangmei Li 8c76d5b0cf HugeGraph-1309: add remove() support to WrappedIterator
Change-Id: Iec68a94fed485852af8d1c838630a108794aac99
2018-08-09 09:56:09 +08:00
liningrui daa967d74d HugeGraph-1301: Move SafeDateFormat class to hugegraph-common module
Change-Id: I8bc07f5b01b400d48393a1dc744c1de2853e392f
2018-08-09 09:56:09 +08:00
liningrui 544b94c919 HugeGraph-1257: Let jersey client use preemptive credentials
Change-Id: Ica97e912e905c0c7ee1353e603651794408564d1
2018-08-09 09:56:09 +08:00
zhangyi51 140cf845b5 hugegraph-1234 add subset util
Change-Id: I1f7a0f5b989191459ae3409d1aeaeaefe2c10c92
2018-08-09 09:56:09 +08:00
Zhangmei Li 9346717bde HugeGraph-1236: add getMap() to HugeConfig
Change-Id: I46d3ea398246e771936a3f4c75adbcdd31d7ad98
2018-08-09 09:56:08 +08:00
liningrui d6d92e4896 HugeGraph-1229: add README.md for project hugegraph-common
Change-Id: Ic881b001c08e47e1fa6ead49ca064ecefd215691
2018-08-09 09:56:08 +08:00
liningrui aa222c4893 HugeGraph-1229: add README.md for project hugegraph-common
Change-Id: Ic1d328b03a1d7eb91d76af615d4146d3f175ef79
2018-08-09 09:56:08 +08:00
liningrui c2db8f55d6 HugeGraph-81: Fixed bug that message and cause placed error
Change-Id: Ic408f158cd814edcd5edffc21bc09ba347da9a8f
2018-08-09 09:56:08 +08:00
Liu Jie 887a4d5a9a HugeGraph-1196: Fix grammer at exits method
Change-Id: Iad9cc2b819684140a0a4509dd6c3331b4dcf86b8
2018-08-09 09:56:08 +08:00
liningrui 5183fb054a HugeGraph-1208: Move compareNumber() from core to common module
Change-Id: I426651f98c7645ccdfc20f04310769eacb6d442a
2018-08-09 09:56:08 +08:00
Liu Jie 1bf8d9e4c0 HugeGraph-1191: rewrite exception handling mechanism at register method
Change-Id: I041f1792f2a4806e73d2ebb93a2b019d9ad73b0b
2018-08-09 09:56:08 +08:00
Zhangmei Li 56a60dca53 HugeGraph-1190: add OptionSpace.keys() method
Change-Id: If43dbfce1926fea95ca99c63b0d5c5531bcd639c
2018-08-09 09:56:07 +08:00
liningrui 12c65918b3 HugeGraph-1183: Add common RestClient for server and client
Change-Id: Iec3c1d11bb57b913f5837af42050bb5b8b8c3705
2018-08-09 09:56:07 +08:00
liningrui cb33bbd436 HugeGraph-1174: Let config reload if some options contains comma
Change-Id: I1e6dd2124aa9f9c3d1a52160b58cbad90cd0c941
2018-08-09 09:56:07 +08:00
liningrui 154e03054e HugeGraph-1171: Modify the way for config options registration
Change-Id: I99a7dec4ac72ee5afa5ed9945fd27a9f536b57cd
2018-08-09 09:56:07 +08:00
Zhangmei Li 8d8333980c HugeGraph-1158: awllow empty Iterator add to ExtendableIterator
Change-Id: Ieabd7a243105c6875fe9adbcebb466daa73ff427
2018-08-09 09:56:07 +08:00
Zhangmei Li fde9c72a0f HugeGraph-1110: let iterators implement AutoCloseable and Metadatable
Change-Id: I5c5f0fe6cafd0dfdc33404613a071927332c6211
2018-08-09 09:56:07 +08:00
Zhangmei Li 749a2d9d1f HugeGraph-1097: fix check error when HugeConfig(Configuration config) with list options
Change-Id: I7a3d0c6a017513368717bed4b32f4501bc2a9049
2018-08-09 09:56:06 +08:00
Zhangmei Li 2ae8e1571b HugeGraph-1097: fix missing check for duplicated options
Change-Id: I542998a0024d83706b0d8c485b4ec8ef40fd310f
2018-08-09 09:56:06 +08:00
Zhangmei Li 8219a10e74 HugeGraph-1075: add allowValues() to OptionChecker
Change-Id: I7752b039c3d8332550e4daf9852bdf7f7610d161
2018-08-09 09:56:06 +08:00
Zhangmei Li 9f994b33de HugeGraph-1000: allow non-check of config options
Change-Id: Ida0a2d88818f0ca53e9ddf886cff88e7ceb52ed8
2018-08-09 09:56:06 +08:00
Zhangmei Li fe8b51d072 HugeGraph-976: add filter-iterator
Change-Id: I8291be7576b0fd1536cc5425c09e26dfda5c4ff0
2018-08-09 09:56:06 +08:00
liningrui 24ff820174 HugeGraph-994: Fixed bug that some key has more than one value will throw an assert exception
Change-Id: I72301a594afe311a6d744514fb8791ec6d6fc954
2018-08-09 09:56:06 +08:00
liningrui 8a44989e32 HugeGraph-990: Fixed bug that compile error when building project
Change-Id: I398165b3b022e55290781b366e2d008f516dfb46
2018-08-09 09:56:06 +08:00
Zhangmei Li 7789bc87d8 HugeGraph-989: add toHex()/fromHex() to class Bytes
Change-Id: I3ef03ea58cdf2fe379e1dbf5b3e0877b4c379745
2018-08-09 09:56:05 +08:00
liningrui 65032356e9 HugeGraph-986: Let prefixOf support generic type
Change-Id: I7f02d3c3556ae6ae9f63888af7f33fe52e505862
2018-08-09 09:56:05 +08:00
liningrui 1804fa7ee1 HugeGraph-984: Fixed bug that multi graphs has same name config option will be overrided
Change-Id: Ia35570b52e00407de7e29e6e38aaf55a88f72c7a
2018-08-09 09:56:05 +08:00
Zhangmei Li 3d3da162de HugeGraph-978: add prefixWith() for bytes
Change-Id: I17a493ef0097f9208f4cfa3aad8bbd159283f4bb
2018-08-09 09:56:05 +08:00
Zhangmei Li b01f3a35df HugeGraph-975: support conversion: number <==> bytes
Change-Id: I8da23ab89f0e3eda99ec744904dd7ef06571a8e2
2018-08-09 09:56:05 +08:00
liningrui 094f8bb56b HugeGraph-935: Add a method 'allUnique'
Change-Id: Iebbcb8acb90844e82ae8e70b559a600543aaf6d8
2018-08-09 09:56:05 +08:00
zhangyi51 d8d4b3eba5 hugegraph-911 add prefixOf method into CollectionUtil
Change-Id: Ia917fc5ec5492547dee6b0477d9c3f947cddb71f
2018-08-09 09:56:04 +08:00
liningrui 5e003a7f2f HugeGraph-830: Catch IOException if create new socket connection failed. Note that, we should try to avoid catch Throwable since it not only catch all exceptions but also catch errors.
Change-Id: I72ae39058d737b1bbbeb70f4f05737fe95ed4ffc
2018-08-09 09:56:04 +08:00
Zhangmei Li 5195740642 HugeGraph-762: add isSimpleType() method to class ReflectionUtil
Change-Id: I7372c982dda9241d3d7d7b688d37d0403268e173
2018-08-09 09:56:04 +08:00
Zhangmei Li 12c53cc17b fix EventHub bugs: HugeGraph-732 and HugeGraph-733
Change-Id: I9395193680b986e543a0af3c08ce434b2b0e329c
2018-08-09 09:56:04 +08:00
Zhangmei Li 4d6c421358 HugeGraph-726: add toList(array) method into class CollectionUtil
Change-Id: Ia8a06f002e66f11935986284f587563ebc0c2257
2018-08-09 09:56:04 +08:00
liningrui 281aab85f2 HugeGraph-645: Add space line between license and package for hugegraph-common
Change-Id: I92a66e429382695b0f2a5742fb16299faace1616
2018-08-09 09:56:01 +08:00
liningrui ca0a9832a6 HugeGraph-596: Passed env varibale from BCLOUD to agile module for hugegraph-common module
Change-Id: Id3b89cccd310625826ca8fc2502133146221b138
2018-08-09 09:55:36 +08:00
liningrui b4a6cc9ab4 HugeGraph-596: fixed bug that hugegraph-common deploy before merge
Change-Id: Ia52ab72006bd8a2ba58254fbf4266f1555ebb8cd
2018-08-09 09:55:36 +08:00
liningrui c24069ee26 HugeGraph-625: fixed bug that there is a line length of more than 80 characters in the license information for hugegraph-common
Change-Id: Ic7cecaa7535f149060701fa16ff8e80f06cf363a
2018-08-09 09:55:33 +08:00
Zhangmei Li 504069e17f HugeGraph-623: rename LoggerFactory.getLogger() to Log.logger()
Change-Id: If9c03e3588334207870d710eba63f8bbf983e14e
2018-08-09 09:54:45 +08:00
Zhangmei Li 705c27b986 HugeGraph-555: add lockAll() for KeyLock
Change-Id: Iac0a396077658b82b67547e3eea5793d54fa01fd
2018-08-09 09:54:45 +08:00
Liu Jie f6cdc8a3ca HugeGraph-547: replace tilNextMillis by tillNextMills as the later is more meaningfull
Change-Id: I4505c1335bfc6eeb03658597f6f6ae5e994a2cf2
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:54:45 +08:00
Zhangmei Li 8bdac2c758 HugeGraph-525: add the const NAME of component hugegraph-common into CommonVersion
Change-Id: I5bcd766bb3435de98833759efcba5d3fa0650499
2018-08-09 09:54:45 +08:00
Zhangmei Li a200deab56 HugeGraph-131: clean up some warnings in LockGroup
Change-Id: I55a359b799119c04ea0e89d013f1c034453c2ba4
2018-08-09 09:54:45 +08:00
Zhangmei Li 5cda854e8d HugeGraph-525: add vertion check util
Change-Id: I57305dd209416620758b5bf183e791f8734af711
2018-08-09 09:54:45 +08:00
Liu Jie f33c09385d HugeGraph-532: Rewrite checksocket class
Change-Id: Iadae3837c2e9e0fddadbebbee097000c281e267c
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:54:44 +08:00
Liu Jie dec8fe9a84 HugeGraph-531: Fix typo at OptionHolder class
Change-Id: I19ea584802edd469d503b9fb57f630bf0c660487
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:54:44 +08:00
liningrui dfd3190392 HugeGraph-527: First add the version to the common module.
Change-Id: I2fd816ba13978d3d4cf2cb7a9724fe2d5f29a010
2018-08-09 09:54:44 +08:00
liningrui b76e0eaeab HugeGraph-527: add customized implemention version to manifest.mf
Change-Id: I569d82397408fb255d8ad9653e8b561ba1a60c1e
2018-08-09 09:54:44 +08:00
zhangyi51 6052985c15 hugegraph-502
add read write lock support

Change-Id: Ic339f5d81c9f475ee11ada38167fe42169c10971
2018-08-09 09:54:44 +08:00
liningrui e05d13098a HugeGraph-482: upgrade log4j to log4j2
Change-Id: If0bfaf91c45eac055e3f851b7f1dd5647d58d175
2018-08-09 09:54:44 +08:00
zhangyi51 9faea02296 hugegraph-499
trivial grammar change.

Change-Id: Ice29a709b9a5b5d7f2f7838d79541f63cf00a0c5
2018-08-09 09:54:43 +08:00
Zhangmei Li 5252a7e481 HugeGraph-410: improve code style
Change-Id: Idce80465ea4cbe92ac836bbc8d293e77ad7c7c5c
2018-08-09 09:54:41 +08:00
Zhangmei Li 0c580690cc HugeGraph-501: fix EventHub ConcurrentModificationException
Change-Id: Idedff1ca762cd56f171152174bdbfb0bef4b8d4f
2018-08-09 09:53:56 +08:00
Liu Jie 315000a600 HugeGraph-503: using bit shift whenever, if not affect the code readability.
Change-Id: Ib36dc135241f77c99d39d458ee144dbe888c541b
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:56 +08:00
Liu Jie d3960c1da4 Always define long variable endwith 'L' indicator.
Change-Id: I5f4d4d5c823ea4e14a135b59fb2384299686b4d5
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:56 +08:00
Liu Jie 9778a8b4b3 HugeGrap-499: fix english grammer in lock
Change-Id: I36c123eb7dfb101f99a176fcd9b2ee1f0f0211d7
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:55 +08:00
Liu Jie 171e723f50 HugeGraph-494: refine logic of lock() menthod
Change-Id: Ic5298b36ecf68f3a2b87b35bd793953e6505a9ae
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:55 +08:00
zhangyi51 9a1417f3dc HugeGraph-487
Add lockManager for mutual exclusion of thread in long time operation.

Change-Id: I155e2b6bb6fffe88e4985c85d8ff68f9c49d04be
2018-08-09 09:53:55 +08:00
Zhangmei Li 9cc9cad29a HugeGraph-476: add destroy() method
Change-Id: I745465ef6f3942f1e6774bacc1e59a1e5a0b200e
2018-08-09 09:53:55 +08:00
Zhangmei Li e88f54a21e HugeGraph-462: add event manager
Change-Id: I471a115fca5c84f8f25c7026fe834be305ab39b6
2018-08-09 09:53:55 +08:00
zhangyi51 ec2599db9a HugeGraph-369
Add lockManager for mutual exclusion of thread in long time operation.

Change-Id: I155e2b6bb6fffe88e4965c85d8ff68f9c49d04be
2018-08-09 09:53:55 +08:00
Zhangmei Li d592690cf7 HugeGraph-254: improve utils class perf with final(inline)
Change-Id: I625be2f4691a7821dbf3107d0f28ce079d46dfee
2018-08-09 09:53:51 +08:00
liningrui 36959044a1 HugeGraph-410: fixed code style of hugegraph-common
Change-Id: I8e123a315e483ed66658ce93c3eaffa61d94cfb3
2018-08-09 09:52:44 +08:00
Zhangmei Li 7bdf878dd4 HugeGraph-407: add KeyLock class
Change-Id: I655bdf4da20e0c6b6d7796958485ab066f0020f1
2018-08-09 09:52:44 +08:00
liningrui 5603b9c6a3 HugeGraph-326: add slf4j-api that has been mistakenly deleted
Change-Id: I7fd0d4ee3b6957878ed2850dd389dd78f42de71e
2018-08-09 09:52:44 +08:00
liningrui cccef5d575 HugeGraph-357: modify return type of TriFunction
Change-Id: I8cfd2dce48e2901af4773ea0c8d867edd6d21562
2018-08-09 09:52:44 +08:00
liningrui db55e237a5 HugeGraph-351: fixed bug that CoreOption constructor has been removed
Change-Id: I04cc0107aec90440ee2ae8c5c6add8a7c787f4f4
2018-08-09 09:52:44 +08:00
liningrui 3e5f626d11 HugeGraph-351: code format and clean up some warnings
Change-Id: I16d328738ead94efcad9d82bb8f27be2c4ca84a9
2018-08-09 09:52:43 +08:00
liningrui 5f305526d7 HugeGraph-344: add distributionManagement to deploy baidu maven repository
Change-Id: I198cd1e8a7d34a85d08b93261f33f07bb29335c9
2018-08-09 09:52:43 +08:00
liningrui a5fa9016ec HugeGraph-341: First commit hugegraph-common code
Change-Id: Icc8f9121d56679b266459125afc33180d8b568bf
2018-08-09 09:52:28 +08:00
3116 changed files with 393734 additions and 94846 deletions

View File

@ -17,12 +17,11 @@
github:
features:
# Enable issue management
issues: true
# Enable wiki for documentation
wiki: true
# Enable projects for project management boards
# Enable projects for project (task)management boards
projects: true
discussions: true
description: A graph database that supports more than 100+ billion data, high performance and scalability (Include OLTP Engine & REST-API & Backends)
homepage: https://hugegraph.apache.org
del_branch_on_merge: true
@ -34,23 +33,32 @@ github:
protected_branches:
master:
required_status_checks:
# strict means "Require branches to be up-to-date before merging".
strict: true
# strict means "Require PR to be up-to-date before merging". (enable when branch unstable)
strict: false
# contexts are the names of checks that must pass (now only enable the basic check)
contexts:
- Analyze (java)
- CodeQL
- build (memory, 8)
- build (memory, 11)
- check-license
- build-server (memory, 11)
- build-commons (11)
required_pull_request_reviews:
dismiss_stale_reviews: true
require_code_owner_reviews: false
required_approving_review_count: 2
required_approving_review_count: 1
# (for non-committer): assign/edit/close issues & PR, without write access to the code
collaborators:
- haohao0103
- kenssa4eedfd
- Tsukilc
# refer https://cwiki.apache.org/confluence/display/INFRA/Git+-+.asf.yaml+features#Git.asf.yamlfeatures-Notificationsettingsforrepositories
notifications:
pullrequests_status: dev@hugegraph.apache.org
# before use the config, we should ensure the "mail" address has set well (exist)
#pullrequests_comment: issues@hugegraph.apache.org
#issues: issues@hugegraph.apache.org
#discussions: issues@hugegraph.apache.org
# use https://selfserve.apache.org to manage it
pullrequests_status: issues@hugegraph.apache.org
pullrequests_comment: issues@hugegraph.apache.org
pullrequests_bot_dependabot: issues@hugegraph.apache.org
issues: issues@hugegraph.apache.org
issues_status: dev@hugegraph.apache.org
issues_comment: issues@hugegraph.apache.org
discussions: dev@hugegraph.apache.org

60
.dockerignore Normal file
View File

@ -0,0 +1,60 @@
#
# 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.
#
# IMPORTANT: .dockerignore does NOT inherit .gitignore — patterns must be restated.
# Build output
**/target/
# Pre-extracted release dirs / archives
apache-hugegraph-*/
**/*.tar
**/*.tar.gz
**/*.zip
**/*.war
# IDE / OS
.idea/
.vscode/
**/*.iml
**/*.iws
**/.DS_Store
# Build / runtime artifacts
**/logs/
**/*.log
**/*.class
**/gen-java/
**/upload-files/
**/build/
**/node_modules/
# Env files
.env.local
.env.*.local
# Git internals
.git
.gitignore
.gitattributes
.github
# Compose / docs not needed in build context
**/docker-compose*.yml
**/docker-compose*.yaml
**/*.md
docs/

View File

@ -21,7 +21,79 @@ root = true
charset = utf-8
end_of_line = lf
insert_final_newline = true
max_line_length = 100
ij_wrap_on_typing = true
ij_visual_guides = 100
[*.{java,xml,py}]
indent_style = space
indent_size = 4
[*.{java,xml}]
# Ignore the IDEA unsupported warning & it works well (indeed)
continuation_indent_size = 8
[*.md]
max_line_length = off
[*.java]
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_do_not_wrap_if_one_line = true
ij_java_annotation_parameter_wrap = normal
ij_java_align_multiline_annotation_parameters = true
ij_java_class_count_to_use_import_on_demand = 100
ij_java_names_count_to_use_import_on_demand = 100
ij_java_imports_layout = $*, |, java.**, |, javax.**, |, org.**, |, com.**, |, *
ij_java_line_comment_at_first_column = false
ij_java_align_multiline_chained_methods = true
ij_java_align_multiline_parameters_in_calls = true
ij_java_align_multiline_binary_operation = true
ij_java_align_multiline_assignment = true
ij_java_align_multiline_ternary_operation = true
ij_java_align_multiline_throws_list = true
ij_java_align_multiline_extends_list = true
ij_java_align_multiline_array_initializer_expression = true
ij_java_call_parameters_wrap = normal
ij_java_method_parameters_wrap = normal
ij_java_resource_list_wrap = normal
ij_java_extends_list_wrap = normal
ij_java_throws_list_wrap = normal
ij_java_method_call_chain_wrap = normal
ij_java_binary_operation_wrap = normal
ij_java_ternary_operation_wrap = normal
ij_java_for_statement_wrap = normal
ij_java_array_initializer_wrap = normal
ij_java_assignment_wrap = normal
ij_java_assert_statement_wrap = normal
ij_java_if_brace_force = if_multiline
ij_java_do_while_brace_force = always
ij_java_while_brace_force = if_multiline
ij_java_for_brace_force = if_multiline
ij_java_wrap_long_lines = true
ij_java_parameter_annotation_wrap = normal
ij_java_enum_constants_wrap = split_into_lines
ij_java_keep_blank_lines_in_declarations = 1
ij_java_keep_blank_lines_in_code = 1
ij_java_keep_blank_lines_between_package_declaration_and_header = 1
ij_java_keep_blank_lines_before_right_brace = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_after_class_header = 1
ij_smart_tabs = true
[*.xml]
max_line_length = 120
ij_visual_guides = 120
ij_xml_text_wrap = off
ij_xml_space_inside_empty_tag = true
[.yaml]
ij_yaml_spaces_within_braces = false
ij_yaml_spaces_within_brackets = false
[.properties]
ij_properties_keep_blank_lines = true

10
.gitattributes vendored
View File

@ -2,13 +2,15 @@
.gitattributes export-ignore
.gitignore export-ignore
.asf.yaml export-ignore
checkstyle.xml export-ignore
apache-release.sh export-ignore
.licenserc.yaml export-ignore
.editorconfig export-ignore
hugegraph-store/hg-store-dist/src/assembly/static/bin/libjemalloc.so export-ignore
hugegraph-store/hg-store-dist/src/assembly/static/bin/libjemalloc_aarch64.so export-ignore
# ignored directory
.github/ export-ignore
hugegraph-dist/scripts/ export-ignore
style/ export-ignore
#assembly/ export-ignore
.idea/ export-ignore
install-dist/scripts/ export-ignore
hugegraph-commons/hugegraph-dist/ export-ignore
docker/ export-ignore

View File

@ -10,18 +10,18 @@ body:
value: >-
### Note (特别注意) :
> 1. 请先**搜索**现有的[Issues](https://github.com/hugegraph/hugegraph/issues) 与
[FAQ](https://hugegraph.github.io/hugegraph-doc/guides/faq.html) 中没有与您相同
> 1. 请先**搜索**现有的[Issues](https://github.com/apache/hugegraph/issues) 与
[FAQ](https://hugegraph.apache.org/docs/guides/faq/) 中没有与您相同
/ 相关的问题 (请勿重复提交)
> 2. 我们需要尽可能**详细**的信息来**复现**问题, 越详细的信息 (包括**日志 / 截图 / 配置**等)
会**越快**被响应和处理
> 3. Issue 标题请保持原有模板分类(例如:`[Bug]`), 长段描述之间可以增加`空行`或使用`序号`标记, 保持排版清晰
> 3. Issue 标题请保留原有分类标签 (例如:`[Bug]`), 长段描述请增加`空行`并使用`序号`标记, 保持排版清晰
> 4. 请在对应的模块提交 issue, 缺乏有效信息 / 长时间 (> 14 天) 没有回复的 issue 可能会被 **关闭**
(更新时会再开启)
- type: dropdown
attributes:
label: Bug Type (问题类型)
@ -31,36 +31,38 @@ body:
- other exception / error (其他异常报错)
- server status (启动/运行异常)
- logic (逻辑设计问题)
- performence (性能下降)
- performance (性能下降)
- others (please edit later)
- type: checkboxes
attributes:
label: Before submit
options:
- label: 我已经确认现有的 [Issues](https://github.com/hugegraph/hugegraph/issues) 与 [FAQ](https://hugegraph.github.io/hugegraph-doc/guides/faq.html) 中没有相同 / 重复问题
- label: '我已经确认现有的 [Issues](https://github.com/apache/hugegraph/issues) 与
[FAQ](https://hugegraph.apache.org/docs/guides/faq/) 中没有相同 / 重复问题 (I have confirmed
and searched that there are no similar problems in the historical issue and documents)'
required: true
- type: textarea
attributes:
label: Environment (环境信息)
description: |
> server version could get from [rest-api](https://hugegraph.github.io/hugegraph-doc/clients/restful-api/other.html) (http://localhost:8080/versions)
> server version could get from [rest-api](https://hugegraph.apache.org/docs/clients/restful-api/) (http://localhost:8080/versions)
value: |
- Server Version: v0.11.x
- Server Version: 1.0.0 (Apache Release Version)
- Backend: RocksDB x nodes, HDD or SSD
- OS: xx CPUs, xx G RAM, Centos 7.x
- OS: xx CPUs, xx G RAM, Ubuntu 2x.x / CentOS 7.x
- Data Size: xx vertices, xx edges <!-- (like 1000W 点, 9000W 边) -->
validations:
required: true
- type: textarea
attributes:
label: Expected & Actual behavior (期望与实际表现)
description: |
> we can refer [How to create a minimal reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) (如何提供最简的可复现用例)
> if possible, please provide screenshots or GIF (请提供清晰的截图, 动图录屏更佳)
placeholder: |
> if possible, please provide **screenshots** / Pic or `GIF` (请提供清晰的截图, 动图录屏更佳)
placeholder: |
type the main problem here
```java
@ -69,7 +71,7 @@ body:
```
validations:
required: true
- type: textarea
attributes:
label: Vertex/Edge example (问题点 / 边数据举例)
@ -84,7 +86,7 @@ body:
"vertex": { "id": "xxx" }
}
render: javascript
- type: textarea
attributes:
label: Schema [VertexLabel, EdgeLabel, IndexLabel] (元数据结构)

View File

@ -2,9 +2,9 @@ blank_issues_enabled: false
# 设置提 issue 前的参考文档
contact_links:
- name: HugeGraph Server Doc
url: https://hugegraph.github.io/hugegraph-doc/quickstart/hugegraph-server.html
- name: HugeGraph Server Doc (EN/CN)
url: https://hugegraph.apache.org/docs/quickstart/hugegraph-server/
about: Please search question here before opening a new issue
- name: HugeGraph API Doc
url: https://hugegraph.github.io/hugegraph-doc/clients/hugegraph-api.html
- name: HugeGraph API Doc (EN/CN)
url: https://hugegraph.apache.org/docs/clients/
about: Please search usage here before opening a new issue

View File

@ -10,6 +10,6 @@ body:
label: Feature Description (功能描述)
description: |
> 请简要描述新功能 / 需求的使用场景或上下文, 最好能给个具体的例子说明
placeholder: type the feature description here
placeholder: type the feature description here
validations:
required: true

View File

@ -8,18 +8,18 @@ body:
value: >-
### Note (特别注意) :
> 1. 请先**搜索**现有的[Issues](https://github.com/hugegraph/hugegraph/issues) 与
[FAQ](https://hugegraph.github.io/hugegraph-doc/guides/faq.html) 中没有与您相同
> 1. 请先**搜索**现有的[Issues](https://github.com/apache/hugegraph/issues) 与
[FAQ](https://hugegraph.apache.org/docs/guides/faq/) 中没有与您相同
/ 相关的问题 (请勿重复提交)
> 2. 我们需要尽可能**详细**的信息来**复现**问题, 越详细的信息 (包括**日志 / 截图 / 配置**等)
会**越快**被响应和处理
> 3. Issue 标题请保持原有模板分类(例如:`[Bug]`), 长段描述之间可以增加`空行`或使用`序号`标记, 保持排版清晰
> 3. Issue 标题请保留原有分类标签 (例如:`[Bug]`), 长段描述请增加`空行`并使用`序号`标记, 保持排版清晰
> 4. 请在对应的模块提交 issue, 缺乏有效信息 / 长时间 (> 14 天) 没有回复的 issue 可能会被 **关闭**
(更新时会再开启)
- type: dropdown
attributes:
label: Problem Type (问题类型)
@ -29,37 +29,40 @@ body:
- server status (启动/运行异常)
- configs (配置项 / 文档相关)
- struct / logic (架构 / 逻辑设计问题)
- performence (性能优化)
- performance (性能优化)
- other exception / error (其他异常报错)
- others (please edit later)
- type: checkboxes
attributes:
label: Before submit
options:
- label: 我已经确认现有的 [Issues](https://github.com/hugegraph/hugegraph/issues) 与 [FAQ](https://hugegraph.github.io/hugegraph-doc/guides/faq.html) 中没有相同 / 重复问题
- label: '我已经确认现有的 [Issues](https://github.com/apache/hugegraph/issues) 与
[FAQ](https://hugegraph.apache.org/docs/guides/faq/) 中没有相同 / 重复问题 (I have confirmed
and searched that there are no similar problems in the historical issue and documents)'
required: true
- type: textarea
attributes:
label: Environment (环境信息)
description: |
> server version could get from [rest-api](https://hugegraph.github.io/hugegraph-doc/clients/restful-api/other.html) (http://localhost:8080/versions)
> server version could get from [rest-api](https://hugegraph.apache.org/docs/clients/restful-api/) (http://localhost:8080/versions)
value: |
- Server Version: v0.11.x
- Server Version: 1.0.0 (Apache Release Version)
- Backend: RocksDB x nodes, HDD or SSD
- OS: xx CPUs, xx G RAM, Centos 7.x
- OS: xx CPUs, xx G RAM, Ubuntu 2x.x / CentOS 7.x
- Data Size: xx vertices, xx edges <!-- (like 1000W 点, 9000W 边) -->
validations:
required: true
- type: textarea
attributes:
label: Your Question (问题描述)
description: |
> 图使用 / 配置相关问题,请优先参考 [REST-API 文档](https://hugegraph.github.io/hugegraph-doc/clients/hugegraph-api.html), 以及 [Server 配置文档](https://hugegraph.github.io/hugegraph-doc/config/config-option.html)
> if possible, please provide screenshots or GIF (请提供清晰的截图, 动图录屏更佳)
placeholder: |
> 图使用 / 配置相关问题,请优先参考 [REST-API 文档](https://hugegraph.apache.org/docs/clients/restful-api/),
> 以及 [Server 配置文档](https://hugegraph.apache.org/docs/config/)
> if possible, please provide **screenshots** / Pic or `GIF` (请提供清晰的截图, 动图录屏更佳)
placeholder: |
type the main problem here
```java
@ -68,7 +71,7 @@ body:
```
validations:
required: true
- type: textarea
attributes:
label: Vertex/Edge example (问题点 / 边数据举例)
@ -83,7 +86,7 @@ body:
"vertex": { "id": "xxx" }
}
render: javascript
- type: textarea
attributes:
label: Schema [VertexLabel, EdgeLabel, IndexLabel] (元数据结构)

67
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,67 @@
<!--
Thank you very much for contributing to Apache HugeGraph, we are happy that you want to help us improve it!
Here are some tips for you:
1. If this is your first time, please read the [contributing guidelines](https://github.com/apache/hugegraph/blob/master/CONTRIBUTING.md)
2. If a PR fix/close an issue, type the message "close xxx" (xxx is the link of related
issue) in the content, GitHub will auto link it (Required)
3. Name the PR title in "Google Commit Format", start with "feat | fix | perf | refactor | doc | chore",
such like: "feat(core): support the PageRank algorithm" or "fix: wrong break in the compute loop" (module is optional)
skip it if you are unsure about which is the best component.
4. One PR address one issue, better not to mix up multiple issues.
5. Put an `x` in the `[ ]` to mark the item as CHECKED. `[x]` (or click it directly after
published)
-->
## Purpose of the PR
- close #xxx <!-- or use "fix #xxx", "xxx" is the ID-link of related issue, e.g: close #1024 -->
<!--
Please explain more context in this section, clarify why the changes are needed.
e.g:
- If you propose a new API, clarify the use case for a new API.
- If you fix a bug, you can clarify why it is a bug, and should be associated with an issue.
-->
## Main Changes
<!-- Please clarify what changes you are proposing. The purpose of this section is to outline the changes and how this PR fixes the issue. These change logs are helpful for better and faster reviews.)
For example:
- If you introduce a new feature, please show detailed design here or add the link of design documentation.
- If you refactor some codes with changing classes, showing the class hierarchy will help reviewers.
- If there is a discussion in the mailing list, please add the link. -->
## Verifying these changes
<!-- Please pick the proper options below -->
- [ ] Trivial rework / code cleanup without any test coverage. (No Need)
- [ ] Already covered by existing tests, such as *(please modify tests here)*.
- [ ] Need tests and can be verified as follows:
- xxx
## Does this PR potentially affect the following parts?
<!-- DO NOT REMOVE THIS SECTION. CHECK THE PROPER BOX ONLY. -->
- [ ] Dependencies ([add/update license](https://hugegraph.apache.org/docs/contribution-guidelines/contribute/#321-check-licenses) info & [regenerate_known_dependencies.sh](../install-dist/scripts/dependency/regenerate_known_dependencies.sh)) <!-- Don't forget to add/update the info in "LICENSE" & "NOTICE" files (both in root & dist module) -->
- [ ] Modify configurations
- [ ] The public API
- [ ] Other affects (typed here)
- [ ] Nope
## Documentation Status
<!-- DO NOT REMOVE THIS SECTION. CHECK THE PROPER BOX ONLY. -->
- [ ] `Doc - TODO` <!-- Your PR changes impact docs and you will update later -->
- [ ] `Doc - Done` <!-- Related docs have been already added or updated -->
- [ ] `Doc - No Need` <!-- Your PR changes don't impact/need docs -->

43
.github/configs/settings.xml vendored Normal file
View File

@ -0,0 +1,43 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>github</id>
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
</servers>
<profiles>
<profile>
<id>local-repo</id>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>staged-releases</id>
<url>https://repository.apache.org/content/groups/staging/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>staged-releases</id>
<url>https://repository.apache.org/content/groups/staging/</url>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>local-repo</activeProfile>
</activeProfiles>
</settings>

View File

@ -1,124 +0,0 @@
language: java
jdk:
- openjdk8
dist: xenial
sudo: required
cache:
directories:
- $HOME/.m2
- $HOME/downloads
branches:
only:
- master
- /^release-.*$/
- /^test-.*$/
- /^v[0-9]\..*$/
install: mvn compile -Dmaven.javadoc.skip=true | grep -v "Downloading\|Downloaded"
before_script:
- $TRAVIS_DIR/install-backend.sh
script:
- mvn test -P core-test,$BACKEND
- $TRAVIS_DIR/run-api-test.sh
- $TRAVIS_DIR/run-unit-test.sh
after_success:
- bash <(curl -s https://codecov.io/bash)
jobs:
include:
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=memory SUITE=tinkerpop
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=cassandra SUITE=tinkerpop
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=scylladb SUITE=tinkerpop
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=mysql SUITE=tinkerpop
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=hbase SUITE=structure
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=hbase SUITE=process
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=rocksdb SUITE=tinkerpop
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: tinkerpop-test
if: branch =~ env(RELEASE_BRANCH)
env: BACKEND=postgresql SUITE=tinkerpop
script: $TRAVIS_DIR/run-tinkerpop-test.sh
- stage: deploy
if: tag =~ env(RELEASE_TAG)
script: skip
before_deploy:
- |
if [ $DEPLOYED = 0 ]; then
DEPLOYED=1
mvn clean package -DskipTests
else
echo "Skipping before_deploy since it has been executed once."
fi
deploy:
- provider: releases
skip_cleanup: true
file_glob: true
file: "$TRAVIS_BUILD_DIR/hugegraph-*.tar.gz"
api_key:
secure: nSGEnk5tJsTHMGABO8OJMTk47L3QA2O4xHXLKGIuTK5kLGJkrl0Bs27IveggLxf1E7DSrhcfNW44yIjn5lWA/5QX3DweWH4FGDAgWYFyj7QsBZl7WT2NReMW7BLzpvsIjyEKDw5pLbYBOpOrHflmyQB4w0oXTZVl6awll7JicuL1air7lpqJ4Ju4ukj1mo6rcX3MHRkzgMuS5eemArm8T15y9IlDqK3gmjVUOVo7LoYDFaq3eMzQ7ufrOFiiVIV2LUxn2t2/YRcKU05zal4IKifMKbXISX5u7ZwYe8T14ZQ7eMTOzmFY21gv3HEg+KXWh4gq8HvG4FKbzrl+KYSacJ1xINJQaQGIOD7Pz7vzQdj9wpM/WLqmYF5SE5ZYzXV3ejrtYlEUpJQSnpyiHlfyRuDRzYq/dB2V1ua6t9xkbjL/a2uqHa9WjbOi1jqw2E2XSnx794pzCvKYn1RLOiqpzVlEnb3cPb5M7vl9wsGf5MFLS8zLmMa5DyJn+e45W6GpW1zT4uLl2yR3Ja9ROlVapAb4aMyhKnWQZtUMDVhD6Xjj/CAumeOQLe31NM3i8NK2L0iEYSFWUigLEcCapXo3aOVlzckdJ6p7k94dFd5wcg/EY2aFMhyjYUKUFP1V535uB4ZKvf/dotMKY29nsYyceYgOJ/VNZt2BPZ8oCdc8+ys=
on:
tags: true
- provider: script
skip_cleanup: true
script:
echo $GPG_KEY_ENC_PASSW | gpg -d --passphrase-fd 0 $TRAVIS_DIR/private-key.gpg.gpg | gpg --import &&
mvn deploy --settings $TRAVIS_DIR/maven.xml -DskipTests=true -B -U -P release
on:
tags: true
env:
matrix:
- BACKEND=memory
- BACKEND=cassandra
- BACKEND=scylladb
- BACKEND=mysql
- BACKEND=hbase
- BACKEND=rocksdb
- BACKEND=postgresql
global:
- RELEASE_BRANCH=^release-.*$
- RELEASE_TAG=^v[0-9]\..*$
- TRAVIS_DIR=hugegraph-dist/src/assembly/travis
- DEPLOYED=0
- secure: dYmFTVeEtRzLNaHp9ToTV/+CkTD0/rEj+K7dRN8wsv/yg4pbqwnyWbSXcqMlj6iNFzAz3nPbmFLCvAWON9/SMN9iJIT6x/xfcf+LqCT8QWczo2nc9xeX144ij2VHX1Drvtk5fRTMaTXRfWEQIrjqx2yrJTIdrXWzWSaZLFv1CRCUizEiGGCePnzUWxx9dBypNyC6IaH6lIv8uN5E6+10SYhb7UJGjWUMDg1bCeW9X7X2wg4QpsGDzlGFXT2EBPU/dAb5attTAtW8dKxrCZqZJTPWe0BarXDBR4PO15BC+a0V1g8LwexedtDjJeFRcGPaJ5NN4d3jDSusCzt5Jf4U0Wa1gDRMVTU3jT+KYkm5eoV4wOZMySobjh6VpQH/LyL0QTDy5apRPAxw+wO+tc91P+nkJmnlr3pN8abtMZ6NciZizUBYQRgR/m2Ir0stvtbZxBQOATuPtBgNDKiDgVdSYcRJzSqYEMFOn35AvsDZ9aUsyC8k29PCUZ0gQO2Is6cV1ClFBnM52hfU9XX0gu+NviSnYNGvcokod8z9VjGtnM7V3LYjqXSFqO9kkMbOmkME1tD2Bh/klw2/OM+2tBBZiAgxB89st5jSUHI4a2hpUyaQBezJUcU9t2vVT/zAVEIqzw2PDxkMU7t0n6L1x+qUIUTG/WynfIni5msxuR7HoiU=
- secure: XbX6AX5zDPc2PcWYAMW+6fazqRRUqpgQkt4eXUugLuVIYZBmJ0WqncEhJ4+mdwOGPIhnP2HsOaSeK2eE/O+iLY2XpBFbugoBgm9VaZlCC4CY1gRNHaanYg64Lrm3NPY3n08IHRMazHqMpJwUqNO+OG/6QwkepULQLj5Rluf716AoXHa7IEJhAIrwr+OXQvdEaJdUXlS1lRycXVeYtOewl7qYxCO4dD4RMhPlNykh9KEK7fd5wnPkiUsp1SwF4g5XsaLvGXmT/qQ1nj8oa9Caej/iaj6HMKG3BO057mq4KK5JDxTPWhBueNpEkUwldAnrMhYWLRnNf4IyjUsaB/Pmi6HspzcaiORPLYwPmdvLGGSnYwbtO+fAHebgpgOnj/vGmRmY4YtIkYdFtbPBI0HpbGB77tqNRFCe/5deLrjx0hXJBfoKTy7d42SI1eBhNR0svZYUHkSfuXwly6hMTlH1DN/bumMFxfXDkY9PFHlzV1Mn3vb9BxKTaP88hJsWk7JqgniqUF7EWAc0EhHMbJct2gC0pDc95z4Yy9391n7/XWJErhIdYon1Ukds5+a43xFXoy76gR4LuMDpzzCnutMjhC2yDuGaZx/DfkPBb5JFU7SHtTKj05zb73Moogi7qqbH8jwcwoSfogAKyrIAWTcAgvJ2LVnRzwdsiLTc6MEagiM=
- secure: GKdjRHR35FBPY6oGBfjVdGxnVeoMmZHgNCnsyGNvRVJiQLhXBjUQ9bYjxPRX3JkmztdofNVd3gV8xqIOfLD6XA/0qHVvZ5GlWK4O77eGDur5InobzMlRDIUvJkpqM2SdSU8vKoAUBWgKnfzvlbA14kiwCID72zDVa/E8G0gBl0GZ2zWXIWRg0zC3ZyaJwTZC8WLqn0Kl7UxMy6i/xmK1F+apLooFIBEXYZuoH3pY83L4BvPozmJzT66HonrfcnaifaVHShBntPhQ6Sjlq5suMhtQENcPqWxaORL69s6Y/uF+RAdmnRHPZnXFhjRvq3rQAdMKM/DBOcaYlu1aIxCJJmWLm+b+75EQgdtwYGtwDpunzKXzH7ewB6rTYAghJNjGxt/KfROniooAs8mO3DqhygV5/BInJk0aKab5GlHCAioesV7TKSObhSDlKU8CSBRr/j8T7anL+lkXVZ89fkGg+EBSoXkVCNwQjank1NrHWCJQpNVndHzWIoGk0gcjTf01+iMDGIJDQZhcEuLu8wZbvDjLo/qEah247G0JabDMNBdyMZpg96bWDgArMkWa2FnWX25A7Cfgm1JymXdOZCIJrHbYWWAyoaXNrjZezQ8NPnE5uOWJIKfBnjnyPtKPoWjLuqpXmqcggbl8iRiy1EdWs/N39Q7qcFtJ5lTN9q1kDeI=
- secure: MOn1SM0cwpKshyhCAZ5pdDVcu1VZ6s11lOuO/3rskKwxsWfL3duxg5yV5iAmyIPeBB69kzYg6zEIHOM7cjocR55bakurkaYiSE+OBYKickjryNnYFJ6gAaEmgykFHpwhlIKkyceiApgMJ4LFDNhd48GGjBLfpJZcLFfHbCwg3Mpr+KSihrrv9z2+omEuwsW43FoIoeFiYdx3Z2LoggLtGKbWjjbbf/Lq+ozb+O6J7pTJpIV3WwZ42M39HB+9whiMHeu5PAoOXzDsScyJ4fkInMbTUg1mqWlzg1mlAfOgFOmAzNcBhTqOBYkF0QDsOP/V6cXKVMe/P9AU+MPf86vrNgse8iW5DF5VNoyN15HztvNdyvdSTJRncym1LfloYaYFyhBZ87PLT98erenqmFJym7atrcH5xiQwD+19g35H09Fmw8N2ZsHZKHccZuKqb3bg0+UvdJk4M0PGo/XXse9smHckv6dRjdVZNvdObHcy1jXtGfkp085MYYW2KZ6Zemds54nxe5FYtSs+TOLJNS07wwLc85cDuvirg+4oOsWnaDhr63R4gQPkc34brP+R1e0V5Hsh9tJjjrpl5xWycMbAo4sXIJbf+qrvwwofeZmFtPGtRBirDORycpP9nAczWXE8sDyQxtPbOFzZWefb+zo0gMdtkRfi0693qWft5VcY5+I=
- secure: XIFolSD+Jsx9EyHOo+UHeWeBd+RGbxm5FMiBPe8r3fWr3Evs1HAk6//YyPSvGMGUfJwvEPZ5o5GBGT1hPIy8s9+wgHAOxUWwLFkSHGdeXUHMI6zWCQ09DomFhgBidJGnT63mAnwLOTeOtV953hEJDOWp+nHXB9VrDy1rPR25NIyF6eS2ym7OZBa1tnk87pVXbLBFhmYn75D2Bc0VEc+7HM6WuGc+VQ5hZv04lrlRl4kOdkrrV97ie2v42oW7FnebzqjgTgsEbzlXriXeLlBsNCkdenn8U5pqW0V2Odv8iLNalCvF4rrVxsMTeWpqEEL/keLhFO31B20E6BOlKTJsDYgd/ehYMUdboPmxeOuwY6MA1V98gnXyxu8eVKm3RTV81pma7GxcHEVsnl6kZ3eK2LA0xD5UzOKK4nkUs0gAtEahykjbVJaVva0AOsDUId4U0+fHPRmMA4mbXcsxnivnIAC1XKu45C9/Hot8xgI9EChLKIJmT1DvR+Ey0NT27olOjbCYHUalnM37kd3H33dSfnke9f0Pygm2y61UOjz/t4NAPVPfQSwPgC248Rwb6COoqB72gctLJPfXOpUn8Nzcnv6Sb22YBJ139W9HQ7mLuTE5LpsU7x/9HNH50ILkLFMNLj31fCsLBbXFXafJTuKQ3Y5I69P/56orcL8WWjuchcY=

View File

@ -6,7 +6,7 @@ on:
jobs:
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
TAG_NAME: ${{ github.ref_name }}
steps:

35
.github/workflows/auto-pr-review.yml vendored Normal file
View File

@ -0,0 +1,35 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: "Auto PR Commenter"
on:
pull_request_target:
types: [opened]
jobs:
add-review-comment:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Add review comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
@codecov-ai-reviewer review

View File

@ -1,31 +1,57 @@
name: third-party dependencies check
name: "3rd-party"
on:
push:
branches:
- master
- /^release-.*$/
pull_request:
permissions:
contents: read
jobs:
build:
dependency-check:
runs-on: ubuntu-latest
env:
SCRIPT_DEPENDENCY: hugegraph-dist/scripts/dependency
USE_STAGE: 'false' # Whether to include the stage repository.
SCRIPT_DEPENDENCY: install-dist/scripts/dependency
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Set up JDK 8
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '8'
java-version: '11'
distribution: 'adopt'
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- name: mvn install
run: |
mvn install -DskipTests=true
mvn install -Dmaven.test.skip=true -ntp --fail-at-end
- name: generate current dependencies
run: |
bash $SCRIPT_DEPENDENCY/regenerate_known_dependencies.sh current-dependencies.txt
- name: check third dependencies
run: |
bash $SCRIPT_DEPENDENCY/check_dependencies.sh
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v3
# Refer: https://github.com/actions/dependency-review-action
with:
# TODO: reset critical to low before releasing
fail-on-severity: critical
# Action will fail if dependencies don't match the list
#allow-licenses: Apache-2.0, MIT
#deny-licenses: GPL-3.0, AGPL-1.0, AGPL-3.0, LGPL-2.0, CC-BY-3.0

View File

@ -1,96 +0,0 @@
name: hugegraph-ci
on:
push:
branches:
- master
- 'release-*'
- 'test-*'
pull_request:
branches:
- '**'
jobs:
build:
runs-on: ubuntu-20.04
env:
TRAVIS_DIR: hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: ${{ matrix.BACKEND }}
TRIGGER_BRANCH_NAME: ${{ github.ref_name }}
HEAD_BRANCH_NAME: ${{ github.head_ref }}
BASE_BRANCH_NAME: ${{ github.base_ref }}
TARGET_BRANCH_NAME: ${{ github.base_ref != '' && github.base_ref || github.ref_name }}
RELEASE_BRANCH: ${{ startsWith(github.ref_name, 'release-') || startsWith(github.ref_name, 'test-') || startsWith(github.base_ref, 'release-') }}
strategy:
fail-fast: false
matrix:
BACKEND: [memory, cassandra, scylladb, hbase, rocksdb, mysql, postgresql]
JAVA_VERSION: ['8', '11']
steps:
- name: Install JDK ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Compile
run: |
mvn clean compile -U -Dmaven.javadoc.skip=true | grep -v "Downloading\|Downloaded"
- name: Install JDK 8
uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'zulu'
- name: Prepare env and service
run: |
$TRAVIS_DIR/install-backend.sh $BACKEND
- name: Install JDK ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'
- name: Run unit test
run: |
$TRAVIS_DIR/run-unit-test.sh $BACKEND
- name: Run core test
run: |
$TRAVIS_DIR/run-core-test.sh $BACKEND
- name: Run api test
run: |
$TRAVIS_DIR/run-api-test.sh $BACKEND $REPORT_DIR
- name: Run raft test
if: ${{ env.BACKEND == 'rocksdb' }}
run: |
$TRAVIS_DIR/run-api-test-for-raft.sh $BACKEND $REPORT_DIR
- name: Run TinkerPop test
if: ${{ env.RELEASE_BRANCH == 'true' }}
run: |
$TRAVIS_DIR/run-tinkerpop-test.sh $BACKEND tinkerpop
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
with:
file: ${{ env.REPORT_DIR }}/*.xml

52
.github/workflows/cluster-test-ci.yml vendored Normal file
View File

@ -0,0 +1,52 @@
name: "Cluster Test CI"
on:
push:
branches:
- master
- 'release-*'
- 'test-*'
pull_request:
jobs:
cluster-test:
runs-on: ubuntu-latest
env:
USE_STAGE: 'false' # Whether to include the stage repository.
steps:
- name: Install JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- name: Package
run: |
mvn clean package -U -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -ntp
- name: Run simple cluster test
run: |
mvn test -pl hugegraph-cluster-test/hugegraph-clustertest-test -am -P simple-cluster-test
- name: Run multi cluster test
run: |
mvn test -pl hugegraph-cluster-test/hugegraph-clustertest-test -am -P multi-cluster-test

View File

@ -1,18 +1,18 @@
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [ master, release-*, v*.* ]
branches: [ master, release-* ]
pull_request:
# The branches below must be a subset of the branches above
# branches: [ master ] # enable in all PR
# The branches below must be a subset of the branches above
# branches: [ master ] # enable in all PRs
schedule:
- cron: '33 0 * * 5'
jobs:
analyze:
env:
USE_STAGE: 'false' # Whether to include the stage repository.
name: Analyze
runs-on: ubuntu-latest
permissions:
@ -26,40 +26,46 @@ jobs:
language: [ 'java' ]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java JDK
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '8'
- name: Setup Java JDK
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '11'
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
#- run: |
# make bootstrap
# make release
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

63
.github/workflows/commons-ci.yml vendored Normal file
View File

@ -0,0 +1,63 @@
name: "HugeGraph-Commons CI"
on:
workflow_dispatch:
push:
branches:
- master
- /^release-.*$/
- /^test-.*$/
pull_request:
jobs:
build-commons:
runs-on: ubuntu-latest
env:
USE_STAGE: 'false' # Whether to include the stage repository.
strategy:
fail-fast: false
matrix:
JAVA_VERSION: ['11']
steps:
- name: Install JDK ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
cp -vf .github/configs/settings.xml $HOME/.m2/settings.xml && cat $HOME/.m2/settings.xml
- name: Install
run: |
mvn install -Dmaven.javadoc.skip=true -ntp -Dmaven.test.skip=true
- name: Run common test
run: |
mvn test -pl hugegraph-commons/hugegraph-common -Dtest=UnitTestSuite -DskipCommonsTests=false
- name: Run rpc test
run: |
mvn test -pl hugegraph-commons/hugegraph-rpc -Dtest=UnitTestSuite -DskipCommonsTests=false
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
with:
file: target/jacoco.xml

80
.github/workflows/docker-build-ci.yml vendored Normal file
View File

@ -0,0 +1,80 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: "Docker Build CI"
on:
push:
branches:
- master
- 'release-*'
pull_request:
paths:
- '**/Dockerfile*'
- '.dockerignore'
- 'hugegraph-server/hugegraph-dist/docker/**'
- 'hugegraph-server/hugegraph-dist/src/assembly/static/bin/util.sh'
jobs:
docker-build:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
dockerfile:
- hugegraph-pd/Dockerfile
- hugegraph-store/Dockerfile
- hugegraph-server/Dockerfile
- hugegraph-server/Dockerfile-hstore
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build ${{ matrix.dockerfile }}
run: |
IMAGE_ID=$(docker build -q -f ${{ matrix.dockerfile }} .)
echo "Built: $IMAGE_ID"
echo "IMAGE_ID=$IMAGE_ID" >> "$GITHUB_ENV"
HC=$(docker inspect --format='{{json .Config.Healthcheck}}' "$IMAGE_ID")
echo "Healthcheck: $HC"
[[ "$HC" != "null" ]] || { echo "ERROR: HEALTHCHECK missing in ${{ matrix.dockerfile }}"; exit 1; }
- name: Test server entrypoint property mapping
if: matrix.dockerfile == 'hugegraph-server/Dockerfile'
run: bash hugegraph-server/hugegraph-dist/docker/test/test-docker-entrypoint.sh
# 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
# actually answer. Only the server images run check_port.
# TODO(docker-ci): this pins the probe dependency, not the behaviour it
# protects. A full duplicate-start/stop check needs a booted server with
# a backend, which belongs with the e2e job rather than the image build.
- name: Port preflight can answer inside ${{ matrix.dockerfile }}
if: ${{ startsWith(matrix.dockerfile, 'hugegraph-server/') }}
run: |
STATE=$(docker run --rm "$IMAGE_ID" bash -c \
'source /hugegraph-server/bin/util.sh && port_listen_state 8080')
echo "port_listen_state 8080 -> $STATE"
# Assert a positive answer rather than "not unknown": an empty $STATE
# would otherwise satisfy the check. The step's default `bash -e`
# already aborts on a failed `docker run`, so this only states intent.
[[ "$STATE" == "free" || "$STATE" == "busy" ]] || {
echo "ERROR: no usable socket-table tool (ss/netstat) in ${{ matrix.dockerfile }}"
exit 1
}

View File

@ -1,17 +1,19 @@
name: License checker
name: "License Checker"
on:
push:
branches:
- master
- /^v[0-9]\..*$/
- 'release-*'
pull_request:
jobs:
check-license:
runs-on: ubuntu-latest
env:
USE_STAGE: 'false' # Whether to include the stage repository.
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Check License Header
uses: apache/skywalking-eyes@main
@ -19,4 +21,11 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
log: info
token: ${{ github.token }}
config: .licenserc.yaml
- name: License Check (RAT)
run: |
mvn apache-rat:check -ntp
find ./ -name rat.txt -print0 | xargs -0 -I file cat file > merged-rat.txt
grep "Binaries" merged-rat.txt -C 3 && cat merged-rat.txt

327
.github/workflows/pd-store-ci.yml vendored Normal file
View File

@ -0,0 +1,327 @@
name: "HugeGraph-PD & Store & Hstore CI"
on:
push:
branches:
- master
- 'release-*'
- 'test-*'
pull_request:
# TODO: consider merge to one ci.yml file
jobs:
struct:
runs-on: ubuntu-latest
env:
USE_STAGE: 'false'
steps:
- name: Install JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: Use staged maven repo settings
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml || true
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- name: Resolve project revision
run: echo "REVISION=$(mvn -q -DforceStdout help:evaluate -Dexpression=revision -f pom.xml)" >> $GITHUB_ENV
- name: Build or fetch hugegraph-struct
run: |
if [ -f hugegraph-struct/pom.xml ]; then
echo "[INFO] Found hugegraph-struct source, building from source"
mvn -U -ntp -DskipTests -pl hugegraph-struct -am install
else
echo "[INFO] hugegraph-struct source not found, fetching artifact $REVISION"
if [ -z "$REVISION" ]; then echo "[ERROR] revision not resolved"; exit 1; fi
mvn -U -ntp dependency:get -Dartifact=org.apache.hugegraph:hugegraph-struct:$REVISION
fi
- name: Run hugegraph-struct test
if: ${{ hashFiles('hugegraph-struct/pom.xml') != '' }}
run: |
mvn -U -ntp -pl hugegraph-struct test
pd:
needs: struct
runs-on: ubuntu-latest
env:
# TODO: avoid duplicated env setup in pd & store
USE_STAGE: 'false' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
steps:
- name: Install JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- name: Run common test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-common-test
- name: Run core test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-core-test
# The above tests do not require starting a PD instance.
- 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: Check startup test prerequisites (PD)
id: pd-preflight
run: |
# These jobs run on Linux, where the suites clean up ports with fuser.
# lsof is no longer required: check_port now uses ss/netstat.
for tool in fuser curl java; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "can_run=false" >> "$GITHUB_OUTPUT"
echo "skip_reason=missing tool: $tool" >> "$GITHUB_OUTPUT"
exit 0
fi
done
echo "can_run=true" >> "$GITHUB_OUTPUT"
- name: Run start-hugegraph-pd.sh foreground mode tests
if: steps.pd-preflight.outputs.can_run == 'true'
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
PD_DIR=hugegraph-pd/apache-hugegraph-pd-$VERSION/
$TRAVIS_DIR/test-start-hugegraph-pd.sh $PD_DIR
- name: Startup tests skipped (missing prerequisites)
if: steps.pd-preflight.outputs.can_run == 'false'
run: |
echo "::notice::PD startup tests skipped — ${{ steps.pd-preflight.outputs.skip_reason }}"
- name: Prepare env and service
run: |
$TRAVIS_DIR/start-pd.sh
- name: Run client test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-client-test
- name: Run rest test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-rest-test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
with:
file: ${{ env.REPORT_DIR }}/*.xml
store:
needs: struct
runs-on: ubuntu-latest
env:
USE_STAGE: 'false' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
steps:
- name: Install JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- 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: Check startup test prerequisites (Store)
id: store-preflight
run: |
# These jobs run on Linux, where the suites clean up ports with fuser.
# lsof is no longer required: check_port now uses ss/netstat.
for tool in fuser curl java; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "can_run=false" >> "$GITHUB_OUTPUT"
echo "skip_reason=missing tool: $tool" >> "$GITHUB_OUTPUT"
exit 0
fi
done
LIMIT_N=$(ulimit -n)
if [[ "$LIMIT_N" != "unlimited" ]] && (( LIMIT_N < 1024 )); then
echo "can_run=false" >> "$GITHUB_OUTPUT"
echo "skip_reason=ulimit -n is $LIMIT_N (store requires >= 1024)" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "can_run=true" >> "$GITHUB_OUTPUT"
- name: Run start-hugegraph-store.sh foreground mode tests
if: steps.store-preflight.outputs.can_run == 'true'
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
STORE_DIR=hugegraph-store/apache-hugegraph-store-$VERSION/
$TRAVIS_DIR/test-start-hugegraph-store.sh $STORE_DIR
- name: Startup tests skipped (missing prerequisites)
if: steps.store-preflight.outputs.can_run == 'false'
run: |
echo "::notice::Store startup tests skipped — ${{ steps.store-preflight.outputs.skip_reason }}"
- name: Prepare env and service
run: |
$TRAVIS_DIR/start-pd.sh
$TRAVIS_DIR/start-store.sh
- name: Run common test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-common-test
- name: Run client test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-client-test
- name: Run core test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-core-test
- name: Run rocksdb test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-rocksdb-test
- name: Run server test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-server-test
- name: Run raft-core test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-raftcore-test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
with:
file: ${{ env.REPORT_DIR }}/*.xml
hstore:
needs: struct
runs-on: ubuntu-latest
env:
USE_STAGE: 'false' # 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-') }}
steps:
- name: Install JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- 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: Prepare env and service
run: |
$TRAVIS_DIR/install-backend.sh $BACKEND
- name: Run unit test
run: |
$TRAVIS_DIR/run-unit-test.sh $BACKEND
- name: Run core test
run: |
$TRAVIS_DIR/run-core-test.sh $BACKEND
- name: Run api test
run: |
$TRAVIS_DIR/run-api-test.sh $BACKEND $REPORT_DIR
- name: Run raft test
if: ${{ env.BACKEND == 'rocksdb' }}
run: |
$TRAVIS_DIR/run-api-test-for-raft.sh $BACKEND $REPORT_DIR
- name: Run TinkerPop test
if: ${{ env.RELEASE_BRANCH == 'true' }}
run: |
$TRAVIS_DIR/run-tinkerpop-test.sh $BACKEND tinkerpop
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
with:
file: ${{ env.REPORT_DIR }}/*.xml

85
.github/workflows/rerun-ci.yml vendored Normal file
View File

@ -0,0 +1,85 @@
name: "Rerun CI"
on:
workflow_run:
workflows:
- "HugeGraph-Server CI"
- "HugeGraph-Commons CI"
- "HugeGraph-PD & Store & Hstore CI"
- "Cluster Test CI"
types:
- completed
permissions: {}
env:
MAX_RERUNS: '2'
RETRY_DELAY_SECONDS: '180'
jobs:
decide-rerun-action:
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
runs-on: ubuntu-latest
outputs:
action: ${{ steps.decision.outputs.action }}
steps:
- name: Decide rerun action
id: decision
env:
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
RUN_ID: ${{ github.event.workflow_run.id }}
RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
EVENT_NAME: ${{ github.event.workflow_run.event }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
set -euo pipefail
action="skip"
reason="unsupported event: $EVENT_NAME"
if [[ "$EVENT_NAME" == "push" || "$EVENT_NAME" == "pull_request" ]]; then
if (( RUN_ATTEMPT > MAX_RERUNS )); then
reason="retry limit reached"
else
action="rerun"
reason="within retry limit"
fi
fi
{
echo "action=$action"
echo "reason=$reason"
} >> "$GITHUB_OUTPUT"
{
echo "### Rerun CI decision"
echo ""
echo "- Workflow: $WORKFLOW_NAME"
echo "- Source event: $EVENT_NAME"
echo "- Head branch: $HEAD_BRANCH"
echo "- Run ID: $RUN_ID"
echo "- Current attempt: $RUN_ATTEMPT"
echo "- Max automatic reruns: $MAX_RERUNS"
echo "- Delay seconds: $RETRY_DELAY_SECONDS"
echo "- Action: $action"
echo "- Reason: $reason"
} >> "$GITHUB_STEP_SUMMARY"
rerun-failed-jobs:
needs: decide-rerun-action
if: needs.decide-rerun-action.outputs.action == 'rerun'
permissions:
actions: write
contents: read
runs-on: ubuntu-latest
steps:
- name: Wait before rerun
run: |
sleep "$RETRY_DELAY_SECONDS"
- name: Rerun failed jobs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: |
gh run rerun ${{ github.event.workflow_run.id }} --failed

126
.github/workflows/riscv64-ci.yml vendored Normal file
View File

@ -0,0 +1,126 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: "RISC-V Server CI"
on:
workflow_call:
permissions:
contents: read
env:
BINFMT_IMAGE: >-
tonistiigi/binfmt@sha256:400a4873b838d1b89194d982c45e5fb3cda4593fbfd7e08a02e76b03b21166f0
RISCV64_BASE_IMAGE: >-
ubuntu@sha256:4edded5722eb644868b7b976033d241d2ab3fff0a170924df69b200a59a2b994
DRAGONWELL_RISCV64_ARCHIVE: >-
Alibaba_Dragonwell_Extended_11.0.31.28.11_riscv64_linux.tar.gz
DRAGONWELL_RISCV64_SHA256: >-
7df2d308f0dca7a779d2854e6da19214f99cd77aa6d4982c3bf981a77266a79b
DRAGONWELL_RISCV64_URL: >-
https://github.com/dragonwell-project/dragonwell11/releases/download/dragonwell-extended-11.0.31.28_jdk-11.0.31-ga/Alibaba_Dragonwell_Extended_11.0.31.28.11_riscv64_linux.tar.gz
RISCV64_CONTAINER: >-
hugegraph-riscv64-ci-${{ github.run_id }}-${{ github.run_attempt }}
jobs:
build-server-riscv64:
runs-on: ubuntu-24.04
timeout-minutes: 90
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Start isolated RISC-V environment
run: |
docker run --privileged --rm "$BINFMT_IMAGE" --install riscv64
docker run --detach --init --platform linux/riscv64 \
--name "$RISCV64_CONTAINER" "$RISCV64_BASE_IMAGE" sleep infinity
test "$(docker exec "$RISCV64_CONTAINER" uname -m)" = riscv64
- name: Prepare source and Java 11
run: |
ARCHIVE_PATH="$RUNNER_TEMP/$DRAGONWELL_RISCV64_ARCHIVE"
curl --fail --location --retry 3 --show-error \
"$DRAGONWELL_RISCV64_URL" --output "$ARCHIVE_PATH"
echo "$DRAGONWELL_RISCV64_SHA256 $ARCHIVE_PATH" | sha256sum -c -
docker exec "$RISCV64_CONTAINER" mkdir -p /workspace /opt/dragonwell
git ls-files -z | tar --null --files-from=- -cf - | \
docker exec -i "$RISCV64_CONTAINER" tar -xf - -C /workspace
docker cp "$ARCHIVE_PATH" \
"$RISCV64_CONTAINER:/tmp/$DRAGONWELL_RISCV64_ARCHIVE"
- name: Build and smoke test on RISC-V
run: |
docker exec \
--env DRAGONWELL_RISCV64_ARCHIVE="$DRAGONWELL_RISCV64_ARCHIVE" \
--env DRAGONWELL_RISCV64_SHA256="$DRAGONWELL_RISCV64_SHA256" \
"$RISCV64_CONTAINER" bash -euo pipefail -c '
test "$(uname -m)" = riscv64
apt-get -q update
apt-get -q install -y --no-install-recommends \
ca-certificates curl jq libatomic1 libgcc-s1 libstdc++6 \
lsof maven procps \
protobuf-compiler protobuf-compiler-grpc-java-plugin
ARCHIVE_PATH="/tmp/$DRAGONWELL_RISCV64_ARCHIVE"
echo "$DRAGONWELL_RISCV64_SHA256 $ARCHIVE_PATH" | sha256sum -c -
tar -xzf "$ARCHIVE_PATH" --strip-components=1 -C /opt/dragonwell
rm "$ARCHIVE_PATH"
export JAVA_HOME=/opt/dragonwell
export PATH="$JAVA_HOME/bin:$PATH"
java -XshowSettings:vm -version
test -x /usr/bin/protoc
test -x /usr/bin/grpc_java_plugin
cd /workspace
MAVEN_OPTS="-XX:TieredStopAtLevel=1 -XX:ActiveProcessorCount=2" \
mvn clean package -B -ntp -Drocksdb-only \
-P riscv64-protobuf-tools \
-pl hugegraph-server/hugegraph-dist -am \
-Dmaven.test.skip=true -Dmaven.javadoc.skip=true
hugegraph-server/hugegraph-dist/src/assembly/travis/check-rocksdb-only-dist.sh \
hugegraph-server/apache-hugegraph-server-*/
hugegraph-server/hugegraph-dist/src/assembly/travis/run-native-runtime-smoke-test.sh \
hugegraph-server/apache-hugegraph-server-*/
'
- name: Show server log on failure
if: failure()
run: |
if docker container inspect "$RISCV64_CONTAINER" >/dev/null 2>&1; then
docker exec "$RISCV64_CONTAINER" bash -c '
find /workspace -path "*/logs/hugegraph-server.log" \
-exec tail -n 200 {} \;
' || true
fi
- name: Clean up RISC-V environment
if: always()
run: |
if docker container inspect "$RISCV64_CONTAINER" >/dev/null 2>&1; then
docker rm --force --volumes "$RISCV64_CONTAINER"
fi
if docker container inspect "$RISCV64_CONTAINER" >/dev/null 2>&1; then
echo "RISC-V CI container still exists: $RISCV64_CONTAINER" >&2
exit 1
fi

249
.github/workflows/server-ci.yml vendored Normal file
View File

@ -0,0 +1,249 @@
name: "HugeGraph-Server CI"
on:
push:
branches:
- master
- 'release-*'
- 'test-*'
pull_request:
jobs:
wait-storage-shell-test:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run wait-storage.sh peer failover tests
run: hugegraph-server/hugegraph-dist/src/assembly/travis/test-wait-storage.sh
build-server:
# TODO: we need test & replace it to ubuntu-24.04 or ubuntu-latest
runs-on: ubuntu-22.04
env:
USE_STAGE: 'false' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: ${{ matrix.BACKEND }}
TRIGGER_BRANCH_NAME: ${{ github.ref_name }}
HEAD_BRANCH_NAME: ${{ github.head_ref }}
BASE_BRANCH_NAME: ${{ github.base_ref }}
TARGET_BRANCH_NAME: ${{ github.base_ref != '' && github.base_ref || github.ref_name }}
RELEASE_BRANCH: ${{ startsWith(github.ref_name, 'release-') || startsWith(github.ref_name, 'test-') }}
RAFT_MODE: ${{ startsWith(github.head_ref, 'test') || startsWith(github.head_ref, 'raft') }}
strategy:
fail-fast: false
matrix:
BACKEND: [ memory, rocksdb, hbase ]
JAVA_VERSION: [ '11' ]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
# TODO: Remove this step after install-backend.sh updated
- name: Install Java8 for backend
uses: actions/setup-java@v4
with:
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: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
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
run: |
mvn clean compile -U -Dmaven.javadoc.skip=true -ntp
- name: Run check_port unit tests
if: ${{ env.BACKEND == 'rocksdb' }}
run: |
# Validates the ss/netstat port preflight that replaced lsof
$TRAVIS_DIR/test-check-port.sh \
hugegraph-server/hugegraph-dist/src/assembly/static \
hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh
- name: Run Java security properties tests
if: ${{ env.BACKEND == 'rocksdb' }}
run: |
mvn package -Dmaven.test.skip=true -pl hugegraph-server/hugegraph-dist -am -ntp
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
SERVER_DIR=hugegraph-server/apache-hugegraph-server-$VERSION/
$TRAVIS_DIR/test-java-security-properties.sh $SERVER_DIR
- name: Check startup test prerequisites
id: server-preflight
if: ${{ env.BACKEND == 'rocksdb' }}
run: |
# Note: lsof removed from prerequisites; check_port now uses ss, falling back
# to netstat, and warns without blocking when neither can answer.
# This job always runs on Linux (ubuntu-22.04), which uses fuser for port cleanup.
for tool in crontab curl java; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "can_run=false" >> "$GITHUB_OUTPUT"
echo "skip_reason=missing tool: $tool" >> "$GITHUB_OUTPUT"
exit 0
fi
done
if ! command -v fuser >/dev/null 2>&1; then
echo "can_run=false" >> "$GITHUB_OUTPUT"
echo "skip_reason=missing tool: fuser (required for Linux port cleanup)" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "can_run=true" >> "$GITHUB_OUTPUT"
- name: Run start-hugegraph.sh foreground mode tests
if: ${{ env.BACKEND == 'rocksdb' && steps.server-preflight.outputs.can_run == 'true' }}
run: |
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
- name: Startup tests skipped (missing prerequisites)
if: ${{ env.BACKEND == 'rocksdb' && steps.server-preflight.outputs.can_run == 'false' }}
run: |
echo "::notice::Server startup tests skipped — ${{ steps.server-preflight.outputs.skip_reason }}"
- name: Run unit test
run: |
$TRAVIS_DIR/run-unit-test.sh $BACKEND
- name: Run core test
run: |
$TRAVIS_DIR/run-core-test.sh $BACKEND
- name: Run api test
run: |
if [ "$BACKEND" = "rocksdb" ]; then
$TRAVIS_DIR/run-api-test.sh $BACKEND $REPORT_DIR true
else
$TRAVIS_DIR/run-api-test.sh $BACKEND $REPORT_DIR
fi
# TODO: disable raft test in normal PR due to the always timeout problem
- name: Run raft test
if: ${{ env.RAFT_MODE == 'true' && env.BACKEND == 'rocksdb' }}
run: |
$TRAVIS_DIR/run-api-test-for-raft.sh $BACKEND $REPORT_DIR
- name: Run TinkerPop test
if: ${{ env.RELEASE_BRANCH == 'true' }}
run: |
echo "[WARNING] Enter Tinkerpop Test, current 'github.ref_name' is ${{ github.ref_name }}"
$TRAVIS_DIR/run-tinkerpop-test.sh $BACKEND tinkerpop
- name: Upload coverage to Codecov
# TODO: update to v5 later
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ${{ env.REPORT_DIR }}/*.xml
build-server-macos-rocksdb:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: macos-15-intel
server_java_options: ''
- os: macos-15
server_java_options: '-Xms512m -Xmx2g'
env:
USE_STAGE: 'false' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: rocksdb
JAVA_VERSION: '11'
SERVER_JAVA_OPTIONS: ${{ matrix.server_java_options }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: Install Java ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
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
run: |
mvn clean compile -pl hugegraph-server/hugegraph-test -am -U -Dmaven.javadoc.skip=true -ntp
- name: Run check_port unit tests
# Validates the ss/netstat port preflight that replaced lsof
run: |
$TRAVIS_DIR/test-check-port.sh \
hugegraph-server/hugegraph-dist/src/assembly/static \
hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh
- name: Run RocksDB core test
run: |
$TRAVIS_DIR/run-core-test.sh $BACKEND
- name: Run RocksDB API test
run: |
$TRAVIS_DIR/run-api-test.sh $BACKEND $REPORT_DIR true
- name: Show server log on failure
if: failure()
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
SERVER_DIR=hugegraph-server/apache-hugegraph-server-$VERSION/
if [ -f "$SERVER_DIR/logs/hugegraph-server.log" ]; then
tail -n 200 "$SERVER_DIR/logs/hugegraph-server.log"
fi
- name: Stop RocksDB server
if: always()
run: |
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
SERVER_DIR=hugegraph-server/apache-hugegraph-server-$VERSION/
if [ -f "$SERVER_DIR/bin/pid" ]; then
$TRAVIS_DIR/stop-server.sh $SERVER_DIR || true
fi
build-server-riscv64:
uses: ./.github/workflows/riscv64-ci.yml
permissions:
contents: read

View File

@ -1,4 +1,4 @@
name: Mark stale issues and pull requests
name: "Mark stale issues and pull requests"
on:
schedule:
@ -20,8 +20,8 @@ jobs:
stale-pr-message: 'Due to the lack of activity, the current pr is marked as stale and will be closed after 180 days, any update will remove the stale label'
stale-issue-label: 'inactive'
stale-pr-label: 'inactive'
exempt-issue-labels: 'feature,bug,enhancement,improvement,wontfix,todo,guide,doc,help wanted'
exempt-pr-labels: 'feature,bug,enhancement,improvement,wontfix,todo,guide,doc,help wanted'
exempt-issue-labels: 'feature,bug,enhancement,improvement,todo,guide,doc,help wanted,security'
exempt-pr-labels: 'feature,bug,enhancement,improvement,todo,guide,doc,help wanted,security'
exempt-all-milestones: true
days-before-issue-stale: 15
@ -29,7 +29,7 @@ jobs:
days-before-pr-stale: 30
days-before-pr-close: 180
operations-per-run: 10
start-date: '2017-10-01T00:00:00Z'
start-date: '2016-10-01T00:00:00Z'
exempt-all-assignees: true
remove-stale-when-updated: true

41
.gitignore vendored
View File

@ -19,8 +19,9 @@ gen-java
.svn
### IntelliJ IDEA ###
.idea
.idea/
.idea/*
!.idea/vcs.xml
!.idea/icon.png
*.iws
*.iml
*.ipr
@ -56,7 +57,7 @@ build/
*.pyc
# maven ignore
apache-hugegraph-incubating-*/
apache-hugegraph-*/
output/
*.war
*.zip
@ -65,6 +66,8 @@ output/
tree.txt
*.versionsBackup
.flattened-pom.xml
**/dependency-reduced-pom.xml
install-dist/dist.sh
# eclipse ignore
@ -83,3 +86,35 @@ hs_err_pid*
.mtj.tmp/
# blueJ files
*.ctxt
# docker volumes ignore
hugegraph-server/hugegraph-dist/docker/data/
# AI-IDE prompt files (We only keep AGENTS.md, other files could soft-linked it when needed)
# Serena MCP memories
.serena/*
!.serena/project.yml
!.serena/memories/
.mcp.json
# Claude Projects
CLAUDE.md
CLAUDE_*.md
# Gemini/Google
GEMINI.md
# GitHub Copilot / Microsoft
copilot-instructions.md
.copilot-instructions.md
# Cursor IDE
cursor-instructions.md
.cursor-instructions.md
cursor.md
# Windsurf/Codeium
windsurf.md
windsurf-instructions.md
codeium.md
codeium-instructions.md
# Other AI coding assistants
.ai-instructions.md
*.ai-prompt.md
WARP.md
.mcp.json

BIN
.idea/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

37
.idea/vcs.xml Normal file
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project version="4">
<component name="IssueNavigationConfiguration">
<option name="links">
<list>
<IssueNavigationLink>
<option name="issueRegexp" value="#(\d+)" />
<!--
GitHub share the sequence number of issues and pull requests, and it will redirect to
the right place when the the sequence number not match kind.
-->
<option name="linkRegexp" value="https://github.com/apache/hugegraph/pull/$1" />
</IssueNavigationLink>
</list>
</option>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -26,7 +26,9 @@ header: # `header` section is configurations for source codes license header.
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.
@ -34,20 +36,20 @@ header: # `header` section is configurations for source codes license header.
limitations under the License.
# `pattern` is optional regexp if all the file headers are the same as `license` or the license of `spdx-id` and `copyright-owner`.
pattern: |
Licensed to the Apache Software Foundation under one or more contributor
license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright
ownership. The Apache Software Foundation 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
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.
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.
paths: # `paths` are the path list that will be checked (and fixed) by license-eye, default is ['**'].
- '**'
@ -55,6 +57,9 @@ header: # `header` section is configurations for source codes license header.
- '.gitignore'
- '.gitattributes'
- 'LICENSE'
- 'NOTICE'
- 'DISCLAIMER'
- '.serena/**'
- '**/*.versionsBackup'
- '**/*.versionsBackup'
- '**/*.proto'
@ -66,7 +71,7 @@ header: # `header` section is configurations for source codes license header.
- '**/*.properties'
- '**/RaftRequests.java'
- 'dist/**/*'
- 'hugegraph-dist'
- 'hugegraph-server/hugegraph-dist'
- '**/assembly/static/bin/hugegraph.service'
- 'scripts/dev/reviewers'
- 'scripts/dev/reviewers'
@ -87,6 +92,17 @@ header: # `header` section is configurations for source codes license header.
- '**/META-INF/MANIFEST.MF'
- '.repository/**'
- '**/.flattened-pom.xml'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/SnowflakeIdGenerator.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeScriptTraversal.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/Nameable.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/Cardinality.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/StringEncoding.java'
- 'hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessBasicSuite.java'
- 'hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/StructureBasicSuite.java'
- 'hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherOpProcessor.java'
- 'hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherPlugin.java'
- 'hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/Cardinality.java'
- 'hugegraph-struct/src/main/java/org/apache/hugegraph/type/Namifiable.java'
comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`.
# license-location-threshold specifies the index threshold where the license header can be located,

1
.serena/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/cache

View File

@ -0,0 +1,35 @@
# Architecture and Module Structure
## Three-Tier Architecture
### 1. Client Layer
- Gremlin/Cypher queries, REST APIs, Swagger UI
### 2. Server Layer (hugegraph-server, 8 submodules)
- **REST API** (hugegraph-api): GraphAPI, SchemaAPI, GremlinAPI, CypherAPI, AuthAPI, GraphSpaceAPI (distributed only), ManagerAPI (distributed only)
- **Graph Engine** (hugegraph-core): Schema (with TTL update), traversal, task scheduling, GraphSpace multi-tenancy
- **Backend Interface**: Pluggable via `BackendStore`
### 3. Storage Layer
- RocksDB (default/embedded), HStore (distributed/production)
- HBase (deprecated; planned for removal in 2.0)
## Module Structure (7 top-level modules)
### hugegraph-server (8 submodules)
`hugegraph-core`, `hugegraph-api` (includes `opencypher/`, `space/`), `hugegraph-dist`, `hugegraph-test`, `hugegraph-example`, plus backends: `hugegraph-rocksdb`, `hugegraph-hstore`, `hugegraph-hbase`
### hugegraph-pd (8 submodules)
Placement Driver: `hg-pd-core`, `hg-pd-service`, `hg-pd-client`, `hg-pd-common`, `hg-pd-grpc`, `hg-pd-cli`, `hg-pd-dist`, `hg-pd-test`
### hugegraph-store (9 submodules)
Distributed storage + Raft: `hg-store-core`, `hg-store-node`, `hg-store-client`, `hg-store-common`, `hg-store-grpc`, `hg-store-rocksdb`, `hg-store-cli`, `hg-store-dist`, `hg-store-test`
### Others
- **hugegraph-commons**: Shared utilities, RPC framework
- **hugegraph-struct**: Data structures (must build before PD/Store)
- **install-dist**: Distribution packaging, license files
- **hugegraph-cluster-test**: Cluster integration tests
## Distributed Deployment (BETA)
PD + Store + Server (3+ nodes each), all gRPC. Docker compose configs in `docker/` directory, using bridge networking (migrated from host mode).

View File

@ -0,0 +1,28 @@
# Code Style and Conventions
## Style Tools
- `.editorconfig` — Primary style definition
- `style/checkstyle.xml` — Enforcement (note: `hugegraph-style.xml` was removed)
- `.licenserc.yaml` + apache-rat-plugin + skywalking-eyes — License header validation
## Core Rules
- **Line length**: 100 chars (120 for XML)
- **Indent**: 4 spaces, continuation 8 spaces
- **Charset**: UTF-8, LF line endings, final newline
- **Imports**: Sorted `$*``java``javax``org``com``*`, no star imports (threshold 100)
- **Braces**: `if`/`while`/`for` forced if multiline, `do-while` always
- **Blank lines**: Max 1 in code/declarations
- **JavaDoc**: `<p>` on empty lines, no wrap if one line
## Naming
- Packages: `org.apache.hugegraph.*` (lowercase dot-separated)
- Classes: PascalCase, Methods/Variables: camelCase, Constants: UPPER_SNAKE_CASE
## License
- All source files require Apache 2.0 header
- gRPC generated code excluded from checks
- Validate: `mvn apache-rat:check -ntp` + `mvn editorconfig:check`
## Build
- Java 11 target, `-Xlint:unchecked`, Lombok 1.18.30 (provided/optional)
- Swagger: `io.swagger.core.v3:swagger-jaxrs2-jakarta` for REST API docs

View File

@ -0,0 +1,23 @@
# HugeGraph Ecosystem and Related Projects
## This Repo: apache/hugegraph (server, OLTP)
## Ecosystem
| Repo | Purpose |
|------|---------|
| hugegraph-toolchain | Loader, Hubble (visualization), Tools CLI, Java Client |
| hugegraph-computer | OLAP: PageRank, Connected Components, Shortest Path |
| incubator-hugegraph-ai | Graph RAG, KG construction, NL→Gremlin/Cypher |
| hugegraph-doc | Docs & website (hugegraph.apache.org) |
## Data Flow
```
Sources → hugegraph-loader → hugegraph-server → Hubble / Computer / AI
```
## Integrations
- Big Data: Flink, Spark, HDFS
- Queries: Gremlin (TinkerPop 3.5.1), OpenCypher, REST API + Swagger UI
- Storage: RocksDB (default), HStore (distributed)
## Version: Server 1.7.0, TinkerPop 3.5.1, Java 11+

View File

@ -0,0 +1,49 @@
# Implementation Patterns and Guidelines
## Backend Architecture
- Backends implement `BackendStore` interface from `hugegraph-core`
- Each backend = separate Maven module under `hugegraph-server/`
- Configured via `hugegraph.properties``backend` property
- **Supported backends**: RocksDB (default/embedded), HStore (distributed), HBase (deprecated; planned for removal in 2.0)
## GraphSpace Multi-Tenancy
- Core: `hugegraph-core/.../space/` (GraphSpace, SchemaTemplate, Service, register/)
- API: `hugegraph-api/.../api/space/GraphSpaceAPI.java` (includes GS profile endpoints)
- **Standalone mode**: GraphSpaceAPI and ManagerAPI are disabled
## Auth System
- Disabled by default, enable via `bin/enable-auth.sh`
- ConfigAuthenticator was removed, use standard auth
- Multi-level: Users, Groups, Projects, Targets, Access control
- Location: `hugegraph-api/.../api/auth/`
## gRPC Protocol
- PD protos: `hugegraph-pd/hg-pd-grpc/src/main/proto/`
- Store protos: `hugegraph-store/hg-store-grpc/src/main/proto/`
- After `.proto` changes: `mvn clean compile``target/generated-sources/protobuf/`
## Query Languages
- **Gremlin**: Native TinkerPop 3.5.1
- **OpenCypher**: `hugegraph-api/opencypher/`
- TinkerPop exceptions are passed through in Gremlin responses
## Schema
- Labels support TTL with runtime update
- Edge label conflicting conditions are handled safely
## Testing
- **Profiles**: `unit-test`, `core-test`, `api-test`, `tinkerpop-structure-test`, `tinkerpop-process-test`
- **Backends in CI**: memory, rocksdb, hbase (matrix)
- **Single test class**: `mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,memory -Dtest=ClassName`
- TinkerPop tests: only on `release-*`/`test-*` branches
- Raft tests: only on `test*`/`raft*` branches
## Docker
- Single-node: `docker/docker-compose.yml` (bridge network, pd+store+server)
- Cluster: `docker/docker-compose-3pd-3store-3server.yml`
- Container logs: stdout-based
## CI Pipelines
- `server-ci.yml`: compile + unit/core/API tests (memory/rocksdb/hbase × Java 11)
- `rerun-ci.yml`: auto-rerun flaky failures (max 2 reruns, 180s delay)
- `auto-pr-review.yml`: auto-comment on new PRs

View File

@ -0,0 +1,44 @@
# Key File and Directory Locations
## Build & Config
- `pom.xml` — Root multi-module POM
- `.editorconfig` — Code style rules
- `style/checkstyle.xml` — Checkstyle enforcement (hugegraph-style.xml was removed)
- `.licenserc.yaml` — License checker config
## Server (hugegraph-server)
- Core engine: `hugegraph-core/src/main/java/org/apache/hugegraph/``backend/`, `schema/`, `traversal/`, `task/`
- GraphSpace: `hugegraph-core/.../space/``GraphSpace.java`, `SchemaTemplate.java`, `Service.java`, `register/`
- REST APIs: `hugegraph-api/src/main/java/org/apache/hugegraph/api/``graph/`, `schema/`, `gremlin/`, `cypher/`, `auth/`, `space/` (GraphSpaceAPI), `metrics/`, `arthas/`
- OpenCypher: `hugegraph-api/.../opencypher/`
- Backend interface: `hugegraph-core/.../backend/store/BackendStore.java`
- Distribution: `hugegraph-dist/src/assembly/static/``bin/`, `conf/`, `lib/`, `logs/`
- Tests: `hugegraph-test/src/main/java/.../``unit/`, `core/`, `api/`, `tinkerpop/`
## Docker
- `docker/docker-compose.yml` — Single-node (bridge network, pd+store+server)
- `docker/docker-compose-3pd-3store-3server.yml` — 3-node cluster
- `docker/docker-compose.dev.yml` — Dev mode
## PD Module
- Proto: `hugegraph-pd/hg-pd-grpc/src/main/proto/`
- Dist: `hugegraph-pd/hg-pd-dist/src/assembly/static/`
## Store Module
- Proto: `hugegraph-store/hg-store-grpc/src/main/proto/`
- Dist: `hugegraph-store/hg-store-dist/src/assembly/static/`
## CI Workflows (.github/workflows/)
- `server-ci.yml` — Server tests (matrix: memory/rocksdb/hbase × Java 11)
- `pd-store-ci.yml` — PD, Store & HStore tests
- `commons-ci.yml` — Commons tests
- `cluster-test-ci.yml` — Cluster integration
- `licence-checker.yml` — License headers
- `rerun-ci.yml` — Auto-rerun for flaky workflows
- `auto-pr-review.yml` — Auto-comment on new PRs
- `check-dependencies.yml` — Dependency checks
- `codeql-analysis.yml` — CodeQL security scanning
- `stale.yml` — Stale issue/PR cleanup
## Docs
- `README.md`, `BUILDING.md`, `CONTRIBUTING.md`, `AGENTS.md`, `CLAUDE.md`

View File

@ -0,0 +1,26 @@
# Apache HugeGraph Project Overview
## Project Purpose
Apache HugeGraph is a fast-speed, highly-scalable graph database supporting 10+ billion vertices/edges for OLTP workloads. Graduated from Apache Incubator (incubating branding removed).
## Key Capabilities
- Apache TinkerPop 3 compliant graph database
- Gremlin + OpenCypher query languages
- Schema metadata management (VertexLabel, EdgeLabel, PropertyKey, IndexLabel) with TTL update support
- Multi-type indexes (exact, range, complex conditions)
- Pluggable backend storage (RocksDB default, HStore distributed)
- GraphSpace multi-tenancy (standalone mode disables GraphSpaceAPI/ManagerAPI)
- Swagger UI for REST API documentation
- Integration with Flink/Spark/HDFS
## Technology Stack
- **Language**: Java 11+ (required)
- **Build**: Maven 3.5+
- **Graph Framework**: Apache TinkerPop 3.5.1
- **RPC**: gRPC + Protocol Buffers
- **API Docs**: Swagger (io.swagger.core.v3)
- **Storage**: RocksDB (default/embedded), HStore (distributed/production), HBase (deprecated; planned for removal in 2.0)
## Version
- Current: 1.7.0 (`${revision}` property, Maven flatten plugin)
- License: Apache License 2.0

View File

@ -0,0 +1,58 @@
# Suggested Development Commands
## Build
```bash
mvn clean install -DskipTests # Full build
mvn clean install -pl hugegraph-server -am -DskipTests # Server only
mvn clean compile -U -Dmaven.javadoc.skip=true -ntp # Compile only
mvn clean package -DskipTests # Distribution → install-dist/target/
```
## Test
```bash
# Server tests (memory/rocksdb/hbase backends)
mvn test -pl hugegraph-server/hugegraph-test -am -P unit-test
mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,memory
mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,rocksdb
mvn test -pl hugegraph-server/hugegraph-test -am -P api-test,rocksdb
# Single test class
mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,memory -Dtest=YourTestClass
# TinkerPop compliance (release/test branches only)
mvn test -pl hugegraph-server/hugegraph-test -am -P tinkerpop-structure-test,memory
# PD/Store (build struct first)
mvn install -pl hugegraph-struct -am -DskipTests
mvn test -pl hugegraph-pd/hg-pd-test -am
mvn test -pl hugegraph-store/hg-store-test -am
```
## Validation
```bash
mvn apache-rat:check -ntp # License headers
mvn editorconfig:check # Code style (.editorconfig)
mvn checkstyle:check # Code style (style/checkstyle.xml)
mvn clean compile -Dmaven.javadoc.skip=true # Compile warnings
```
## Server Ops
Scripts in `hugegraph-server/hugegraph-dist/src/assembly/static/bin/` (or extracted distribution `bin/`):
```bash
bin/init-store.sh && bin/start-hugegraph.sh # Init + start
bin/stop-hugegraph.sh # Stop
bin/enable-auth.sh # Enable auth
```
## Docker
```bash
cd docker && docker compose up -d # Single-node (bridge network)
cd docker && docker compose -f docker-compose-3pd-3store-3server.yml up -d # Cluster
```
## Distributed Build (BETA)
```bash
mvn install -pl hugegraph-struct -am -DskipTests # 1. Struct first
mvn clean package -pl hugegraph-pd -am -DskipTests # 2. PD
mvn clean package -pl hugegraph-store -am -DskipTests # 3. Store
```

View File

@ -0,0 +1,32 @@
# Task Completion Checklist
## 1. Code Quality (MANDATORY)
```bash
mvn apache-rat:check -ntp # License headers
mvn editorconfig:check # Style (.editorconfig)
mvn checkstyle:check # Style (style/checkstyle.xml)
mvn clean compile -Dmaven.javadoc.skip=true # Compile warnings
```
## 2. Testing
- Choose backend: `memory` (fast), `rocksdb` (realistic), `hbase` (deprecated compatibility)
- Single test: `-Dtest=ClassName` works with all profiles
- Bug fix → existing tests; New feature → write tests; Refactor → affected module tests
## 3. Dependencies (if adding new)
1. License file → `install-dist/release-docs/licenses/`
2. Declare in `install-dist/release-docs/LICENSE`
3. Append NOTICE → `install-dist/release-docs/NOTICE`
4. Run `./install-dist/scripts/dependency/regenerate_known_dependencies.sh`
## 4. CI Awareness
- `server-ci.yml`: memory/rocksdb/hbase × Java 11
- `rerun-ci.yml`: auto-retries flaky failures
- `licence-checker.yml`: header validation
- Raft tests: only `test*`/`raft*` branches
- TinkerPop tests: only `release-*`/`test-*` branches
## 5. Commit
- NEVER commit unless explicitly asked
- Format: `feat|fix|refactor(module): msg`
- Include issue ID if available

163
.serena/project.yml Normal file
View File

@ -0,0 +1,163 @@
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp
# csharp_omnisharp dart elixir elm erlang
# fortran fsharp go groovy haskell
# java julia kotlin lua markdown
# matlab nix pascal perl php
# php_phpactor powershell python python_jedi r
# rego ruby ruby_solargraph rust scala
# swift terraform toml typescript typescript_vts
# vue yaml zig
# (This list may be outdated. For the current list, see values of Language enum here:
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# - For Free Pascal/Lazarus, use pascal
# Special requirements:
# Some languages require additional setup/installations.
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- java
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# whether to use project's .gitignore files to ignore files
ignore_all_files_in_gitignore: true
# list of additional paths to ignore in this project.
# Same syntax as gitignore, so you can use * and **.
# Note: global ignored_paths from serena_config.yml are also applied additively.
ignored_paths:
# --- HBase is deprecated and planned for removal in 2.0 ---
- "hugegraph-server/hugegraph-hbase/**"
# --- gRPC generated Java (235k lines, never hand-edited, regenerated by mvn compile) ---
- "hugegraph-pd/hg-pd-grpc/src/main/java/**"
- "hugegraph-store/hg-store-grpc/src/main/java/**"
# --- License/legal files (maintained through the release/dependency workflow) ---
- "install-dist/release-docs/licenses/**"
- "install-dist/scripts/dependency/known-dependencies.txt"
# --- Rarely modified tests/examples ---
- "hugegraph-server/hugegraph-test/**/tinkerpop/**"
- "hugegraph-server/hugegraph-example/**"
- "hugegraph-cluster-test/**"
# --- Note: target/, .flattened-pom.xml, .idea/*, apache-hugegraph-*/ already covered by .gitignore ---
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude.
# This extends the existing exclusions (e.g. from the global configuration)
#
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
# the name by which the project can be referenced within Serena
project_name: "server"
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default).
# This extends the existing inclusions (e.g. from the global configuration).
included_optional_tools: []
# list of mode names to that are always to be included in the set of active modes
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this setting overrides the global configuration.
# Set this to [] to disable base modes for this project.
# Set this to a list of mode names to always include the respective modes for this project.
base_modes:
# list of mode names that are to be activated by default.
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
# This setting can, in turn, be overridden by CLI parameters (--mode).
default_modes:
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
fixed_tools: []
# time budget (seconds) per tool call for the retrieval of additional symbol information
# such as docstrings or parameter information.
# This overrides the corresponding setting in the global configuration; see the documentation there.
# If null or missing, use the setting from the global configuration.
symbol_info_budget:
# The language backend to use for this project.
# If not set, the global setting from serena_config.yml is used.
# Valid values: LSP, JetBrains
# Note: the backend is fixed at startup. If a project with a different backend
# is activated post-init, an error will be returned.
language_backend:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:
# list of regex patterns for memories to completely ignore.
# Matching memories will not appear in list_memories or activate_project output
# and cannot be accessed via read_memory or write_memory.
# To access ignored memory files, use the read_file tool on the raw file path.
# Extends the list from the global configuration, merging the two lists.
# Example: ["_archive/.*", "_episodes/.*"]
ignored_memory_patterns: []
# advanced configuration option allowing to configure language server-specific options.
# Maps the language key to the options.
# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available.
# No documentation on options means no options are available.
ls_specific_settings: {}

108
AGENTS.md Normal file
View File

@ -0,0 +1,108 @@
# AGENTS.md
Single source of truth for AI coding agents.
README.md covers human-facing deployment/ecosystem context; only consult it on demand.
## Stack & Modules
Apache HugeGraph — Apache TinkerPop 3 compliant graph database.
Java 11+, Maven 3.5+. Version managed via `${revision}` (currently `1.8.0`).
```
Client (Gremlin / Cypher / REST)
Server = hugegraph-server
├─ hugegraph-api REST, Gremlin/Cypher, auth
├─ hugegraph-core engine, schema, traversal, BackendStore interface
└─ Backend impls rocksdb (default, embedded) │ hstore (distributed)
hugegraph-pd (placement) + hugegraph-store (Raft)
```
Top-level modules: `hugegraph-server` · `hugegraph-pd` · `hugegraph-store` ·
`hugegraph-commons` (shared utils & RPC) · `hugegraph-struct` (data types; dep of PD/Store).
Server submodules worth knowing: `hugegraph-core`, `hugegraph-api`,
`hugegraph-rocksdb`, `hugegraph-hstore`, `hugegraph-test`, `hugegraph-dist`.
## Code Search Anchors
| Area | Path |
|---|---|
| Graph engine | `hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/` |
| REST APIs | `hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/` |
| Backend interface | `hugegraph-server/hugegraph-core/.../backend/store/BackendStore.java` |
| Auth | `hugegraph-server/hugegraph-api/.../api/auth/` |
| gRPC protos | `hugegraph-{pd,store}/hg-{pd,store}-grpc/src/main/proto/` |
Config roots (under each dist module's `src/assembly/static/conf/`):
- Server — `hugegraph.properties`, `rest-server.properties`, `gremlin-server.yaml`
- PD / Store — `application.yml`
## Build
```bash
# All modules
mvn clean install -DskipTests
# Single module
mvn clean install -pl hugegraph-server -am -DskipTests
```
Distributed build order (for HStore-enabled dev):
```bash
mvn install -pl hugegraph-struct -am -DskipTests # 1. shared data types
mvn clean package -pl hugegraph-pd -am -DskipTests # 2. placement driver
mvn clean package -pl hugegraph-store -am -DskipTests # 3. distributed storage
mvn clean package -pl hugegraph-server -am -DskipTests # 4. server
```
Runtime scripts (human-run) live in `hugegraph-server/hugegraph-dist/src/assembly/static/bin/`:
`init-store.sh`, `start-hugegraph.sh`, `stop-hugegraph.sh`.
## Testing
Server tests implicitly prefix `mvn test -pl hugegraph-server/hugegraph-test -am`:
| Profile | Suffix |
|---|---|
| Unit | `-P unit-test` |
| Core | `-P core-test,rocksdb` (swap `rocksdb` for `memory`) |
| API | `-P api-test,rocksdb` |
| TinkerPop structure / process | `-P tinkerpop-{structure,process}-test,memory` |
| Single class | `-P core-test,rocksdb -Dtest=YourTestClass` |
PD / Store tests (need `hugegraph-struct` installed first):
```bash
mvn install -pl hugegraph-struct -am -DskipTests
mvn test -pl hugegraph-pd/hg-pd-test -am
mvn test -pl hugegraph-store/hg-store-test -am
```
Before writing new tests, check existing suites under `hugegraph-server/hugegraph-test/`.
## Style & Pre-commit
- Line 100, 4-space indent, LF, UTF-8, **no star imports**
- Commit format: `feat|fix|refactor(module): msg`
- Run before pushing:
```bash
mvn editorconfig:format # enforce code style
mvn clean compile -Dmaven.javadoc.skip=true # surface warnings
```
## Cross-module notes
- `.proto` edits: `mvn clean compile` regenerates gRPC stubs under
`target/generated-sources/protobuf/` (output packages `*/grpc/` are excluded from Apache RAT).
- Adding a third-party dep: update `install-dist/release-docs/{LICENSE,NOTICE,licenses/}`
and `install-dist/scripts/dependency/known-dependencies.txt`.
- `hugegraph-commons` is shared by every module; `hugegraph-struct` must precede PD/Store;
server backends depend on `hugegraph-core`.
## Additional context files
`.serena/memories/` — notably `suggested_commands.md` and `task_completion_checklist.md`
when a task needs depth beyond this file.

View File

@ -1,28 +1,35 @@
Building hugegraph
Building HugeGraph
--------------
Required:
* Java 8/11
* Maven
* Java 11
* Maven 3.5+
To build without executing tests: `mvn clean package -Dmaven.test.skip=true`
## Building in IDEA
To build without executing tests:
```
mvn clean
mvn package -DskipTests
```
1. Click on "File" -> "Open", choose your project location.
2. Open maven view by click "View" -> "Tool Windows" -> "Maven Projects".
3. Choose root module "hugegraph: Distributed Graph Database", unfold the menu of "Lifecycle".
4. Click the "Toggle 'Skip Tests' Mode" button which is located on the top navibar of "Maven Projects" window to skip tests.
5. Double click "package" or "install" to build a project.
## Building on Eclipse IDE
Note that this has only been tested on Eclipse Neon.2 Release (4.6.2) with m2e (1.7.0.20160603-1933) and m2e-wtp (1.3.1.20160831-1005) plugin.
Could also refer [Dev-In-IDEA](https://hugegraph.apache.org/docs/contribution-guidelines/hugegraph-server-idea-setup/) for more details.
## Building in Eclipse
> Note: this has only been tested on Eclipse Neon.2 Release (4.6.2) with m2e (1.7.0.20160603-1933) and m2e-wtp (1.3.1.20160831-1005) plugin.
To build without executing tests:
1. Right-click on your project -> "Run As..." -> "Run Configurations..."
2. On "Goals", populate with `install`
3. Select the options `Update Snapshots` and `Skip Tests`
4. Before clicking "Run", make sure that Eclipse knows where `JAVA_HOME` is. On same window, go to "Environment" tab and click "New".
4. Before clicking "Run", make sure that Eclipse knows where `JAVA_HOME` is. In the same window, go to "Environment" tab and click "New".
5. Under "Name:", add `JAVA_HOME`
6. Under "Value:", add the path where `java` is located
7. Click "OK"
@ -32,13 +39,3 @@ To find the Java binary in your environment, run the appropriate command for you
* Linux/macOS: `which java`
* Windows: `for %i in (java.exe) do @echo. %~$PATH:i`
## Building on IDEA
To build without executing tests:
1. Click on "File" -> "Open", choose your project location.
2. Open maven view by click "View" -> "Tool Windows" -> "Maven Projects".
3. Choose root module "hugegraph: Distributed Graph Database", unfold the menu of "Lifecycle".
4. Click the "Toggle 'Skip Tests' Mode" button which is located on the top
navibar of "Maven Projects" window to skip tests.
5. Double click "package" or "install" to build project.

View File

@ -1,6 +1,9 @@
# How to Contribute to HugeGraph
Thanks for taking the time to contribute! As an open source project, HugeGraph is looking forward to be contributed from everyone, and we are also grateful to all of the contributors.
> Refer [website-doc](https://hugegraph.apache.org/docs/contribution-guidelines/) for the latest information.
Thanks for taking the time to contribute!
As an open source project, HugeGraph is looking forward to being contributed from everyone, and we are also grateful to all the contributors.
The following is a contribution guide for HugeGraph:
@ -8,19 +11,21 @@ The following is a contribution guide for HugeGraph:
## 1. Preparation
**Recommended**: You can use [GitHub desktop](https://desktop.github.com/) to greatly simplify the PR process.
We can contribute by reporting issues, submitting code patches or any other feedback.
Before submitting the code, we need to do some preparation:
1. Sign up or login to GitHub: [https://github.com](https://github.com)
1. Sign up or login to GitHub: [https://github.com](https://github.com)
2. Fork HugeGraph repo from GitHub: [https://github.com/apache/incubator-hugegraph/fork](https://github.com/apache/incubator-hugegraph/fork)
2. Fork HugeGraph repo from GitHub: [https://github.com/apache/hugegraph/fork](https://github.com/apache/hugegraph/fork)
3. Clone code from fork repo to local: [https://github.com/${GITHUB_USER_NAME}/incubator-hugegraph](https://github.com/${GITHUB_USER_NAME}/incubator-hugegraph)
3. Clone code from fork repo to local: [https://github.com/${GITHUB_USER_NAME}/hugegraph](https://github.com/${GITHUB_USER_NAME}/hugegraph)
```shell
# clone code from remote to local repo
git clone https://github.com/${GITHUB_USER_NAME}/incubator-hugegraph.git hugegraph
git clone https://github.com/${GITHUB_USER_NAME}/hugegraph.git hugegraph
```
4. Configure local HugeGraph repo
@ -29,24 +34,22 @@ Before submitting the code, we need to do some preparation:
cd hugegraph
# add upstream to synchronize the latest code
git remote add hugegraph https://github.com/apache/incubator-hugegraph
git remote add hugegraph https://github.com/apache/hugegraph
# set name and email to push code to github
git config user.name "{full-name}" # like "Jermy Li"
git config user.email "{email-address-of-github}" # like "jermy@apache.org"
```
Optional: You can use [GitHub desktop](https://desktop.github.com/) to greatly simplify the commit and update process.
## 2. Create an Issue on GitHub
If you encounter bugs or have any questions, please go to [GitHub Issues](https://github.com/apache/incubator-hugegraph/issues) to report them and feel free to [create an issue](https://github.com/apache/incubator-hugegraph/issues/new).
If you encounter bugs or have any questions, please go to [GitHub Issues](https://github.com/apache/hugegraph/issues) to report them and feel free to [create an issue](https://github.com/apache/hugegraph/issues/new).
## 3. Make changes of code locally
#### 3.1 Create a new branch
Please don't use master branch for development. Instead we should create a new branch:
Please don't use master branch for development. Instead, we should create a new branch:
```shell
# checkout master branch
@ -63,12 +66,26 @@ Assume that we need to modify some files like "HugeGraph.java" and "HugeFactory.
```shell
# modify code to fix a bug
vim hugegraph-core/src/main/java/com/baidu/hugegraph/HugeGraph.java
vim hugegraph-core/src/main/java/com/baidu/hugegraph/HugeFactory.java
vim hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
vim hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeFactory.java
# run test locally (optional)
mvn test -Pcore-test,memory
```
Note: In order to be consistent with the code style easily, if you use [IDEA](https://www.jetbrains.com/idea/) as your IDE, you can directly [import](https://www.jetbrains.com/help/idea/configuring-code-style.html) our code style [configuration file](./hugegraph-style.xml).
Note: Code style is defined by the `.editorconfig` file at the repository root. Checkstyle rules are defined in `style/checkstyle.xml`. Configure your IDE accordingly.
##### 3.2.1 Check licenses
If we want to add new third-party dependencies to the `HugeGraph` project, we need to do the following things:
1. Find the third-party dependent repository, put the dependent `license` file into [./install-dist/release-docs/licenses/](https://github.com/apache/hugegraph/tree/master/install-dist/release-docs/licenses) path.
2. Declare the dependency in [./install-dist/release-docs/LICENSE](https://github.com/apache/hugegraph/blob/master/install-dist/release-docs/LICENSE) `LICENSE` information.
3. Find the NOTICE file in the repository and append it to [./install-dist/release-docs/NOTICE](https://github.com/apache/hugegraph/blob/master/install-dist/release-docs/NOTICE) file (skip this step if there is no NOTICE file).
4. Execute locally [./install-dist/scripts/dependency/regenerate_known_dependencies.sh](https://github.com/apache/hugegraph/blob/master/install-dist/scripts/dependency/regenerate_known_dependencies.sh) to update the dependency list [known-dependencies.txt](https://github.com/apache/hugegraph/blob/master/install-dist/scripts/dependency/known-dependencies.txt) (or manually update).
**Example**: A new third-party dependency is introduced into the project -> `ant-1.9.1.jar`
- The project source code is located at: https://github.com/apache/ant/tree/rel/1.9.1
- LICENSE file: https://github.com/apache/ant/blob/rel/1.9.1/LICENSE
- NOTICE file: https://github.com/apache/ant/blob/rel/1.9.1/NOTICE
The license information of `ant-1.9.1.jar` needs to be specified in the LICENSE file, and the notice information needs to be specified in the NOTICE file. The detailed LICENSE file corresponding to ant-1.9.1.jar needs to be copied to our licenses/ directory. Finally, update the known-dependencies.txt file.
#### 3.3 Commit changes to git repo
@ -76,8 +93,8 @@ After the code has been completed, we submit them to the local git repo:
```shell
# add files to local git index
git add hugegraph-core/src/main/java/com/baidu/hugegraph/HugeGraph.java
git add hugegraph-core/src/main/java/com/baidu/hugegraph/HugeFactory.java
git add hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
git add hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeFactory.java
# commit to local git repo
git commit
```
@ -90,7 +107,7 @@ Fix bug: run deploy multiple times
fix #ISSUE_ID
```
> Please remember to fill in the issue id, which was generated by GitHub after issue creation.
> Please remember to fill in the issue id, which GitHub generated after issue creation.
#### 3.4 Push commit to GitHub fork repo
@ -106,11 +123,7 @@ Note that since GitHub requires submitting code through `username + token` (inst
## 4. Create a Pull Request
Go to the web page of GitHub fork repo, there would be a chance to create a Pull Request after pushing to a new branch, just click button "Compare & pull request" to do it. Then edit the description for proposed changes, which can just be copied from the commit message.
Please sign the HugeGraph CLA when contributing code for the first time. You can sign the CLA by just posting a Pull Request Comment same as the below format:
`I have read the CLA Document and I hereby sign the CLA`
Go to the web page of GitHub fork repo, there would be a chance to create a Pull Request after pushing to a new branch, click the button "Compare & pull request" to do it. Then edit the description for proposed changes, which can just be copied from the commit message.
Note: please make sure the email address you used to submit the code is bound to the GitHub account. For how to bind the email address, please refer to https://github.com/settings/emails:
<img width="1280" alt="image" src="https://user-images.githubusercontent.com/9625821/163522445-2a50a72a-dea2-434f-9868-3a0d40d0d037.png">
@ -120,7 +133,7 @@ Note: please make sure the email address you used to submit the code is bound to
Maintainers will start the code review after all the **automatic** checks are passed:
- Check: Contributor License Agreement is signed
- Check: Travis CI builds is passed (automatically Test and Deploy)
- Check: Travis CI builds are passed (automatically Test and Deploy)
The commit will be accepted and merged if there is no problem after review.
@ -160,8 +173,8 @@ And push it to GitHub fork repo again:
git push -f origin bugfix-branch:bugfix-branch
```
GitHub will automatically update the Pull Request after we push it, just wait for code review.
GitHub will automatically update the Pull Request after we push it, wait for code review.
Any question please contact to us through [hugegraph@googlegroups.com](mailto:hugegraph@googlegroups.com) or [other contact information](https://hugegraph.github.io/hugegraph-doc/).
For Any question, please contact us through [dev@hugegraph.apache.org](mailto:dev@hugegraph.apache.org) ([subscriber](https://hugegraph.apache.org/docs/contribution-guidelines/subscribe/) only)

View File

@ -1,68 +0,0 @@
#
# 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.
#
FROM ubuntu:xenial
LABEL maintainer="HugeGraph Docker Maintainers <hugegraph@googlegroups.com>"
ENV PKG_URL https://github.com/hugegraph
# 1. Install needed dependencies of GraphServer & RocksDB
RUN set -x \
&& apt-get -q update \
&& apt-get -q install -y --no-install-recommends --no-install-suggests \
curl \
lsof \
g++ \
gcc \
openjdk-8-jdk \
&& apt-get clean
# && rm -rf /var/lib/apt/lists/*
# 2. Init HugeGraph Sever
# (Optional) You can set the ip of github to speed up the local build
# && echo "192.30.253.112 github.com\n151.101.44.249 github.global.ssl.fastly.net" >> /etc/hosts \
ENV SERVER_VERSION 0.12.0
RUN set -e \
&& mkdir -p /root/hugegraph-server \
&& curl -L -S ${PKG_URL}/hugegraph/releases/download/v${SERVER_VERSION}/hugegraph-${SERVER_VERSION}.tar.gz -o /root/server.tar.gz \
&& tar xzf /root/server.tar.gz --strip-components 1 -C /root/hugegraph-server \
&& rm /root/server.tar.gz \
&& cd /root/hugegraph-server/ \
&& sed -i "s/^restserver.url.*$/restserver.url=http:\/\/0.0.0.0:8080/g" ./conf/rest-server.properties \
&& sed -n '65p' ./bin/start-hugegraph.sh | grep "&" > /dev/null && sed -i 65{s/\&$/#/g} ./bin/start-hugegraph.sh \
&& sed -n '75p' ./bin/start-hugegraph.sh | grep "exit" > /dev/null && sed -i 75{s/^/#/g} ./bin/start-hugegraph.sh \
&& ./bin/init-store.sh
# 3. Prepare for HugeGraph Studio
ENV STUDIO_VERSION 0.10.0
# (Optional) You can set the ip of github to speed up the local build
# && echo "192.30.253.112 github.com\n151.101.44.249 github.global.ssl.fastly.net" >> /etc/hosts \
RUN set -e \
&& mkdir -p /root/hugegraph-studio \
&& curl -L -S ${PKG_URL}/hugegraph-studio/releases/download/v${STUDIO_VERSION}/hugegraph-studio-${STUDIO_VERSION}.tar.gz -o /root/studio.tar.gz \
&& tar xzf /root/studio.tar.gz --strip-components 1 -C /root/hugegraph-studio \
&& rm /root/studio.tar.gz \
&& cd /root/hugegraph-studio/ \
&& sed -i "s/^studio.server.host.*$/studio.server.host=0.0.0.0/g" ./conf/hugegraph-studio.properties \
&& sed -i "s/^graph.server.host.*$/graph.server.host=0.0.0.0/g" ./conf/hugegraph-studio.properties
EXPOSE 8080 8088
WORKDIR /root
VOLUME /root
ENTRYPOINT ["./hugegraph-server/bin/start-hugegraph.sh"]

20
LICENSE
View File

@ -1,4 +1,4 @@
Apache License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@ -200,3 +200,21 @@ Apache License
See the License for the specific language governing permissions and
limitations under the License.
========================================================================
Apache 2.0 licenses
========================================================================
The following components are provided under the Apache License. See project link for details.
The text of each license is the standard Apache 2.0 license.
hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/StructureBasicSuite.java from https://github.com/apache/tinkerpop
hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessBasicSuite.java from https://github.com/apache/tinkerpop
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/SnowflakeIdGenerator.java from https://github.com/twitter-archive/snowflake
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeScriptTraversal.java from https://github.com/apache/tinkerpop
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/Nameable.java from https://github.com/JanusGraph/janusgraph
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/Cardinality.java from https://github.com/JanusGraph/janusgraph
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/StringEncoding.java from https://github.com/JanusGraph/janusgraph
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherOpProcessor.java from https://github.com/opencypher/cypher-for-gremlin
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherPlugin.java from https://github.com/opencypher/cypher-for-gremlin
hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/Cardinality.java from https://github.com/JanusGraph/janusgraph
hugegraph-struct/src/main/java/org/apache/hugegraph/type/Namifiable.java from https://github.com/JanusGraph/janusgraph

55
NOTICE Normal file
View File

@ -0,0 +1,55 @@
Apache HugeGraph
Copyright 2022-2026 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
The initial codebase was donated to the ASF by HugeGraph Authors, copyright 2017-2021.
-----------------------------------------------------------------------
This product contains code form the Apache TinkerPop Project:
-----------------------------------------------------------------------
Apache TinkerPop
Copyright 2015-2022 The Apache Software Foundation.
------------------------------------------------------------------------
Activiti
------------------------------------------------------------------------
Activiti BPM Platform
Copyright 2010-2014 Alfresco Software, Ltd.
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriterHelper.java
contains DelegatingXMLStreamWriter.java and IndentingXMLStreamWriter.java from
https://github.com/Activiti/Activiti/tree/activiti-5.16/modules/activiti-bpmn-converter/src/main/java/org/activiti/bpmn/converter
------------------------------------------------------------------------
Apache Kerby
------------------------------------------------------------------------
Apache Kerby
Copyright 2015-2017 The Apache Software Foundation
gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/JaasKrbUtil.java
from
https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/client/JaasKrbUtil.java
-----------------------------------------------------------------------
This product contains code form the JanusGraph Project:
-----------------------------------------------------------------------
==============================================================
JanusGraph: Distributed Graph Database
Copyright 2012 with JanusGraph Authors
==============================================================
This product includes software developed by JanusGraph contributors listed
in CONTRIBUTORS.txt; JanusGraph copyright holders are listed in AUTHORS.txt.
This product is based on Titan, originally developed by Aurelius (acquired by
DataStax) and the following individuals:
* Matthias Broecheler
* Dan LaRocque
* Marko A. Rodriguez
* Stephen Mallette
* Pavel Yaskevich

398
README.md
View File

@ -1,48 +1,390 @@
<div align="center">
<img width="720" alt="hugegraph-logo" src="https://user-images.githubusercontent.com/17706099/149281100-c296db08-2861-4174-a31f-e2a92ebeeb72.png" style="zoom:100%;" />
</div>
<h1 align="center">
<img width="720" alt="hugegraph-logo" src="https://github.com/apache/hugegraph/assets/38098239/e02ffaed-4562-486b-ba8f-e68d02bb0ea6" style="zoom:100%;" />
</h1>
<p align="center">
A graph database that supports more than 10+ billion data, high performance and scalability
</p>
<hr/>
<h3 align="center">A graph database that supports more than 10 billion vertices & edges, high performance and scalability</h3>
<div align="center">
[![License](https://img.shields.io/badge/license-Apache%202-0E78BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Build Status](https://github.com/hugegraph/hugegraph/actions/workflows/ci.yml/badge.svg)](https://github.com/hugegraph/hugegraph/actions/workflows/ci.yml)
[![Codecov](https://codecov.io/gh/hugegraph/hugegraph/branch/master/graph/badge.svg)](https://codecov.io/gh/hugegraph/hugegraph)
[![GitHub Releases Downloads](https://img.shields.io/github/downloads/hugegraph/hugegraph/total.svg)](https://github.com/hugegraph/hugegraph/releases)
[![HugeGraph-Server CI](https://github.com/apache/hugegraph/actions/workflows/server-ci.yml/badge.svg)](https://github.com/apache/hugegraph/actions/workflows/server-ci.yml)
[![HugeGraph-PD & Store CI](https://github.com/apache/hugegraph/actions/workflows/pd-store-ci.yml/badge.svg)](https://github.com/apache/hugegraph/actions/workflows/pd-store-ci.yml)
[![GitHub Releases Downloads](https://img.shields.io/github/downloads/apache/hugegraph/total.svg)](https://github.com/apache/hugegraph/releases)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/apache/hugegraph)
[HugeGraph](https://hugegraph.apache.org/) is a fast-speed and highly-scalable [graph database](https://en.wikipedia.org/wiki/Graph_database). Billions of vertices and edges can be easily stored into and queried from HugeGraph due to its excellent OLTP ability. As compliance to [Apache TinkerPop 3](https://tinkerpop.apache.org/) framework, various complicated graph queries can be accomplished through [Gremlin](https://tinkerpop.apache.org/gremlin.html)(a powerful graph traversal language).
</div>
---
**Quick Navigation:** [Architecture](#architecture) • [Quick Start](#quick-start) • [Module Map](#module-map) • [Ecosystem](#ecosystem) • [For Contributors](#for-contributors) • [Community](#community)
---
## What is Apache HugeGraph?
[HugeGraph](https://hugegraph.apache.org/) is a fast and highly-scalable [graph database](https://en.wikipedia.org/wiki/Graph_database).
Billions of vertices and edges can be easily stored into and queried from HugeGraph due to its excellent OLTP capabilities.
HugeGraph is compliant with the [Apache TinkerPop 3](https://tinkerpop.apache.org/) framework allowing complicated graph queries to be
achieved through the powerful [Gremlin](https://tinkerpop.apache.org/gremlin.html) graph traversal language.
## Features
- Compliance to [Apache TinkerPop 3](https://tinkerpop.apache.org/), supporting [Gremlin](https://tinkerpop.apache.org/gremlin.html)
- Schema Metadata Management, including VertexLabel, EdgeLabel, PropertyKey and IndexLabel
- Multi-type Indexes, supporting exact query, range query and complex conditions combination query
- Plug-in Backend Store Driver Framework, supporting RocksDB, Cassandra, ScyllaDB, HBase and MySQL now and easy to add other backend store driver if needed
- Integration with Hadoop/Spark
- **Schema Metadata Management**: VertexLabel, EdgeLabel, PropertyKey, and IndexLabel
- **Multi-type Indexes**: Exact query, range query, and complex conditions combination query
- **Plug-in Backend Store Framework**: RocksDB powers standalone deployments and HStore powers distributed clusters. See the [backend evolution guide](hugegraph-server/README.md#backend-evolution-and-compatibility) for compatibility details.
- **Big Data Integration**: Seamless integration with `Flink`/`Spark`/`HDFS`
- **Complete Graph Ecosystem**: In/out-memory Graph Computing + Graph Visualization & Tools + Graph Learning & AI
- **Dual Query Language Support**: [Gremlin](https://tinkerpop.apache.org/gremlin.html) (via [Apache TinkerPop 3](https://tinkerpop.apache.org/)) and [Cypher](https://en.wikipedia.org/wiki/Cypher_(query_language)) (OpenCypher)
## Getting Started
## Ecosystem
The project [homepage](https://hugegraph.apache.org/docs/) contains more information on HugeGraph and provides links to **documentation**, getting-started guides and release downloads.
Complete **HugeGraph** ecosystem components:
And here are links of other repositories:
1. [hugegraph-toolchain](https://github.com/apache/incubator-hugegraph-toolchain) (include loader/dashboard/tool/client)
2. [hugegraph-computer](https://github.com/apache/incubator-hugegraph-computer) (graph computing system)
3. [hugegraph-commons](https://github.com/apache/incubator-hugegraph-commons) (include common & rpc module)
4. [hugegraph-website](https://github.com/apache/incubator-hugegraph-doc) (include doc & website code)
1. **[hugegraph-toolchain](https://github.com/apache/hugegraph-toolchain)** - Graph tools suite
- [Loader](https://github.com/apache/hugegraph-toolchain/tree/master/hugegraph-loader) - Data import tool
- [Dashboard](https://github.com/apache/hugegraph-toolchain/tree/master/hugegraph-hubble) - Web visualization platform
- [Tool](https://github.com/apache/hugegraph-toolchain/tree/master/hugegraph-tools) - Command-line utilities
- [Client](https://github.com/apache/hugegraph-toolchain/tree/master/hugegraph-client) - Java/Python client SDK
2. **[hugegraph-computer](https://github.com/apache/hugegraph-computer)** - Integrated **graph computing** system
3. **[hugegraph-ai](https://github.com/apache/hugegraph-ai)** - **Graph AI/LLM/Knowledge Graph** integration
4. **[hugegraph-website](https://github.com/apache/hugegraph-doc)** - **Documentation & website** repository
## Architecture
HugeGraph supports both **standalone** and **distributed** deployments:
```
┌─────────────────────────────────────────────────────┐
│ Client Layer │
│ Gremlin Console │ REST API │ Cypher │ SDK/Tools │
└─────────────────────────┬───────────────────────────┘
┌─────────────────────────▼───────────────────────────┐
│ HugeGraph Server (:8080) │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ REST API │ │ Gremlin │ │ Cypher Engine │ │
│ │(Jersey 3)│ │ (TP 3.5) │ │ (OpenCypher) │ │
│ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │
│ └─────────────┼─────────────────┘ │
│ ┌────────▼────────┐ │
│ │ Graph Engine │ │
│ │(hugegraph-core) │ │
│ └────────┬────────┘ │
└─────────────────────┼───────────────────────────────┘
┌─────────────────┴─────────────────┐
│ │
┌──────────────▼──────────────┐ ┌──────────────▼──────────────┐
│ Standalone Mode │ │ Distributed Mode │
│ ┌───────────────────────┐ │ │ ┌───────────────────────┐ │
│ │ RocksDB │ │ │ │ HugeGraph-PD │ │
│ │ (embedded) │ │ │ │ (Raft, 3-5 nodes) │ │
│ └───────────────────────┘ │ │ │ :8620/:8686 │ │
│ │ │ └───────────┬───────────┘ │
│ Use Case: │ │ │ │
│ Development/Testing │ │ ┌───────────▼───────────┐ │
│ Single Node │ │ │ HStore │ │
│ │ │ │ (Raft, 3+ nodes) │ │
│ Data Scale: < 1TB :8520
└─────────────────────────────┘ │ └───────────────────────┘ │
│ │
│ Use Case: │
│ Production/HA/Cluster │
│ │
│ Data Scale: < 1000 TB
└─────────────────────────────┘
```
See the [backend evolution guide](hugegraph-server/README.md#backend-evolution-and-compatibility) for lifecycle and historical compatibility guidance.
### Deployment Mode Comparison
| Mode | Components | Use Case | Data Scale | High Availability |
|------|------------|----------|------------|-------------------|
| **Standalone** | Server + RocksDB | Development, Testing, Single Node | < 1TB | Basic |
| **Distributed** | Server + PD + HStore | Production, HA, Horizontal Scaling | < 1000 TB | Yes |
### Module Overview
| Module | Description |
|--------|-------------|
| [hugegraph-server](hugegraph-server) | Core graph engine with REST API, Gremlin/Cypher support, and pluggable backends (RocksDB default) |
| [hugegraph-pd](hugegraph-pd/README.md) | Placement Driver for distributed mode - handles meta storage, partition management and cluster scheduling |
| [hugegraph-store](hugegraph-store/README.md) | Distributed storage with Raft consensus for high availability and horizontal scaling |
| [hugegraph-commons](hugegraph-commons) | Shared utilities, RPC framework and common components |
<details>
<summary><b>📊 Click to view detailed architecture diagram (Mermaid)</b></summary>
```mermaid
flowchart TB
CLIENTS["Client Layer<br/>Gremlin Console · REST Client · Cypher Client · SDK/Tools"]
subgraph Server["HugeGraph Server :8080"]
API[REST API<br/>Jersey 3]
GS[Gremlin Server<br/>TinkerPop 3.5]
CS[Cypher Engine<br/>OpenCypher]
CORE[Graph Engine<br/>hugegraph-core]
API --> CORE
GS --> CORE
CS --> CORE
end
subgraph Storage["Storage Layer"]
subgraph Standalone["Standalone Mode"]
ROCKS[(RocksDB<br/>Embedded)]
end
subgraph Distributed["Distributed Mode"]
PD_HSTORE[PD + HStore<br/>Raft Cluster]
end
end
CLIENTS --> Server
CORE --> ROCKS
CORE --> PD_HSTORE
style Server fill:#e1f5ff
style Distributed fill:#fff4e1
style Standalone fill:#f0f0f0
```
</details>
## Quick Start
### 5 Minutes Quick Start
```bash
# Start HugeGraph (standalone mode)
docker run -itd --name=hugegraph -p 8080:8080 hugegraph/hugegraph:1.7.0
# Verify server is running
curl http://localhost:8080/versions
# Try a Gremlin query
curl -X POST http://localhost:8080/gremlin \
-H "Content-Type: application/json" \
-d '{"gremlin":"g.V().limit(5)"}'
```
> **Production Note**: For production environments or public network exposure, you **must** enable the [AuthSystem](https://hugegraph.apache.org/docs/config/config-authentication/) for security.
### Prerequisites
- **Java 11+** (required)
- **Maven 3.5+** (for building from source)
### Option 1: Docker (Fastest)
Docker is the quickest way to get started for **testing or development**:
```bash
# Basic usage
docker run -itd --name=hugegraph -p 8080:8080 hugegraph/hugegraph:1.7.0
# With sample graph preloaded
docker run -itd --name=hugegraph -e PRELOAD=true -p 8080:8080 hugegraph/hugegraph:1.7.0
# With authentication enabled
docker run -itd --name=hugegraph -e PASSWORD=your_password -p 8080:8080 hugegraph/hugegraph:1.7.0
```
For advanced Docker configurations, see:
* [Docker Documentation](https://hugegraph.apache.org/docs/quickstart/hugegraph-server/#3-deploy)
* [Docker Compose Examples](./docker/)
* [Docker README](./docker/README.md)
* [Server Docker README](hugegraph-server/hugegraph-dist/docker/README.md)
> **Docker Desktop (Mac/Windows)**: The 3-node distributed cluster (`docker/docker-compose-3pd-3store-3server.yml`) uses Docker bridge networking and works on all platforms including Docker Desktop. Allocate at least 12 GB memory to Docker Desktop.
> **Note**: Docker images are convenience releases, not **official ASF distribution artifacts**. See [ASF Release Distribution Policy](https://infra.apache.org/release-distribution.html#dockerhub) for details.
>
> **Version Tags**: Use release tags (e.g., `1.7.0`) for stable deployments. The `latest` tag should only be used for testing or development.
<details>
<summary><b>Option 2: Download Binary Package</b></summary>
Download pre-built packages from the [Download Page](https://hugegraph.apache.org/docs/download/download/):
```bash
# Download and extract
# For historical 1.7.0 and earlier releases, use the archive URL and
# set PACKAGE=apache-hugegraph-incubating-{version} instead.
BASE_URL="https://downloads.apache.org/hugegraph/{version}"
PACKAGE="apache-hugegraph-{version}"
# Historical alternative:
# BASE_URL="https://archive.apache.org/dist/incubator/hugegraph/{version}"
# PACKAGE="apache-hugegraph-incubating-{version}"
wget ${BASE_URL}/${PACKAGE}.tar.gz
tar -xzf ${PACKAGE}.tar.gz
cd ${PACKAGE}
# Initialize backend storage
bin/init-store.sh
# Start server
bin/start-hugegraph.sh
# Check server status
bin/monitor-hugegraph.sh
```
For detailed instructions, see the [Binary Installation Guide](https://hugegraph.apache.org/docs/quickstart/hugegraph-server/#32-download-the-binary-tar-tarball).
</details>
<details>
<summary><b>Option 3: Build from Source</b></summary>
Build from source for development or customization:
```bash
# Clone repository
git clone https://github.com/apache/hugegraph.git
cd hugegraph
# Build all modules (skip tests for faster build)
mvn clean package -DskipTests
# Extract built package
tar -xzf target/apache-hugegraph-{version}.tar.gz
cd apache-hugegraph-{version}/apache-hugegraph-server-{version}
# Initialize and start
bin/init-store.sh
bin/start-hugegraph.sh
```
For detailed build instructions, see [BUILDING.md](BUILDING.md) and [Build from Source Guide](https://hugegraph.apache.org/docs/quickstart/hugegraph-server/#33-source-code-compilation).
</details>
<details>
<summary><b>Verify Installation</b></summary>
Once the server is running, verify the installation:
```bash
# Check server version
curl http://localhost:8080/versions
# Expected output:
# {
# "versions": {
# "version": "v1",
# "core": "1.7.0",
# "gremlin": "3.5.1",
# "api": "1.7.0"
# }
# }
# Try Gremlin console (if installed locally)
bin/gremlin-console.sh
# In Gremlin console:
gremlin> :remote connect tinkerpop.server conf/remote.yaml
gremlin> :> g.V().limit(5)
```
For comprehensive documentation, visit the [HugeGraph Documentation](https://hugegraph.apache.org/docs/).
</details>
## Module Map
**Developer Navigation**: Find the right module for your task
| I want to... | Module | Key Path |
|--------------|--------|----------|
| Understand graph operations | `hugegraph-core` | `StandardHugeGraph.java` |
| Modify REST APIs | `hugegraph-api` | `src/.../api/` |
| Add storage backend | `hugegraph-core` | `BackendStore.java` |
| Develop Gremlin features | `hugegraph-core` | `src/.../traversal/` |
| Develop Cypher features | `hugegraph-api` | `src/.../opencypher/` |
| Work on distributed coordination | `hugegraph-pd` | `hg-pd-core/` |
| Work on distributed storage | `hugegraph-store` | `hg-store-core/` |
| Add backend implementations | `hugegraph-server/hugegraph-{backend}` | `hugegraph-rocksdb/`, `hugegraph-hstore/` |
| Understand configuration | `hugegraph-dist` | `src/assembly/static/conf/` |
| Run tests | `hugegraph-test` | Test suites with multiple profiles |
For detailed architecture and development guidance, see [AGENTS.md](AGENTS.md).
<details>
<summary><b>For Contributors</b></summary>
**New to HugeGraph?** Follow this path to get started:
1. **Understand the Architecture**
- Read [AGENTS.md](AGENTS.md) for detailed module structure and development patterns
- Review the [Architecture Diagram](#architecture) above
2. **Set Up Your Environment**
- Install Java 11+ and Maven 3.5+
- Follow [BUILDING.md](BUILDING.md) for build instructions
- Configure your IDE to use `.editorconfig` for code style and `style/checkstyle.xml` for Checkstyle rules
3. **Find Your First Issue**
- Browse [Good First Issues](https://github.com/apache/hugegraph/issues?q=label%3A%22good+first+issue%22)
- Check [Help Wanted Issues](https://github.com/apache/hugegraph/issues?q=label%3A%22help+wanted%22)
4. **Learn the Codebase**
- Use the [Module Map](#module-map) to navigate
- Try [DeepWiki](https://deepwiki.com/apache/hugegraph) for AI-powered codebase understanding
- Run tests to understand behavior: `mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,memory`
- Try modifying a test and see what breaks
5. **Code Standards**
- Line length: 100 characters
- Indentation: 4 spaces
- No star imports
- Commit format: `feat|fix|refactor(module): description`
6. **Submit Your Contribution**
- Read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines
- Follow the [Contribution Guidelines](https://hugegraph.apache.org/docs/contribution-guidelines/)
- Use [GitHub Desktop](https://desktop.github.com/) to simplify the PR process
</details>
## Contributing
Welcome to contribute to HugeGraph, please see [`How to Contribute`](CONTRIBUTING.md) for more information.
Welcome to contribute to HugeGraph!
- **How to Contribute**: See [CONTRIBUTING.md](CONTRIBUTING.md) and [Contribution Guidelines](https://hugegraph.apache.org/docs/contribution-guidelines/)
- **Code Style**: Configure your IDE to use `.editorconfig` for code style and `style/checkstyle.xml` for Checkstyle rules
- **PR Tool**: [GitHub Desktop](https://desktop.github.com/) is recommended for simpler workflow
Thank you to all the contributors who have helped make HugeGraph better!
[![contributors graph](https://contrib.rocks/image?repo=apache/hugegraph)](https://github.com/apache/hugegraph/graphs/contributors)
## License
HugeGraph is licensed under Apache 2.0 License.
HugeGraph is licensed under [Apache 2.0 License](LICENSE).
## Community
**Get Help & Stay Connected**
- **[GitHub Issues](https://github.com/apache/hugegraph/issues)**: Report bugs and request features (quick response)
- **Mailing List**: [dev@hugegraph.apache.org](mailto:dev@hugegraph.apache.org) ([subscribe here](https://hugegraph.apache.org/docs/contribution-guidelines/subscribe/))
- **Slack**: [ASF HugeGraph Channel](https://the-asf.slack.com/archives/C059UU2FJ23)
- **WeChat**: Scan the QR code to follow Apache HugeGraph official account
<p align="center">
<img src="https://github.com/apache/hugegraph-doc/blob/master/assets/images/wechat.png?raw=true" alt="WeChat QR Code" width="300"/>
</p>
## Thanks
HugeGraph relies on the [TinkerPop](http://tinkerpop.apache.org) framework, we refer to the storage structure of Titan and the schema definition of DataStax.
Thanks to TinkerPop, thanks to Titan, thanks to DataStax. Thanks to all other organizations or authors who contributed to the project.
HugeGraph relies on the [Apache TinkerPop](http://tinkerpop.apache.org) framework. We are grateful to the TinkerPop community, Titan, and DataStax for their foundational work. Thanks to all contributors and organizations who have helped make HugeGraph possible.
You are welcome to contribute to HugeGraph, and we are looking forward to working with you to build an excellent open source community.
You are welcome to contribute to HugeGraph, and we look forward to working with you to build an excellent open-source community.

284
docker/README.md Normal file
View File

@ -0,0 +1,284 @@
# HugeGraph Docker Deployment
This directory contains Docker Compose files for running HugeGraph:
| File | Description |
|------|-------------|
| `docker-compose.yml` | Single-node cluster using pre-built images from Docker Hub |
| `docker-compose.dev.yml` | Single-node cluster built from source (for developers) |
| `docker-compose-3pd-3store-3server.yml` | 3-node distributed cluster (PD + Store + Server) |
## Prerequisites
- **Docker Engine** 20.10+ (or Docker Desktop 4.x+)
- **Docker Compose** v2 (included in Docker Desktop)
- **Memory**: Allocate at least **12 GB** to Docker Desktop (Settings → Resources → Memory). The 3-node cluster runs 9 JVM processes (3 PD + 3 Store + 3 Server) which are memory-intensive. Insufficient memory causes OOM kills that appear as silent Raft failures.
> [!IMPORTANT]
> The 12 GB minimum is for Docker Desktop. On Linux with native Docker, ensure the host has at least 12 GB of free memory.
---
## Single-Node Setup
Two compose files are available for running a single-node cluster (1 PD + 1 Store + 1 Server):
### Option A: Quick Start (pre-built images)
Uses pre-built images from Docker Hub. Best for **end users** who want to run HugeGraph quickly.
```bash
cd docker
HUGEGRAPH_VERSION=1.7.0 docker compose up -d
```
- Images: `hugegraph/pd:1.7.0`, `hugegraph/store:1.7.0`, `hugegraph/server:1.7.0`
- `pull_policy: always` — always pulls the specified image tag
> **Note**: Use release tags (e.g., `1.7.0`) for stable deployments. The `latest` tag is intended for testing or development only.
- PD healthcheck endpoint: `/v1/health`
- Single PD, single Store (`HG_PD_INITIAL_STORE_LIST: store:8500`), single Server
- Server healthcheck endpoint: `/versions`
### Option B: Development Build (build from source)
Builds images locally from source Dockerfiles. Best for **developers** who want to test local changes.
```bash
cd docker
docker compose -f docker-compose.dev.yml up -d
```
- Images: built from source via `build: context: ..` with Dockerfiles
- No `pull_policy` — builds locally, doesn't pull
- Entrypoint scripts are baked into the built image (no volume mounts)
- PD healthcheck endpoint: `/v1/health`
- Otherwise identical env vars and structure to the quickstart file
### Key Differences
| | `docker-compose.yml` (quickstart) | `docker-compose.dev.yml` (dev build) |
|---|---|---|
| **Images** | Pull from Docker Hub | Build from source |
| **Who it's for** | End users | Developers |
| **pull_policy** | `always` | not set (build) |
**Verify** (both options):
```bash
curl http://localhost:8080/versions
```
---
## 3-Node Cluster Quickstart
```bash
cd docker
HUGEGRAPH_VERSION=1.7.0 docker compose -f docker-compose-3pd-3store-3server.yml up -d
# To stop and remove all data volumes (clean restart)
docker compose -f docker-compose-3pd-3store-3server.yml down -v
```
**Startup ordering** is enforced via `depends_on` with `condition: service_healthy`:
1. **PD nodes** start first and must pass healthchecks (`/v1/health`)
2. **Store nodes** start after all PD nodes are healthy
3. **Server nodes** start after all Store nodes are healthy
This ensures PD and Store are healthy before the server starts. The server entrypoint still performs a best-effort partition wait after launch, so partition assignment may take a little longer.
**Verify the cluster is healthy**:
```bash
# Check PD health
curl http://localhost:8620/v1/health
# Check Store health
curl http://localhost:8520/v1/health
# Check Server (Graph API)
curl http://localhost:8080/versions
# List registered stores via PD
curl http://localhost:8620/v1/stores
# List partitions
curl http://localhost:8620/v1/partitions
```
---
## Environment Variable Reference
Configuration is injected via environment variables. The old `docker/configs/application-pd*.yml` and `docker/configs/application-store*.yml` files are no longer used.
### PD Environment Variables
| Variable | Required | Default | Maps To (`application.yml`) | Description |
|----------|----------|---------|-----------------------------|-------------|
| `HG_PD_GRPC_HOST` | Yes | — | `grpc.host` | This node's hostname/IP for gRPC |
| `HG_PD_RAFT_ADDRESS` | Yes | — | `raft.address` | This node's Raft address (e.g. `pd0:8610`) |
| `HG_PD_RAFT_PEERS_LIST` | Yes | — | `raft.peers-list` | All PD peers (e.g. `pd0:8610,pd1:8610,pd2:8610`) |
| `HG_PD_INITIAL_STORE_LIST` | Yes | — | `pd.initial-store-list` | Expected stores (e.g. `store0:8500,store1:8500,store2:8500`) |
| `HG_PD_GRPC_PORT` | No | `8686` | `grpc.port` | gRPC server port |
| `HG_PD_REST_PORT` | No | `8620` | `server.port` | REST API port |
| `HG_PD_DATA_PATH` | No | `/hugegraph-pd/pd_data` | `pd.data-path` | Metadata storage path |
| `HG_PD_INITIAL_STORE_COUNT` | No | `1` | `pd.initial-store-count` | Min stores for cluster availability |
**Deprecated aliases** (still work but log a warning):
| Deprecated | Use Instead |
|------------|-------------|
| `GRPC_HOST` | `HG_PD_GRPC_HOST` |
| `RAFT_ADDRESS` | `HG_PD_RAFT_ADDRESS` |
| `RAFT_PEERS` | `HG_PD_RAFT_PEERS_LIST` |
| `PD_INITIAL_STORE_LIST` | `HG_PD_INITIAL_STORE_LIST` |
### Store Environment Variables
| Variable | Required | Default | Maps To (`application.yml`) | Description |
|----------|----------|---------|-----------------------------|-------------|
| `HG_STORE_PD_ADDRESS` | Yes | — | `pdserver.address` | PD gRPC addresses (e.g. `pd0:8686,pd1:8686,pd2:8686`) |
| `HG_STORE_GRPC_HOST` | Yes | — | `grpc.host` | This node's hostname (e.g. `store0`) |
| `HG_STORE_RAFT_ADDRESS` | Yes | — | `raft.address` | This node's Raft address (e.g. `store0:8510`) |
| `HG_STORE_GRPC_PORT` | No | `8500` | `grpc.port` | gRPC server port |
| `HG_STORE_REST_PORT` | No | `8520` | `server.port` | REST API port |
| `HG_STORE_DATA_PATH` | No | `/hugegraph-store/storage` | `app.data-path` | Data storage path |
**Deprecated aliases** (still work but log a warning):
| Deprecated | Use Instead |
|------------|-------------|
| `PD_ADDRESS` | `HG_STORE_PD_ADDRESS` |
| `GRPC_HOST` | `HG_STORE_GRPC_HOST` |
| `RAFT_ADDRESS` | `HG_STORE_RAFT_ADDRESS` |
### Server Environment Variables
| Variable | Required | Default | Maps To | Description |
|----------|----------|---------|-----------------------------|-------------|
| `HG_SERVER_BACKEND` | Yes | — | `backend` in `hugegraph.properties` | Storage backend (e.g. `hstore`) |
| `HG_SERVER_PD_PEERS` | Yes | — | `pd.peers` | PD cluster addresses (e.g. `pd0:8686,pd1:8686,pd2:8686`) |
| `STORE_REST` | No | — | Used by `wait-partition.sh` | Store REST endpoint for partition verification (e.g. `store0:8520`) |
| `PASSWORD` | No | — | Enables auth mode | Optional authentication password; ignored when `HG_SERVER_INIT_STORE_ENABLED` is `false` (see below) |
| `HG_SERVER_INIT_STORE_ENABLED` | No | `true` | `init_store.enabled` in `rest-server.properties` | Set `false` in PD/HStore deployments so init-store skips local backend and admin initialization |
> **The built-in authenticator with `HG_SERVER_INIT_STORE_ENABLED=false`
> requires `usePD=true` and an HStore-backed `auth.graph_store`, unless
> `auth.remote_url` delegates auth elsewhere.** With init-store skipped, the
> server creates the built-in admin in PD metadata, and only an HStore auth
> graph uses the PD-backed auth manager that can read that account. init-store
> exits non-zero when the combination is unusable, rather than leaving a server
> nobody can log in to. A custom `auth.authenticator` is exempt because it
> manages its own identities.
>
> `docker/init_complete` is written by init-store itself, and only after it has
> initialized. A skipped run therefore records nothing, whether it was disabled
> by the variable or by the property in a mounted `rest-server.properties`, so a
> later re-enable is still able to initialize. The marker only short-circuits
> re-initialization: init-store runs on every container start, and a disabled
> one performs the fail-closed check above first, so a marker left by an
> earlier release or an earlier enabled run cannot bypass it.
>
> **`PASSWORD` does not reach that path.** init-store reads it from standard
> input, and a disabled one returns before doing so. The admin is instead
> created from `auth.admin_pa`, whose `pa` default is public, so init-store
> refuses to skip unless it is explicitly set to a non-empty value in a mounted
> `rest-server.properties`. It applies only when the account is first created,
> so changing it later does not rotate an existing password.
**Deprecated aliases** (still work but log a warning):
| Deprecated | Use Instead |
|------------|-------------|
| `BACKEND` | `HG_SERVER_BACKEND` |
| `PD_PEERS` | `HG_SERVER_PD_PEERS` |
---
## Port Reference
The table below reflects the published host ports in `docker-compose-3pd-3store-3server.yml`.
The single-node compose file (`docker-compose.yml`) only publishes the REST/API ports (`8620`, `8520`, `8080`) by default.
| Service | Container Port | Host Port | Protocol | Purpose |
|---------|---------------|-----------|----------|---------|
| pd0 | 8620 | 8620 | HTTP | REST API |
| pd0 | 8686 | 8686 | gRPC | PD gRPC |
| pd0 | 8610 | — | TCP | Raft (internal only) |
| pd1 | 8620 | 8621 | HTTP | REST API |
| pd1 | 8686 | 8687 | gRPC | PD gRPC |
| pd2 | 8620 | 8622 | HTTP | REST API |
| pd2 | 8686 | 8688 | gRPC | PD gRPC |
| store0 | 8500 | 8500 | gRPC | Store gRPC |
| store0 | 8510 | 8510 | TCP | Raft |
| store0 | 8520 | 8520 | HTTP | REST API |
| store1 | 8500 | 8501 | gRPC | Store gRPC |
| store1 | 8510 | 8511 | TCP | Raft |
| store1 | 8520 | 8521 | HTTP | REST API |
| store2 | 8500 | 8502 | gRPC | Store gRPC |
| store2 | 8510 | 8512 | TCP | Raft |
| store2 | 8520 | 8522 | HTTP | REST API |
| server0 | 8080 | 8080 | HTTP | Graph API |
| server1 | 8080 | 8081 | HTTP | Graph API |
| server2 | 8080 | 8082 | HTTP | Graph API |
---
## Healthcheck Endpoints
| Service | Endpoint | Expected |
|---------|----------|----------|
| PD | `GET /v1/health` | `200 OK` |
| Store | `GET /v1/health` | `200 OK` |
| Server | `GET /versions` | `200 OK` with version JSON |
---
## Troubleshooting
### Containers Exiting or Restarting (OOM Kills)
**Symptom**: Containers exit with code 137, or restart loops. Raft logs show election timeouts.
**Cause**: Docker Desktop does not have enough memory. The 9 JVM processes require at least 12 GB.
**Fix**: Docker Desktop → Settings → Resources → Memory → set to **12 GB** or higher. Restart Docker Desktop.
```bash
# Check if containers were OOM killed
docker inspect hg-pd0 | grep -i oom
docker stats --no-stream
```
### Raft Leader Election Failure
**Symptom**: PD logs show repeated `Leader election timeout`. Store nodes cannot register.
**Cause**: PD nodes cannot reach each other on the Raft port (8610), or `HG_PD_RAFT_PEERS_LIST` is misconfigured.
**Fix**:
1. Verify all PD containers are running: `docker compose -f docker-compose-3pd-3store-3server.yml ps`
2. Check PD logs: `docker logs hg-pd0`
3. Verify network connectivity: `docker exec hg-pd0 ping pd1`
4. Ensure `HG_PD_RAFT_PEERS_LIST` is identical on all PD nodes
### Partition Assignment Not Completing
**Symptom**: Server starts but graph operations fail. Store logs show `partition not found`.
**Cause**: PD has not finished assigning partitions to stores, or stores did not register successfully.
**Fix**:
1. Check registered stores: `curl http://localhost:8620/v1/stores`
2. Check partition status: `curl http://localhost:8620/v1/partitions`
3. Wait for partition assignment (can take 13 minutes after all stores register)
4. Check server logs for the `wait-partition.sh` script output: `docker logs hg-server0`
### Connection Refused Errors
**Symptom**: Stores cannot connect to PD, or Server cannot connect to Store.
**Cause**: Services are using `127.0.0.1` instead of container hostnames, or the `hg-net` bridge network is misconfigured.
**Fix**: Ensure all `HG_*` env vars use container hostnames (`pd0`, `store0`, etc.), not `127.0.0.1` or `localhost`.

View File

@ -0,0 +1,202 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: hugegraph-3x3
networks:
hg-net:
driver: bridge
volumes:
hg-pd0-data:
hg-pd1-data:
hg-pd2-data:
hg-store0-data:
hg-store1-data:
hg-store2-data:
# ── Shared service defaults ──────────────────────────────────────────
x-pd-common: &pd-common
image: hugegraph/pd:${HUGEGRAPH_VERSION:-latest}
pull_policy: missing
restart: unless-stopped
networks: [hg-net]
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8620/v1/health >/dev/null || exit 1"]
interval: 15s
timeout: 10s
retries: 30
start_period: 120s
x-store-common: &store-common
image: hugegraph/store:${HUGEGRAPH_VERSION:-latest}
pull_policy: missing
restart: unless-stopped
networks: [hg-net]
depends_on:
pd0: { condition: service_healthy }
pd1: { condition: service_healthy }
pd2: { condition: service_healthy }
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8520/v1/health >/dev/null || exit 1"]
interval: 15s
timeout: 15s
retries: 40
start_period: 120s
x-server-common: &server-common
image: hugegraph/server:${HUGEGRAPH_VERSION:-latest}
pull_policy: missing
restart: unless-stopped
networks: [hg-net]
depends_on:
store0: { condition: service_healthy }
store1: { condition: service_healthy }
store2: { condition: service_healthy }
environment:
STORE_REST: store0:8520
HG_SERVER_BACKEND: hstore
HG_SERVER_PD_PEERS: pd0:8686,pd1:8686,pd2:8686
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/versions >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 30
start_period: 60s
# ── Services ──────────────────────────────────────────────────────────
services:
# --- PD cluster (3 nodes) ---
pd0:
<<: *pd-common
container_name: hg-pd0
hostname: pd0
networks: [ hg-net ]
environment:
HG_PD_GRPC_HOST: pd0
HG_PD_GRPC_PORT: "8686"
HG_PD_REST_PORT: "8620"
HG_PD_RAFT_ADDRESS: pd0:8610
HG_PD_RAFT_PEERS_LIST: pd0:8610,pd1:8610,pd2:8610
HG_PD_INITIAL_STORE_LIST: store0:8500,store1:8500,store2:8500
HG_PD_DATA_PATH: /hugegraph-pd/pd_data
HG_PD_INITIAL_STORE_COUNT: 3
ports: ["8620:8620", "8686:8686"]
volumes:
- hg-pd0-data:/hugegraph-pd/pd_data
pd1:
<<: *pd-common
container_name: hg-pd1
hostname: pd1
networks: [ hg-net ]
environment:
HG_PD_GRPC_HOST: pd1
HG_PD_GRPC_PORT: "8686"
HG_PD_REST_PORT: "8620"
HG_PD_RAFT_ADDRESS: pd1:8610
HG_PD_RAFT_PEERS_LIST: pd0:8610,pd1:8610,pd2:8610
HG_PD_INITIAL_STORE_LIST: store0:8500,store1:8500,store2:8500
HG_PD_DATA_PATH: /hugegraph-pd/pd_data
HG_PD_INITIAL_STORE_COUNT: 3
ports: ["8621:8620", "8687:8686"]
volumes:
- hg-pd1-data:/hugegraph-pd/pd_data
pd2:
<<: *pd-common
container_name: hg-pd2
hostname: pd2
networks: [ hg-net ]
environment:
HG_PD_GRPC_HOST: pd2
HG_PD_GRPC_PORT: "8686"
HG_PD_REST_PORT: "8620"
HG_PD_RAFT_ADDRESS: pd2:8610
HG_PD_RAFT_PEERS_LIST: pd0:8610,pd1:8610,pd2:8610
HG_PD_INITIAL_STORE_LIST: store0:8500,store1:8500,store2:8500
HG_PD_DATA_PATH: /hugegraph-pd/pd_data
HG_PD_INITIAL_STORE_COUNT: 3
ports: ["8622:8620", "8688:8686"]
volumes:
- hg-pd2-data:/hugegraph-pd/pd_data
# --- Store cluster (3 nodes) ---
store0:
<<: *store-common
container_name: hg-store0
hostname: store0
environment:
HG_STORE_PD_ADDRESS: pd0:8686,pd1:8686,pd2:8686
HG_STORE_GRPC_HOST: store0
HG_STORE_GRPC_PORT: "8500"
HG_STORE_REST_PORT: "8520"
HG_STORE_RAFT_ADDRESS: store0:8510
HG_STORE_DATA_PATH: /hugegraph-store/storage
ports: ["8500:8500", "8510:8510", "8520:8520"]
volumes:
- hg-store0-data:/hugegraph-store/storage
store1:
<<: *store-common
container_name: hg-store1
hostname: store1
environment:
HG_STORE_PD_ADDRESS: pd0:8686,pd1:8686,pd2:8686
HG_STORE_GRPC_HOST: store1
HG_STORE_GRPC_PORT: "8500"
HG_STORE_REST_PORT: "8520"
HG_STORE_RAFT_ADDRESS: store1:8510
HG_STORE_DATA_PATH: /hugegraph-store/storage
ports: ["8501:8500", "8511:8510", "8521:8520"]
volumes:
- hg-store1-data:/hugegraph-store/storage
store2:
<<: *store-common
container_name: hg-store2
hostname: store2
environment:
HG_STORE_PD_ADDRESS: pd0:8686,pd1:8686,pd2:8686
HG_STORE_GRPC_HOST: store2
HG_STORE_GRPC_PORT: "8500"
HG_STORE_REST_PORT: "8520"
HG_STORE_RAFT_ADDRESS: store2:8510
HG_STORE_DATA_PATH: /hugegraph-store/storage
ports: ["8502:8500", "8512:8510", "8522:8520"]
volumes:
- hg-store2-data:/hugegraph-store/storage
# --- Server cluster (3 nodes) ---
server0:
<<: *server-common
container_name: hg-server0
hostname: server0
ports: ["8080:8080"]
server1:
<<: *server-common
container_name: hg-server1
hostname: server1
ports: ["8081:8080"]
server2:
<<: *server-common
container_name: hg-server2
hostname: server2
ports: ["8082:8080"]

View File

@ -0,0 +1,106 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: hugegraph-single
networks:
hg-net:
driver: bridge
volumes:
hg-pd-data:
hg-store-data:
services:
pd:
build:
context: ..
dockerfile: hugegraph-pd/Dockerfile
container_name: hg-pd
hostname: pd
restart: unless-stopped
networks: [hg-net]
environment:
HG_PD_GRPC_HOST: pd
HG_PD_GRPC_PORT: "8686"
HG_PD_REST_PORT: "8620"
HG_PD_RAFT_ADDRESS: pd:8610
HG_PD_RAFT_PEERS_LIST: pd:8610
HG_PD_INITIAL_STORE_LIST: store:8500
HG_PD_DATA_PATH: /hugegraph-pd/pd_data
ports:
- "8620:8620"
volumes:
- hg-pd-data:/hugegraph-pd/pd_data
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8620/v1/health >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
store:
build:
context: ..
dockerfile: hugegraph-store/Dockerfile
container_name: hg-store
hostname: store
restart: unless-stopped
networks: [hg-net]
depends_on:
pd:
condition: service_healthy
environment:
HG_STORE_PD_ADDRESS: pd:8686
HG_STORE_GRPC_HOST: store
HG_STORE_GRPC_PORT: "8500"
HG_STORE_REST_PORT: "8520"
HG_STORE_RAFT_ADDRESS: store:8510
HG_STORE_DATA_PATH: /hugegraph-store/storage
ports:
- "8520:8520"
volumes:
- hg-store-data:/hugegraph-store/storage
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8520/v1/health >/dev/null || exit 1"]
interval: 10s
timeout: 10s
retries: 30
start_period: 30s
server:
build:
context: ..
dockerfile: hugegraph-server/Dockerfile-hstore
container_name: hg-server
hostname: server
restart: unless-stopped
networks: [hg-net]
depends_on:
store:
condition: service_healthy
environment:
HG_SERVER_BACKEND: hstore
HG_SERVER_PD_PEERS: pd:8686
ports:
- "8080:8080"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/versions >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 30
start_period: 60s

103
docker/docker-compose.yml Normal file
View File

@ -0,0 +1,103 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
name: hugegraph-single
networks:
hg-net:
driver: bridge
volumes:
hg-pd-data:
hg-store-data:
services:
pd:
image: hugegraph/pd:${HUGEGRAPH_VERSION:-latest}
pull_policy: always
container_name: hg-pd
hostname: pd
restart: unless-stopped
networks: [hg-net]
environment:
HG_PD_GRPC_HOST: pd
HG_PD_GRPC_PORT: "8686"
HG_PD_REST_PORT: "8620"
HG_PD_RAFT_ADDRESS: pd:8610
HG_PD_RAFT_PEERS_LIST: pd:8610
HG_PD_INITIAL_STORE_LIST: store:8500
HG_PD_DATA_PATH: /hugegraph-pd/pd_data
ports:
- "8620:8620"
volumes:
- hg-pd-data:/hugegraph-pd/pd_data
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8620/v1/health >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30s
store:
image: hugegraph/store:${HUGEGRAPH_VERSION:-latest}
pull_policy: always
container_name: hg-store
hostname: store
restart: unless-stopped
networks: [hg-net]
depends_on:
pd:
condition: service_healthy
environment:
HG_STORE_PD_ADDRESS: pd:8686
HG_STORE_GRPC_HOST: store
HG_STORE_GRPC_PORT: "8500"
HG_STORE_REST_PORT: "8520"
HG_STORE_RAFT_ADDRESS: store:8510
HG_STORE_DATA_PATH: /hugegraph-store/storage
ports:
- "8520:8520"
volumes:
- hg-store-data:/hugegraph-store/storage
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8520/v1/health >/dev/null || exit 1"]
interval: 10s
timeout: 10s
retries: 30
start_period: 60s
server:
image: hugegraph/server:${HUGEGRAPH_VERSION:-latest}
pull_policy: always
container_name: hg-server
hostname: server
restart: unless-stopped
networks: [hg-net]
depends_on:
store:
condition: service_healthy
environment:
HG_SERVER_BACKEND: hstore
HG_SERVER_PD_PEERS: pd:8686
ports:
- "8080:8080"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/versions >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 30
start_period: 60s

109
docker/hbase/Dockerfile Normal file
View File

@ -0,0 +1,109 @@
# 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.
#
# Standalone HBase 2.6.5 image for HugeGraph HBase backend testing.
# Exposes ZooKeeper on 2181 with znode /hbase (matching hugegraph.properties defaults).
FROM eclipse-temurin:11-jre-jammy
ARG HBASE_VERSION=2.6.5
ARG HBASE_PRIMARY_URL=https://archive.apache.org/dist/hbase/${HBASE_VERSION}/hbase-${HBASE_VERSION}-bin.tar.gz
ARG HBASE_FALLBACK_URL=https://downloads.apache.org/hbase/${HBASE_VERSION}/hbase-${HBASE_VERSION}-bin.tar.gz
ARG ALLOW_UNVERIFIED_DOWNLOAD=false
ENV HBASE_VERSION=${HBASE_VERSION}
ENV HBASE_HOME=/opt/hbase
ENV PATH=${HBASE_HOME}/bin:${PATH}
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
netcat-openbsd \
&& rm -rf /var/lib/apt/lists/*
RUN set -eux; \
download_ok=0; \
downloaded_url=""; \
for url in "${HBASE_PRIMARY_URL}" "${HBASE_FALLBACK_URL}"; do \
[ -n "${url}" ] || continue; \
echo "Downloading HBase from ${url}"; \
if curl -fL --retry 8 --retry-delay 5 --retry-all-errors \
--connect-timeout 30 --max-time 1800 "${url}" -o /tmp/hbase.tar.gz; then \
download_ok=1; \
downloaded_url="${url}"; \
break; \
fi; \
echo "Download failed for ${url}, trying next source..."; \
rm -f /tmp/hbase.tar.gz; \
done; \
if [ "${download_ok}" -ne 1 ]; then \
echo "Unable to download HBase ${HBASE_VERSION} tarball from configured sources"; \
exit 1; \
fi; \
checksum_ok=0; \
for checksum_url in "${downloaded_url}.sha512" "${HBASE_PRIMARY_URL}.sha512" "${HBASE_FALLBACK_URL}.sha512"; do \
[ -n "${checksum_url}" ] || continue; \
if curl -fL --retry 5 --retry-delay 3 --retry-all-errors \
--connect-timeout 30 "${checksum_url}" -o /tmp/hbase.tar.gz.sha512 2>/dev/null; then \
checksum_ok=1; \
break; \
fi; \
done; \
if [ "${checksum_ok}" -eq 1 ]; then \
echo "Verifying SHA512 checksum..."; \
expected_hash=$(grep -Eio '[a-f0-9]{128}' /tmp/hbase.tar.gz.sha512 | head -n 1 | tr 'A-F' 'a-f' || true); \
if [ -z "$expected_hash" ]; then \
expected_hash=$(awk '{for (i = 1; i <= NF; i++) if (length($i) >= 8 && $i ~ /^[0-9A-Fa-f]+$/) hash = hash $i} END {if (length(hash) >= 128) print tolower(substr(hash, 1, 128))}' /tmp/hbase.tar.gz.sha512 || true); \
fi; \
if [ -n "$expected_hash" ]; then \
actual_hash=$(sha512sum /tmp/hbase.tar.gz | awk '{print $1}'); \
if [ "$expected_hash" = "$actual_hash" ]; then \
echo "SHA512 verified OK"; \
else \
echo "ERROR: SHA512 mismatch"; \
echo " Expected: $expected_hash"; \
echo " Actual: $actual_hash"; \
exit 1; \
fi; \
else \
if [ "${ALLOW_UNVERIFIED_DOWNLOAD}" = "true" ]; then \
echo "WARNING: Could not parse SHA512 file (ALLOW_UNVERIFIED_DOWNLOAD=true)"; \
else \
echo "ERROR: Could not parse SHA512 file"; \
exit 1; \
fi; \
fi; \
else \
if [ "${ALLOW_UNVERIFIED_DOWNLOAD}" = "true" ]; then \
echo "WARNING: Could not download SHA512 file (ALLOW_UNVERIFIED_DOWNLOAD=true)"; \
else \
echo "ERROR: Could not download SHA512 file"; \
exit 1; \
fi; \
fi; \
tar -xzf /tmp/hbase.tar.gz -C /opt; \
mv /opt/hbase-${HBASE_VERSION} ${HBASE_HOME}; \
rm -f /tmp/hbase.tar.gz /tmp/hbase.tar.gz.sha512
# hbase-site.xml: standalone mode, znode=/hbase (matches hugegraph.properties)
COPY hbase-site.xml ${HBASE_HOME}/conf/hbase-site.xml
# Entrypoint: start HBase then tail the master log
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 2181 16000 16010 16020 16030
ENTRYPOINT ["/entrypoint.sh"]

305
docker/hbase/README.md Normal file
View File

@ -0,0 +1,305 @@
# HugeGraph + HBase Backend
This guide covers running HugeGraph with HBase backend.
> **Deprecation notice:** The HBase backend is deprecated and is planned for removal in HugeGraph 2.0. Existing deployments should plan a migration to a maintained backend.
> All commands below run from the repository root (this project folder).
Use this once at the start of your terminal session:
```bash
ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$ROOT_DIR"
```
---
## Quick Start Paths (Choose One)
<details>
<summary><b>Option 1: Standalone HugeGraph (using start-hugegraph.sh)</b></summary>
Prerequisite: build local artifact first.
mvn clean package -DskipTests
```
cd "$ROOT_DIR"
```
```bash
# 1) Start HBase
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml down -v
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml build --no-cache hbase
HBASE_MASTER_HOSTNAME=localhost HBASE_REGIONSERVER_HOSTNAME=localhost \
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml up -d
until docker exec hg-hbase-test nc -z localhost 2181 >/dev/null 2>&1; do sleep 2; done
echo "HBase ZooKeeper is reachable on 2181"
# Optional troubleshooting stream:
# docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml logs -f hbase
```
```bash
# 2) Configure HugeGraph (standalone runtime)
SERVER_DIR="$(find . -maxdepth 4 -type d -path './hugegraph-server/apache-hugegraph-server-*' | head -n 1)"
[ -n "$SERVER_DIR" ] || { echo "Build artifact not found"; exit 1; }
CONF="$SERVER_DIR/conf/graphs/hugegraph.properties"
perl -pi -e 's/^backend=.*/backend=hbase/' "$CONF"
perl -pi -e 's/^serializer=.*/serializer=hbase/' "$CONF"
perl -pi -e 's/^#(hbase\.hosts=.*)/$1/' "$CONF"
perl -pi -e 's/^#(hbase\.port=.*)/$1/' "$CONF"
perl -pi -e 's/^#(hbase\.znode_parent=.*)/$1/' "$CONF"
perl -pi -e 's/^hbase\.hosts=.*/hbase.hosts=localhost/' "$CONF"
perl -pi -e 's/^hbase\.port=.*/hbase.port=2181/' "$CONF"
perl -pi -e 's|^hbase\.znode_parent=.*|hbase.znode_parent=/hbase|' "$CONF"
grep -E '^(backend|serializer|hbase\.)' "$CONF"
```
```bash
# 3) Init and start server
cd "$SERVER_DIR"
printf 'pa\npa\n' | ./bin/init-store.sh
./bin/start-hugegraph.sh
# 4) Verify backend logs mention hbase
cd "$ROOT_DIR"
grep -Eai 'hbase|rocksdb|hstore' "$SERVER_DIR"/logs/*.log | tail -n 30
```
</details>
<details>
<summary><b>Option 2: Docker HugeGraph (fully containerized)</b></summary>
```
cd "$ROOT_DIR"
```
```bash
# 1) Start HBase
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml down -v
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml build --no-cache hbase
HBASE_HOSTNAME=hbase docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml up -d
until docker exec hg-hbase-test nc -z localhost 2181 >/dev/null 2>&1; do sleep 2; done
echo "HBase ZooKeeper is reachable on 2181"
# Optional troubleshooting stream:
# docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml logs -f hbase
```
```bash
# 2) Build HugeGraph server image
docker build -f hugegraph-server/Dockerfile -t hugegraph/server:dev .
# 3) Resolve HBase network
HBASE_NETWORK="$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{println $k}}{{end}}' hg-hbase-test | head -n 1)"
echo "$HBASE_NETWORK"
```
```bash
# 4) One-shot init-store
docker rm -f hg-server-init >/dev/null 2>&1 || true
docker run --rm --name hg-server-init \
--network "$HBASE_NETWORK" \
hugegraph/server:dev \
bash -lc '
set -euo pipefail
CONF=/hugegraph-server/conf/graphs/hugegraph.properties
perl -pi -e "s/^backend=.*/backend=hbase/" "$CONF"
perl -pi -e "s/^serializer=.*/serializer=hbase/" "$CONF"
perl -pi -e "s/^#(hbase\.hosts=.*)/\$1/" "$CONF"
perl -pi -e "s/^#(hbase\.port=.*)/\$1/" "$CONF"
perl -pi -e "s/^#(hbase\.znode_parent=.*)/\$1/" "$CONF"
perl -pi -e "s/^hbase\.hosts=.*/hbase.hosts=hbase/" "$CONF"
perl -pi -e "s/^hbase\.port=.*/hbase.port=2181/" "$CONF"
perl -pi -e "s|^hbase\.znode_parent=.*|hbase.znode_parent=/hbase|" "$CONF"
printf "pa\npa\n" | ./bin/init-store.sh
'
```
```bash
# 5) Start HugeGraph container
docker rm -f hg-server-dev-hbase >/dev/null 2>&1 || true
docker run -d --name hg-server-dev-hbase \
--network "$HBASE_NETWORK" \
-p 8080:8080 \
-p 8182:8182 \
hugegraph/server:dev \
bash -lc '
set -euo pipefail
CONF=/hugegraph-server/conf/graphs/hugegraph.properties
perl -pi -e "s/^backend=.*/backend=hbase/" "$CONF"
perl -pi -e "s/^serializer=.*/serializer=hbase/" "$CONF"
perl -pi -e "s/^#(hbase\.hosts=.*)/\$1/" "$CONF"
perl -pi -e "s/^#(hbase\.port=.*)/\$1/" "$CONF"
perl -pi -e "s/^#(hbase\.znode_parent=.*)/\$1/" "$CONF"
perl -pi -e "s/^hbase\.hosts=.*/hbase.hosts=hbase/" "$CONF"
perl -pi -e "s/^hbase\.port=.*/hbase.port=2181/" "$CONF"
perl -pi -e "s|^hbase\.znode_parent=.*|hbase.znode_parent=/hbase|" "$CONF"
./bin/start-hugegraph.sh -t 120
tail -f /hugegraph-server/logs/hugegraph-server.log
'
```
```bash
# 6) Verify hbase backend
docker exec hg-server-dev-hbase bash -lc "grep -E '^(backend|serializer|hbase\.)' /hugegraph-server/conf/graphs/hugegraph.properties"
docker exec hg-server-dev-hbase bash -lc "grep -Ei 'hbase|rocksdb|hstore' /hugegraph-server/logs/*.log | tail -n 30"
```
</details>
After either path is up, run the shared tests below.
---
## Common Testing Steps
### Apache HugeGraph Persistent Runbook (REST Engine)
### Prerequisites and Constants
- Base URL: `http://localhost:8080`
- Graph target name: `hugegraph`
- Storage backend: persistent (HBase/RocksDB/HStore)
---
### Step 1: Purge Database (Fresh Restart)
Wipe any conflicting test records and data schema.
```bash
curl -X DELETE "http://localhost:8080/graphspaces/DEFAULT/graphs/hugegraph/clear?confirm_message=I%27m+sure+to+delete+all+data"
```
Status `204 No Content` confirms success.
---
### Step 2: Provision Structural Schema
1) Register property keys:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "name", "data_type": "TEXT", "cardinality": "SINGLE"}' \
"http://localhost:8080/graphs/hugegraph/schema/propertykeys"
```
2) Register vertex label (PRIMARY_KEY):
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "person", "id_strategy": "PRIMARY_KEY", "properties": ["name"], "primary_keys": ["name"]}' \
"http://localhost:8080/graphs/hugegraph/schema/vertexlabels"
```
3) Register edge label:
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "knows", "source_label": "person", "target_label": "person", "properties": []}' \
"http://localhost:8080/graphs/hugegraph/schema/edgelabels"
```
---
### Step 3: Populate Graph Elements
1) Batch write vertices (Alice and Bob):
```bash
curl -X POST -H "Content-Type: application/json" \
-d '[{"label": "person", "properties": {"name": "Alice"}}, {"label": "person", "properties": {"name": "Bob"}}]' \
"http://localhost:8080/graphs/hugegraph/graph/vertices/batch"
```
Response should include IDs similar to `1:Alice` and `1:Bob`.
2) Create directed edge (Alice knows Bob):
```bash
curl -X POST -H "Content-Type: application/json" \
-d '{"label": "knows", "outV": "1:Alice", "inV": "1:Bob", "properties": {}}' \
"http://localhost:8080/graphs/hugegraph/graph/edges"
```
---
### Step 4: Synchronous Verification and Traversal
1) Verify target K-hop output:
```bash
curl -s "http://localhost:8080/graphs/hugegraph/traversers/kout?source=%221:Alice%22&direction=OUT&max_depth=1"
```
Expected output: `{"vertices":["1:Bob"]}`
2) Verify relation path structure:
```bash
curl -s "http://localhost:8080/graphs/hugegraph/traversers/rays?source=%221:Alice%22&direction=OUT&label=knows&max_depth=1"
```
Expected output contains: `rays":[{"objects":["1:Alice","1:Bob"]}]`
---
### Troubleshooting Cheat Sheet
- URI syntax error: do not append literal `"` inside bare URLs. Use URL-encoded values (`%22`).
- Property missing errors: prefer native `/traversers/*` APIs for synchronous reads.
---
## Cleanup
Run cleanup only after testing is complete.
### Standalone HugeGraph + Docker HBase
```bash
cd "$SERVER_DIR" && ./bin/stop-hugegraph.sh
cd "$ROOT_DIR"
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml down -v
```
### Docker HugeGraph + Docker HBase
```bash
docker rm -f hg-server-init >/dev/null 2>&1 || true
docker rm -f hg-server-dev-hbase
docker compose -p hg-hbase -f docker/hbase/docker-compose.hbase.yml down -v
```
---
## Troubleshooting
| Symptom | Fix |
|---|---|
| `UnknownHostException: hbase:16000` | HugeGraph container is not on same Docker network as HBase. Verify `HBASE_NETWORK` and `--network`. |
| RocksDB logs in server output | `backend=rocksdb` still active; re-run backend config and restart. |
| `TableNotFoundException` on API calls | Tables not initialized; re-run `init-store.sh` from selected path. |
| Port 8182 already in use | `lsof -i :8182` then `kill <PID>`. |
| HBase container not starting | Check `lsof -i :2181`; increase Docker memory to >= 4 GB. |
---
## Verification Checklist
- [ ] `backend=hbase` in `hugegraph.properties`
- [ ] Server logs show HBase client messages (not RocksDB/HStore)
- [ ] HBase tables exist in `default_hugegraph:*`
- [ ] REST runbook queries return expected graph data
- [ ] Data survives server restart
---
## References
- HBase official docs: https://hbase.apache.org/
- HugeGraph HBase backend: `hugegraph-server/hugegraph-hbase/`
- HBase Docker Compose: `docker/hbase/docker-compose.hbase.yml`
- HBase Docker config: `docker/hbase/hbase-site.xml`

View File

@ -0,0 +1,79 @@
# 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.
#
# HBase standalone for local HugeGraph HBase backend development & testing.
#
# Usage:
# Start: docker compose -f docker/hbase/docker-compose.hbase.yml up -d
# Standalone HugeGraph on host:
# HBASE_MASTER_HOSTNAME=localhost HBASE_REGIONSERVER_HOSTNAME=localhost \
# docker compose -f docker/hbase/docker-compose.hbase.yml up -d
# Wait: until docker exec hg-hbase-test nc -z localhost 2181; do sleep 2; done
# Verify: nc -z localhost 2181 && echo "ZooKeeper OK"
# Test: mvn test -pl hugegraph-server/hugegraph-test -am -P core-test,hbase
# Stop: docker compose -f docker/hbase/docker-compose.hbase.yml down -v
#
# HugeGraph test config (hugegraph-server/hugegraph-test/src/main/resources/hugegraph.properties):
# hbase.hosts=localhost
# hbase.port=2181
# hbase.znode_parent=/hbase
#
# Ports exposed to host:
# 2181 - ZooKeeper (HBase embedded)
# 16000 - HBase Master RPC
# 16010 - HBase Master Web UI -> http://localhost:16010
# 16020 - HBase RegionServer RPC
# 16030 - HBase RegionServer Web UI -> http://localhost:16030
services:
hbase:
build:
context: .
dockerfile: Dockerfile
args:
HBASE_VERSION: "2.6.5"
# Optional overrides for flaky networks/corporate mirrors.
HBASE_PRIMARY_URL: "${HBASE_PRIMARY_URL:-https://downloads.apache.org/hbase/2.6.5/hbase-2.6.5-bin.tar.gz}"
HBASE_FALLBACK_URL: "${HBASE_FALLBACK_URL:-https://archive.apache.org/dist/hbase/2.6.5/hbase-2.6.5-bin.tar.gz}"
image: hugegraph/hbase:2.6.5
container_name: hg-hbase-test
hostname: "${HBASE_HOSTNAME:-hbase}"
environment:
HBASE_HOSTNAME: "${HBASE_HOSTNAME:-hbase}"
HBASE_MASTER_HOSTNAME: "${HBASE_MASTER_HOSTNAME:-}"
HBASE_REGIONSERVER_HOSTNAME: "${HBASE_REGIONSERVER_HOSTNAME:-}"
ports:
- "2181:2181" # ZooKeeper (matches hbase.port in hugegraph.properties)
- "16000:16000" # Master RPC
- "16010:16010" # Master Web UI -> http://localhost:16010
- "16020:16020" # RegionServer RPC
- "16030:16030" # RegionServer Web UI -> http://localhost:16030
volumes:
- hbase-data:/tmp/hbase
- hbase-zk-data:/tmp/zookeeper
healthcheck:
# nc -z confirms ZooKeeper is accepting connections
test: ["CMD", "nc", "-z", "localhost", "2181"]
interval: 10s
timeout: 10s
retries: 15
start_period: 90s
restart: unless-stopped
volumes:
hbase-data:
hbase-zk-data:

View File

@ -0,0 +1,99 @@
#!/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 -e
HBASE_HOSTNAME="${HBASE_HOSTNAME:-hbase}"
HBASE_MASTER_HOSTNAME="${HBASE_MASTER_HOSTNAME:-${HBASE_HOSTNAME}}"
HBASE_REGIONSERVER_HOSTNAME="${HBASE_REGIONSERVER_HOSTNAME:-${HBASE_HOSTNAME}}"
HBASE_SITE_XML="${HBASE_HOME}/conf/hbase-site.xml"
escape_sed_replacement() {
local value="$1"
if [[ "$value" == *$'\n'* ]]; then
echo "Property values must not contain newlines" >&2
exit 1
fi
printf '%s' "$value" | sed -e 's/[\\&|]/\\&/g'
}
set_xml_property_value() {
local property_name="$1"
local property_value
property_value=$(escape_sed_replacement "$2")
# The in-place replacement below expects the standard HBase layout where
# <name>...</name> is followed by <value>...</value> on the next line.
# Fail loudly if the property entry is missing to avoid silent misconfig.
if ! grep -Fq "<name>${property_name}</name>" "${HBASE_SITE_XML}"; then
echo "Missing required property '${property_name}' in ${HBASE_SITE_XML}" >&2
exit 1
fi
sed -i "/<name>${property_name//./\\.}<\\/name>/ {n; s|<value>.*</value>|<value>${property_value}</value>|;}" "${HBASE_SITE_XML}"
}
set_xml_property_value "hbase.master.hostname" "${HBASE_MASTER_HOSTNAME}"
set_xml_property_value "hbase.regionserver.hostname" "${HBASE_REGIONSERVER_HOSTNAME}"
echo "Starting HBase ${HBASE_VERSION} standalone..."
echo "HBase container hostname fallback: ${HBASE_HOSTNAME}"
echo "HBase advertised master hostname: ${HBASE_MASTER_HOSTNAME}"
echo "HBase advertised regionserver hostname: ${HBASE_REGIONSERVER_HOSTNAME}"
# Start services explicitly to avoid SSH-based helper assumptions in containers
${HBASE_HOME}/bin/hbase-daemon.sh start zookeeper
${HBASE_HOME}/bin/hbase-daemon.sh start master
${HBASE_HOME}/bin/hbase-daemon.sh start regionserver
echo "HBase started. Waiting for ZooKeeper on port 2181..."
zk_attempts=0
until nc -z localhost 2181; do
zk_attempts=$((zk_attempts + 1))
if [ "$zk_attempts" -ge 120 ]; then
echo "Timed out waiting for ZooKeeper on 2181"
${HBASE_HOME}/bin/hbase-daemon.sh status || true
exit 1
fi
sleep 1
done
echo "ZooKeeper is ready."
echo "Waiting for HBase Master..."
master_attempts=0
until echo "status 'simple'" | ${HBASE_HOME}/bin/hbase shell -n 2>/dev/null | grep -E -q "([1-9][0-9]*[[:space:]]+live[[:space:]]+servers|[1-9][0-9]*[[:space:]]+servers|servers:[[:space:]]*[1-9])"; do
master_attempts=$((master_attempts + 1))
if [ "$master_attempts" -ge 180 ]; then
echo "Timed out waiting for HBase master/regionserver readiness"
${HBASE_HOME}/bin/hbase-daemon.sh status || true
tail -n 80 ${HBASE_HOME}/logs/hbase-*.out ${HBASE_HOME}/logs/hbase-*.log \
2>/dev/null || true
exit 1
fi
sleep 3
done
echo "HBase is ready. Master + RegionServer online."
# Tail all daemon logs so `docker logs` includes startup/runtime issues
shopt -s nullglob
log_files=("${HBASE_HOME}/logs"/hbase-*.out "${HBASE_HOME}/logs"/hbase-*.log)
if [ ${#log_files[@]} -gt 0 ]; then
exec tail -F "${log_files[@]}"
fi
exec tail -f /dev/null

View File

@ -0,0 +1,89 @@
<?xml version="1.0"?>
<!--
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.
-->
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<!-- Standalone mode: use local filesystem -->
<property>
<name>hbase.rootdir</name>
<value>file:///tmp/hbase</value>
</property>
<!-- Embedded ZooKeeper data directory -->
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/tmp/zookeeper</value>
</property>
<!-- Keep ZooKeeper quorum explicit for containerized single-node setup -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>localhost</value>
</property>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
<!-- Allow unlimited ZooKeeper client connections -->
<property>
<name>hbase.zookeeper.property.maxClientCnxns</name>
<value>0</value>
</property>
<!-- Match hugegraph.properties: hbase.znode_parent=/hbase -->
<property>
<name>zookeeper.znode.parent</name>
<value>/hbase</value>
</property>
<!-- Longer tick + session for slow CI/test environments -->
<property>
<name>hbase.zookeeper.property.tickTime</name>
<value>6000</value>
</property>
<property>
<name>zookeeper.session.timeout</name>
<value>180000</value>
</property>
<!-- Pseudo-distributed mode so master + regionserver run as distinct daemons -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!-- Local FS in single-node Docker may not support async WAL hflush -->
<property>
<name>hbase.wal.provider</name>
<value>filesystem</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
<property>
<name>hbase.master.hostname</name>
<value>localhost</value>
</property>
<property>
<name>hbase.regionserver.hostname</name>
<value>localhost</value>
</property>
<property>
<name>hbase.master.ipc.address</name>
<value>0.0.0.0</value>
</property>
<property>
<name>hbase.regionserver.ipc.address</name>
<value>0.0.0.0</value>
</property>
</configuration>

View File

@ -1,178 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hugegraph-api</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph-rpc</artifactId>
<exclusions>
<!-- conflict with jraft -->
<exclusion>
<groupId>com.alipay.sofa</groupId>
<artifactId>bolt</artifactId>
</exclusion>
<exclusion>
<groupId>com.alipay.sofa.common</groupId>
<artifactId>sofa-common-tools</artifactId>
</exclusion>
<exclusion>
<groupId>com.alipay.sofa</groupId>
<artifactId>hessian</artifactId>
</exclusion>
<!-- conflict with cassandra-netty/tinkerpop-server -->
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-server</artifactId>
<exclusions>
<exclusion>
<groupId>com.github.jeremyh</groupId>
<artifactId>jBCrypt</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-framework</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http-server</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http-servlet</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jersey3</artifactId>
</dependency>
<dependency>
<groupId>org.opencypher.gremlin</groupId>
<artifactId>translation</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.1.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<index>true</index>
<manifest>
<addDefaultImplementationEntries>
false
</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>
true
</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<!-- TODO: update it -->
<Implementation-Version>0.69.0.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,195 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.NotSupportedException;
import jakarta.ws.rs.core.MediaType;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.apache.hugegraph.metrics.MetricsUtil;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeException;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.Meter;
import com.google.common.collect.ImmutableMap;
public class API {
protected static final Logger LOG = Log.logger(API.class);
public static final String CHARSET = "UTF-8";
public static final String TEXT_PLAIN = MediaType.TEXT_PLAIN;
public static final String APPLICATION_JSON = MediaType.APPLICATION_JSON;
public static final String APPLICATION_JSON_WITH_CHARSET =
APPLICATION_JSON + ";charset=" + CHARSET;
public static final String JSON = MediaType.APPLICATION_JSON_TYPE
.getSubtype();
public static final String ACTION_APPEND = "append";
public static final String ACTION_ELIMINATE = "eliminate";
public static final String ACTION_CLEAR = "clear";
private static final Meter SUCCEED_METER =
MetricsUtil.registerMeter(API.class, "commit-succeed");
private static final Meter ILLEGAL_ARG_ERROR_METER =
MetricsUtil.registerMeter(API.class, "illegal-arg");
private static final Meter EXPECTED_ERROR_METER =
MetricsUtil.registerMeter(API.class, "expected-error");
private static final Meter UNKNOWN_ERROR_METER =
MetricsUtil.registerMeter(API.class, "unknown-error");
public static HugeGraph graph(GraphManager manager, String graph) {
HugeGraph g = manager.graph(graph);
if (g == null) {
throw new NotFoundException(String.format(
"Graph '%s' does not exist", graph));
}
return g;
}
public static HugeGraph graph4admin(GraphManager manager, String graph) {
return graph(manager, graph).hugegraph();
}
public static <R> R commit(HugeGraph g, Callable<R> callable) {
Consumer<Throwable> rollback = (error) -> {
if (error != null) {
LOG.error("Failed to commit", error);
}
try {
g.tx().rollback();
} catch (Throwable e) {
LOG.error("Failed to rollback", e);
}
};
try {
R result = callable.call();
g.tx().commit();
SUCCEED_METER.mark();
return result;
} catch (IllegalArgumentException | NotFoundException |
ForbiddenException e) {
ILLEGAL_ARG_ERROR_METER.mark();
rollback.accept(null);
throw e;
} catch (RuntimeException e) {
EXPECTED_ERROR_METER.mark();
rollback.accept(e);
throw e;
} catch (Throwable e) {
UNKNOWN_ERROR_METER.mark();
rollback.accept(e);
// TODO: throw the origin exception 'e'
throw new HugeException("Failed to commit", e);
}
}
public static void commit(HugeGraph g, Runnable runnable) {
commit(g, () -> {
runnable.run();
return null;
});
}
public static Object[] properties(Map<String, Object> properties) {
Object[] list = new Object[properties.size() * 2];
int i = 0;
for (Map.Entry<String, Object> prop : properties.entrySet()) {
list[i++] = prop.getKey();
list[i++] = prop.getValue();
}
return list;
}
protected static void checkCreatingBody(Checkable body) {
E.checkArgumentNotNull(body, "The request body can't be empty");
body.checkCreate(false);
}
protected static void checkUpdatingBody(Checkable body) {
E.checkArgumentNotNull(body, "The request body can't be empty");
body.checkUpdate();
}
protected static void checkCreatingBody(
Collection<? extends Checkable> bodies) {
E.checkArgumentNotNull(bodies, "The request body can't be empty");
for (Checkable body : bodies) {
E.checkArgument(body != null,
"The batch body can't contain null record");
body.checkCreate(true);
}
}
protected static void checkUpdatingBody(
Collection<? extends Checkable> bodies) {
E.checkArgumentNotNull(bodies, "The request body can't be empty");
for (Checkable body : bodies) {
E.checkArgumentNotNull(body,
"The batch body can't contain null record");
body.checkUpdate();
}
}
@SuppressWarnings("unchecked")
protected static Map<String, Object> parseProperties(String properties) {
if (properties == null || properties.isEmpty()) {
return ImmutableMap.of();
}
Map<String, Object> props = null;
try {
props = JsonUtil.fromJson(properties, Map.class);
} catch (Exception ignored) {
// ignore
}
// If properties is the string "null", props will be null
E.checkArgument(props != null,
"Invalid request with properties: %s", properties);
return props;
}
public static boolean checkAndParseAction(String action) {
E.checkArgumentNotNull(action, "The action param can't be empty");
if (action.equals(ACTION_APPEND)) {
return true;
} else if (action.equals(ACTION_ELIMINATE)) {
return false;
} else {
throw new NotSupportedException(
String.format("Not support action '%s'", action));
}
}
}

View File

@ -1,215 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.auth;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Path;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.auth.HugeAccess;
import org.apache.hugegraph.auth.HugePermission;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/auth/accesses")
@Singleton
@Tag(name = "AccessAPI")
public class AccessAPI extends API {
private static final Logger LOG = Log.logger(AccessAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonAccess jsonAccess) {
LOG.debug("Graph [{}] create access: {}", graph, jsonAccess);
checkCreatingBody(jsonAccess);
HugeGraph g = graph(manager, graph);
HugeAccess access = jsonAccess.build();
access.id(manager.authManager().createAccess(access));
return manager.serializer(g).writeAuthElement(access);
}
@PUT
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
JsonAccess jsonAccess) {
LOG.debug("Graph [{}] update access: {}", graph, jsonAccess);
checkUpdatingBody(jsonAccess);
HugeGraph g = graph(manager, graph);
HugeAccess access;
try {
access = manager.authManager().getAccess(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid access id: " + id);
}
access = jsonAccess.build(access);
manager.authManager().updateAccess(access);
return manager.serializer(g).writeAuthElement(access);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group") String group,
@QueryParam("target") String target,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] list belongs by group {} or target {}",
graph, group, target);
E.checkArgument(group == null || target == null,
"Can't pass both group and target at the same time");
HugeGraph g = graph(manager, graph);
List<HugeAccess> belongs;
if (group != null) {
Id id = UserAPI.parseId(group);
belongs = manager.authManager().listAccessByGroup(id, limit);
} else if (target != null) {
Id id = UserAPI.parseId(target);
belongs = manager.authManager().listAccessByTarget(id, limit);
} else {
belongs = manager.authManager().listAllAccess(limit);
}
return manager.serializer(g).writeAuthElements("accesses", belongs);
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get access: {}", graph, id);
HugeGraph g = graph(manager, graph);
HugeAccess access = manager.authManager().getAccess(UserAPI.parseId(id));
return manager.serializer(g).writeAuthElement(access);
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] delete access: {}", graph, id);
@SuppressWarnings("unused") // just check if the graph exists
HugeGraph g = graph(manager, graph);
try {
manager.authManager().deleteAccess(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid access id: " + id);
}
}
@JsonIgnoreProperties(value = {"id", "access_creator",
"access_create", "access_update"})
private static class JsonAccess implements Checkable {
@JsonProperty("group")
private String group;
@JsonProperty("target")
private String target;
@JsonProperty("access_permission")
private HugePermission permission;
@JsonProperty("access_description")
private String description;
public HugeAccess build(HugeAccess access) {
E.checkArgument(this.group == null ||
access.source().equals(UserAPI.parseId(this.group)),
"The group of access can't be updated");
E.checkArgument(this.target == null ||
access.target().equals(UserAPI.parseId(this.target)),
"The target of access can't be updated");
E.checkArgument(this.permission == null ||
access.permission().equals(this.permission),
"The permission of access can't be updated");
if (this.description != null) {
access.description(this.description);
}
return access;
}
public HugeAccess build() {
HugeAccess access = new HugeAccess(UserAPI.parseId(this.group),
UserAPI.parseId(this.target));
access.permission(this.permission);
access.description(this.description);
return access;
}
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.group,
"The group of access can't be null");
E.checkArgumentNotNull(this.target,
"The target of access can't be null");
E.checkArgumentNotNull(this.permission,
"The permission of access can't be null");
}
@Override
public void checkUpdate() {
E.checkArgumentNotNull(this.description,
"The description of access can't be null");
}
}
}

View File

@ -1,206 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.auth;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.inject.Singleton;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.auth.HugeBelong;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/auth/belongs")
@Singleton
@Tag(name = "BelongAPI")
public class BelongAPI extends API {
private static final Logger LOG = Log.logger(BelongAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonBelong jsonBelong) {
LOG.debug("Graph [{}] create belong: {}", graph, jsonBelong);
checkCreatingBody(jsonBelong);
HugeGraph g = graph(manager, graph);
HugeBelong belong = jsonBelong.build();
belong.id(manager.authManager().createBelong(belong));
return manager.serializer(g).writeAuthElement(belong);
}
@PUT
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
JsonBelong jsonBelong) {
LOG.debug("Graph [{}] update belong: {}", graph, jsonBelong);
checkUpdatingBody(jsonBelong);
HugeGraph g = graph(manager, graph);
HugeBelong belong;
try {
belong = manager.authManager().getBelong(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid belong id: " + id);
}
belong = jsonBelong.build(belong);
manager.authManager().updateBelong(belong);
return manager.serializer(g).writeAuthElement(belong);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("user") String user,
@QueryParam("group") String group,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] list belongs by user {} or group {}",
graph, user, group);
E.checkArgument(user == null || group == null,
"Can't pass both user and group at the same time");
HugeGraph g = graph(manager, graph);
List<HugeBelong> belongs;
if (user != null) {
Id id = UserAPI.parseId(user);
belongs = manager.authManager().listBelongByUser(id, limit);
} else if (group != null) {
Id id = UserAPI.parseId(group);
belongs = manager.authManager().listBelongByGroup(id, limit);
} else {
belongs = manager.authManager().listAllBelong(limit);
}
return manager.serializer(g).writeAuthElements("belongs", belongs);
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get belong: {}", graph, id);
HugeGraph g = graph(manager, graph);
HugeBelong belong = manager.authManager().getBelong(UserAPI.parseId(id));
return manager.serializer(g).writeAuthElement(belong);
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] delete belong: {}", graph, id);
@SuppressWarnings("unused") // just check if the graph exists
HugeGraph g = graph(manager, graph);
try {
manager.authManager().deleteBelong(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid belong id: " + id);
}
}
@JsonIgnoreProperties(value = {"id", "belong_creator",
"belong_create", "belong_update"})
private static class JsonBelong implements Checkable {
@JsonProperty("user")
private String user;
@JsonProperty("group")
private String group;
@JsonProperty("belong_description")
private String description;
public HugeBelong build(HugeBelong belong) {
E.checkArgument(this.user == null ||
belong.source().equals(UserAPI.parseId(this.user)),
"The user of belong can't be updated");
E.checkArgument(this.group == null ||
belong.target().equals(UserAPI.parseId(this.group)),
"The group of belong can't be updated");
if (this.description != null) {
belong.description(this.description);
}
return belong;
}
public HugeBelong build() {
HugeBelong belong = new HugeBelong(UserAPI.parseId(this.user),
UserAPI.parseId(this.group));
belong.description(this.description);
return belong;
}
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.user,
"The user of belong can't be null");
E.checkArgumentNotNull(this.group,
"The group of belong can't be null");
}
@Override
public void checkUpdate() {
E.checkArgumentNotNull(this.description,
"The description of belong can't be null");
}
}
}

View File

@ -1,183 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.auth;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.inject.Singleton;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.auth.HugeGroup;
import org.apache.hugegraph.backend.id.IdGenerator;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/auth/groups")
@Singleton
@Tag(name = "GroupAPI")
public class GroupAPI extends API {
private static final Logger LOG = Log.logger(GroupAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonGroup jsonGroup) {
LOG.debug("Graph [{}] create group: {}", graph, jsonGroup);
checkCreatingBody(jsonGroup);
HugeGraph g = graph(manager, graph);
HugeGroup group = jsonGroup.build();
group.id(manager.authManager().createGroup(group));
return manager.serializer(g).writeAuthElement(group);
}
@PUT
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
JsonGroup jsonGroup) {
LOG.debug("Graph [{}] update group: {}", graph, jsonGroup);
checkUpdatingBody(jsonGroup);
HugeGraph g = graph(manager, graph);
HugeGroup group;
try {
group = manager.authManager().getGroup(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid group id: " + id);
}
group = jsonGroup.build(group);
manager.authManager().updateGroup(group);
return manager.serializer(g).writeAuthElement(group);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] list groups", graph);
HugeGraph g = graph(manager, graph);
List<HugeGroup> groups = manager.authManager().listAllGroups(limit);
return manager.serializer(g).writeAuthElements("groups", groups);
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get group: {}", graph, id);
HugeGraph g = graph(manager, graph);
HugeGroup group = manager.authManager().getGroup(IdGenerator.of(id));
return manager.serializer(g).writeAuthElement(group);
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] delete group: {}", graph, id);
@SuppressWarnings("unused") // just check if the graph exists
HugeGraph g = graph(manager, graph);
try {
manager.authManager().deleteGroup(IdGenerator.of(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid group id: " + id);
}
}
@JsonIgnoreProperties(value = {"id", "group_creator",
"group_create", "group_update"})
private static class JsonGroup implements Checkable {
@JsonProperty("group_name")
private String name;
@JsonProperty("group_description")
private String description;
public HugeGroup build(HugeGroup group) {
E.checkArgument(this.name == null || group.name().equals(this.name),
"The name of group can't be updated");
if (this.description != null) {
group.description(this.description);
}
return group;
}
public HugeGroup build() {
HugeGroup group = new HugeGroup(this.name);
group.description(this.description);
return group;
}
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.name,
"The name of group can't be null");
}
@Override
public void checkUpdate() {
E.checkArgumentNotNull(this.description,
"The description of group can't be null");
}
}
}

View File

@ -1,160 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.auth;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import javax.security.sasl.AuthenticationException;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.NotAuthorizedException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.AuthenticationFilter;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.auth.AuthConstant;
import org.apache.hugegraph.auth.UserWithRole;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/auth")
@Singleton
@Tag(name = "LoginAPI")
public class LoginAPI extends API {
private static final Logger LOG = Log.logger(LoginAPI.class);
@POST
@Timed
@Path("login")
@Status(Status.OK)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String login(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonLogin jsonLogin) {
LOG.debug("Graph [{}] user login: {}", graph, jsonLogin);
checkCreatingBody(jsonLogin);
try {
String token = manager.authManager()
.loginUser(jsonLogin.name, jsonLogin.password);
HugeGraph g = graph(manager, graph);
return manager.serializer(g)
.writeMap(ImmutableMap.of("token", token));
} catch (AuthenticationException e) {
throw new NotAuthorizedException(e.getMessage(), e);
}
}
@DELETE
@Timed
@Path("logout")
@Status(Status.OK)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public void logout(@Context GraphManager manager,
@PathParam("graph") String graph,
@HeaderParam(HttpHeaders.AUTHORIZATION) String auth) {
E.checkArgument(StringUtils.isNotEmpty(auth),
"Request header Authorization must not be null");
LOG.debug("Graph [{}] user logout: {}", graph, auth);
if (!auth.startsWith(AuthenticationFilter.BEARER_TOKEN_PREFIX)) {
throw new BadRequestException(
"Only HTTP Bearer authentication is supported");
}
String token = auth.substring(AuthenticationFilter.BEARER_TOKEN_PREFIX
.length());
manager.authManager().logoutUser(token);
}
@GET
@Timed
@Path("verify")
@Status(Status.OK)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String verifyToken(@Context GraphManager manager,
@PathParam("graph") String graph,
@HeaderParam(HttpHeaders.AUTHORIZATION)
String token) {
E.checkArgument(StringUtils.isNotEmpty(token),
"Request header Authorization must not be null");
LOG.debug("Graph [{}] get user: {}", graph, token);
if (!token.startsWith(AuthenticationFilter.BEARER_TOKEN_PREFIX)) {
throw new BadRequestException(
"Only HTTP Bearer authentication is supported");
}
token = token.substring(AuthenticationFilter.BEARER_TOKEN_PREFIX
.length());
UserWithRole userWithRole = manager.authManager().validateUser(token);
HugeGraph g = graph(manager, graph);
return manager.serializer(g)
.writeMap(ImmutableMap.of(AuthConstant.TOKEN_USER_NAME,
userWithRole.username(),
AuthConstant.TOKEN_USER_ID,
userWithRole.userId()));
}
private static class JsonLogin implements Checkable {
@JsonProperty("user_name")
private String name;
@JsonProperty("user_password")
private String password;
@Override
public void checkCreate(boolean isBatch) {
E.checkArgument(!StringUtils.isEmpty(this.name),
"The name of user can't be null");
E.checkArgument(!StringUtils.isEmpty(this.password),
"The password of user can't be null");
}
@Override
public void checkUpdate() {
// pass
}
}
}

View File

@ -1,203 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.auth;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.auth.HugeTarget;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/auth/targets")
@Singleton
@Tag(name = "TargetAPI")
public class TargetAPI extends API {
private static final Logger LOG = Log.logger(TargetAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonTarget jsonTarget) {
LOG.debug("Graph [{}] create target: {}", graph, jsonTarget);
checkCreatingBody(jsonTarget);
HugeGraph g = graph(manager, graph);
HugeTarget target = jsonTarget.build();
target.id(manager.authManager().createTarget(target));
return manager.serializer(g).writeAuthElement(target);
}
@PUT
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
JsonTarget jsonTarget) {
LOG.debug("Graph [{}] update target: {}", graph, jsonTarget);
checkUpdatingBody(jsonTarget);
HugeGraph g = graph(manager, graph);
HugeTarget target;
try {
target = manager.authManager().getTarget(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid target id: " + id);
}
target = jsonTarget.build(target);
manager.authManager().updateTarget(target);
return manager.serializer(g).writeAuthElement(target);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] list targets", graph);
HugeGraph g = graph(manager, graph);
List<HugeTarget> targets = manager.authManager().listAllTargets(limit);
return manager.serializer(g).writeAuthElements("targets", targets);
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get target: {}", graph, id);
HugeGraph g = graph(manager, graph);
HugeTarget target = manager.authManager().getTarget(UserAPI.parseId(id));
return manager.serializer(g).writeAuthElement(target);
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] delete target: {}", graph, id);
@SuppressWarnings("unused") // just check if the graph exists
HugeGraph g = graph(manager, graph);
try {
manager.authManager().deleteTarget(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid target id: " + id);
}
}
@JsonIgnoreProperties(value = {"id", "target_creator",
"target_create", "target_update"})
private static class JsonTarget implements Checkable {
@JsonProperty("target_name")
private String name;
@JsonProperty("target_graph")
private String graph;
@JsonProperty("target_url")
private String url;
@JsonProperty("target_resources") // error when List<HugeResource>
private List<Map<String, Object>> resources;
public HugeTarget build(HugeTarget target) {
E.checkArgument(this.name == null ||
target.name().equals(this.name),
"The name of target can't be updated");
E.checkArgument(this.graph == null ||
target.graph().equals(this.graph),
"The graph of target can't be updated");
if (this.url != null) {
target.url(this.url);
}
if (this.resources != null) {
target.resources(JsonUtil.toJson(this.resources));
}
return target;
}
public HugeTarget build() {
HugeTarget target = new HugeTarget(this.name, this.graph, this.url);
if (this.resources != null) {
target.resources(JsonUtil.toJson(this.resources));
}
return target;
}
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.name,
"The name of target can't be null");
E.checkArgumentNotNull(this.graph,
"The graph of target can't be null");
E.checkArgumentNotNull(this.url,
"The url of target can't be null");
}
@Override
public void checkUpdate() {
E.checkArgument(this.url != null ||
this.resources != null,
"Expect one of target url/resources");
}
}
}

View File

@ -1,234 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.auth;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.auth.HugeUser;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.id.IdGenerator;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.util.StringEncoding;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/auth/users")
@Singleton
@Tag(name = "UserAPI")
public class UserAPI extends API {
private static final Logger LOG = Log.logger(UserAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonUser jsonUser) {
LOG.debug("Graph [{}] create user: {}", graph, jsonUser);
checkCreatingBody(jsonUser);
HugeGraph g = graph(manager, graph);
HugeUser user = jsonUser.build();
user.id(manager.authManager().createUser(user));
return manager.serializer(g).writeAuthElement(user);
}
@PUT
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
JsonUser jsonUser) {
LOG.debug("Graph [{}] update user: {}", graph, jsonUser);
checkUpdatingBody(jsonUser);
HugeGraph g = graph(manager, graph);
HugeUser user;
try {
user = manager.authManager().getUser(UserAPI.parseId(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid user id: " + id);
}
user = jsonUser.build(user);
manager.authManager().updateUser(user);
return manager.serializer(g).writeAuthElement(user);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] list users", graph);
HugeGraph g = graph(manager, graph);
List<HugeUser> users = manager.authManager().listAllUsers(limit);
return manager.serializer(g).writeAuthElements("users", users);
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get user: {}", graph, id);
HugeGraph g = graph(manager, graph);
HugeUser user = manager.authManager().getUser(IdGenerator.of(id));
return manager.serializer(g).writeAuthElement(user);
}
@GET
@Timed
@Path("{id}/role")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String role(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get user role: {}", graph, id);
@SuppressWarnings("unused") // just check if the graph exists
HugeGraph g = graph(manager, graph);
HugeUser user = manager.authManager().getUser(IdGenerator.of(id));
return manager.authManager().rolePermission(user).toJson();
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] delete user: {}", graph, id);
@SuppressWarnings("unused") // just check if the graph exists
HugeGraph g = graph(manager, graph);
try {
manager.authManager().deleteUser(IdGenerator.of(id));
} catch (NotFoundException e) {
throw new IllegalArgumentException("Invalid user id: " + id);
}
}
protected static Id parseId(String id) {
return IdGenerator.of(id);
}
@JsonIgnoreProperties(value = {"id", "user_creator",
"user_create", "user_update"})
private static class JsonUser implements Checkable {
@JsonProperty("user_name")
private String name;
@JsonProperty("user_password")
private String password;
@JsonProperty("user_phone")
private String phone;
@JsonProperty("user_email")
private String email;
@JsonProperty("user_avatar")
private String avatar;
@JsonProperty("user_description")
private String description;
public HugeUser build(HugeUser user) {
E.checkArgument(this.name == null || user.name().equals(this.name),
"The name of user can't be updated");
if (this.password != null) {
user.password(StringEncoding.hashPassword(this.password));
}
if (this.phone != null) {
user.phone(this.phone);
}
if (this.email != null) {
user.email(this.email);
}
if (this.avatar != null) {
user.avatar(this.avatar);
}
if (this.description != null) {
user.description(this.description);
}
return user;
}
public HugeUser build() {
HugeUser user = new HugeUser(this.name);
user.password(StringEncoding.hashPassword(this.password));
user.phone(this.phone);
user.email(this.email);
user.avatar(this.avatar);
user.description(this.description);
return user;
}
@Override
public void checkCreate(boolean isBatch) {
E.checkArgument(!StringUtils.isEmpty(this.name),
"The name of user can't be null");
E.checkArgument(!StringUtils.isEmpty(this.password),
"The password of user can't be null");
}
@Override
public void checkUpdate() {
E.checkArgument(!StringUtils.isEmpty(this.password) ||
this.phone != null ||
this.email != null ||
this.avatar != null,
"Expect one of user password/phone/email/avatar]");
}
}
}

View File

@ -1,291 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.filter;
import java.io.IOException;
import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.annotation.Priority;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotAuthorizedException;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang3.StringUtils;
import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.utils.Charsets;
import org.slf4j.Logger;
import org.apache.hugegraph.auth.HugeAuthenticator;
import org.apache.hugegraph.auth.HugeAuthenticator.RequiredPerm;
import org.apache.hugegraph.auth.HugeAuthenticator.RolePerm;
import org.apache.hugegraph.auth.HugeAuthenticator.User;
import org.apache.hugegraph.auth.RolePermission;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.google.common.collect.ImmutableList;
@Provider
@PreMatching
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
public static final String BASIC_AUTH_PREFIX = "Basic ";
public static final String BEARER_TOKEN_PREFIX = "Bearer ";
private static final Logger LOG = Log.logger(AuthenticationFilter.class);
private static final List<String> WHITE_API_LIST = ImmutableList.of(
"auth/login",
"versions"
);
@Context
private jakarta.inject.Provider<GraphManager> managerProvider;
@Context
private jakarta.inject.Provider<Request> requestProvider;
@Override
public void filter(ContainerRequestContext context) throws IOException {
if (AuthenticationFilter.isWhiteAPI(context)) {
return;
}
User user = this.authenticate(context);
Authorizer authorizer = new Authorizer(user, context.getUriInfo());
context.setSecurityContext(authorizer);
}
protected User authenticate(ContainerRequestContext context) {
GraphManager manager = this.managerProvider.get();
E.checkState(manager != null, "Context GraphManager is absent");
if (!manager.requireAuthentication()) {
// Return anonymous user with admin role if disable authentication
return User.ANONYMOUS;
}
// Get peer info
Request request = this.requestProvider.get();
String peer = null;
String path = null;
if (request != null) {
peer = request.getRemoteAddr() + ":" + request.getRemotePort();
path = request.getRequestURI();
}
Map<String, String> credentials = new HashMap<>();
// Extract authentication credentials
String auth = context.getHeaderString(HttpHeaders.AUTHORIZATION);
if (auth == null) {
throw new NotAuthorizedException(
"Authentication credentials are required",
"Missing authentication credentials");
}
if (auth.startsWith(BASIC_AUTH_PREFIX)) {
auth = auth.substring(BASIC_AUTH_PREFIX.length());
auth = new String(DatatypeConverter.parseBase64Binary(auth),
Charsets.ASCII_CHARSET);
String[] values = auth.split(":");
if (values.length != 2) {
throw new BadRequestException(
"Invalid syntax for username and password");
}
final String username = values[0];
final String password = values[1];
if (StringUtils.isEmpty(username) ||
StringUtils.isEmpty(password)) {
throw new BadRequestException(
"Invalid syntax for username and password");
}
credentials.put(HugeAuthenticator.KEY_USERNAME, username);
credentials.put(HugeAuthenticator.KEY_PASSWORD, password);
} else if (auth.startsWith(BEARER_TOKEN_PREFIX)) {
String token = auth.substring(BEARER_TOKEN_PREFIX.length());
credentials.put(HugeAuthenticator.KEY_TOKEN, token);
} else {
throw new BadRequestException(
"Only HTTP Basic or Bearer authentication is supported");
}
credentials.put(HugeAuthenticator.KEY_ADDRESS, peer);
credentials.put(HugeAuthenticator.KEY_PATH, path);
// Validate the extracted credentials
try {
return manager.authenticate(credentials);
} catch (AuthenticationException e) {
throw new NotAuthorizedException("Authentication failed",
e.getMessage());
}
}
public static class Authorizer implements SecurityContext {
private final UriInfo uri;
private final User user;
private final Principal principal;
public Authorizer(final User user, final UriInfo uri) {
E.checkNotNull(user, "user");
E.checkNotNull(uri, "uri");
this.uri = uri;
this.user = user;
this.principal = new UserPrincipal();
}
public String username() {
return this.user.username();
}
public RolePermission role() {
return this.user.role();
}
@Override
public Principal getUserPrincipal() {
return this.principal;
}
@Override
public boolean isUserInRole(String required) {
if (required.equals(HugeAuthenticator.KEY_DYNAMIC)) {
// Let the resource itself determine dynamically
return true;
} else {
return this.matchPermission(required);
}
}
@Override
public boolean isSecure() {
return "https".equals(this.uri.getRequestUri().getScheme());
}
@Override
public String getAuthenticationScheme() {
return SecurityContext.BASIC_AUTH;
}
private boolean matchPermission(String required) {
boolean valid;
RequiredPerm requiredPerm;
if (!required.startsWith(HugeAuthenticator.KEY_OWNER)) {
// Permission format like: "admin"
requiredPerm = new RequiredPerm();
requiredPerm.owner(required);
} else {
// The required like: $owner=graph1 $action=vertex_write
requiredPerm = RequiredPerm.fromPermission(required);
/*
* Replace owner value(it may be a variable) if the permission
* format like: "$owner=$graph $action=vertex_write"
*/
String owner = requiredPerm.owner();
if (owner.startsWith(HugeAuthenticator.VAR_PREFIX)) {
// Replace `$graph` with graph name like "graph1"
int prefixLen = HugeAuthenticator.VAR_PREFIX.length();
assert owner.length() > prefixLen;
owner = owner.substring(prefixLen);
owner = this.getPathParameter(owner);
requiredPerm.owner(owner);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Verify permission {} {} for user '{}' with role {}",
requiredPerm.action().string(),
requiredPerm.resourceObject(),
this.user.username(), this.user.role());
}
// verify role permission
valid = RolePerm.match(this.role(), requiredPerm);
if (!valid && LOG.isInfoEnabled() &&
!required.equals(HugeAuthenticator.USER_ADMIN)) {
LOG.info("User '{}' is denied to {} {}",
this.user.username(), requiredPerm.action().string(),
requiredPerm.resourceObject());
}
return valid;
}
private String getPathParameter(String key) {
List<String> params = this.uri.getPathParameters().get(key);
E.checkState(params != null && params.size() == 1,
"There is no matched path parameter: '%s'", key);
return params.get(0);
}
private final class UserPrincipal implements Principal {
@Override
public String getName() {
return Authorizer.this.user.getName();
}
@Override
public String toString() {
return Authorizer.this.user.toString();
}
@Override
public int hashCode() {
return Authorizer.this.user.hashCode();
}
@Override
public boolean equals(Object obj) {
return Authorizer.this.user.equals(obj);
}
}
}
public static boolean isWhiteAPI(ContainerRequestContext context) {
String path = context.getUriInfo().getPath();
for (String whiteApi : WHITE_API_LIST) {
if (path.endsWith(whiteApi)) {
return true;
}
}
return false;
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.filter;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.zip.GZIPInputStream;
import jakarta.inject.Singleton;
import jakarta.ws.rs.NameBinding;
import jakarta.ws.rs.ext.Provider;
import jakarta.ws.rs.ext.ReaderInterceptor;
import jakarta.ws.rs.ext.ReaderInterceptorContext;
@Provider
@Singleton
@DecompressInterceptor.Decompress
public class DecompressInterceptor implements ReaderInterceptor {
public static final String GZIP = "gzip";
@Override
public Object aroundReadFrom(ReaderInterceptorContext context)
throws IOException {
// NOTE: Currently we just support GZIP
String encoding = context.getHeaders().getFirst("Content-Encoding");
if (!GZIP.equalsIgnoreCase(encoding)) {
return context.proceed();
}
context.setInputStream(new GZIPInputStream(context.getInputStream()));
return context.proceed();
}
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Decompress {
String value() default GZIP;
}
}

View File

@ -1,110 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.filter;
import java.util.List;
import java.util.Set;
import jakarta.inject.Singleton;
import jakarta.ws.rs.ServiceUnavailableException;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.PathSegment;
import jakarta.ws.rs.ext.Provider;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.config.ServerOptions;
import org.apache.hugegraph.define.WorkLoad;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.E;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.RateLimiter;
@Provider
@Singleton
@PreMatching
public class LoadDetectFilter implements ContainerRequestFilter {
private static final Set<String> WHITE_API_LIST = ImmutableSet.of(
"",
"apis",
"metrics",
"versions"
);
// Call gc every 30+ seconds if memory is low and request frequently
private static final RateLimiter GC_RATE_LIMITER =
RateLimiter.create(1.0 / 30);
@Context
private jakarta.inject.Provider<HugeConfig> configProvider;
@Context
private jakarta.inject.Provider<WorkLoad> loadProvider;
@Override
public void filter(ContainerRequestContext context) {
if (LoadDetectFilter.isWhiteAPI(context)) {
return;
}
HugeConfig config = this.configProvider.get();
int maxWorkerThreads = config.get(ServerOptions.MAX_WORKER_THREADS);
WorkLoad load = this.loadProvider.get();
// There will be a thread doesn't work, dedicated to statistics
if (load.incrementAndGet() >= maxWorkerThreads) {
throw new ServiceUnavailableException(String.format(
"The server is too busy to process the request, " +
"you can config %s to adjust it or try again later",
ServerOptions.MAX_WORKER_THREADS.name()));
}
long minFreeMemory = config.get(ServerOptions.MIN_FREE_MEMORY);
long allocatedMem = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
long presumableFreeMem = (Runtime.getRuntime().maxMemory() -
allocatedMem) / Bytes.MB;
if (presumableFreeMem < minFreeMemory) {
gcIfNeeded();
throw new ServiceUnavailableException(String.format(
"The server available memory %s(MB) is below than " +
"threshold %s(MB) and can't process the request, " +
"you can config %s to adjust it or try again later",
presumableFreeMem, minFreeMemory,
ServerOptions.MIN_FREE_MEMORY.name()));
}
}
public static boolean isWhiteAPI(ContainerRequestContext context) {
List<PathSegment> segments = context.getUriInfo().getPathSegments();
E.checkArgument(segments.size() > 0, "Invalid request uri '%s'",
context.getUriInfo().getPath());
String rootPath = segments.get(0).getPath();
return WHITE_API_LIST.contains(rootPath);
}
private static void gcIfNeeded() {
if (GC_RATE_LIMITER.tryAcquire(1)) {
System.gc();
}
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.filter;
import jakarta.inject.Singleton;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.ext.Provider;
import org.apache.hugegraph.define.WorkLoad;
@Provider
@Singleton
public class LoadReleaseFilter implements ContainerResponseFilter {
@Context
private jakarta.inject.Provider<WorkLoad> loadProvider;
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) {
if (LoadDetectFilter.isWhiteAPI(requestContext)) {
return;
}
WorkLoad load = this.loadProvider.get();
load.decrementAndGet();
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.filter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import jakarta.ws.rs.NameBinding;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.ext.Provider;
@Provider
public class StatusFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext)
throws IOException {
if (responseContext.getStatus() == 200) {
for (Annotation i : responseContext.getEntityAnnotations()) {
if (i instanceof Status) {
responseContext.setStatus(((Status) i).value());
break;
}
}
}
}
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
int OK = 200;
int CREATED = 201;
int ACCEPTED = 202;
int value();
}
}

View File

@ -1,574 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.util.function.TriFunction;
import org.apache.hugegraph.config.ServerOptions;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.UpdateStrategy;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.CompressInterceptor.Compress;
import org.apache.hugegraph.api.filter.DecompressInterceptor.Decompress;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.EdgeId;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.ConditionQuery;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.structure.HugeEdge;
import org.apache.hugegraph.structure.HugeVertex;
import org.apache.hugegraph.traversal.optimize.QueryHolder;
import org.apache.hugegraph.traversal.optimize.TraversalUtil;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/graph/edges")
@Singleton
@Tag(name = "EdgeAPI")
public class EdgeAPI extends BatchAPI {
private static final Logger LOG = Log.logger(EdgeAPI.class);
@POST
@Timed(name = "single-create")
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_write"})
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonEdge jsonEdge) {
LOG.debug("Graph [{}] create edge: {}", graph, jsonEdge);
checkCreatingBody(jsonEdge);
HugeGraph g = graph(manager, graph);
if (jsonEdge.sourceLabel != null && jsonEdge.targetLabel != null) {
/*
* NOTE: If the vertex id is correct but label not match with id,
* we allow to create it here
*/
vertexLabel(g, jsonEdge.sourceLabel,
"Invalid source vertex label '%s'");
vertexLabel(g, jsonEdge.targetLabel,
"Invalid target vertex label '%s'");
}
Vertex srcVertex = getVertex(g, jsonEdge.source, jsonEdge.sourceLabel);
Vertex tgtVertex = getVertex(g, jsonEdge.target, jsonEdge.targetLabel);
Edge edge = commit(g, () -> {
return srcVertex.addEdge(jsonEdge.label, tgtVertex,
jsonEdge.properties());
});
return manager.serializer(g).writeEdge(edge);
}
@POST
@Timed(name = "batch-create")
@Decompress
@Path("batch")
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_write"})
public String create(@Context HugeConfig config,
@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("check_vertex")
@DefaultValue("true") boolean checkVertex,
List<JsonEdge> jsonEdges) {
LOG.debug("Graph [{}] create edges: {}", graph, jsonEdges);
checkCreatingBody(jsonEdges);
checkBatchSize(config, jsonEdges);
HugeGraph g = graph(manager, graph);
TriFunction<HugeGraph, Object, String, Vertex> getVertex =
checkVertex ? EdgeAPI::getVertex : EdgeAPI::newVertex;
return this.commit(config, g, jsonEdges.size(), () -> {
List<Id> ids = new ArrayList<>(jsonEdges.size());
for (JsonEdge jsonEdge : jsonEdges) {
/*
* NOTE: If the query param 'checkVertex' is false,
* then the label is correct and not matched id,
* it will be allowed currently
*/
Vertex srcVertex = getVertex.apply(g, jsonEdge.source,
jsonEdge.sourceLabel);
Vertex tgtVertex = getVertex.apply(g, jsonEdge.target,
jsonEdge.targetLabel);
Edge edge = srcVertex.addEdge(jsonEdge.label, tgtVertex,
jsonEdge.properties());
ids.add((Id) edge.id());
}
return manager.serializer(g).writeIds(ids);
});
}
/**
* Batch update steps are same like vertices
*/
@PUT
@Timed(name = "batch-update")
@Decompress
@Path("batch")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_write"})
public String update(@Context HugeConfig config,
@Context GraphManager manager,
@PathParam("graph") String graph,
BatchEdgeRequest req) {
BatchEdgeRequest.checkUpdate(req);
LOG.debug("Graph [{}] update edges: {}", graph, req);
checkUpdatingBody(req.jsonEdges);
checkBatchSize(config, req.jsonEdges);
HugeGraph g = graph(manager, graph);
Map<Id, JsonEdge> map = new HashMap<>(req.jsonEdges.size());
TriFunction<HugeGraph, Object, String, Vertex> getVertex =
req.checkVertex ? EdgeAPI::getVertex : EdgeAPI::newVertex;
return this.commit(config, g, map.size(), () -> {
// 1.Put all newEdges' properties into map (combine first)
req.jsonEdges.forEach(newEdge -> {
Id newEdgeId = getEdgeId(graph(manager, graph), newEdge);
JsonEdge oldEdge = map.get(newEdgeId);
this.updateExistElement(oldEdge, newEdge,
req.updateStrategies);
map.put(newEdgeId, newEdge);
});
// 2.Get all oldEdges and update with new ones
Object[] ids = map.keySet().toArray();
Iterator<Edge> oldEdges = g.edges(ids);
oldEdges.forEachRemaining(oldEdge -> {
JsonEdge newEdge = map.get(oldEdge.id());
this.updateExistElement(g, oldEdge, newEdge,
req.updateStrategies);
});
// 3.Add all finalEdges
List<Edge> edges = new ArrayList<>(map.size());
map.values().forEach(finalEdge -> {
Vertex srcVertex = getVertex.apply(g, finalEdge.source,
finalEdge.sourceLabel);
Vertex tgtVertex = getVertex.apply(g, finalEdge.target,
finalEdge.targetLabel);
edges.add(srcVertex.addEdge(finalEdge.label, tgtVertex,
finalEdge.properties()));
});
// If return ids, the ids.size() maybe different with the origins'
return manager.serializer(g).writeEdges(edges.iterator(), false);
});
}
@PUT
@Timed(name = "single-update")
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_write"})
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
@QueryParam("action") String action,
JsonEdge jsonEdge) {
LOG.debug("Graph [{}] update edge: {}", graph, jsonEdge);
checkUpdatingBody(jsonEdge);
if (jsonEdge.id != null) {
E.checkArgument(id.equals(jsonEdge.id),
"The ids are different between url and " +
"request body ('%s' != '%s')", id, jsonEdge.id);
}
// Parse action param
boolean append = checkAndParseAction(action);
HugeGraph g = graph(manager, graph);
HugeEdge edge = (HugeEdge) g.edge(id);
EdgeLabel edgeLabel = edge.schemaLabel();
for (String key : jsonEdge.properties.keySet()) {
PropertyKey pkey = g.propertyKey(key);
E.checkArgument(edgeLabel.properties().contains(pkey.id()),
"Can't update property for edge '%s' because " +
"there is no property key '%s' in its edge label",
id, key);
}
commit(g, () -> updateProperties(edge, jsonEdge, append));
return manager.serializer(g).writeEdge(edge);
}
@GET
@Timed
@Compress
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("vertex_id") String vertexId,
@QueryParam("direction") String direction,
@QueryParam("label") String label,
@QueryParam("properties") String properties,
@QueryParam("keep_start_p")
@DefaultValue("false") boolean keepStartP,
@QueryParam("offset") @DefaultValue("0") long offset,
@QueryParam("page") String page,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] query edges by vertex: {}, direction: {}, " +
"label: {}, properties: {}, offset: {}, page: {}, limit: {}",
graph, vertexId, direction,
label, properties, offset, page, limit);
Map<String, Object> props = parseProperties(properties);
if (page != null) {
E.checkArgument(offset == 0,
"Not support querying edges based on paging " +
"and offset together");
}
Id vertex = VertexAPI.checkAndParseVertexId(vertexId);
Direction dir = parseDirection(direction);
HugeGraph g = graph(manager, graph);
GraphTraversal<?, Edge> traversal;
if (vertex != null) {
if (label != null) {
traversal = g.traversal().V(vertex).toE(dir, label);
} else {
traversal = g.traversal().V(vertex).toE(dir);
}
} else {
if (label != null) {
traversal = g.traversal().E().hasLabel(label);
} else {
traversal = g.traversal().E();
}
}
// Convert relational operator like P.gt()/P.lt()
for (Map.Entry<String, Object> prop : props.entrySet()) {
Object value = prop.getValue();
if (!keepStartP && value instanceof String &&
((String) value).startsWith(TraversalUtil.P_CALL)) {
prop.setValue(TraversalUtil.parsePredicate((String) value));
}
}
for (Map.Entry<String, Object> entry : props.entrySet()) {
traversal = traversal.has(entry.getKey(), entry.getValue());
}
if (page == null) {
traversal = traversal.range(offset, offset + limit);
} else {
traversal = traversal.has(QueryHolder.SYSPROP_PAGE, page)
.limit(limit);
}
try {
return manager.serializer(g).writeEdges(traversal, page != null);
} finally {
if (g.tx().isOpen()) {
g.tx().close();
}
}
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_read"})
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id) {
LOG.debug("Graph [{}] get edge by id '{}'", graph, id);
HugeGraph g = graph(manager, graph);
try {
Edge edge = g.edge(id);
return manager.serializer(g).writeEdge(edge);
} finally {
if (g.tx().isOpen()) {
g.tx().close();
}
}
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@RolesAllowed({"admin", "$owner=$graph $action=edge_delete"})
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String id,
@QueryParam("label") String label) {
LOG.debug("Graph [{}] remove vertex by id '{}'", graph, id);
HugeGraph g = graph(manager, graph);
commit(g, () -> {
try {
g.removeEdge(label, id);
} catch (NotFoundException e) {
throw new IllegalArgumentException(String.format(
"No such edge with id: '%s', %s", id, e));
} catch (NoSuchElementException e) {
throw new IllegalArgumentException(String.format(
"No such edge with id: '%s'", id));
}
});
}
private static void checkBatchSize(HugeConfig config,
List<JsonEdge> edges) {
int max = config.get(ServerOptions.MAX_EDGES_PER_BATCH);
if (edges.size() > max) {
throw new IllegalArgumentException(String.format(
"Too many edges for one time post, " +
"the maximum number is '%s'", max));
}
if (edges.size() == 0) {
throw new IllegalArgumentException(
"The number of edges can't be 0");
}
}
private static Vertex getVertex(HugeGraph graph,
Object id, String label) {
HugeVertex vertex;
try {
vertex = (HugeVertex) graph.vertices(id).next();
} catch (NoSuchElementException e) {
throw new IllegalArgumentException(String.format(
"Invalid vertex id '%s'", id));
}
if (label != null && !vertex.label().equals(label)) {
throw new IllegalArgumentException(String.format(
"The label of vertex '%s' is unmatched, users expect " +
"label '%s', actual label stored is '%s'",
id, label, vertex.label()));
}
// Clone a new vertex to support multi-thread access
return vertex.copy();
}
private static Vertex newVertex(HugeGraph g, Object id, String label) {
VertexLabel vl = vertexLabel(g, label, "Invalid vertex label '%s'");
Id idValue = HugeVertex.getIdValue(id);
return new HugeVertex(g, idValue, vl);
}
private static VertexLabel vertexLabel(HugeGraph graph, String label,
String message) {
try {
// NOTE: don't use SchemaManager because it will throw 404
return graph.vertexLabel(label);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(String.format(message, label));
}
}
public static Direction parseDirection(String direction) {
if (direction == null || direction.isEmpty()) {
return Direction.BOTH;
}
try {
return Direction.valueOf(direction);
} catch (Exception e) {
throw new IllegalArgumentException(String.format(
"Direction value must be in [OUT, IN, BOTH], " +
"but got '%s'", direction));
}
}
private Id getEdgeId(HugeGraph g, JsonEdge newEdge) {
String sortKeys = "";
Id labelId = g.edgeLabel(newEdge.label).id();
List<Id> sortKeyIds = g.edgeLabel(labelId).sortKeys();
if (!sortKeyIds.isEmpty()) {
List<Object> sortKeyValues = new ArrayList<>(sortKeyIds.size());
sortKeyIds.forEach(skId -> {
PropertyKey pk = g.propertyKey(skId);
String sortKey = pk.name();
Object sortKeyValue = newEdge.properties.get(sortKey);
E.checkArgument(sortKeyValue != null,
"The value of sort key '%s' can't be null",
sortKey);
sortKeyValue = pk.validValueOrThrow(sortKeyValue);
sortKeyValues.add(sortKeyValue);
});
sortKeys = ConditionQuery.concatValues(sortKeyValues);
}
EdgeId edgeId = new EdgeId(HugeVertex.getIdValue(newEdge.source),
Directions.OUT, labelId, sortKeys,
HugeVertex.getIdValue(newEdge.target));
if (newEdge.id != null) {
E.checkArgument(edgeId.asString().equals(newEdge.id),
"The ids are different between server and " +
"request body ('%s' != '%s'). And note the sort " +
"key values should either be null or equal to " +
"the origin value when specified edge id",
edgeId, newEdge.id);
}
return edgeId;
}
protected static class BatchEdgeRequest {
@JsonProperty("edges")
public List<JsonEdge> jsonEdges;
@JsonProperty("update_strategies")
public Map<String, UpdateStrategy> updateStrategies;
@JsonProperty("check_vertex")
public boolean checkVertex = false;
@JsonProperty("create_if_not_exist")
public boolean createIfNotExist = true;
private static void checkUpdate(BatchEdgeRequest req) {
E.checkArgumentNotNull(req, "BatchEdgeRequest can't be null");
E.checkArgumentNotNull(req.jsonEdges,
"Parameter 'edges' can't be null");
E.checkArgument(req.updateStrategies != null &&
!req.updateStrategies.isEmpty(),
"Parameter 'update_strategies' can't be empty");
E.checkArgument(req.createIfNotExist == true,
"Parameter 'create_if_not_exist' " +
"dose not support false now");
}
@Override
public String toString() {
return String.format("BatchEdgeRequest{jsonEdges=%s," +
"updateStrategies=%s," +
"checkVertex=%s,createIfNotExist=%s}",
this.jsonEdges, this.updateStrategies,
this.checkVertex, this.createIfNotExist);
}
}
private static class JsonEdge extends JsonElement {
@JsonProperty("outV")
public Object source;
@JsonProperty("outVLabel")
public String sourceLabel;
@JsonProperty("inV")
public Object target;
@JsonProperty("inVLabel")
public String targetLabel;
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.label, "Expect the label of edge");
E.checkArgumentNotNull(this.source, "Expect source vertex id");
E.checkArgumentNotNull(this.target, "Expect target vertex id");
if (isBatch) {
E.checkArgumentNotNull(this.sourceLabel,
"Expect source vertex label");
E.checkArgumentNotNull(this.targetLabel,
"Expect target vertex label");
} else {
E.checkArgument(this.sourceLabel == null &&
this.targetLabel == null ||
this.sourceLabel != null &&
this.targetLabel != null,
"The both source and target vertex label " +
"are either passed in, or not passed in");
}
this.checkUpdate();
}
@Override
public void checkUpdate() {
E.checkArgumentNotNull(this.properties,
"The properties of edge can't be null");
for (Map.Entry<String, Object> entry : this.properties.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
E.checkArgumentNotNull(value, "Not allowed to set value of " +
"property '%s' to null for edge '%s'",
key, this.id);
}
}
@Override
public Object[] properties() {
return API.properties(this.properties);
}
@Override
public String toString() {
return String.format("JsonEdge{label=%s, " +
"source-vertex=%s, source-vertex-label=%s, " +
"target-vertex=%s, target-vertex-label=%s, " +
"properties=%s}",
this.label, this.source, this.sourceLabel,
this.target, this.targetLabel,
this.properties);
}
}
}

View File

@ -1,479 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.graph;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.config.ServerOptions;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.UpdateStrategy;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.CompressInterceptor.Compress;
import org.apache.hugegraph.api.filter.DecompressInterceptor.Decompress;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.id.SplicingIdGenerator;
import org.apache.hugegraph.backend.query.ConditionQuery;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.structure.HugeVertex;
import org.apache.hugegraph.traversal.optimize.QueryHolder;
import org.apache.hugegraph.traversal.optimize.Text;
import org.apache.hugegraph.traversal.optimize.TraversalUtil;
import org.apache.hugegraph.type.define.IdStrategy;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/graph/vertices")
@Singleton
@Tag(name = "VertexAPI")
public class VertexAPI extends BatchAPI {
private static final Logger LOG = Log.logger(VertexAPI.class);
@POST
@Timed(name = "single-create")
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_write"})
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonVertex jsonVertex) {
LOG.debug("Graph [{}] create vertex: {}", graph, jsonVertex);
checkCreatingBody(jsonVertex);
HugeGraph g = graph(manager, graph);
Vertex vertex = commit(g, () -> g.addVertex(jsonVertex.properties()));
return manager.serializer(g).writeVertex(vertex);
}
@POST
@Timed(name = "batch-create")
@Decompress
@Path("batch")
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_write"})
public String create(@Context HugeConfig config,
@Context GraphManager manager,
@PathParam("graph") String graph,
List<JsonVertex> jsonVertices) {
LOG.debug("Graph [{}] create vertices: {}", graph, jsonVertices);
checkCreatingBody(jsonVertices);
checkBatchSize(config, jsonVertices);
HugeGraph g = graph(manager, graph);
return this.commit(config, g, jsonVertices.size(), () -> {
List<Id> ids = new ArrayList<>(jsonVertices.size());
for (JsonVertex vertex : jsonVertices) {
ids.add((Id) g.addVertex(vertex.properties()).id());
}
return manager.serializer(g).writeIds(ids);
});
}
/**
* Batch update steps like:
* 1. Get all newVertices' ID &amp; combine first
* 2. Get all oldVertices &amp; update
* 3. Add the final vertex together
*/
@PUT
@Timed(name = "batch-update")
@Decompress
@Path("batch")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_write"})
public String update(@Context HugeConfig config,
@Context GraphManager manager,
@PathParam("graph") String graph,
BatchVertexRequest req) {
BatchVertexRequest.checkUpdate(req);
LOG.debug("Graph [{}] update vertices: {}", graph, req);
checkUpdatingBody(req.jsonVertices);
checkBatchSize(config, req.jsonVertices);
HugeGraph g = graph(manager, graph);
Map<Id, JsonVertex> map = new HashMap<>(req.jsonVertices.size());
return this.commit(config, g, map.size(), () -> {
/*
* 1.Put all newVertices' properties into map (combine first)
* - Consider primary-key & user-define ID mode first
*/
req.jsonVertices.forEach(newVertex -> {
Id newVertexId = getVertexId(g, newVertex);
JsonVertex oldVertex = map.get(newVertexId);
this.updateExistElement(oldVertex, newVertex,
req.updateStrategies);
map.put(newVertexId, newVertex);
});
// 2.Get all oldVertices and update with new vertices
Object[] ids = map.keySet().toArray();
Iterator<Vertex> oldVertices = g.vertices(ids);
oldVertices.forEachRemaining(oldVertex -> {
JsonVertex newVertex = map.get(oldVertex.id());
this.updateExistElement(g, oldVertex, newVertex,
req.updateStrategies);
});
// 3.Add finalVertices and return them
List<Vertex> vertices = new ArrayList<>(map.size());
map.values().forEach(finalVertex -> {
vertices.add(g.addVertex(finalVertex.properties()));
});
// If return ids, the ids.size() maybe different with the origins'
return manager.serializer(g)
.writeVertices(vertices.iterator(), false);
});
}
@PUT
@Timed(name = "single-update")
@Path("{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_write"})
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String idValue,
@QueryParam("action") String action,
JsonVertex jsonVertex) {
LOG.debug("Graph [{}] update vertex: {}", graph, jsonVertex);
checkUpdatingBody(jsonVertex);
Id id = checkAndParseVertexId(idValue);
// Parse action param
boolean append = checkAndParseAction(action);
HugeGraph g = graph(manager, graph);
HugeVertex vertex = (HugeVertex) g.vertex(id);
VertexLabel vertexLabel = vertex.schemaLabel();
for (String key : jsonVertex.properties.keySet()) {
PropertyKey pkey = g.propertyKey(key);
E.checkArgument(vertexLabel.properties().contains(pkey.id()),
"Can't update property for vertex '%s' because " +
"there is no property key '%s' in its vertex label",
id, key);
}
commit(g, () -> updateProperties(vertex, jsonVertex, append));
return manager.serializer(g).writeVertex(vertex);
}
@GET
@Timed
@Compress
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("label") String label,
@QueryParam("properties") String properties,
@QueryParam("keep_start_p")
@DefaultValue("false") boolean keepStartP,
@QueryParam("offset") @DefaultValue("0") long offset,
@QueryParam("page") String page,
@QueryParam("limit") @DefaultValue("100") long limit) {
LOG.debug("Graph [{}] query vertices by label: {}, properties: {}, " +
"offset: {}, page: {}, limit: {}",
graph, label, properties, offset, page, limit);
Map<String, Object> props = parseProperties(properties);
if (page != null) {
E.checkArgument(offset == 0,
"Not support querying vertices based on paging " +
"and offset together");
}
HugeGraph g = graph(manager, graph);
GraphTraversal<Vertex, Vertex> traversal = g.traversal().V();
if (label != null) {
traversal = traversal.hasLabel(label);
}
// Convert relational operator like P.gt()/P.lt()
for (Map.Entry<String, Object> prop : props.entrySet()) {
Object value = prop.getValue();
if (!keepStartP && value instanceof String &&
((String) value).startsWith(TraversalUtil.P_CALL)) {
prop.setValue(TraversalUtil.parsePredicate((String) value));
}
}
for (Map.Entry<String, Object> entry : props.entrySet()) {
traversal = traversal.has(entry.getKey(), entry.getValue());
}
if (page == null) {
traversal = traversal.range(offset, offset + limit);
} else {
traversal = traversal.has(QueryHolder.SYSPROP_PAGE, page)
.limit(limit);
}
try {
return manager.serializer(g).writeVertices(traversal,
page != null);
} finally {
if (g.tx().isOpen()) {
g.tx().close();
}
}
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_read"})
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String idValue) {
LOG.debug("Graph [{}] get vertex by id '{}'", graph, idValue);
Id id = checkAndParseVertexId(idValue);
HugeGraph g = graph(manager, graph);
try {
Vertex vertex = g.vertex(id);
return manager.serializer(g).writeVertex(vertex);
} finally {
if (g.tx().isOpen()) {
g.tx().close();
}
}
}
@DELETE
@Timed
@Path("{id}")
@Consumes(APPLICATION_JSON)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_delete"})
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") String idValue,
@QueryParam("label") String label) {
LOG.debug("Graph [{}] remove vertex by id '{}'", graph, idValue);
Id id = checkAndParseVertexId(idValue);
HugeGraph g = graph(manager, graph);
commit(g, () -> {
try {
g.removeVertex(label, id);
} catch (NotFoundException e) {
throw new IllegalArgumentException(String.format(
"No such vertex with id: '%s', %s", id, e));
} catch (NoSuchElementException e) {
throw new IllegalArgumentException(String.format(
"No such vertex with id: '%s'", id));
}
});
}
public static Id checkAndParseVertexId(String idValue) {
if (idValue == null) {
return null;
}
boolean uuid = idValue.startsWith("U\"");
if (uuid) {
idValue = idValue.substring(1);
}
try {
Object id = JsonUtil.fromJson(idValue, Object.class);
return uuid ? Text.uuid((String) id) : HugeVertex.getIdValue(id);
} catch (Exception e) {
throw new IllegalArgumentException(String.format(
"The vertex id must be formatted as Number/String/UUID" +
", but got '%s'", idValue));
}
}
private static void checkBatchSize(HugeConfig config,
List<JsonVertex> vertices) {
int max = config.get(ServerOptions.MAX_VERTICES_PER_BATCH);
if (vertices.size() > max) {
throw new IllegalArgumentException(String.format(
"Too many vertices for one time post, " +
"the maximum number is '%s'", max));
}
if (vertices.size() == 0) {
throw new IllegalArgumentException(
"The number of vertices can't be 0");
}
}
private static Id getVertexId(HugeGraph g, JsonVertex vertex) {
VertexLabel vertexLabel = g.vertexLabel(vertex.label);
String labelId = vertexLabel.id().asString();
IdStrategy idStrategy = vertexLabel.idStrategy();
E.checkArgument(idStrategy != IdStrategy.AUTOMATIC,
"Automatic Id strategy is not supported now");
if (idStrategy == IdStrategy.PRIMARY_KEY) {
List<Id> pkIds = vertexLabel.primaryKeys();
List<Object> pkValues = new ArrayList<>(pkIds.size());
for (Id pkId : pkIds) {
String propertyKey = g.propertyKey(pkId).name();
Object propertyValue = vertex.properties.get(propertyKey);
E.checkArgument(propertyValue != null,
"The value of primary key '%s' can't be null",
propertyKey);
pkValues.add(propertyValue);
}
String value = ConditionQuery.concatValues(pkValues);
return SplicingIdGenerator.splicing(labelId, value);
} else if (idStrategy == IdStrategy.CUSTOMIZE_UUID) {
return Text.uuid(String.valueOf(vertex.id));
} else {
assert idStrategy == IdStrategy.CUSTOMIZE_NUMBER ||
idStrategy == IdStrategy.CUSTOMIZE_STRING;
return HugeVertex.getIdValue(vertex.id);
}
}
private static class BatchVertexRequest {
@JsonProperty("vertices")
public List<JsonVertex> jsonVertices;
@JsonProperty("update_strategies")
public Map<String, UpdateStrategy> updateStrategies;
@JsonProperty("create_if_not_exist")
public boolean createIfNotExist = true;
private static void checkUpdate(BatchVertexRequest req) {
E.checkArgumentNotNull(req, "BatchVertexRequest can't be null");
E.checkArgumentNotNull(req.jsonVertices,
"Parameter 'vertices' can't be null");
E.checkArgument(req.updateStrategies != null &&
!req.updateStrategies.isEmpty(),
"Parameter 'update_strategies' can't be empty");
E.checkArgument(req.createIfNotExist,
"Parameter 'create_if_not_exist' " +
"dose not support false now");
}
@Override
public String toString() {
return String.format("BatchVertexRequest{jsonVertices=%s," +
"updateStrategies=%s,createIfNotExist=%s}",
this.jsonVertices, this.updateStrategies,
this.createIfNotExist);
}
}
private static class JsonVertex extends JsonElement {
@Override
public void checkCreate(boolean isBatch) {
this.checkUpdate();
}
@Override
public void checkUpdate() {
E.checkArgumentNotNull(this.properties,
"The properties of vertex can't be null");
for (Map.Entry<String, Object> e : this.properties.entrySet()) {
String key = e.getKey();
Object value = e.getValue();
E.checkArgumentNotNull(value, "Not allowed to set value of " +
"property '%s' to null for vertex '%s'",
key, this.id);
}
}
@Override
public Object[] properties() {
Object[] props = API.properties(this.properties);
int newSize = props.length;
int appendIndex = newSize;
if (this.label != null) {
newSize += 2;
}
if (this.id != null) {
newSize += 2;
}
if (newSize == props.length) {
return props;
}
Object[] newProps = Arrays.copyOf(props, newSize);
if (this.label != null) {
newProps[appendIndex++] = T.label;
newProps[appendIndex++] = this.label;
}
if (this.id != null) {
newProps[appendIndex++] = T.id;
// Keep value++ to avoid code trap
newProps[appendIndex++] = this.id;
}
return newProps;
}
@Override
public String toString() {
return String.format("JsonVertex{label=%s, properties=%s}",
this.label, this.properties);
}
}
}

View File

@ -1,113 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.gremlin;
import org.opencypher.gremlin.translation.TranslationFacade;
import org.slf4j.Logger;
import org.apache.hugegraph.api.filter.CompressInterceptor.Compress;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response;
@Path("graphs/{graph}/cypher")
@Singleton
@Tag(name = "CypherAPI")
public class CypherAPI extends GremlinQueryAPI {
private static final Logger LOG = Log.logger(CypherAPI.class);
@GET
@Timed
@Compress(buffer = (1024 * 40))
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Response query(@PathParam("graph") String graph,
@Context HttpHeaders headers,
@QueryParam("cypher") String cypher) {
LOG.debug("Graph [{}] query by cypher: {}", graph, cypher);
return this.queryByCypher(graph, headers, cypher);
}
@POST
@Timed
@Compress
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Response post(@PathParam("graph") String graph,
@Context HttpHeaders headers,
String cypher) {
LOG.debug("Graph [{}] query by cypher: {}", graph, cypher);
return this.queryByCypher(graph, headers, cypher);
}
private Response queryByCypher(String graph,
HttpHeaders headers,
String cypher) {
E.checkArgument(cypher != null && !cypher.isEmpty(),
"The cypher parameter can't be null or empty");
String gremlin = this.translateCpyher2Gremlin(graph, cypher);
LOG.debug("translated gremlin is {}", gremlin);
String auth = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
String request = "{" +
"\"gremlin\":\"" + gremlin + "\"," +
"\"bindings\":{}," +
"\"language\":\"gremlin-groovy\"," +
"\"aliases\":{\"g\":\"__g_" + graph + "\"}}";
Response response = this.client().doPostRequest(auth, request);
return transformResponseIfNeeded(response);
}
private String translateCpyher2Gremlin(String graph, String cypher) {
TranslationFacade translator = new TranslationFacade();
String gremlin = translator.toGremlinGroovy(cypher);
gremlin = this.buildQueryableGremlin(graph, gremlin);
return gremlin;
}
private String buildQueryableGremlin(String graph, String gremlin) {
/*
* `CREATE (a:person { name : 'test', age: 20) return a`
* would be translated to:
* `g.addV('person').as('a').property(single, 'name', 'test') ...`,
* but hugegraph don't support `.property(single, k, v)`,
* so we replace it to `.property(k, v)` here
*/
gremlin = gremlin.replace(".property(single,", ".property(");
return gremlin;
}
}

View File

@ -1,87 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.gremlin;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import org.apache.hugegraph.api.filter.CompressInterceptor.Compress;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.metrics.MetricsUtil;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.annotation.Timed;
import jakarta.inject.Singleton;
@Path("gremlin")
@Singleton
@Tag(name = "GremlinAPI")
public class GremlinAPI extends GremlinQueryAPI {
private static final Histogram GREMLIN_INPUT_HISTOGRAM =
MetricsUtil.registerHistogram(GremlinAPI.class, "gremlin-input");
private static final Histogram GREMLIN_OUTPUT_HISTOGRAM =
MetricsUtil.registerHistogram(GremlinAPI.class, "gremlin-output");
@POST
@Timed
@Compress
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Response post(@Context HugeConfig conf,
@Context HttpHeaders headers,
String request) {
/* The following code is reserved for forwarding request */
// context.getRequestDispatcher(location).forward(request, response);
// return Response.seeOther(UriBuilder.fromUri(location).build())
// .build();
// Response.temporaryRedirect(UriBuilder.fromUri(location).build())
// .build();
String auth = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
Response response = this.client().doPostRequest(auth, request);
GREMLIN_INPUT_HISTOGRAM.update(request.length());
GREMLIN_OUTPUT_HISTOGRAM.update(response.getLength());
return transformResponseIfNeeded(response);
}
@GET
@Timed
@Compress(buffer = (1024 * 40))
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Response get(@Context HugeConfig conf,
@Context HttpHeaders headers,
@Context UriInfo uriInfo) {
String auth = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
String query = uriInfo.getRequestUri().getRawQuery();
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
Response response = this.client().doGetRequest(auth, params);
GREMLIN_INPUT_HISTOGRAM.update(query.length());
GREMLIN_OUTPUT_HISTOGRAM.update(response.getLength());
return transformResponseIfNeeded(response);
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.gremlin;
import java.util.List;
import java.util.Map;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import org.apache.hugegraph.api.filter.CompressInterceptor;
import org.apache.hugegraph.rest.AbstractRestClient;
import org.apache.hugegraph.testutil.Whitebox;
import org.apache.hugegraph.util.E;
public class GremlinClient extends AbstractRestClient {
private final WebTarget webTarget;
public GremlinClient(String url, int timeout,
int maxTotal, int maxPerRoute) {
super(url, timeout, maxTotal, maxPerRoute);
this.webTarget = Whitebox.getInternalState(this, "target");
E.checkNotNull(this.webTarget, "target");
}
@Override
protected void checkStatus(Response response, Response.Status... statuses) {
// pass
}
public Response doPostRequest(String auth, String req) {
Entity<?> body = Entity.entity(req, MediaType.APPLICATION_JSON);
return this.webTarget.request()
.header(HttpHeaders.AUTHORIZATION, auth)
.accept(MediaType.APPLICATION_JSON)
.acceptEncoding(CompressInterceptor.GZIP)
.post(body);
}
public Response doGetRequest(String auth,
MultivaluedMap<String, String> params) {
WebTarget target = this.webTarget;
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
E.checkArgument(entry.getValue().size() == 1,
"Invalid query param '%s', can only accept " +
"one value, but got %s",
entry.getKey(), entry.getValue());
target = target.queryParam(entry.getKey(), entry.getValue().get(0));
}
return target.request()
.header(HttpHeaders.AUTHORIZATION, auth)
.accept(MediaType.APPLICATION_JSON)
.acceptEncoding(CompressInterceptor.GZIP)
.get();
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.job;
import java.util.Map;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.server.RestServer;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.job.AlgorithmJob;
import org.apache.hugegraph.job.JobBuilder;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
@Path("graphs/{graph}/jobs/algorithm")
@Singleton
public class AlgorithmAPI extends API {
private static final Logger LOG = Log.logger(RestServer.class);
@POST
@Timed
@Path("/{name}")
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Map<String, Id> post(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String algorithm,
Map<String, Object> parameters) {
LOG.debug("Graph [{}] schedule algorithm job: {}", graph, parameters);
E.checkArgument(algorithm != null && !algorithm.isEmpty(),
"The algorithm name can't be empty");
if (parameters == null) {
parameters = ImmutableMap.of();
}
if (!AlgorithmJob.check(algorithm, parameters)) {
throw new NotFoundException("Not found algorithm: " + algorithm);
}
HugeGraph g = graph(manager, graph);
Map<String, Object> input = ImmutableMap.of("algorithm", algorithm,
"parameters", parameters);
JobBuilder<Object> builder = JobBuilder.of(g);
builder.name("algorithm:" + algorithm)
.input(JsonUtil.toJson(input))
.job(new AlgorithmJob());
return ImmutableMap.of("task_id", builder.schedule().id());
}
}

View File

@ -1,87 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.job;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.job.ComputerJob;
import org.apache.hugegraph.job.JobBuilder;
import org.apache.hugegraph.task.HugeTask;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/jobs/computer")
@Singleton
@Tag(name = "ComputerAPI")
public class ComputerAPI extends API {
private static final Logger LOG = Log.logger(ComputerAPI.class);
@POST
@Timed
@Path("/{name}")
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Map<String, Id> post(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String computer,
Map<String, Object> parameters) {
LOG.debug("Graph [{}] schedule computer job: {}", graph, parameters);
E.checkArgument(computer != null && !computer.isEmpty(),
"The computer name can't be empty");
if (parameters == null) {
parameters = ImmutableMap.of();
}
if (!ComputerJob.check(computer, parameters)) {
throw new NotFoundException("Not found computer: " + computer);
}
HugeGraph g = graph(manager, graph);
Map<String, Object> input = ImmutableMap.of("computer", computer,
"parameters", parameters);
JobBuilder<Object> builder = JobBuilder.of(g);
builder.name("computer:" + computer)
.input(JsonUtil.toJson(input))
.job(new ComputerJob());
HugeTask<Object> task = builder.schedule();
return ImmutableMap.of("task_id", task.id());
}
}

View File

@ -1,210 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.job;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.util.HashMap;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.apache.hugegraph.metrics.MetricsUtil;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeException;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.job.GremlinJob;
import org.apache.hugegraph.job.JobBuilder;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/jobs/gremlin")
@Singleton
@Tag(name = "GremlinAPI")
public class GremlinAPI extends API {
private static final Logger LOG = Log.logger(GremlinAPI.class);
private static final int MAX_NAME_LENGTH = 256;
private static final Histogram GREMLIN_JOB_INPUT_HISTOGRAM =
MetricsUtil.registerHistogram(GremlinAPI.class, "gremlin-input");
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=gremlin_execute"})
public Map<String, Id> post(@Context GraphManager manager,
@PathParam("graph") String graph,
GremlinRequest request) {
LOG.debug("Graph [{}] schedule gremlin job: {}", graph, request);
checkCreatingBody(request);
GREMLIN_JOB_INPUT_HISTOGRAM.update(request.gremlin.length());
HugeGraph g = graph(manager, graph);
request.aliase(graph, "graph");
JobBuilder<Object> builder = JobBuilder.of(g);
builder.name(request.name())
.input(request.toJson())
.job(new GremlinJob());
return ImmutableMap.of("task_id", builder.schedule().id());
}
public static class GremlinRequest implements Checkable {
// See org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer
@JsonProperty
private String gremlin;
@JsonProperty
private Map<String, Object> bindings = new HashMap<>();
@JsonProperty
private String language = "gremlin-groovy";
@JsonProperty
private Map<String, String> aliases = new HashMap<>();
public String gremlin() {
return this.gremlin;
}
public void gremlin(String gremlin) {
this.gremlin = gremlin;
}
public Map<String, Object> bindings() {
return this.bindings;
}
public void bindings(Map<String, Object> bindings) {
this.bindings = bindings;
}
public void binding(String name, Object value) {
this.bindings.put(name, value);
}
public String language() {
return this.language;
}
public void language(String language) {
this.language = language;
}
public Map<String, String> aliases() {
return this.aliases;
}
public void aliases(Map<String, String> aliases) {
this.aliases = aliases;
}
public void aliase(String key, String value) {
this.aliases.put(key, value);
}
public String name() {
// Get the first line of script as the name
String firstLine = this.gremlin.split("\r\n|\r|\n", 2)[0];
final Charset charset = Charset.forName(CHARSET);
final byte[] bytes = firstLine.getBytes(charset);
if (bytes.length <= MAX_NAME_LENGTH) {
return firstLine;
}
/*
* Reference https://stackoverflow.com/questions/3576754/truncating-strings-by-bytes
*/
CharsetDecoder decoder = charset.newDecoder();
decoder.onMalformedInput(CodingErrorAction.IGNORE);
decoder.reset();
ByteBuffer buffer = ByteBuffer.wrap(bytes, 0, MAX_NAME_LENGTH);
try {
return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) {
throw new HugeException("Failed to decode truncated bytes of " +
"gremlin first line", e);
}
}
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.gremlin,
"The gremlin parameter can't be null");
E.checkArgumentNotNull(this.language,
"The language parameter can't be null");
E.checkArgument(this.aliases == null || this.aliases.isEmpty(),
"There is no need to pass gremlin aliases");
}
public String toJson() {
Map<String, Object> map = new HashMap<>();
map.put("gremlin", this.gremlin);
map.put("bindings", this.bindings);
map.put("language", this.language);
map.put("aliases", this.aliases);
return JsonUtil.toJson(map);
}
public static GremlinRequest fromJson(String json) {
@SuppressWarnings("unchecked")
Map<String, Object> map = JsonUtil.fromJson(json, Map.class);
String gremlin = (String) map.get("gremlin");
@SuppressWarnings("unchecked")
Map<String, Object> bindings = (Map<String, Object>)
map.get("bindings");
String language = (String) map.get("language");
@SuppressWarnings("unchecked")
Map<String, String> aliases = (Map<String, String>)
map.get("aliases");
GremlinRequest request = new GremlinRequest();
request.gremlin(gremlin);
request.bindings(bindings);
request.language(language);
request.aliases(aliases);
return request;
}
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.job;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/jobs/rebuild")
@Singleton
@Tag(name = "RebuildAPI")
public class RebuildAPI extends API {
private static final Logger LOG = Log.logger(RebuildAPI.class);
@PUT
@Timed
@Path("vertexlabels/{name}")
@Status(Status.ACCEPTED)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_write"})
public Map<String, Id> vertexLabelRebuild(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] rebuild vertex label: {}", graph, name);
HugeGraph g = graph(manager, graph);
return ImmutableMap.of("task_id",
g.schema().vertexLabel(name).rebuildIndex());
}
@PUT
@Timed
@Path("edgelabels/{name}")
@Status(Status.ACCEPTED)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_write"})
public Map<String, Id> edgeLabelRebuild(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] rebuild edge label: {}", graph, name);
HugeGraph g = graph(manager, graph);
return ImmutableMap.of("task_id",
g.schema().edgeLabel(name).rebuildIndex());
}
@PUT
@Timed
@Path("indexlabels/{name}")
@Status(Status.ACCEPTED)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_write"})
public Map<String, Id> indexLabelRebuild(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] rebuild index label: {}", graph, name);
HugeGraph g = graph(manager, graph);
return ImmutableMap.of("task_id",
g.schema().indexLabel(name).rebuild());
}
}

View File

@ -1,187 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.job;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotSupportedException;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.groovy.util.Maps;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.id.IdGenerator;
import org.apache.hugegraph.backend.page.PageInfo;
import org.apache.hugegraph.task.HugeTask;
import org.apache.hugegraph.task.TaskScheduler;
import org.apache.hugegraph.task.TaskStatus;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/tasks")
@Singleton
@Tag(name = "TaskAPI")
public class TaskAPI extends API {
private static final Logger LOG = Log.logger(TaskAPI.class);
private static final long NO_LIMIT = -1L;
public static final String ACTION_CANCEL = "cancel";
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Map<String, Object> list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("status") String status,
@QueryParam("ids") List<Long> ids,
@QueryParam("limit")
@DefaultValue("100") long limit,
@QueryParam("page") String page) {
LOG.debug("Graph [{}] list tasks with status {}, ids {}, " +
"limit {}, page {}", graph, status, ids, limit, page);
TaskScheduler scheduler = graph(manager, graph).taskScheduler();
Iterator<HugeTask<Object>> iter;
if (!ids.isEmpty()) {
E.checkArgument(status == null,
"Not support status when query task by ids, " +
"but got status='%s'", status);
E.checkArgument(page == null,
"Not support page when query task by ids, " +
"but got page='%s'", page);
// Set limit to NO_LIMIT to ignore limit when query task by ids
limit = NO_LIMIT;
List<Id> idList = ids.stream().map(IdGenerator::of)
.collect(Collectors.toList());
iter = scheduler.tasks(idList);
} else {
if (status == null) {
iter = scheduler.tasks(null, limit, page);
} else {
iter = scheduler.tasks(parseStatus(status), limit, page);
}
}
List<Object> tasks = new ArrayList<>();
while (iter.hasNext()) {
tasks.add(iter.next().asMap(false));
}
if (limit != NO_LIMIT && tasks.size() > limit) {
tasks = tasks.subList(0, (int) limit);
}
if (page == null) {
return Maps.of("tasks", tasks);
} else {
return Maps.of("tasks", tasks, "page", PageInfo.pageInfo(iter));
}
}
@GET
@Timed
@Path("{id}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Map<String, Object> get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") long id) {
LOG.debug("Graph [{}] get task: {}", graph, id);
TaskScheduler scheduler = graph(manager, graph).taskScheduler();
return scheduler.task(IdGenerator.of(id)).asMap();
}
@DELETE
@Timed
@Path("{id}")
public void delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") long id) {
LOG.debug("Graph [{}] delete task: {}", graph, id);
TaskScheduler scheduler = graph(manager, graph).taskScheduler();
HugeTask<?> task = scheduler.delete(IdGenerator.of(id));
E.checkArgument(task != null, "There is no task with id '%s'", id);
}
@PUT
@Timed
@Path("{id}")
@Status(Status.ACCEPTED)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public Map<String, Object> update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("id") long id,
@QueryParam("action") String action) {
LOG.debug("Graph [{}] cancel task: {}", graph, id);
if (!ACTION_CANCEL.equals(action)) {
throw new NotSupportedException(String.format(
"Not support action '%s'", action));
}
TaskScheduler scheduler = graph(manager, graph).taskScheduler();
HugeTask<?> task = scheduler.task(IdGenerator.of(id));
if (!task.completed() && !task.cancelling()) {
scheduler.cancel(task);
if (task.cancelling() || task.cancelled()) {
return task.asMap();
}
}
assert task.completed() || task.cancelling();
throw new BadRequestException(String.format(
"Can't cancel task '%s' which is completed or cancelling",
id));
}
private static TaskStatus parseStatus(String status) {
try {
return TaskStatus.valueOf(status.toUpperCase());
} catch (Exception e) {
throw new IllegalArgumentException(String.format(
"Status value must be in %s, but got '%s'",
Arrays.asList(TaskStatus.values()), status));
}
}
}

View File

@ -1,163 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.metrics;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.LinkedHashMap;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.metrics.MetricsModule;
import org.apache.hugegraph.metrics.ServerReporter;
import org.apache.hugegraph.metrics.SystemMetrics;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.backend.store.BackendMetrics;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.Metric;
import com.codahale.metrics.annotation.Timed;
@Singleton
@Path("metrics")
@Tag(name = "MetricsAPI")
public class MetricsAPI extends API {
private static final Logger LOG = Log.logger(MetricsAPI.class);
private SystemMetrics systemMetrics;
static {
JsonUtil.registerModule(new MetricsModule(SECONDS, MILLISECONDS, false));
}
public MetricsAPI() {
this.systemMetrics = new SystemMetrics();
}
@GET
@Timed
@Path("system")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String system() {
return JsonUtil.toJson(this.systemMetrics.metrics());
}
@GET
@Timed
@Path("backend")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String backend(@Context GraphManager manager) {
Map<String, Map<String, Object>> results = InsertionOrderUtil.newMap();
for (String graph : manager.graphs()) {
HugeGraph g = manager.graph(graph);
Map<String, Object> metrics = InsertionOrderUtil.newMap();
metrics.put(BackendMetrics.BACKEND, g.backend());
try {
metrics.putAll(g.metadata(null, "metrics"));
} catch (Throwable e) {
metrics.put(BackendMetrics.EXCEPTION, e.toString());
LOG.debug("Failed to get backend metrics", e);
}
results.put(graph, metrics);
}
return JsonUtil.toJson(results);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String all() {
ServerReporter reporter = ServerReporter.instance();
Map<String, Map<String, ? extends Metric>> result = new LinkedHashMap<>();
result.put("gauges", reporter.gauges());
result.put("counters", reporter.counters());
result.put("histograms", reporter.histograms());
result.put("meters", reporter.meters());
result.put("timers", reporter.timers());
return JsonUtil.toJson(result);
}
@GET
@Timed
@Path("gauges")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String gauges() {
ServerReporter reporter = ServerReporter.instance();
return JsonUtil.toJson(reporter.gauges());
}
@GET
@Timed
@Path("counters")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String counters() {
ServerReporter reporter = ServerReporter.instance();
return JsonUtil.toJson(reporter.counters());
}
@GET
@Timed
@Path("histograms")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String histograms() {
ServerReporter reporter = ServerReporter.instance();
return JsonUtil.toJson(reporter.histograms());
}
@GET
@Timed
@Path("meters")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String meters() {
ServerReporter reporter = ServerReporter.instance();
return JsonUtil.toJson(reporter.meters());
}
@GET
@Timed
@Path("timers")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
public String timers() {
ServerReporter reporter = ServerReporter.instance();
return JsonUtil.toJson(reporter.timers());
}
}

View File

@ -1,287 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.profile;
import java.io.File;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotSupportedException;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.auth.HugeAuthenticator.RequiredPerm;
import org.apache.hugegraph.auth.HugePermission;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.type.define.GraphMode;
import org.apache.hugegraph.type.define.GraphReadMode;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
@Path("graphs")
@Singleton
@Tag(name = "GraphsAPI")
public class GraphsAPI extends API {
private static final Logger LOG = Log.logger(GraphsAPI.class);
private static final String CONFIRM_CLEAR = "I'm sure to delete all data";
private static final String CONFIRM_DROP = "I'm sure to drop the graph";
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$dynamic"})
public Object list(@Context GraphManager manager,
@Context SecurityContext sc) {
Set<String> graphs = manager.graphs();
// Filter by user role
Set<String> filterGraphs = new HashSet<>();
for (String graph : graphs) {
String role = RequiredPerm.roleFor(graph, HugePermission.READ);
if (sc.isUserInRole(role)) {
try {
HugeGraph g = graph(manager, graph);
filterGraphs.add(g.name());
} catch (ForbiddenException ignored) {
// ignore
}
}
}
return ImmutableMap.of("graphs", filterGraphs);
}
@GET
@Timed
@Path("{name}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$name"})
public Object get(@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Get graph by name '{}'", name);
HugeGraph g = graph(manager, name);
return ImmutableMap.of("name", g.name(), "backend", g.backend());
}
@DELETE
@Timed
@Path("{name}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public void drop(@Context GraphManager manager,
@PathParam("name") String name,
@QueryParam("confirm_message") String message) {
LOG.debug("Drop graph by name '{}'", name);
E.checkArgument(CONFIRM_DROP.equals(message),
"Please take the message: %s", CONFIRM_DROP);
manager.dropGraph(name);
}
@POST
@Timed
@Path("{name}")
@Consumes(TEXT_PLAIN)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Object create(@Context GraphManager manager,
@PathParam("name") String name,
@QueryParam("clone_graph_name") String clone,
String configText) {
LOG.debug("Create graph '{}' with clone graph '{}', config text '{}'",
name, clone, configText);
HugeGraph graph;
if (StringUtils.isNotEmpty(clone)) {
graph = manager.cloneGraph(clone, name, configText);
} else {
graph = manager.createGraph(name, configText);
}
return ImmutableMap.of("name", graph.name(),
"backend", graph.backend());
}
@GET
@Timed
@Path("{name}/conf")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
public File getConf(@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Get graph configuration by name '{}'", name);
HugeGraph g = graph4admin(manager, name);
HugeConfig config = (HugeConfig) g.configuration();
File file = config.file();
if (file == null) {
throw new NotSupportedException("Can't access the api in " +
"a node which started with non local file config.");
}
return file;
}
@DELETE
@Timed
@Path("{name}/clear")
@Consumes(APPLICATION_JSON)
@RolesAllowed("admin")
public void clear(@Context GraphManager manager,
@PathParam("name") String name,
@QueryParam("confirm_message") String message) {
LOG.debug("Clear graph by name '{}'", name);
E.checkArgument(CONFIRM_CLEAR.equals(message),
"Please take the message: %s", CONFIRM_CLEAR);
HugeGraph g = graph(manager, name);
g.truncateBackend();
}
@PUT
@Timed
@Path("{name}/snapshot_create")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$name"})
public Object createSnapshot(@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Create snapshot for graph '{}'", name);
HugeGraph g = graph(manager, name);
g.createSnapshot();
return ImmutableMap.of(name, "snapshot_created");
}
@PUT
@Timed
@Path("{name}/snapshot_resume")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$name"})
public Object resumeSnapshot(@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Resume snapshot for graph '{}'", name);
HugeGraph g = graph(manager, name);
g.resumeSnapshot();
return ImmutableMap.of(name, "snapshot_resumed");
}
@PUT
@Timed
@Path("{name}/compact")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public String compact(@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Manually compact graph '{}'", name);
HugeGraph g = graph(manager, name);
return JsonUtil.toJson(g.metadata(null, "compact"));
}
@PUT
@Timed
@Path("{name}/mode")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$name"})
public Map<String, GraphMode> mode(@Context GraphManager manager,
@PathParam("name") String name,
GraphMode mode) {
LOG.debug("Set mode to: '{}' of graph '{}'", mode, name);
E.checkArgument(mode != null, "Graph mode can't be null");
HugeGraph g = graph(manager, name);
g.mode(mode);
return ImmutableMap.of("mode", mode);
}
@GET
@Timed
@Path("{name}/mode")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$name"})
public Map<String, GraphMode> mode(@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Get mode of graph '{}'", name);
HugeGraph g = graph(manager, name);
return ImmutableMap.of("mode", g.mode());
}
@PUT
@Timed
@Path("{name}/graph_read_mode")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
public Map<String, GraphReadMode> graphReadMode(
@Context GraphManager manager,
@PathParam("name") String name,
GraphReadMode readMode) {
LOG.debug("Set graph-read-mode to: '{}' of graph '{}'",
readMode, name);
E.checkArgument(readMode != null,
"Graph-read-mode can't be null");
HugeGraph g = graph(manager, name);
g.readMode(readMode);
return ImmutableMap.of("graph_read_mode", readMode);
}
@GET
@Timed
@Path("{name}/graph_read_mode")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$name"})
public Map<String, GraphReadMode> graphReadMode(
@Context GraphManager manager,
@PathParam("name") String name) {
LOG.debug("Get graph-read-mode of graph '{}'", name);
HugeGraph g = graph(manager, name);
return ImmutableMap.of("graph_read_mode", g.readMode());
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.profile;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.PermitAll;
import jakarta.inject.Singleton;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.version.ApiVersion;
import org.apache.hugegraph.version.CoreVersion;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
@Path("versions")
@Singleton
@Tag(name = "VersionAPI")
public class VersionAPI extends API {
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@PermitAll
public Object list() {
Map<String, String> versions = ImmutableMap.of("version", "v1",
"core", CoreVersion.VERSION.toString(),
"gremlin", CoreVersion.GREMLIN_VERSION,
"api", ApiVersion.VERSION.toString());
return ImmutableMap.of("versions", versions);
}
}

View File

@ -1,217 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.raft;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeException;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.store.raft.RaftAddPeerJob;
import org.apache.hugegraph.backend.store.raft.RaftGroupManager;
import org.apache.hugegraph.backend.store.raft.RaftRemovePeerJob;
import org.apache.hugegraph.job.JobBuilder;
import org.apache.hugegraph.util.DateUtil;
import org.apache.hugegraph.util.JsonUtil;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/raft")
@Singleton
@Tag(name = "RaftAPI")
public class RaftAPI extends API {
private static final Logger LOG = Log.logger(RaftAPI.class);
@GET
@Timed
@Path("list_peers")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Map<String, List<String>> listPeers(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group")
@DefaultValue("default")
String group) {
LOG.debug("Graph [{}] prepare to get leader", graph);
HugeGraph g = graph(manager, graph);
RaftGroupManager raftManager = raftGroupManager(g, group, "list_peers");
List<String> peers = raftManager.listPeers();
return ImmutableMap.of(raftManager.group(), peers);
}
@GET
@Timed
@Path("get_leader")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Map<String, String> getLeader(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group")
@DefaultValue("default")
String group) {
LOG.debug("Graph [{}] prepare to get leader", graph);
HugeGraph g = graph(manager, graph);
RaftGroupManager raftManager = raftGroupManager(g, group, "get_leader");
String leaderId = raftManager.getLeader();
return ImmutableMap.of(raftManager.group(), leaderId);
}
@POST
@Timed
@Status(Status.OK)
@Path("transfer_leader")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Map<String, String> transferLeader(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group")
@DefaultValue("default")
String group,
@QueryParam("endpoint")
String endpoint) {
LOG.debug("Graph [{}] prepare to transfer leader to: {}",
graph, endpoint);
HugeGraph g = graph(manager, graph);
RaftGroupManager raftManager = raftGroupManager(g, group,
"transfer_leader");
String leaderId = raftManager.transferLeaderTo(endpoint);
return ImmutableMap.of(raftManager.group(), leaderId);
}
@POST
@Timed
@Status(Status.OK)
@Path("set_leader")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Map<String, String> setLeader(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group")
@DefaultValue("default")
String group,
@QueryParam("endpoint")
String endpoint) {
LOG.debug("Graph [{}] prepare to set leader to: {}",
graph, endpoint);
HugeGraph g = graph(manager, graph);
RaftGroupManager raftManager = raftGroupManager(g, group, "set_leader");
String leaderId = raftManager.setLeader(endpoint);
return ImmutableMap.of(raftManager.group(), leaderId);
}
@POST
@Timed
@Status(Status.OK)
@Path("add_peer")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Map<String, Id> addPeer(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group") @DefaultValue("default")
String group,
@QueryParam("endpoint") String endpoint) {
LOG.debug("Graph [{}] prepare to add peer: {}", graph, endpoint);
HugeGraph g = graph(manager, graph);
RaftGroupManager raftManager = raftGroupManager(g, group, "add_peer");
JobBuilder<String> builder = JobBuilder.of(g);
String name = String.format("raft-group-[%s]-add-peer-[%s]-at-[%s]",
raftManager.group(), endpoint,
DateUtil.now());
Map<String, String> inputs = new HashMap<>();
inputs.put("endpoint", endpoint);
builder.name(name)
.input(JsonUtil.toJson(inputs))
.job(new RaftAddPeerJob());
return ImmutableMap.of("task_id", builder.schedule().id());
}
@POST
@Timed
@Status(Status.OK)
@Path("remove_peer")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin"})
public Map<String, Id> removePeer(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("group")
@DefaultValue("default") String group,
@QueryParam("endpoint") String endpoint) {
LOG.debug("Graph [{}] prepare to remove peer: {}", graph, endpoint);
HugeGraph g = graph(manager, graph);
RaftGroupManager raftManager = raftGroupManager(g, group,
"remove_peer");
JobBuilder<String> builder = JobBuilder.of(g);
String name = String.format("raft-group-[%s]-remove-peer-[%s]-at-[%s]",
raftManager.group(), endpoint,
DateUtil.now());
Map<String, String> inputs = new HashMap<>();
inputs.put("endpoint", endpoint);
builder.name(name)
.input(JsonUtil.toJson(inputs))
.job(new RaftRemovePeerJob());
return ImmutableMap.of("task_id", builder.schedule().id());
}
private static RaftGroupManager raftGroupManager(HugeGraph graph,
String group,
String operation) {
RaftGroupManager raftManager = graph.raftGroupManager();
if (raftManager == null) {
throw new HugeException("Allowed %s operation only when " +
"working on raft mode", operation);
}
return raftManager;
}
}

View File

@ -1,274 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.schema;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.Userdata;
import org.apache.hugegraph.type.define.Frequency;
import org.apache.hugegraph.type.define.GraphMode;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/schema/edgelabels")
@Singleton
@Tag(name = "EdgeLabelAPI")
public class EdgeLabelAPI extends API {
private static final Logger LOG = Log.logger(EdgeLabelAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_label_write"})
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonEdgeLabel jsonEdgeLabel) {
LOG.debug("Graph [{}] create edge label: {}", graph, jsonEdgeLabel);
checkCreatingBody(jsonEdgeLabel);
HugeGraph g = graph(manager, graph);
EdgeLabel.Builder builder = jsonEdgeLabel.convert2Builder(g);
EdgeLabel edgeLabel = builder.create();
return manager.serializer(g).writeEdgeLabel(edgeLabel);
}
@PUT
@Timed
@Path("{name}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_label_write"})
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name,
@QueryParam("action") String action,
JsonEdgeLabel jsonEdgeLabel) {
LOG.debug("Graph [{}] {} edge label: {}",
graph, action, jsonEdgeLabel);
checkUpdatingBody(jsonEdgeLabel);
E.checkArgument(name.equals(jsonEdgeLabel.name),
"The name in url(%s) and body(%s) are different",
name, jsonEdgeLabel.name);
// Parse action param
boolean append = checkAndParseAction(action);
HugeGraph g = graph(manager, graph);
EdgeLabel.Builder builder = jsonEdgeLabel.convert2Builder(g);
EdgeLabel edgeLabel = append ? builder.append() : builder.eliminate();
return manager.serializer(g).writeEdgeLabel(edgeLabel);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_label_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("names") List<String> names) {
boolean listAll = CollectionUtils.isEmpty(names);
if (listAll) {
LOG.debug("Graph [{}] list edge labels", graph);
} else {
LOG.debug("Graph [{}] get edge labels by names {}", graph, names);
}
HugeGraph g = graph(manager, graph);
List<EdgeLabel> labels;
if (listAll) {
labels = g.schema().getEdgeLabels();
} else {
labels = new ArrayList<>(names.size());
for (String name : names) {
labels.add(g.schema().getEdgeLabel(name));
}
}
return manager.serializer(g).writeEdgeLabels(labels);
}
@GET
@Timed
@Path("{name}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_label_read"})
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] get edge label by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
EdgeLabel edgeLabel = g.schema().getEdgeLabel(name);
return manager.serializer(g).writeEdgeLabel(edgeLabel);
}
@DELETE
@Timed
@Path("{name}")
@Status(Status.ACCEPTED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=edge_label_delete"})
public Map<String, Id> delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] remove edge label by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
// Throw 404 if not exists
g.schema().getEdgeLabel(name);
return ImmutableMap.of("task_id",
g.schema().edgeLabel(name).remove());
}
/**
* JsonEdgeLabel is only used to receive create and append requests
*/
@JsonIgnoreProperties(value = {"index_labels", "status"})
private static class JsonEdgeLabel implements Checkable {
@JsonProperty("id")
public long id;
@JsonProperty("name")
public String name;
@JsonProperty("source_label")
public String sourceLabel;
@JsonProperty("target_label")
public String targetLabel;
@JsonProperty("frequency")
public Frequency frequency;
@JsonProperty("properties")
public String[] properties;
@JsonProperty("sort_keys")
public String[] sortKeys;
@JsonProperty("nullable_keys")
public String[] nullableKeys;
@JsonProperty("ttl")
public long ttl;
@JsonProperty("ttl_start_time")
public String ttlStartTime;
@JsonProperty("enable_label_index")
public Boolean enableLabelIndex;
@JsonProperty("user_data")
public Userdata userdata;
@JsonProperty("check_exist")
public Boolean checkExist;
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.name,
"The name of edge label can't be null");
}
private EdgeLabel.Builder convert2Builder(HugeGraph g) {
EdgeLabel.Builder builder = g.schema().edgeLabel(this.name);
if (this.id != 0) {
E.checkArgument(this.id > 0,
"Only positive number can be assign as " +
"edge label id");
E.checkArgument(g.mode() == GraphMode.RESTORING,
"Only accept edge label id when graph in " +
"RESTORING mode, but '%s' is in mode '%s'",
g, g.mode());
builder.id(this.id);
}
if (this.sourceLabel != null) {
builder.sourceLabel(this.sourceLabel);
}
if (this.targetLabel != null) {
builder.targetLabel(this.targetLabel);
}
if (this.frequency != null) {
builder.frequency(this.frequency);
}
if (this.properties != null) {
builder.properties(this.properties);
}
if (this.sortKeys != null) {
builder.sortKeys(this.sortKeys);
}
if (this.nullableKeys != null) {
builder.nullableKeys(this.nullableKeys);
}
if (this.enableLabelIndex != null) {
builder.enableLabelIndex(this.enableLabelIndex);
}
if (this.userdata != null) {
builder.userdata(this.userdata);
}
if (this.checkExist != null) {
builder.checkExist(this.checkExist);
}
if (this.ttl != 0) {
builder.ttl(this.ttl);
}
if (this.ttlStartTime != null) {
E.checkArgument(this.ttl > 0,
"Only set ttlStartTime when ttl is " +
"positive, but got ttl: %s", this.ttl);
builder.ttlStartTime(this.ttlStartTime);
}
return builder;
}
@Override
public String toString() {
return String.format("JsonEdgeLabel{" +
"name=%s, sourceLabel=%s, targetLabel=%s, frequency=%s, " +
"sortKeys=%s, nullableKeys=%s, properties=%s, ttl=%s, " +
"ttlStartTime=%s}",
this.name, this.sourceLabel, this.targetLabel,
this.frequency, this.sortKeys, this.nullableKeys,
this.properties, this.ttl, this.ttlStartTime);
}
}
}

View File

@ -1,294 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.schema;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.schema.IndexLabel;
import org.apache.hugegraph.schema.SchemaElement;
import org.apache.hugegraph.schema.Userdata;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.GraphMode;
import org.apache.hugegraph.type.define.IndexType;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/schema/indexlabels")
@Singleton
@Tag(name = "IndexLabelAPI")
public class IndexLabelAPI extends API {
private static final Logger LOG = Log.logger(IndexLabelAPI.class);
@POST
@Timed
@Status(Status.ACCEPTED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_label_write"})
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonIndexLabel jsonIndexLabel) {
LOG.debug("Graph [{}] create index label: {}", graph, jsonIndexLabel);
checkCreatingBody(jsonIndexLabel);
HugeGraph g = graph(manager, graph);
IndexLabel.Builder builder = jsonIndexLabel.convert2Builder(g);
SchemaElement.TaskWithSchema il = builder.createWithTask();
il.indexLabel(mapIndexLabel(il.indexLabel()));
return manager.serializer(g).writeTaskWithSchema(il);
}
@PUT
@Timed
@Path("{name}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name,
@QueryParam("action") String action,
IndexLabelAPI.JsonIndexLabel jsonIndexLabel) {
LOG.debug("Graph [{}] {} index label: {}",
graph, action, jsonIndexLabel);
checkUpdatingBody(jsonIndexLabel);
E.checkArgument(name.equals(jsonIndexLabel.name),
"The name in url(%s) and body(%s) are different",
name, jsonIndexLabel.name);
// Parse action parameter
boolean append = checkAndParseAction(action);
HugeGraph g = graph(manager, graph);
IndexLabel.Builder builder = jsonIndexLabel.convert2Builder(g);
IndexLabel indexLabel = append ? builder.append() : builder.eliminate();
return manager.serializer(g).writeIndexlabel(mapIndexLabel(indexLabel));
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_label_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("names") List<String> names) {
boolean listAll = CollectionUtils.isEmpty(names);
if (listAll) {
LOG.debug("Graph [{}] list index labels", graph);
} else {
LOG.debug("Graph [{}] get index labels by names {}", graph, names);
}
HugeGraph g = graph(manager, graph);
List<IndexLabel> labels;
if (listAll) {
labels = g.schema().getIndexLabels();
} else {
labels = new ArrayList<>(names.size());
for (String name : names) {
labels.add(g.schema().getIndexLabel(name));
}
}
return manager.serializer(g).writeIndexlabels(mapIndexLabels(labels));
}
@GET
@Timed
@Path("{name}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_label_read"})
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] get index label by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
IndexLabel indexLabel = g.schema().getIndexLabel(name);
return manager.serializer(g).writeIndexlabel(mapIndexLabel(indexLabel));
}
@DELETE
@Timed
@Path("{name}")
@Status(Status.ACCEPTED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=index_label_delete"})
public Map<String, Id> delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] remove index label by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
// Throw 404 if not exists
g.schema().getIndexLabel(name);
return ImmutableMap.of("task_id",
g.schema().indexLabel(name).remove());
}
private static List<IndexLabel> mapIndexLabels(List<IndexLabel> labels) {
List<IndexLabel> results = new ArrayList<>(labels.size());
for (IndexLabel il : labels) {
results.add(mapIndexLabel(il));
}
return results;
}
/**
* Map RANGE_INT/RANGE_FLOAT/RANGE_LONG/RANGE_DOUBLE to RANGE
*/
private static IndexLabel mapIndexLabel(IndexLabel label) {
if (label.indexType().isRange()) {
label = (IndexLabel) label.copy();
label.indexType(IndexType.RANGE);
}
return label;
}
/**
* JsonIndexLabel is only used to receive create and append requests
*/
@JsonIgnoreProperties(value = {"status"})
private static class JsonIndexLabel implements Checkable {
@JsonProperty("id")
public long id;
@JsonProperty("name")
public String name;
@JsonProperty("base_type")
public HugeType baseType;
@JsonProperty("base_value")
public String baseValue;
@JsonProperty("index_type")
public IndexType indexType;
@JsonProperty("fields")
public String[] fields;
@JsonProperty("user_data")
public Userdata userdata;
@JsonProperty("check_exist")
public Boolean checkExist;
@JsonProperty("rebuild")
public Boolean rebuild;
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.name,
"The name of index label can't be null");
E.checkArgumentNotNull(this.baseType,
"The base type of index label '%s' " +
"can't be null", this.name);
E.checkArgument(this.baseType == HugeType.VERTEX_LABEL ||
this.baseType == HugeType.EDGE_LABEL,
"The base type of index label '%s' can only be " +
"either VERTEX_LABEL or EDGE_LABEL", this.name);
E.checkArgumentNotNull(this.baseValue,
"The base value of index label '%s' " +
"can't be null", this.name);
E.checkArgumentNotNull(this.indexType,
"The index type of index label '%s' " +
"can't be null", this.name);
}
@Override
public void checkUpdate() {
E.checkArgumentNotNull(this.name,
"The name of index label can't be null");
E.checkArgument(this.baseType == null,
"The base type of index label '%s' must be null",
this.name);
E.checkArgument(this.baseValue == null,
"The base value of index label '%s' must be null",
this.name);
E.checkArgument(this.indexType == null,
"The index type of index label '%s' must be null",
this.name);
}
private IndexLabel.Builder convert2Builder(HugeGraph g) {
IndexLabel.Builder builder = g.schema().indexLabel(this.name);
if (this.id != 0) {
E.checkArgument(this.id > 0,
"Only positive number can be assign as " +
"index label id");
E.checkArgument(g.mode() == GraphMode.RESTORING,
"Only accept index label id when graph in " +
"RESTORING mode, but '%s' is in mode '%s'",
g, g.mode());
builder.id(this.id);
}
if (this.baseType != null) {
assert this.baseValue != null;
builder.on(this.baseType, this.baseValue);
}
if (this.indexType != null) {
builder.indexType(this.indexType);
}
if (this.fields != null && this.fields.length > 0) {
builder.by(this.fields);
}
if (this.userdata != null) {
builder.userdata(this.userdata);
}
if (this.checkExist != null) {
builder.checkExist(this.checkExist);
}
if (this.rebuild != null) {
builder.rebuild(this.rebuild);
}
return builder;
}
@Override
public String toString() {
return String.format("JsonIndexLabel{name=%s, baseType=%s," +
"baseValue=%s, indexType=%s, fields=%s}",
this.name, this.baseType, this.baseValue,
this.indexType, this.fields);
}
}
}

View File

@ -1,274 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.schema;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.id.IdGenerator;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.SchemaElement;
import org.apache.hugegraph.schema.Userdata;
import org.apache.hugegraph.type.define.AggregateType;
import org.apache.hugegraph.type.define.Cardinality;
import org.apache.hugegraph.type.define.DataType;
import org.apache.hugegraph.type.define.GraphMode;
import org.apache.hugegraph.type.define.WriteType;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/schema/propertykeys")
@Singleton
@Tag(name = "PropertyKeyAPI")
public class PropertyKeyAPI extends API {
private static final Logger LOG = Log.logger(PropertyKeyAPI.class);
@POST
@Timed
@Status(Status.ACCEPTED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=property_key_write"})
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonPropertyKey jsonPropertyKey) {
LOG.debug("Graph [{}] create property key: {}",
graph, jsonPropertyKey);
checkCreatingBody(jsonPropertyKey);
HugeGraph g = graph(manager, graph);
PropertyKey.Builder builder = jsonPropertyKey.convert2Builder(g);
SchemaElement.TaskWithSchema pk = builder.createWithTask();
return manager.serializer(g).writeTaskWithSchema(pk);
}
@PUT
@Timed
@Status(Status.ACCEPTED)
@Path("{name}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=property_key_write"})
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name,
@QueryParam("action") String action,
PropertyKeyAPI.JsonPropertyKey jsonPropertyKey) {
LOG.debug("Graph [{}] {} property key: {}",
graph, action, jsonPropertyKey);
checkUpdatingBody(jsonPropertyKey);
E.checkArgument(name.equals(jsonPropertyKey.name),
"The name in url(%s) and body(%s) are different",
name, jsonPropertyKey.name);
HugeGraph g = graph(manager, graph);
if (ACTION_CLEAR.equals(action)) {
PropertyKey propertyKey = g.propertyKey(name);
E.checkArgument(propertyKey.olap(),
"Only olap property key can do action clear, " +
"but got '%s'", propertyKey);
Id id = g.clearPropertyKey(propertyKey);
SchemaElement.TaskWithSchema pk =
new SchemaElement.TaskWithSchema(propertyKey, id);
return manager.serializer(g).writeTaskWithSchema(pk);
}
// Parse action parameter
boolean append = checkAndParseAction(action);
PropertyKey.Builder builder = jsonPropertyKey.convert2Builder(g);
PropertyKey propertyKey = append ?
builder.append() :
builder.eliminate();
SchemaElement.TaskWithSchema pk =
new SchemaElement.TaskWithSchema(propertyKey, IdGenerator.ZERO);
return manager.serializer(g).writeTaskWithSchema(pk);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=property_key_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("names") List<String> names) {
boolean listAll = CollectionUtils.isEmpty(names);
if (listAll) {
LOG.debug("Graph [{}] list property keys", graph);
} else {
LOG.debug("Graph [{}] get property keys by names {}", graph, names);
}
HugeGraph g = graph(manager, graph);
List<PropertyKey> propKeys;
if (listAll) {
propKeys = g.schema().getPropertyKeys();
} else {
propKeys = new ArrayList<>(names.size());
for (String name : names) {
propKeys.add(g.schema().getPropertyKey(name));
}
}
return manager.serializer(g).writePropertyKeys(propKeys);
}
@GET
@Timed
@Path("{name}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=property_key_read"})
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] get property key by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
PropertyKey propertyKey = g.schema().getPropertyKey(name);
return manager.serializer(g).writePropertyKey(propertyKey);
}
@DELETE
@Timed
@Status(Status.ACCEPTED)
@Path("{name}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=property_key_delete"})
public Map<String, Id> delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] remove property key by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
// Throw 404 if not exists
g.schema().getPropertyKey(name);
return ImmutableMap.of("task_id",
g.schema().propertyKey(name).remove());
}
/**
* JsonPropertyKey is only used to receive create and append requests
*/
@JsonIgnoreProperties(value = {"status"})
private static class JsonPropertyKey implements Checkable {
@JsonProperty("id")
public long id;
@JsonProperty("name")
public String name;
@JsonProperty("cardinality")
public Cardinality cardinality;
@JsonProperty("data_type")
public DataType dataType;
@JsonProperty("aggregate_type")
public AggregateType aggregateType;
@JsonProperty("write_type")
public WriteType writeType;
@JsonProperty("properties")
public String[] properties;
@JsonProperty("user_data")
public Userdata userdata;
@JsonProperty("check_exist")
public Boolean checkExist;
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.name,
"The name of property key can't be null");
E.checkArgument(this.properties == null ||
this.properties.length == 0,
"Not allowed to pass properties when " +
"creating property key since it doesn't " +
"support meta properties currently");
}
private PropertyKey.Builder convert2Builder(HugeGraph g) {
PropertyKey.Builder builder = g.schema().propertyKey(this.name);
if (this.id != 0) {
E.checkArgument(this.id > 0,
"Only positive number can be assign as " +
"property key id");
E.checkArgument(g.mode() == GraphMode.RESTORING,
"Only accept property key id when graph in " +
"RESTORING mode, but '%s' is in mode '%s'",
g, g.mode());
builder.id(this.id);
}
if (this.cardinality != null) {
builder.cardinality(this.cardinality);
}
if (this.dataType != null) {
builder.dataType(this.dataType);
}
if (this.aggregateType != null) {
builder.aggregateType(this.aggregateType);
}
if (this.writeType != null) {
builder.writeType(this.writeType);
}
if (this.userdata != null) {
builder.userdata(this.userdata);
}
if (this.checkExist != null) {
builder.checkExist(this.checkExist);
}
return builder;
}
@Override
public String toString() {
return String.format("JsonPropertyKey{name=%s, cardinality=%s, " +
"dataType=%s, aggregateType=%s, " +
"writeType=%s, properties=%s}",
this.name, this.cardinality,
this.dataType, this.aggregateType,
this.writeType, this.properties);
}
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.schema;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.schema.SchemaManager;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/schema")
@Singleton
@Tag(name = "SchemaAPI")
public class SchemaAPI extends API {
private static final Logger LOG = Log.logger(SchemaAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=schema_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph) {
LOG.debug("Graph [{}] list all schema", graph);
HugeGraph g = graph(manager, graph);
SchemaManager schema = g.schema();
Map<String, List<?>> schemaMap = new LinkedHashMap<>(4);
schemaMap.put("propertykeys", schema.getPropertyKeys());
schemaMap.put("vertexlabels", schema.getVertexLabels());
schemaMap.put("edgelabels", schema.getEdgeLabels());
schemaMap.put("indexlabels", schema.getIndexLabels());
return manager.serializer(g).writeMap(schemaMap);
}
}

View File

@ -1,266 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.schema;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.Checkable;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.StatusFilter.Status;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.schema.Userdata;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.type.define.GraphMode;
import org.apache.hugegraph.type.define.IdStrategy;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
@Path("graphs/{graph}/schema/vertexlabels")
@Singleton
@Tag(name = "VertexLabelAPI")
public class VertexLabelAPI extends API {
private static final Logger LOG = Log.logger(VertexLabelAPI.class);
@POST
@Timed
@Status(Status.CREATED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_label_write"})
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
JsonVertexLabel jsonVertexLabel) {
LOG.debug("Graph [{}] create vertex label: {}",
graph, jsonVertexLabel);
checkCreatingBody(jsonVertexLabel);
HugeGraph g = graph(manager, graph);
VertexLabel.Builder builder = jsonVertexLabel.convert2Builder(g);
VertexLabel vertexLabel = builder.create();
return manager.serializer(g).writeVertexLabel(vertexLabel);
}
@PUT
@Timed
@Path("{name}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_label_write"})
public String update(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name,
@QueryParam("action") String action,
JsonVertexLabel jsonVertexLabel) {
LOG.debug("Graph [{}] {} vertex label: {}",
graph, action, jsonVertexLabel);
checkUpdatingBody(jsonVertexLabel);
E.checkArgument(name.equals(jsonVertexLabel.name),
"The name in url(%s) and body(%s) are different",
name, jsonVertexLabel.name);
// Parse action parameter
boolean append = checkAndParseAction(action);
HugeGraph g = graph(manager, graph);
VertexLabel.Builder builder = jsonVertexLabel.convert2Builder(g);
VertexLabel vertexLabel = append ?
builder.append() :
builder.eliminate();
return manager.serializer(g).writeVertexLabel(vertexLabel);
}
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_label_read"})
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("names") List<String> names) {
boolean listAll = CollectionUtils.isEmpty(names);
if (listAll) {
LOG.debug("Graph [{}] list vertex labels", graph);
} else {
LOG.debug("Graph [{}] get vertex labels by names {}", graph, names);
}
HugeGraph g = graph(manager, graph);
List<VertexLabel> labels;
if (listAll) {
labels = g.schema().getVertexLabels();
} else {
labels = new ArrayList<>(names.size());
for (String name : names) {
labels.add(g.schema().getVertexLabel(name));
}
}
return manager.serializer(g).writeVertexLabels(labels);
}
@GET
@Timed
@Path("{name}")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_label_read"})
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] get vertex label by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
VertexLabel vertexLabel = g.schema().getVertexLabel(name);
return manager.serializer(g).writeVertexLabel(vertexLabel);
}
@DELETE
@Timed
@Path("{name}")
@Status(Status.ACCEPTED)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed({"admin", "$owner=$graph $action=vertex_label_delete"})
public Map<String, Id> delete(@Context GraphManager manager,
@PathParam("graph") String graph,
@PathParam("name") String name) {
LOG.debug("Graph [{}] remove vertex label by name '{}'", graph, name);
HugeGraph g = graph(manager, graph);
// Throw 404 if not exists
g.schema().getVertexLabel(name);
return ImmutableMap.of("task_id",
g.schema().vertexLabel(name).remove());
}
/**
* JsonVertexLabel is only used to receive create and append requests
*/
@JsonIgnoreProperties(value = {"index_labels", "status"})
private static class JsonVertexLabel implements Checkable {
@JsonProperty("id")
public long id;
@JsonProperty("name")
public String name;
@JsonProperty("id_strategy")
public IdStrategy idStrategy;
@JsonProperty("properties")
public String[] properties;
@JsonProperty("primary_keys")
public String[] primaryKeys;
@JsonProperty("nullable_keys")
public String[] nullableKeys;
@JsonProperty("ttl")
public long ttl;
@JsonProperty("ttl_start_time")
public String ttlStartTime;
@JsonProperty("enable_label_index")
public Boolean enableLabelIndex;
@JsonProperty("user_data")
public Userdata userdata;
@JsonProperty("check_exist")
public Boolean checkExist;
@Override
public void checkCreate(boolean isBatch) {
E.checkArgumentNotNull(this.name,
"The name of vertex label can't be null");
}
private VertexLabel.Builder convert2Builder(HugeGraph g) {
VertexLabel.Builder builder = g.schema().vertexLabel(this.name);
if (this.id != 0) {
E.checkArgument(this.id > 0,
"Only positive number can be assign as " +
"vertex label id");
E.checkArgument(g.mode() == GraphMode.RESTORING,
"Only accept vertex label id when graph in " +
"RESTORING mode, but '%s' is in mode '%s'",
g, g.mode());
builder.id(this.id);
}
if (this.idStrategy != null) {
builder.idStrategy(this.idStrategy);
}
if (this.properties != null) {
builder.properties(this.properties);
}
if (this.primaryKeys != null) {
builder.primaryKeys(this.primaryKeys);
}
if (this.nullableKeys != null) {
builder.nullableKeys(this.nullableKeys);
}
if (this.enableLabelIndex != null) {
builder.enableLabelIndex(this.enableLabelIndex);
}
if (this.userdata != null) {
builder.userdata(this.userdata);
}
if (this.checkExist != null) {
builder.checkExist(this.checkExist);
}
if (this.ttl != 0) {
builder.ttl(this.ttl);
}
if (this.ttlStartTime != null) {
E.checkArgument(this.ttl > 0,
"Only set ttlStartTime when ttl is " +
"positive, but got ttl: %s", this.ttl);
builder.ttlStartTime(this.ttlStartTime);
}
return builder;
}
@Override
public String toString() {
return String.format("JsonVertexLabel{" +
"name=%s, idStrategy=%s, primaryKeys=%s, nullableKeys=%s, " +
"properties=%s, ttl=%s, ttlStartTime=%s}",
this.name, this.idStrategy, this.primaryKeys,
this.nullableKeys, this.properties, this.ttl,
this.ttlStartTime);
}
}
}

View File

@ -1,95 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.ShortestPathTraverser;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableList;
@Path("graphs/{graph}/traversers/allshortestpaths")
@Singleton
@Tag(name = "AllShortestPathsAPI")
public class AllShortestPathsAPI extends API {
private static final Logger LOG = Log.logger(AllShortestPathsAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String source,
@QueryParam("target") String target,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("skip_degree")
@DefaultValue("0") long skipDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity) {
LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " +
"direction {}, edge label {}, max depth '{}', " +
"max degree '{}', skipped degree '{}' and capacity '{}'",
graph, source, target, direction, edgeLabel, depth,
maxDegree, skipDegree, capacity);
Id sourceId = VertexAPI.checkAndParseVertexId(source);
Id targetId = VertexAPI.checkAndParseVertexId(target);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
ShortestPathTraverser traverser = new ShortestPathTraverser(g);
List<String> edgeLabels = edgeLabel == null ? ImmutableList.of() :
ImmutableList.of(edgeLabel);
HugeTraverser.PathSet paths = traverser.allShortestPaths(
sourceId, targetId, dir, edgeLabels,
depth, maxDegree, skipDegree, capacity);
return manager.serializer(g).writePaths("paths", paths, false);
}
}

View File

@ -1,200 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.traversal.algorithm.CustomizedCrosspointsTraverser;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/traversers/customizedcrosspoints")
@Singleton
@Tag(name = "CustomizedCrosspointsAPI")
public class CustomizedCrosspointsAPI extends API {
private static final Logger LOG = Log.logger(CustomizedCrosspointsAPI.class);
@POST
@Timed
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String post(@Context GraphManager manager,
@PathParam("graph") String graph,
CrosspointsRequest request) {
E.checkArgumentNotNull(request,
"The crosspoints request body can't be null");
E.checkArgumentNotNull(request.sources,
"The sources of crosspoints request " +
"can't be null");
E.checkArgument(request.pathPatterns != null &&
!request.pathPatterns.isEmpty(),
"The steps of crosspoints request can't be empty");
LOG.debug("Graph [{}] get customized crosspoints from source vertex " +
"'{}', with path_pattern '{}', with_path '{}', with_vertex " +
"'{}', capacity '{}' and limit '{}'", graph, request.sources,
request.pathPatterns, request.withPath, request.withVertex,
request.capacity, request.limit);
HugeGraph g = graph(manager, graph);
Iterator<Vertex> sources = request.sources.vertices(g);
List<CustomizedCrosspointsTraverser.PathPattern> patterns;
patterns = pathPatterns(g, request);
CustomizedCrosspointsTraverser traverser =
new CustomizedCrosspointsTraverser(g);
CustomizedCrosspointsTraverser.CrosspointsPaths paths;
paths = traverser.crosspointsPaths(sources, patterns, request.capacity,
request.limit);
Iterator<Vertex> iter = QueryResults.emptyIterator();
if (!request.withVertex) {
return manager.serializer(g).writeCrosspoints(paths, iter,
request.withPath);
}
Set<Id> ids = new HashSet<>();
if (request.withPath) {
for (HugeTraverser.Path p : paths.paths()) {
ids.addAll(p.vertices());
}
} else {
ids = paths.crosspoints();
}
if (!ids.isEmpty()) {
iter = g.vertices(ids.toArray());
}
return manager.serializer(g).writeCrosspoints(paths, iter,
request.withPath);
}
private static List<CustomizedCrosspointsTraverser.PathPattern>
pathPatterns(HugeGraph graph, CrosspointsRequest request) {
int stepSize = request.pathPatterns.size();
List<CustomizedCrosspointsTraverser.PathPattern> pathPatterns;
pathPatterns = new ArrayList<>(stepSize);
for (PathPattern pattern : request.pathPatterns) {
CustomizedCrosspointsTraverser.PathPattern pathPattern;
pathPattern = new CustomizedCrosspointsTraverser.PathPattern();
for (Step step : pattern.steps) {
pathPattern.add(step.jsonToStep(graph));
}
pathPatterns.add(pathPattern);
}
return pathPatterns;
}
private static class CrosspointsRequest {
@JsonProperty("sources")
public Vertices sources;
@JsonProperty("path_patterns")
public List<PathPattern> pathPatterns;
@JsonProperty("capacity")
public long capacity = Long.parseLong(DEFAULT_CAPACITY);
@JsonProperty("limit")
public int limit = Integer.parseInt(DEFAULT_PATHS_LIMIT);
@JsonProperty("with_path")
public boolean withPath = false;
@JsonProperty("with_vertex")
public boolean withVertex = false;
@Override
public String toString() {
return String.format("CrosspointsRequest{sourceVertex=%s," +
"pathPatterns=%s,withPath=%s,withVertex=%s," +
"capacity=%s,limit=%s}", this.sources,
this.pathPatterns, this.withPath,
this.withVertex, this.capacity, this.limit);
}
}
private static class PathPattern {
@JsonProperty("steps")
public List<Step> steps;
@Override
public String toString() {
return String.format("PathPattern{steps=%s", this.steps);
}
}
private static class Step {
@JsonProperty("direction")
public Directions direction;
@JsonProperty("labels")
public List<String> labels;
@JsonProperty("properties")
public Map<String, Object> properties;
@JsonAlias("degree")
@JsonProperty("max_degree")
public long maxDegree = Long.parseLong(DEFAULT_MAX_DEGREE);
@JsonProperty("skip_degree")
public long skipDegree = 0L;
@Override
public String toString() {
return String.format("Step{direction=%s,labels=%s,properties=%s," +
"maxDegree=%s,skipDegree=%s}",
this.direction, this.labels, this.properties,
this.maxDegree, this.skipDegree);
}
private CustomizedCrosspointsTraverser.Step jsonToStep(HugeGraph g) {
return new CustomizedCrosspointsTraverser.Step(g, this.direction,
this.labels,
this.properties,
this.maxDegree,
this.skipDegree);
}
}
}

View File

@ -1,201 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_SAMPLE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_WEIGHT;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.traversal.algorithm.CustomizePathsTraverser;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.steps.WeightedEdgeStep;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/traversers/customizedpaths")
@Singleton
@Tag(name = "CustomizedPathsAPI")
public class CustomizedPathsAPI extends API {
private static final Logger LOG = Log.logger(CustomizedPathsAPI.class);
@POST
@Timed
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String post(@Context GraphManager manager,
@PathParam("graph") String graph,
PathRequest request) {
E.checkArgumentNotNull(request, "The path request body can't be null");
E.checkArgumentNotNull(request.sources,
"The sources of path request can't be null");
E.checkArgument(request.steps != null && !request.steps.isEmpty(),
"The steps of path request can't be empty");
if (request.sortBy == null) {
request.sortBy = SortBy.NONE;
}
LOG.debug("Graph [{}] get customized paths from source vertex '{}', " +
"with steps '{}', sort by '{}', capacity '{}', limit '{}' " +
"and with_vertex '{}'", graph, request.sources, request.steps,
request.sortBy, request.capacity, request.limit,
request.withVertex);
HugeGraph g = graph(manager, graph);
Iterator<Vertex> sources = request.sources.vertices(g);
List<WeightedEdgeStep> steps = step(g, request);
boolean sorted = request.sortBy != SortBy.NONE;
CustomizePathsTraverser traverser = new CustomizePathsTraverser(g);
List<HugeTraverser.Path> paths;
paths = traverser.customizedPaths(sources, steps, sorted,
request.capacity, request.limit);
if (sorted) {
boolean incr = request.sortBy == SortBy.INCR;
paths = CustomizePathsTraverser.topNPath(paths, incr,
request.limit);
}
if (!request.withVertex) {
return manager.serializer(g).writePaths("paths", paths, false);
}
Set<Id> ids = new HashSet<>();
for (HugeTraverser.Path p : paths) {
ids.addAll(p.vertices());
}
Iterator<Vertex> iter = QueryResults.emptyIterator();
if (!ids.isEmpty()) {
iter = g.vertices(ids.toArray());
}
return manager.serializer(g).writePaths("paths", paths, false, iter);
}
private static List<WeightedEdgeStep> step(HugeGraph graph,
PathRequest req) {
int stepSize = req.steps.size();
List<WeightedEdgeStep> steps = new ArrayList<>(stepSize);
for (Step step : req.steps) {
steps.add(step.jsonToStep(graph));
}
return steps;
}
private static class PathRequest {
@JsonProperty("sources")
public Vertices sources;
@JsonProperty("steps")
public List<Step> steps;
@JsonProperty("sort_by")
public SortBy sortBy;
@JsonProperty("capacity")
public long capacity = Long.parseLong(DEFAULT_CAPACITY);
@JsonProperty("limit")
public int limit = Integer.parseInt(DEFAULT_PATHS_LIMIT);
@JsonProperty("with_vertex")
public boolean withVertex = false;
@Override
public String toString() {
return String.format("PathRequest{sourceVertex=%s,steps=%s," +
"sortBy=%s,capacity=%s,limit=%s," +
"withVertex=%s}", this.sources, this.steps,
this.sortBy, this.capacity, this.limit,
this.withVertex);
}
}
private static class Step {
@JsonProperty("direction")
public Directions direction;
@JsonProperty("labels")
public List<String> labels;
@JsonProperty("properties")
public Map<String, Object> properties;
@JsonAlias("degree")
@JsonProperty("max_degree")
public long maxDegree = Long.parseLong(DEFAULT_MAX_DEGREE);
@JsonProperty("skip_degree")
public long skipDegree = 0L;
@JsonProperty("weight_by")
public String weightBy;
@JsonProperty("default_weight")
public double defaultWeight = Double.parseDouble(DEFAULT_WEIGHT);
@JsonProperty("sample")
public long sample = Long.parseLong(DEFAULT_SAMPLE);
@Override
public String toString() {
return String.format("Step{direction=%s,labels=%s,properties=%s," +
"maxDegree=%s,skipDegree=%s," +
"weightBy=%s,defaultWeight=%s,sample=%s}",
this.direction, this.labels, this.properties,
this.maxDegree, this.skipDegree,
this.weightBy, this.defaultWeight,
this.sample);
}
private WeightedEdgeStep jsonToStep(HugeGraph g) {
return new WeightedEdgeStep(g, this.direction, this.labels,
this.properties, this.maxDegree,
this.skipDegree, this.weightBy,
this.defaultWeight, this.sample);
}
}
private enum SortBy {
INCR,
DECR,
NONE
}
}

View File

@ -1,126 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PAGE_LIMIT;
import java.util.Iterator;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.filter.CompressInterceptor.Compress;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.ConditionQuery;
import org.apache.hugegraph.backend.store.Shard;
import org.apache.hugegraph.structure.HugeEdge;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/traversers/edges")
@Singleton
@Tag(name = "EdgesAPI")
public class EdgesAPI extends API {
private static final Logger LOG = Log.logger(EdgesAPI.class);
@GET
@Timed
@Compress
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String list(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("ids") List<String> stringIds) {
LOG.debug("Graph [{}] get edges by ids: {}", graph, stringIds);
E.checkArgument(stringIds != null && !stringIds.isEmpty(),
"The ids parameter can't be null or empty");
Object[] ids = new Id[stringIds.size()];
for (int i = 0; i < ids.length; i++) {
ids[i] = HugeEdge.getIdValue(stringIds.get(i), false);
}
HugeGraph g = graph(manager, graph);
Iterator<Edge> edges = g.edges(ids);
return manager.serializer(g).writeEdges(edges, false);
}
@GET
@Timed
@Path("shards")
@Compress
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String shards(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("split_size") long splitSize) {
LOG.debug("Graph [{}] get vertex shards with split size '{}'",
graph, splitSize);
HugeGraph g = graph(manager, graph);
List<Shard> shards = g.metadata(HugeType.EDGE_OUT, "splits", splitSize);
return manager.serializer(g).writeList("shards", shards);
}
@GET
@Timed
@Path("scan")
@Compress
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String scan(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("start") String start,
@QueryParam("end") String end,
@QueryParam("page") String page,
@QueryParam("page_limit")
@DefaultValue(DEFAULT_PAGE_LIMIT) long pageLimit) {
LOG.debug("Graph [{}] query edges by shard(start: {}, end: {}, " +
"page: {}) ", graph, start, end, page);
HugeGraph g = graph(manager, graph);
ConditionQuery query = new ConditionQuery(HugeType.EDGE_OUT);
query.scan(start, end);
query.page(page);
if (query.paging()) {
query.limit(pageLimit);
}
Iterator<Edge> edges = g.edges(query);
return manager.serializer(g).writeEdges(edges, query.paging());
}
}

View File

@ -1,191 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_ELEMENTS_LIMIT;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.Query;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.structure.HugeVertex;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.KneighborTraverser;
import org.apache.hugegraph.traversal.algorithm.records.KneighborRecords;
import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
@Path("graphs/{graph}/traversers/kneighbor")
@Singleton
@Tag(name = "KneighborAPI")
public class KneighborAPI extends TraverserAPI {
private static final Logger LOG = Log.logger(KneighborAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String sourceV,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("limit")
@DefaultValue(DEFAULT_ELEMENTS_LIMIT) int limit) {
LOG.debug("Graph [{}] get k-neighbor from '{}' with " +
"direction '{}', edge label '{}', max depth '{}', " +
"max degree '{}' and limit '{}'",
graph, sourceV, direction, edgeLabel, depth,
maxDegree, limit);
Id source = VertexAPI.checkAndParseVertexId(sourceV);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
Set<Id> ids;
try (KneighborTraverser traverser = new KneighborTraverser(g)) {
ids = traverser.kneighbor(source, dir, edgeLabel,
depth, maxDegree, limit);
}
return manager.serializer(g).writeList("vertices", ids);
}
@POST
@Timed
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String post(@Context GraphManager manager,
@PathParam("graph") String graph,
Request request) {
E.checkArgumentNotNull(request, "The request body can't be null");
E.checkArgumentNotNull(request.source,
"The source of request can't be null");
E.checkArgument(request.step != null,
"The steps of request can't be null");
if (request.countOnly) {
E.checkArgument(!request.withVertex && !request.withPath,
"Can't return vertex or path when count only");
}
LOG.debug("Graph [{}] get customized kneighbor from source vertex " +
"'{}', with step '{}', limit '{}', count_only '{}', " +
"with_vertex '{}' and with_path '{}'",
graph, request.source, request.step, request.limit,
request.countOnly, request.withVertex, request.withPath);
HugeGraph g = graph(manager, graph);
Id sourceId = HugeVertex.getIdValue(request.source);
EdgeStep step = step(g, request.step);
KneighborRecords results;
try (KneighborTraverser traverser = new KneighborTraverser(g)) {
results = traverser.customizedKneighbor(sourceId, step,
request.maxDepth,
request.limit);
}
long size = results.size();
if (request.limit != Query.NO_LIMIT && size > request.limit) {
size = request.limit;
}
List<Id> neighbors = request.countOnly ?
ImmutableList.of() : results.ids(request.limit);
HugeTraverser.PathSet paths = new HugeTraverser.PathSet();
if (request.withPath) {
paths.addAll(results.paths(request.limit));
}
Iterator<Vertex> iter = QueryResults.emptyIterator();
if (request.withVertex && !request.countOnly) {
Set<Id> ids = new HashSet<>(neighbors);
if (request.withPath) {
for (HugeTraverser.Path p : paths) {
ids.addAll(p.vertices());
}
}
if (!ids.isEmpty()) {
iter = g.vertices(ids.toArray());
}
}
return manager.serializer(g).writeNodesWithPath("kneighbor", neighbors,
size, paths, iter);
}
private static class Request {
@JsonProperty("source")
public Object source;
@JsonProperty("step")
public TraverserAPI.Step step;
@JsonProperty("max_depth")
public int maxDepth;
@JsonProperty("limit")
public int limit = Integer.parseInt(DEFAULT_ELEMENTS_LIMIT);
@JsonProperty("count_only")
public boolean countOnly = false;
@JsonProperty("with_vertex")
public boolean withVertex = false;
@JsonProperty("with_path")
public boolean withPath = false;
@Override
public String toString() {
return String.format("PathRequest{source=%s,step=%s,maxDepth=%s" +
"limit=%s,countOnly=%s,withVertex=%s," +
"withPath=%s}", this.source, this.step,
this.maxDepth, this.limit, this.countOnly,
this.withVertex, this.withPath);
}
}
}

View File

@ -1,206 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_ELEMENTS_LIMIT;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.Query;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.structure.HugeVertex;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.KoutTraverser;
import org.apache.hugegraph.traversal.algorithm.records.KoutRecords;
import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
@Path("graphs/{graph}/traversers/kout")
@Singleton
@Tag(name = "KoutAPI")
public class KoutAPI extends TraverserAPI {
private static final Logger LOG = Log.logger(KoutAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String source,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("nearest")
@DefaultValue("true") boolean nearest,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity,
@QueryParam("limit")
@DefaultValue(DEFAULT_ELEMENTS_LIMIT) int limit) {
LOG.debug("Graph [{}] get k-out from '{}' with " +
"direction '{}', edge label '{}', max depth '{}', nearest " +
"'{}', max degree '{}', capacity '{}' and limit '{}'",
graph, source, direction, edgeLabel, depth, nearest,
maxDegree, capacity, limit);
Id sourceId = VertexAPI.checkAndParseVertexId(source);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
Set<Id> ids;
try (KoutTraverser traverser = new KoutTraverser(g)) {
ids = traverser.kout(sourceId, dir, edgeLabel, depth,
nearest, maxDegree, capacity, limit);
}
return manager.serializer(g).writeList("vertices", ids);
}
@POST
@Timed
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String post(@Context GraphManager manager,
@PathParam("graph") String graph,
Request request) {
E.checkArgumentNotNull(request, "The request body can't be null");
E.checkArgumentNotNull(request.source,
"The source of request can't be null");
E.checkArgument(request.step != null,
"The steps of request can't be null");
if (request.countOnly) {
E.checkArgument(!request.withVertex && !request.withPath,
"Can't return vertex or path when count only");
}
LOG.debug("Graph [{}] get customized kout from source vertex '{}', " +
"with step '{}', max_depth '{}', nearest '{}', " +
"count_only '{}', capacity '{}', limit '{}', " +
"with_vertex '{}' and with_path '{}'",
graph, request.source, request.step, request.maxDepth,
request.nearest, request.countOnly, request.capacity,
request.limit, request.withVertex, request.withPath);
HugeGraph g = graph(manager, graph);
Id sourceId = HugeVertex.getIdValue(request.source);
EdgeStep step = step(g, request.step);
KoutRecords results;
try (KoutTraverser traverser = new KoutTraverser(g)) {
results = traverser.customizedKout(sourceId, step,
request.maxDepth,
request.nearest,
request.capacity,
request.limit);
}
long size = results.size();
if (request.limit != Query.NO_LIMIT && size > request.limit) {
size = request.limit;
}
List<Id> neighbors = request.countOnly ?
ImmutableList.of() : results.ids(request.limit);
HugeTraverser.PathSet paths = new HugeTraverser.PathSet();
if (request.withPath) {
paths.addAll(results.paths(request.limit));
}
Iterator<Vertex> iter = QueryResults.emptyIterator();
if (request.withVertex && !request.countOnly) {
Set<Id> ids = new HashSet<>(neighbors);
if (request.withPath) {
for (HugeTraverser.Path p : paths) {
ids.addAll(p.vertices());
}
}
if (!ids.isEmpty()) {
iter = g.vertices(ids.toArray());
}
}
return manager.serializer(g).writeNodesWithPath("kout", neighbors,
size, paths, iter);
}
private static class Request {
@JsonProperty("source")
public Object source;
@JsonProperty("step")
public TraverserAPI.Step step;
@JsonProperty("max_depth")
public int maxDepth;
@JsonProperty("nearest")
public boolean nearest = true;
@JsonProperty("count_only")
public boolean countOnly = false;
@JsonProperty("capacity")
public long capacity = Long.parseLong(DEFAULT_CAPACITY);
@JsonProperty("limit")
public int limit = Integer.parseInt(DEFAULT_ELEMENTS_LIMIT);
@JsonProperty("with_vertex")
public boolean withVertex = false;
@JsonProperty("with_path")
public boolean withPath = false;
@Override
public String toString() {
return String.format("KoutRequest{source=%s,step=%s,maxDepth=%s" +
"nearest=%s,countOnly=%s,capacity=%s," +
"limit=%s,withVertex=%s,withPath=%s}",
this.source, this.step, this.maxDepth,
this.nearest, this.countOnly, this.capacity,
this.limit, this.withVertex, this.withPath);
}
}
}

View File

@ -1,128 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.MultiNodeShortestPathTraverser;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/traversers/multinodeshortestpath")
@Singleton
@Tag(name = "MultiNodeShortestPathAPI")
public class MultiNodeShortestPathAPI extends TraverserAPI {
private static final Logger LOG = Log.logger(MultiNodeShortestPathAPI.class);
@POST
@Timed
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String post(@Context GraphManager manager,
@PathParam("graph") String graph,
Request request) {
E.checkArgumentNotNull(request, "The request body can't be null");
E.checkArgumentNotNull(request.vertices,
"The vertices of request can't be null");
E.checkArgument(request.step != null,
"The steps of request can't be null");
LOG.debug("Graph [{}] get multiple node shortest path from " +
"vertices '{}', with step '{}', max_depth '{}', capacity " +
"'{}' and with_vertex '{}'",
graph, request.vertices, request.step, request.maxDepth,
request.capacity, request.withVertex);
HugeGraph g = graph(manager, graph);
Iterator<Vertex> vertices = request.vertices.vertices(g);
EdgeStep step = step(g, request.step);
List<HugeTraverser.Path> paths;
try (MultiNodeShortestPathTraverser traverser =
new MultiNodeShortestPathTraverser(g)) {
paths = traverser.multiNodeShortestPath(vertices, step,
request.maxDepth,
request.capacity);
}
if (!request.withVertex) {
return manager.serializer(g).writePaths("paths", paths, false);
}
Set<Id> ids = new HashSet<>();
for (HugeTraverser.Path p : paths) {
ids.addAll(p.vertices());
}
Iterator<Vertex> iter = QueryResults.emptyIterator();
if (!ids.isEmpty()) {
iter = g.vertices(ids.toArray());
}
return manager.serializer(g).writePaths("paths", paths, false, iter);
}
private static class Request {
@JsonProperty("vertices")
public Vertices vertices;
@JsonProperty("step")
public Step step;
@JsonProperty("max_depth")
public int maxDepth;
@JsonProperty("capacity")
public long capacity = Long.parseLong(DEFAULT_CAPACITY);
@JsonProperty("with_vertex")
public boolean withVertex = false;
@Override
public String toString() {
return String.format("Request{vertices=%s,step=%s,maxDepth=%s" +
"capacity=%s,withVertex=%s}",
this.vertices, this.step, this.maxDepth,
this.capacity, this.withVertex);
}
}
}

View File

@ -1,185 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEPTH;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.traversal.algorithm.CollectionPathsTraverser;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.PathsTraverser;
import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
@Path("graphs/{graph}/traversers/paths")
@Singleton
@Tag(name = "PathsAPI")
public class PathsAPI extends TraverserAPI {
private static final Logger LOG = Log.logger(PathsAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String source,
@QueryParam("target") String target,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity,
@QueryParam("limit")
@DefaultValue(DEFAULT_PATHS_LIMIT) int limit) {
LOG.debug("Graph [{}] get paths from '{}', to '{}' with " +
"direction {}, edge label {}, max depth '{}', " +
"max degree '{}', capacity '{}' and limit '{}'",
graph, source, target, direction, edgeLabel, depth,
maxDegree, capacity, limit);
Id sourceId = VertexAPI.checkAndParseVertexId(source);
Id targetId = VertexAPI.checkAndParseVertexId(target);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
PathsTraverser traverser = new PathsTraverser(g);
HugeTraverser.PathSet paths = traverser.paths(sourceId, dir, targetId,
dir.opposite(), edgeLabel,
depth, maxDegree, capacity,
limit);
return manager.serializer(g).writePaths("paths", paths, false);
}
@POST
@Timed
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String post(@Context GraphManager manager,
@PathParam("graph") String graph,
Request request) {
E.checkArgumentNotNull(request, "The request body can't be null");
E.checkArgumentNotNull(request.sources,
"The sources of request can't be null");
E.checkArgumentNotNull(request.targets,
"The targets of request can't be null");
E.checkArgumentNotNull(request.step,
"The step of request can't be null");
E.checkArgument(request.depth > 0 && request.depth <= DEFAULT_MAX_DEPTH,
"The depth of request must be in (0, %s], " +
"but got: %s", DEFAULT_MAX_DEPTH, request.depth);
LOG.debug("Graph [{}] get paths from source vertices '{}', target " +
"vertices '{}', with step '{}', max depth '{}', " +
"capacity '{}', limit '{}' and with_vertex '{}'",
graph, request.sources, request.targets, request.step,
request.depth, request.capacity, request.limit,
request.withVertex);
HugeGraph g = graph(manager, graph);
Iterator<Vertex> sources = request.sources.vertices(g);
Iterator<Vertex> targets = request.targets.vertices(g);
EdgeStep step = step(g, request.step);
CollectionPathsTraverser traverser = new CollectionPathsTraverser(g);
Collection<HugeTraverser.Path> paths;
paths = traverser.paths(sources, targets, step, request.depth,
request.nearest, request.capacity,
request.limit);
if (!request.withVertex) {
return manager.serializer(g).writePaths("paths", paths, false);
}
Set<Id> ids = new HashSet<>();
for (HugeTraverser.Path p : paths) {
ids.addAll(p.vertices());
}
Iterator<Vertex> iter = QueryResults.emptyIterator();
if (!ids.isEmpty()) {
iter = g.vertices(ids.toArray());
}
return manager.serializer(g).writePaths("paths", paths, false, iter);
}
private static class Request {
@JsonProperty("sources")
public Vertices sources;
@JsonProperty("targets")
public Vertices targets;
@JsonProperty("step")
public TraverserAPI.Step step;
@JsonProperty("max_depth")
public int depth;
@JsonProperty("nearest")
public boolean nearest = false;
@JsonProperty("capacity")
public long capacity = Long.parseLong(DEFAULT_CAPACITY);
@JsonProperty("limit")
public int limit = Integer.parseInt(DEFAULT_PATHS_LIMIT);
@JsonProperty("with_vertex")
public boolean withVertex = false;
@Override
public String toString() {
return String.format("PathRequest{sources=%s,targets=%s,step=%s," +
"maxDepth=%s,nearest=%s,capacity=%s," +
"limit=%s,withVertex=%s}", this.sources,
this.targets, this.step, this.depth,
this.nearest, this.capacity,
this.limit, this.withVertex);
}
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.SubGraphTraverser;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/traversers/rays")
@Singleton
@Tag(name = "RaysAPI")
public class RaysAPI extends API {
private static final Logger LOG = Log.logger(RaysAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String sourceV,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity,
@QueryParam("limit")
@DefaultValue(DEFAULT_PATHS_LIMIT) int limit) {
LOG.debug("Graph [{}] get rays paths from '{}' with " +
"direction '{}', edge label '{}', max depth '{}', " +
"max degree '{}', capacity '{}' and limit '{}'",
graph, sourceV, direction, edgeLabel, depth, maxDegree,
capacity, limit);
Id source = VertexAPI.checkAndParseVertexId(sourceV);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
SubGraphTraverser traverser = new SubGraphTraverser(g);
HugeTraverser.PathSet paths = traverser.rays(source, dir, edgeLabel,
depth, maxDegree,
capacity, limit);
return manager.serializer(g).writePaths("rays", paths, false);
}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.SubGraphTraverser;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/traversers/rings")
@Singleton
@Tag(name = "RingsAPI")
public class RingsAPI extends API {
private static final Logger LOG = Log.logger(RingsAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String sourceV,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("source_in_ring")
@DefaultValue("true") boolean sourceInRing,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity,
@QueryParam("limit")
@DefaultValue(DEFAULT_PATHS_LIMIT) int limit) {
LOG.debug("Graph [{}] get rings paths reachable from '{}' with " +
"direction '{}', edge label '{}', max depth '{}', " +
"source in ring '{}', max degree '{}', capacity '{}' " +
"and limit '{}'",
graph, sourceV, direction, edgeLabel, depth, sourceInRing,
maxDegree, capacity, limit);
Id source = VertexAPI.checkAndParseVertexId(sourceV);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
SubGraphTraverser traverser = new SubGraphTraverser(g);
HugeTraverser.PathSet paths = traverser.rings(source, dir, edgeLabel,
depth, sourceInRing,
maxDegree, capacity, limit);
return manager.serializer(g).writePaths("rings", paths, false);
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_ELEMENTS_LIMIT;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import java.util.Set;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.traversal.algorithm.SameNeighborTraverser;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/traversers/sameneighbors")
@Singleton
@Tag(name = "SameNeighborsAPI")
public class SameNeighborsAPI extends API {
private static final Logger LOG = Log.logger(SameNeighborsAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("vertex") String vertex,
@QueryParam("other") String other,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("limit")
@DefaultValue(DEFAULT_ELEMENTS_LIMIT) int limit) {
LOG.debug("Graph [{}] get same neighbors between '{}' and '{}' with " +
"direction {}, edge label {}, max degree '{}' and limit '{}'",
graph, vertex, other, direction, edgeLabel, maxDegree, limit);
Id sourceId = VertexAPI.checkAndParseVertexId(vertex);
Id targetId = VertexAPI.checkAndParseVertexId(other);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
SameNeighborTraverser traverser = new SameNeighborTraverser(g);
Set<Id> neighbors = traverser.sameNeighbors(sourceId, targetId, dir,
edgeLabel, maxDegree, limit);
return manager.serializer(g).writeList("same_neighbors", neighbors);
}
}

View File

@ -1,96 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import java.util.List;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.traversal.algorithm.HugeTraverser;
import org.apache.hugegraph.traversal.algorithm.ShortestPathTraverser;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableList;
@Path("graphs/{graph}/traversers/shortestpath")
@Singleton
@Tag(name = "ShortestPathAPI")
public class ShortestPathAPI extends API {
private static final Logger LOG = Log.logger(ShortestPathAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String source,
@QueryParam("target") String target,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("skip_degree")
@DefaultValue("0") long skipDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity) {
LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " +
"direction {}, edge label {}, max depth '{}', " +
"max degree '{}', skipped maxDegree '{}' and capacity '{}'",
graph, source, target, direction, edgeLabel, depth,
maxDegree, skipDegree, capacity);
Id sourceId = VertexAPI.checkAndParseVertexId(source);
Id targetId = VertexAPI.checkAndParseVertexId(target);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
ShortestPathTraverser traverser = new ShortestPathTraverser(g);
List<String> edgeLabels = edgeLabel == null ? ImmutableList.of() :
ImmutableList.of(edgeLabel);
HugeTraverser.Path path = traverser.shortestPath(sourceId, targetId,
dir, edgeLabels, depth,
maxDegree, skipDegree,
capacity);
return manager.serializer(g).writeList("path", path.vertices());
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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.
*/
package org.apache.hugegraph.api.traversers;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;
import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT;
import java.util.Iterator;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.inject.Singleton;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.hugegraph.core.GraphManager;
import org.slf4j.Logger;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.api.API;
import org.apache.hugegraph.api.graph.EdgeAPI;
import org.apache.hugegraph.api.graph.VertexAPI;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.query.QueryResults;
import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser;
import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser.WeightedPaths;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;
@Path("graphs/{graph}/traversers/singlesourceshortestpath")
@Singleton
@Tag(name = "SingleSourceShortestPathAPI")
public class SingleSourceShortestPathAPI extends API {
private static final Logger LOG = Log.logger(SingleSourceShortestPathAPI.class);
@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("source") String source,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("weight") String weight,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("skip_degree")
@DefaultValue("0") long skipDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity,
@QueryParam("limit")
@DefaultValue(DEFAULT_PATHS_LIMIT) int limit,
@QueryParam("with_vertex") boolean withVertex) {
LOG.debug("Graph [{}] get single source shortest path from '{}' " +
"with direction {}, edge label {}, weight property {}, " +
"max degree '{}', limit '{}' and with vertex '{}'",
graph, source, direction, edgeLabel,
weight, maxDegree, withVertex);
Id sourceId = VertexAPI.checkAndParseVertexId(source);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
HugeGraph g = graph(manager, graph);
SingleSourceShortestPathTraverser traverser =
new SingleSourceShortestPathTraverser(g);
WeightedPaths paths = traverser.singleSourceShortestPaths(
sourceId, dir, edgeLabel, weight,
maxDegree, skipDegree, capacity, limit);
Iterator<Vertex> iterator = QueryResults.emptyIterator();
assert paths != null;
if (!paths.isEmpty() && withVertex) {
iterator = g.vertices(paths.vertices().toArray());
}
return manager.serializer(g).writeWeightedPaths(paths, iterator);
}
}

Some files were not shown because too many files have changed in this diff Show More