diff --git a/.asf.yaml b/.asf.yaml
index 581a611dc9..8bf1cbee0c 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -42,7 +42,8 @@ github:
- Analyze (java)
- CodeQL
- check-license
- - build (memory, 11)
+ - build-server (memory, 11)
+ - build-commons (11)
required_pull_request_reviews:
dismiss_stale_reviews: true
require_code_owner_reviews: false
diff --git a/.gitattributes b/.gitattributes
index ca5e57db70..85f64d198b 100755
--- a/.gitattributes
+++ b/.gitattributes
@@ -12,4 +12,5 @@ hugegraph-store/hg-store-dist/src/assembly/static/bin/libjemalloc_aarch64.so exp
.github/ export-ignore
.idea/ export-ignore
install-dist/scripts/ export-ignore
+hugegraph-commons/hugegraph-dist/ export-ignore
docker/ export-ignore
diff --git a/.github/workflows/check-dependencies.yml b/.github/workflows/check-dependencies.yml
index 6e3c572889..68f8c0e0c9 100644
--- a/.github/workflows/check-dependencies.yml
+++ b/.github/workflows/check-dependencies.yml
@@ -32,7 +32,7 @@ jobs:
- name: mvn install
run: |
- mvn install -DskipTests=true -ntp
+ mvn install -Dmaven.test.skip=true -ntp
- name: generate current dependencies
run: |
bash $SCRIPT_DEPENDENCY/regenerate_known_dependencies.sh current-dependencies.txt
diff --git a/.github/workflows/commons-ci.yml b/.github/workflows/commons-ci.yml
new file mode 100644
index 0000000000..856a88b43d
--- /dev/null
+++ b/.github/workflows/commons-ci.yml
@@ -0,0 +1,64 @@
+name: "HugeGraph-Commons CI"
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - /^release-.*$/
+ - /^test-.*$/
+ pull_request:
+
+jobs:
+ build-commons:
+ runs-on: ubuntu-latest
+ env:
+ # TODO: reset use stage to false later
+ USE_STAGE: 'true' # 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: Compile
+ run: |
+ mvn compile -Dmaven.javadoc.skip=true -ntp
+
+ - name: Run common test
+ run: |
+ mvn test -pl hugegraph-commons/hugegraph-common -Dtest=UnitTestSuite
+
+ - name: Run rpc test
+ run: |
+ mvn test -pl hugegraph-commons/hugegraph-rpc -Dtest=UnitTestSuite
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3.0.0
+ with:
+ file: target/jacoco.xml
diff --git a/.github/workflows/pd-store-ci.yml b/.github/workflows/pd-store-ci.yml
index c0f4825251..44d4456920 100644
--- a/.github/workflows/pd-store-ci.yml
+++ b/.github/workflows/pd-store-ci.yml
@@ -1,4 +1,4 @@
-name: "Graph PD & Store & Hstore CI"
+name: "HugeGraph-PD & Store & Hstore CI"
on:
push:
@@ -14,7 +14,8 @@ jobs:
runs-on: ubuntu-latest
env:
# TODO: avoid duplicated env setup in pd & store
- USE_STAGE: 'false' # Whether to include the stage repository.
+ # TODO: reset use stage to false later
+ USE_STAGE: 'true' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
@@ -46,11 +47,11 @@ jobs:
- name: Run common test
run: |
- mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-common-test
+ mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-common-test -DskipCommonsTests=true
- name: Run core test
run: |
- mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-core-test
+ mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-core-test -DskipCommonsTests=true
# The above tests do not require starting a PD instance.
@@ -64,11 +65,11 @@ jobs:
- name: Run client test
run: |
- mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-client-test
+ mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-client-test -DskipCommonsTests=true
- name: Run rest test
run: |
- mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-rest-test
+ mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-rest-test -DskipCommonsTests=true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
@@ -79,7 +80,7 @@ jobs:
# TODO: avoid duplicated env setup
runs-on: ubuntu-latest
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ USE_STAGE: 'true' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
@@ -120,27 +121,27 @@ jobs:
- name: Run common test
run: |
- mvn test -pl hugegraph-store/hg-store-test -am -P store-common-test
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-common-test -DskipCommonsTests=true
- name: Run client test
run: |
- mvn test -pl hugegraph-store/hg-store-test -am -P store-client-test
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-client-test -DskipCommonsTests=true
- name: Run core test
run: |
- mvn test -pl hugegraph-store/hg-store-test -am -P store-core-test
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-core-test -DskipCommonsTests=true
- name: Run rocksdb test
run: |
- mvn test -pl hugegraph-store/hg-store-test -am -P store-rocksdb-test
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-rocksdb-test -DskipCommonsTests=true
- name: Run server test
run: |
- mvn test -pl hugegraph-store/hg-store-test -am -P store-server-test
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-server-test -DskipCommonsTests=true
- name: Run raft-core test
run: |
- mvn test -pl hugegraph-store/hg-store-test -am -P store-raftcore-test
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-raftcore-test -DskipCommonsTests=true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
diff --git a/.github/workflows/server-ci.yml b/.github/workflows/server-ci.yml
index bbf8a5eab6..7f7879ad05 100644
--- a/.github/workflows/server-ci.yml
+++ b/.github/workflows/server-ci.yml
@@ -1,4 +1,4 @@
-name: "Graph Server CI"
+name: "HugeGraph-Server CI"
on:
push:
@@ -9,11 +9,13 @@ on:
pull_request:
jobs:
+ # TODO: rename to build-server later
build:
# TODO: we need test & replace it to ubuntu-24.04 or ubuntu-latest
runs-on: ubuntu-20.04
env:
- USE_STAGE: 'false' # Whether to include the stage repository.
+ # TODO: reset use stage to false later
+ USE_STAGE: 'true' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: ${{ matrix.BACKEND }}
diff --git a/BUILDING.md b/BUILDING.md
index b7342e68d6..d4c807c748 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -6,7 +6,7 @@ Required:
* Java 11
* Maven 3.5+
-To build without executing tests: `mvn clean package -DskipTests`
+To build without executing tests: `mvn clean package -Dmaven.test.skip=true`
## Building in IDEA
diff --git a/hugegraph-commons/README.md b/hugegraph-commons/README.md
new file mode 100644
index 0000000000..4ec2ebb5bb
--- /dev/null
+++ b/hugegraph-commons/README.md
@@ -0,0 +1,66 @@
+# hugegraph-commons
+
+[![License](https://img.shields.io/badge/license-Apache%202-0E78BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+[![codecov](https://codecov.io/gh/hugegraph/hugegraph-common/branch/master/graph/badge.svg)](https://codecov.io/gh/hugegraph/hugegraph-common)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.hugegraph/hugegraph-common/badge.svg)](https://mvnrepository.com/artifact/org.apache.hugegraph/hugegraph-common)
+[![CodeQL](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/codeql-analysis.yml)
+[![hugegraph-commons ci](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/ci.yml/badge.svg)](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/ci.yml)
+
+
+hugegraph-commons is a common module for [HugeGraph](https://github.com/apache/hugegraph) and its peripheral components.
+hugegraph-commons encapsulates locks, configurations, events, iterators, rest and some
+numeric or collection util classes to simplify the development of HugeGraph and its components.
+
+## Components
+
+- Lock: atomic lock, key lock, lock group and lock manger
+- Config: register and load config option with security check
+- Event: listening and notification, do something asynchronously
+- Iterator: some iterators with extra functions, map, filter, extend, etc.
+- Rest: RESTful client implemented on OkHttp, POST, PUT, GET and DELETE
+- Util: performance analyzer, version checker, numeric and Collection utils, log and exception utils, etc.
+- Rpc: rpc component for inner module communication, currently it's based on [Sofa-RPC](https://github.com/sofastack/sofa-rpc)
+
+You could use import the dependencies in `maven` like this:
+
+```xml
+
+ org.apache.hugegraph
+ hugegraph-common
+ 1.2.0
+
+```
+
+## Learn More
+
+The [doc page](https://hugegraph.apache.org/docs/) contains more information about hugegraph modules.
+
+And here are links of other repositories:
+1. [hugegraph-server](https://github.com/apache/hugegraph) (graph's core component - OLTP server)
+2. [hugegraph-toolchain](https://github.com/apache/hugegraph-toolchain) (include loader/dashboard/tool/client)
+3. [hugegraph-computer](https://github.com/apache/hugegraph-computer) (graph processing system - OLAP)
+4. [hugegraph-website/doc](https://github.com/apache/hugegraph-doc) (include doc & website code)
+
+
+
+## Contributing
+
+- Welcome to contribute to HugeGraph, please see [How to Contribute](https://hugegraph.apache.org/docs/contribution-guidelines/contribute/) for more information.
+- Note: It's recommended to use [GitHub Desktop](https://desktop.github.com/) to greatly simplify the PR and commit process.
+- Thank you to all the people who already contributed to HugeGraph!
+
+[![contributors graph](https://contrib.rocks/image?repo=apache/hugegraph-commons)](https://github.com/apache/incubator-hugegraph-commons/graphs/contributors)
+
+## Licence
+
+Same as HugeGraph, hugegraph-commons are also licensed under [Apache 2.0](./LICENSE) License.
+
+### Contact Us
+
+---
+
+ - [GitHub Issues](https://github.com/apache/incubator-hugegraph-commons/issues): Feedback on usage issues and functional requirements (quick response)
+ - Feedback Email: [dev@hugegraph.apache.org](mailto:dev@hugegraph.apache.org) ([subscriber](https://hugegraph.apache.org/docs/contribution-guidelines/subscribe/) only)
+ - WeChat public account: Apache HugeGraph, welcome to scan this QR code to follow us.
+
+
diff --git a/hugegraph-commons/hugegraph-common/README.md b/hugegraph-commons/hugegraph-common/README.md
new file mode 100644
index 0000000000..8614ba126b
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/README.md
@@ -0,0 +1,23 @@
+# hugegraph-common
+
+[![License](https://img.shields.io/badge/license-Apache%202-0E78BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+[![Build Status](https://travis-ci.org/hugegraph/hugegraph-common.svg?branch=master)](https://travis-ci.org/hugegraph/hugegraph-common)
+[![codecov](https://codecov.io/gh/hugegraph/hugegraph-common/branch/master/graph/badge.svg)](https://codecov.io/gh/hugegraph/hugegraph-common)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.hugegraph/hugegraph-common/badge.svg)](https://mvnrepository.com/artifact/org.apache.hugegraph/hugegraph-common)
+
+hugegraph-common is a common module for [HugeGraph](https://github.com/hugegraph/hugegraph) and its peripheral components.
+hugegraph-common encapsulates locks, configurations, events, iterators, rest and some
+numeric or collection util classes to simplify the development of HugeGraph and
+its components.
+
+## Components
+
+- Lock: atomic lock, key lock, lock group and lock manger
+- Config: register and load config option with security check
+- Event: listening and notification, do something asynchronously
+- Iterator: some iterators with extra functions, map, filter, extend, etc.
+- Rest: RESTful client implemented on Jersey, POST, PUT, GET and DELETE
+- Util: Performance analyzer, version checker, numeric and Collection utils, log and exception utils, etc.
+
+## Licence
+The same as HugeGraph, hugegraph-common is also licensed under Apache 2.0 License.
diff --git a/hugegraph-commons/hugegraph-common/build.sh b/hugegraph-commons/hugegraph-common/build.sh
new file mode 100644
index 0000000000..b2cb6211b9
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/build.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env 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.
+#
+
+export MAVEN_HOME=/home/scmtools/buildkit/maven/apache-maven-3.3.9/
+export JAVA_HOME=/home/scmtools/buildkit/java/jdk1.8.0_25/
+export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH
+
+mvn clean test -Dtest=UnitTestSuite
diff --git a/hugegraph-commons/hugegraph-common/pom.xml b/hugegraph-commons/hugegraph-common/pom.xml
new file mode 100644
index 0000000000..2010869b17
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/pom.xml
@@ -0,0 +1,302 @@
+
+
+
+ 4.0.0
+
+ org.apache.hugegraph
+ hugegraph-commons
+ ${revision}
+ ../pom.xml
+
+
+ hugegraph-common
+ ${project.artifactId}
+ https://github.com/apache/incubator-hugegraph-commons/tree/master/hugegraph-common
+
+ hugegraph-common is a common module for HugeGraph and its peripheral components.
+ hugegraph-common encapsulates locks, configurations, events, iterators, rest and some
+ numeric or collection util classes to simplify the development of HugeGraph and its
+ components.
+
+
+
+
+ 1.18.8
+ 4.10.0
+
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+
+
+ org.mockito
+ mockito-core
+ ${mockito.version}
+ test
+
+
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j2.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j2.version}
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j2.version}
+
+
+
+
+ org.glassfish
+ javax.json
+ ${javax.json.version}
+
+
+ commons-configuration
+ commons-configuration
+ ${commons.configuration.version}
+
+
+ org.apache.commons
+ commons-configuration2
+ ${commons.configuration2.version}
+
+
+ commons-logging
+ commons-logging
+
+
+ commons-lang3
+ org.apache.commons
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons.lang3.version}
+
+
+ commons-beanutils
+ commons-beanutils
+ ${commons.beanutils.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ commons-io
+ commons-io
+ ${commons.io.version}
+
+
+ commons-collections
+ commons-collections
+ ${commons.collections.version}
+
+
+ commons-codec
+ commons-codec
+ ${commons.codec.version}
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+ jsr305
+ com.google.code.findbugs
+
+
+
+
+
+ com.google.code.findbugs
+ jsr305
+ ${jsr305.version}
+
+
+
+ joda-time
+ joda-time
+ 2.10.8
+
+
+
+
+ org.javassist
+ javassist
+ ${javassist.version}
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jaxb-annotations
+ ${jackson.version}
+
+
+ jakarta.xml.bind-api
+ jakarta.xml.bind
+
+
+
+
+ com.fasterxml.jackson.jaxrs
+ jackson-jaxrs-base
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.jaxrs
+ jackson-jaxrs-json-provider
+ ${jackson.version}
+
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ ${sun.xml.version}
+ runtime
+
+
+ jakarta.xml.bind-api
+ jakarta.xml.bind
+
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+
+
+ com.squareup.okhttp3
+ logging-interceptor
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ true
+
+
+
+
+
+
+ com.squareup.okhttp3
+ okhttp-bom
+ ${okhttp.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.2
+
+
+ pre-unit-test
+
+ prepare-agent
+
+
+
+ post-unit-test
+ test
+
+ report
+
+
+ ${project.parent.build.directory}
+
+
+
+
+
+
+
+
+
+ apache-release
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+
+
+
+
+
+
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/AtomicLock.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/AtomicLock.java
new file mode 100644
index 0000000000..6f7a669d7d
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/AtomicLock.java
@@ -0,0 +1,82 @@
+/*
+ * 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.concurrent;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+public class AtomicLock {
+
+ private static final Logger LOG = Log.logger(LockManager.class);
+
+ private String name;
+ private AtomicReference sign;
+
+ public AtomicLock(String name) {
+ this.name = name;
+ this.sign = new AtomicReference<>();
+ }
+
+ public boolean tryLock() {
+ Thread current = Thread.currentThread();
+ return this.sign.compareAndSet(null, current);
+ }
+
+ public void unlock() {
+ if (this.sign.get() == null) {
+ return;
+ }
+ Thread current = Thread.currentThread();
+ if (!this.sign.compareAndSet(current, null)) {
+ throw new RuntimeException(String.format(
+ "Thread '%s' trying to unlock '%s' " +
+ "which is held by other threads now.",
+ current.getName(), this.name));
+ }
+ }
+
+ public boolean lock(int retries) {
+ // The interval between retries is exponential growth, most wait
+ // interval is 2^(retries-1)s. If retries=0, don't retry.
+ if (retries < 0 || retries > 10) {
+ throw new IllegalArgumentException(String.format(
+ "Locking retry times should be in [0, 10], but got %d",
+ retries));
+ }
+
+ boolean isLocked = false;
+ try {
+ for (int i = 0; !(isLocked = this.tryLock()) && i < retries; i++) {
+ Thread.sleep(1000 * (1L << i));
+ }
+ } catch (InterruptedException ignored) {
+ LOG.info("Thread sleep is interrupted.");
+ }
+ return isLocked;
+ }
+
+ public String name() {
+ return this.name;
+ }
+
+ public void name(String name) {
+ this.name = name;
+ }
+}
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/BarrierEvent.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/BarrierEvent.java
new file mode 100644
index 0000000000..3c8734d16d
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/BarrierEvent.java
@@ -0,0 +1,104 @@
+/*
+ * 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.concurrent;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.hugegraph.util.E;
+
+public class BarrierEvent {
+
+ private final Lock lock = new ReentrantLock();
+ private final Condition cond = lock.newCondition();
+ private volatile boolean signaled = false;
+
+ /**
+ * Wait forever until the signal is received.
+ * @throws InterruptedException if interrupted.
+ */
+ public void await() throws InterruptedException {
+ this.lock.lock();
+ try {
+ while (!this.signaled) {
+ this.cond.await();
+ }
+ } finally {
+ this.lock.unlock();
+ }
+ }
+
+ /**
+ * Wait specified time in milliseconds.
+ * @param timeout: the time in millisecond to wait.
+ * @return true if signal is received, false if time out.
+ * @throws InterruptedException if interrupted.
+ */
+ public boolean await(long timeout) throws InterruptedException {
+ E.checkArgument(timeout >= 0L,
+ "The time must be >= 0, but got '%d'.",
+ timeout);
+ long deadline = System.currentTimeMillis() + timeout;
+ this.lock.lock();
+ try {
+ while (!this.signaled) {
+ timeout = deadline - System.currentTimeMillis();
+ if (timeout > 0) {
+ this.cond.await(timeout, TimeUnit.MILLISECONDS);
+ }
+ if (System.currentTimeMillis() >= deadline) {
+ return this.signaled;
+ }
+ }
+ } finally {
+ this.lock.unlock();
+ }
+ return true;
+ }
+
+ public void reset() {
+ this.lock.lock();
+ try {
+ this.signaled = false;
+ } finally {
+ this.lock.unlock();
+ }
+ }
+
+ public void signal() {
+ this.lock.lock();
+ try {
+ this.signaled = true;
+ this.cond.signal();
+ } finally {
+ this.lock.unlock();
+ }
+ }
+
+ public void signalAll() {
+ this.lock.lock();
+ try {
+ this.signaled = true;
+ this.cond.signalAll();
+ } finally {
+ this.lock.unlock();
+ }
+ }
+}
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/KeyLock.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/KeyLock.java
new file mode 100644
index 0000000000..44ca8803ca
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/KeyLock.java
@@ -0,0 +1,144 @@
+/*
+ * 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.concurrent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.locks.Lock;
+
+import org.apache.hugegraph.util.E;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Striped;
+
+/**
+ * KeyLock provide an interface of segment lock
+ */
+public class KeyLock {
+
+ private Striped locks;
+
+ public KeyLock() {
+ // The default size is availableProcessors() * 4
+ this(Runtime.getRuntime().availableProcessors() << 2);
+ }
+
+ public KeyLock(int size) {
+ this.locks = Striped.lock(size);
+ }
+
+ private int indexOf(Lock lock) {
+ for (int i = 0; i < this.locks.size(); i++) {
+ if (this.locks.getAt(i) == lock) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Lock an object
+ * @param key The object to lock
+ * @return The lock(locked) of passed key
+ */
+ public final Lock lock(Object key) {
+ E.checkArgument(key != null, "Lock key can't be null");
+ Lock lock = this.locks.get(key);
+ lock.lock();
+ return lock;
+ }
+
+ /**
+ * Unlock an object
+ * @param key The object to unlock
+ */
+ public final void unlock(Object key) {
+ E.checkArgument(key != null, "Unlock key can't be null");
+ this.locks.get(key).unlock();
+ }
+
+ /**
+ * Lock a list of object with sorted order
+ * @param keys The objects to lock
+ * @return The locks(locked) of keys
+ */
+ public final List lockAll(Object... keys) {
+ E.checkArgument(keys != null && keys.length > 0,
+ "Lock keys can't be null or empty");
+ List locks = new ArrayList<>(keys.length);
+ for (Object key : keys) {
+ E.checkArgument(key != null, "Lock key can't be null");
+ Lock lock = this.locks.get(key);
+ locks.add(lock);
+ }
+ locks.sort((a, b) -> {
+ int diff = a.hashCode() - b.hashCode();
+ if (diff == 0 && a != b) {
+ diff = this.indexOf(a) - this.indexOf(b);
+ assert diff != 0;
+ }
+ return diff;
+ });
+ for (Lock lock : locks) {
+ lock.lock();
+ }
+ return Collections.unmodifiableList(locks);
+ }
+
+ /**
+ * Lock two objects with sorted order
+ * NOTE: This is to optimize the performance of lockAll(keys)
+ * @param key1 The first object
+ * @param key2 The second object
+ * @return locks for the two objects
+ */
+ public List lockAll(Object key1, Object key2) {
+ E.checkArgument(key1 != null, "Lock key can't be null");
+ E.checkArgument(key2 != null, "Lock key can't be null");
+ Lock lock1 = this.locks.get(key1);
+ Lock lock2 = this.locks.get(key2);
+
+ int diff = lock1.hashCode() - lock2.hashCode();
+ if (diff == 0 && lock1 != lock2) {
+ diff = this.indexOf(lock1) - this.indexOf(lock2);
+ assert diff != 0;
+ }
+
+ List locks = diff > 0 ?
+ ImmutableList.of(lock2, lock1) :
+ ImmutableList.of(lock1, lock2);
+
+ for (Lock lock : locks) {
+ lock.lock();
+ }
+
+ return locks;
+ }
+
+ /**
+ * Unlock a list of object
+ * @param locks The locks to unlock
+ */
+ public final void unlockAll(List locks) {
+ E.checkArgument(locks != null, "Unlock locks can't be null");
+ for (int i = locks.size(); i > 0; i--) {
+ assert this.indexOf(locks.get(i - 1)) != -1;
+ locks.get(i - 1).unlock();
+ }
+ }
+}
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/LockGroup.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/LockGroup.java
new file mode 100644
index 0000000000..aa864ecaf8
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/LockGroup.java
@@ -0,0 +1,85 @@
+/*
+ * 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.concurrent;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class LockGroup {
+
+ private final String name;
+ private final Map locksMap;
+
+ public LockGroup(String lockGroup) {
+ this.name = lockGroup;
+ this.locksMap = new ConcurrentHashMap<>();
+ }
+
+ public Lock lock(String lockName) {
+ if (!this.locksMap.containsKey(lockName)) {
+ this.locksMap.putIfAbsent(lockName, new ReentrantLock());
+ }
+ return (Lock) this.locksMap.get(lockName);
+ }
+
+ public AtomicLock atomicLock(String lockName) {
+ if (!this.locksMap.containsKey(lockName)) {
+ this.locksMap.putIfAbsent(lockName, new AtomicLock(lockName));
+ }
+ return (AtomicLock) this.locksMap.get(lockName);
+ }
+
+ public ReadWriteLock readWriteLock(String lockName) {
+ if (!this.locksMap.containsKey(lockName)) {
+ this.locksMap.putIfAbsent(lockName, new ReentrantReadWriteLock());
+ }
+ return (ReadWriteLock) this.locksMap.get(lockName);
+ }
+
+ public KeyLock keyLock(String lockName) {
+ if (!this.locksMap.containsKey(lockName)) {
+ this.locksMap.putIfAbsent(lockName, new KeyLock());
+ }
+ return (KeyLock) this.locksMap.get(lockName);
+ }
+
+ public KeyLock keyLock(String lockName, int size) {
+ if (!this.locksMap.containsKey(lockName)) {
+ this.locksMap.putIfAbsent(lockName, new KeyLock(size));
+ }
+ return (KeyLock) this.locksMap.get(lockName);
+ }
+
+ public > RowLock rowLock(String lockName) {
+ if (!this.locksMap.containsKey(lockName)) {
+ this.locksMap.putIfAbsent(lockName, new RowLock<>());
+ }
+ Object value = this.locksMap.get(lockName);
+ @SuppressWarnings("unchecked")
+ RowLock lock = (RowLock) value;
+ return lock;
+ }
+
+ public String name() {
+ return this.name;
+ }
+}
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/LockManager.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/LockManager.java
new file mode 100644
index 0000000000..e686c67895
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/LockManager.java
@@ -0,0 +1,71 @@
+/*
+ * 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.concurrent;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class LockManager {
+
+ private static final LockManager INSTANCE = new LockManager();
+
+ public static LockManager instance() {
+ return INSTANCE;
+ }
+
+ private Map lockGroupMap;
+
+ private LockManager() {
+ this.lockGroupMap = new ConcurrentHashMap<>();
+ }
+
+ public boolean exists(String group) {
+ return this.lockGroupMap.containsKey(group);
+ }
+
+ public LockGroup create(String group) {
+ if (exists(group)) {
+ throw new RuntimeException(String.format(
+ "LockGroup '%s' already exists", group));
+ }
+ LockGroup lockGroup = new LockGroup(group);
+ LockGroup previous = this.lockGroupMap.putIfAbsent(group, lockGroup);
+ if (previous != null) {
+ return previous;
+ }
+ return lockGroup;
+ }
+
+ public LockGroup get(String group) {
+ LockGroup lockGroup = this.lockGroupMap.get(group);
+ if (lockGroup == null) {
+ throw new RuntimeException(String.format(
+ "LockGroup '%s' does not exists", group));
+ }
+ return lockGroup;
+ }
+
+ public void destroy(String group) {
+ if (this.exists(group)) {
+ this.lockGroupMap.remove(group);
+ } else {
+ throw new RuntimeException(String.format(
+ "LockGroup '%s' does not exists", group));
+ }
+ }
+}
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/PausableScheduledThreadPool.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/PausableScheduledThreadPool.java
new file mode 100644
index 0000000000..a820aeb638
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/PausableScheduledThreadPool.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hugegraph.concurrent;
+
+import java.util.List;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+public class PausableScheduledThreadPool extends ScheduledThreadPoolExecutor {
+
+ private static final Logger LOG = Log.logger(PausableScheduledThreadPool.class);
+
+ private volatile boolean paused = false;
+
+ public PausableScheduledThreadPool(int corePoolSize,
+ ThreadFactory factory) {
+ super(corePoolSize, factory);
+ }
+
+ public synchronized void pauseSchedule() {
+ this.paused = true;
+ LOG.info("PausableScheduledThreadPool was paused");
+ }
+
+ public synchronized void resumeSchedule() {
+ this.paused = false;
+ this.notifyAll();
+ LOG.info("PausableScheduledThreadPool was resumed");
+ }
+
+ @Override
+ protected void beforeExecute(Thread t, Runnable r) {
+ synchronized (this) {
+ while (this.paused) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) {
+ LOG.warn("PausableScheduledThreadPool was interrupted");
+ }
+ }
+ }
+ super.beforeExecute(t, r);
+ }
+
+ @Override
+ public void shutdown() {
+ if (this.paused) {
+ this.resumeSchedule();
+ }
+ super.shutdown();
+ }
+
+ @Override
+ public List shutdownNow() {
+ if (this.paused) {
+ this.resumeSchedule();
+ }
+ return super.shutdownNow();
+ }
+}
diff --git a/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/RowLock.java b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/RowLock.java
new file mode 100644
index 0000000000..3908803771
--- /dev/null
+++ b/hugegraph-commons/hugegraph-common/src/main/java/org/apache/hugegraph/concurrent/RowLock.java
@@ -0,0 +1,98 @@
+/*
+ * 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.concurrent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.hugegraph.util.E;
+
+public class RowLock> {
+
+ private final Map locks = new ConcurrentHashMap<>();
+ private final ThreadLocal