From dd8a3d377f8f64e9022e8ef891766f773a3e7a54 Mon Sep 17 00:00:00 2001
From: Peng Junzhi <201250214@smail.nju.edu.cn>
Date: Fri, 5 Apr 2024 12:15:26 +0800
Subject: [PATCH 1/6] refact: prepare for integrating store modules
---
.github/workflows/pd-store.yml | 42 +++++
hugegraph-store/.gitignore | 2 +
hugegraph-store/README.md | 9 +-
hugegraph-store/pom.xml | 317 +++++++++++++++++++++++++++++++++
pom.xml | 6 +-
5 files changed, 371 insertions(+), 5 deletions(-)
create mode 100644 hugegraph-store/.gitignore
create mode 100644 hugegraph-store/pom.xml
diff --git a/.github/workflows/pd-store.yml b/.github/workflows/pd-store.yml
index 65fb3ccc9c..7c45e0faad 100644
--- a/.github/workflows/pd-store.yml
+++ b/.github/workflows/pd-store.yml
@@ -49,3 +49,45 @@ jobs:
uses: codecov/codecov-action@v3.0.0
with:
file: ${{ env.REPORT_DIR }}/*.xml
+
+ store:
+ # TODO: avoid duplicated env setup
+ runs-on: ubuntu-latest
+ env:
+ USE_STAGE: 'true' # Whether to include the stage repository.
+ 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
+ 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: Run common test
+ run: |
+ mvn test -pl hugegraph-store/hg-store-test -am -P store-common-test
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3.0.0
+ with:
+ file: ${{ env.REPORT_DIR }}/*.xml
diff --git a/hugegraph-store/.gitignore b/hugegraph-store/.gitignore
new file mode 100644
index 0000000000..afb9ae8375
--- /dev/null
+++ b/hugegraph-store/.gitignore
@@ -0,0 +1,2 @@
+# Exclude the generated PB files
+hg-store-grpc/src/main/java/
diff --git a/hugegraph-store/README.md b/hugegraph-store/README.md
index bef8b53c8a..cd2dedb900 100644
--- a/hugegraph-store/README.md
+++ b/hugegraph-store/README.md
@@ -1,5 +1,8 @@
-# HugeGraph Store
+> Note: From revision 1.5.0, the code of HugeGraph-Store will be adapted to this location (WIP).
-HugeGraph Store is a new built-in storage backend, which uses RocksDB as the distributed backend storage engine.
+# HugeGraph Store (BETA)
-> Note: Currently, the contents of this folder are empty. Starting from revision 1.5.0, the code of HugeGraph Store will be adapted to this location (WIP).
+HugeGraph Store is a new built-in storage backend, which uses RocksDB as the distributed backend
+storage engine.
+
+> BTW, if you meet any problem when using HugeGraph Store, please feel free to contact us for help
diff --git a/hugegraph-store/pom.xml b/hugegraph-store/pom.xml
new file mode 100644
index 0000000000..0bb8cd96e1
--- /dev/null
+++ b/hugegraph-store/pom.xml
@@ -0,0 +1,317 @@
+
+
+
+
+
+ 4.0.0
+
+ hugegraph-store
+ ${revision}
+ pom
+
+
+ org.apache.hugegraph
+ hugegraph
+ ${revision}
+ ../pom.xml
+
+
+
+ hg-store-common
+ hg-store-grpc
+ hg-store-client
+ hg-store-test
+
+
+
+
+
+
+
+
+
+ 1.5.0
+ 11
+ 11
+ 2.15.0
+ ${project.basedir}/..
+
+
+
+
+
+
+ org.apache.hugegraph
+ hg-store-common
+ ${project.version}
+
+
+ org.apache.hugegraph
+ hg-store-grpc
+ ${project.version}
+
+
+
+
+
+
+
+ org.apache.hugegraph
+ hg-store-client
+ ${project.version}
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ 2.15.0
+
+
+
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.4
+
+
+
+ prepare-agent
+
+
+
+
+
+ org.codehaus.mojo
+ flatten-maven-plugin
+ 1.2.7
+
+ true
+ resolveCiFriendliesOnly
+
+
+
+ flatten
+ process-resources
+
+ flatten
+
+
+
+ flatten.clean
+ clean
+
+ clean
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+
+
+
+ ${project.basedir}/
+
+ *.tar
+ *.tar.gz
+ .flattened-pom.xml
+
+ dist/**
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ store-common-test
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.20
+
+
+ store-common-test
+
+ test
+
+ test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index ff448ffc29..273270f9d4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,8 +92,7 @@
hugegraph-serverhugegraph-pd
-
-
+ hugegraph-store
@@ -177,8 +176,11 @@
**/hbase-*/****/apache-cassandra-*/****/pid
+
+ **/tmp/****/src/main/java/org/apache/hugegraph/pd/grpc/**
+ **/src/main/java/org/apache/hugegraph/store/grpc/**true
From 2a39813d354bb82a498db1b0a252706e5443ce9a Mon Sep 17 00:00:00 2001
From: Peng Junzhi <201250214@smail.nju.edu.cn>
Date: Fri, 5 Apr 2024 11:53:46 +0800
Subject: [PATCH 2/6] feat(store): integrate `store-common` submodule
---
hugegraph-store/hg-store-common/pom.xml | 33 ++++
.../store/buffer/ByteBufferAllocator.java | 63 ++++++++
.../hugegraph/store/buffer/KVByteBuffer.java | 98 ++++++++++++
.../org/apache/hugegraph/store/term/Bits.java | 66 ++++++++
.../apache/hugegraph/store/term/HgPair.java | 142 ++++++++++++++++++
.../apache/hugegraph/store/term/HgTriple.java | 79 ++++++++++
6 files changed, 481 insertions(+)
create mode 100644 hugegraph-store/hg-store-common/pom.xml
create mode 100644 hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/ByteBufferAllocator.java
create mode 100644 hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/KVByteBuffer.java
create mode 100644 hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/Bits.java
create mode 100644 hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgPair.java
create mode 100644 hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgTriple.java
diff --git a/hugegraph-store/hg-store-common/pom.xml b/hugegraph-store/hg-store-common/pom.xml
new file mode 100644
index 0000000000..7746c76155
--- /dev/null
+++ b/hugegraph-store/hg-store-common/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ 4.0.0
+
+
+ org.apache.hugegraph
+ hugegraph-store
+ ${revision}
+ ../pom.xml
+
+
+ hg-store-common
+
diff --git a/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/ByteBufferAllocator.java b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/ByteBufferAllocator.java
new file mode 100644
index 0000000000..25a5f1814b
--- /dev/null
+++ b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/ByteBufferAllocator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.store.buffer;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ByteBufferAllocator {
+
+ // size of each Buffer
+ final int capacity;
+ // max num of Buffers
+ final int maxCount;
+ final BlockingQueue freeQueue = new LinkedBlockingQueue<>();
+ // current num of Buffers in queue
+ AtomicInteger totalCount;
+
+ public ByteBufferAllocator(int cap, int count) {
+ this.capacity = cap;
+ this.maxCount = count;
+ this.totalCount = new AtomicInteger(0);
+ }
+
+ public ByteBuffer get() throws InterruptedException {
+ ByteBuffer buffer = null;
+ while (buffer == null) {
+ if (freeQueue.size() > 0) {
+ buffer = freeQueue.poll();
+ } else if (totalCount.get() < maxCount) {
+ buffer = ByteBuffer.allocate(capacity);
+ totalCount.incrementAndGet();
+ } else {
+ buffer = freeQueue.poll(1, TimeUnit.SECONDS);
+ }
+ }
+ return buffer;
+ }
+
+ public void release(ByteBuffer buffer) {
+ if (freeQueue.size() < maxCount) {
+ buffer.clear();
+ freeQueue.add(buffer);
+ }
+ }
+}
diff --git a/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/KVByteBuffer.java b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/KVByteBuffer.java
new file mode 100644
index 0000000000..524a0f58fc
--- /dev/null
+++ b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/buffer/KVByteBuffer.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.store.buffer;
+
+import java.nio.ByteBuffer;
+
+public class KVByteBuffer {
+
+ ByteBuffer buffer;
+
+ public KVByteBuffer(int capacity) {
+ buffer = ByteBuffer.allocate(capacity);
+ }
+
+ public KVByteBuffer(byte[] buffer) {
+ this.buffer = ByteBuffer.wrap(buffer);
+ }
+
+ public KVByteBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ public void clear() {
+ this.buffer.clear();
+ }
+
+ public KVByteBuffer flip() {
+ buffer.flip();
+ return this;
+ }
+
+ public ByteBuffer getBuffer() {
+ return buffer;
+ }
+
+ public ByteBuffer copyBuffer() {
+ byte[] buf = new byte[buffer.position()];
+ System.arraycopy(buffer.array(), 0, buf, 0, buffer.position());
+ return ByteBuffer.wrap(buf);
+ }
+
+ public void put(byte data) {
+ buffer.put(data);
+ }
+
+ public void put(byte[] data) {
+ if (data != null) {
+ buffer.putInt(data.length);
+ buffer.put(data);
+ }
+ }
+
+ public byte[] getBytes() {
+ int len = buffer.getInt();
+ byte[] data = new byte[len];
+ buffer.get(data);
+ return data;
+ }
+
+ public byte get() {
+ return buffer.get();
+ }
+
+ public void putInt(int data) {
+ buffer.putInt(data);
+ }
+
+ public int getInt() {
+ return buffer.getInt();
+ }
+
+ public byte[] array() {
+ return this.buffer.array();
+ }
+
+ public int position() {
+ return this.buffer.position();
+ }
+
+ public final boolean hasRemaining() {
+ return this.buffer.hasRemaining();
+ }
+}
diff --git a/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/Bits.java b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/Bits.java
new file mode 100644
index 0000000000..2b78a22b8d
--- /dev/null
+++ b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/Bits.java
@@ -0,0 +1,66 @@
+/*
+ * 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.store.term;
+
+import java.nio.ByteBuffer;
+
+public class Bits {
+
+ /**
+ * 大头字节序写入short
+ */
+ public static void putShort(byte[] buf, int offSet, int x) {
+ buf[offSet] = (byte) (x >> 8);
+ buf[offSet + 1] = (byte) (x);
+ }
+
+ public static void putInt(byte[] buf, int offSet, int x) {
+ buf[offSet] = (byte) (x >> 24);
+ buf[offSet + 1] = (byte) (x >> 16);
+ buf[offSet + 2] = (byte) (x >> 8);
+ buf[offSet + 3] = (byte) (x);
+ }
+
+ /**
+ * 大头字节序读取short
+ */
+ public static int getShort(byte[] buf, int offSet) {
+ int x = buf[offSet] & 0xff;
+ x = (x << 8) + (buf[offSet + 1] & 0xff);
+ return x;
+ }
+
+ public static int getInt(byte[] buf, int offSet) {
+ int x = (buf[offSet] << 24)
+ + ((buf[offSet + 1] & 0xff) << 16)
+ + ((buf[offSet + 2] & 0xff) << 8)
+ + (buf[offSet + 3] & 0xff);
+ return x;
+ }
+
+ public static void put(byte[] buf, int offSet, byte[] srcBuf) {
+ System.arraycopy(srcBuf, 0, buf, offSet, srcBuf.length);
+ }
+
+ public static int toInt(byte[] bytes) {
+ ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
+ buffer.put(bytes);
+ buffer.flip();//need flip
+ return buffer.getInt();
+ }
+}
diff --git a/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgPair.java b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgPair.java
new file mode 100644
index 0000000000..84aa00b9af
--- /dev/null
+++ b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgPair.java
@@ -0,0 +1,142 @@
+/*
+ * 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.store.term;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Copy from javafx.util:Pair
+ * TODO: refer license later, ?% match, maybe refer to avafx.util:Pair
+ *
+ * created on 2021/10/15
+ */
+public class HgPair implements Serializable {
+
+ /**
+ * Key of this Pair.
+ */
+ private K key;
+ /**
+ * Value of this Pair.
+ */
+ private V value;
+
+ public HgPair() {
+
+ }
+
+ /**
+ * Creates a new pair
+ *
+ * @param key The key for this pair
+ * @param value The value to use for this pair
+ */
+ public HgPair(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Gets the key for this pair.
+ *
+ * @return key for this pair
+ */
+ public K getKey() {
+ return key;
+ }
+
+ public void setKey(K key) {
+ this.key = key;
+ }
+
+ /**
+ * Gets the value for this pair.
+ *
+ * @return value for this pair
+ */
+ public V getValue() {
+ return value;
+ }
+
+ public void setValue(V value) {
+ this.value = value;
+ }
+
+ /**
+ *
String representation of this
+ * Pair.
+ *
+ *
The default name/value delimiter '=' is always used.
The hash code is calculated using both the name and
+ * the value of the Pair.
+ *
+ * @return hash code for this Pair
+ */
+ @Override
+ public int hashCode() {
+ // name's hashCode is multiplied by an arbitrary prime number (13)
+ // in order to make sure there is a difference in the hashCode between
+ // these two parameters:
+ // name: a value: aa
+ // name: aa value: a
+ return key.hashCode() * 13 + (value == null ? 0 : value.hashCode());
+ }
+
+ /**
+ *
Test this Pair for equality with another
+ * Object.
+ *
+ *
If the Object to be tested is not a
+ * Pair or is null, then this method
+ * returns false.
+ *
+ *
Two Pairs are considered equal if and only if
+ * both the names and values are equal.
+ *
+ * @param o the Object to test for
+ * equality with this Pair
+ * @return true if the given Object is
+ * equal to this Pair else false
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof HgPair) {
+ HgPair pair = (HgPair) o;
+ if (!Objects.equals(key, pair.key)) {
+ return false;
+ }
+ return Objects.equals(value, pair.value);
+ }
+ return false;
+ }
+}
diff --git a/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgTriple.java b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgTriple.java
new file mode 100644
index 0000000000..5206b24447
--- /dev/null
+++ b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/term/HgTriple.java
@@ -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.
+ */
+
+package org.apache.hugegraph.store.term;
+
+import java.util.Objects;
+
+/**
+ * created on 2021/10/19
+ */
+public class HgTriple {
+
+ private final X x;
+ private final Y y;
+ private final Z z;
+ private int hash = -1;
+
+ public HgTriple(X x, Y y, Z z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public X getX() {
+ return x;
+ }
+
+ public Y getY() {
+ return y;
+ }
+
+ public Z getZ() {
+ return z;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ HgTriple, ?, ?> hgTriple = (HgTriple, ?, ?>) o;
+ return Objects.equals(x, hgTriple.x) && Objects.equals(y, hgTriple.y) &&
+ Objects.equals(z, hgTriple.z);
+ }
+
+ @Override
+ public int hashCode() {
+ if (hash == -1) {
+ hash = Objects.hash(x, y, z);
+ }
+ return this.hash;
+ }
+
+ @Override
+ public String toString() {
+ return "HgTriple{" +
+ "x=" + x +
+ ", y=" + y +
+ ", z=" + z +
+ '}';
+ }
+}
From 0f820a7a1d897169069d74399122e938a524c9c6 Mon Sep 17 00:00:00 2001
From: Peng Junzhi <201250214@smail.nju.edu.cn>
Date: Fri, 5 Apr 2024 11:54:08 +0800
Subject: [PATCH 3/6] feat(store): integrate `store-grpc` submodule
---
hugegraph-store/hg-store-grpc/pom.xml | 162 ++++
.../store/grpc/stream/HgStoreStreamGrpc.java | 560 +++++++++++
.../store/grpc/stream/HgStoreStreamProto.java | 78 ++
.../hugegraph/store/grpc/stream/KvStream.java | 910 ++++++++++++++++++
.../store/grpc/stream/KvStreamOrBuilder.java | 70 ++
.../store/grpc/stream/store_stream.proto | 45 +
.../src/main/proto/graphpb.proto | 137 +++
.../src/main/proto/healthy.proto | 30 +
.../src/main/proto/store_common.proto | 113 +++
.../src/main/proto/store_session.proto | 136 +++
.../src/main/proto/store_state.proto | 73 ++
.../src/main/proto/store_stream_meta.proto | 108 +++
12 files changed, 2422 insertions(+)
create mode 100644 hugegraph-store/hg-store-grpc/pom.xml
create mode 100644 hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/HgStoreStreamGrpc.java
create mode 100644 hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/HgStoreStreamProto.java
create mode 100644 hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/KvStream.java
create mode 100644 hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/KvStreamOrBuilder.java
create mode 100644 hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/store_stream.proto
create mode 100644 hugegraph-store/hg-store-grpc/src/main/proto/graphpb.proto
create mode 100644 hugegraph-store/hg-store-grpc/src/main/proto/healthy.proto
create mode 100644 hugegraph-store/hg-store-grpc/src/main/proto/store_common.proto
create mode 100644 hugegraph-store/hg-store-grpc/src/main/proto/store_session.proto
create mode 100644 hugegraph-store/hg-store-grpc/src/main/proto/store_state.proto
create mode 100644 hugegraph-store/hg-store-grpc/src/main/proto/store_stream_meta.proto
diff --git a/hugegraph-store/hg-store-grpc/pom.xml b/hugegraph-store/hg-store-grpc/pom.xml
new file mode 100644
index 0000000000..dac8a811d7
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/pom.xml
@@ -0,0 +1,162 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.hugegraph
+ hugegraph-store
+ ${revision}
+ ../pom.xml
+
+
+ hg-store-grpc
+
+
+ 11
+ 11
+
+ 1.6.2
+ 1.39.0
+ 3.17.2
+ 0.6.1
+
+
+
+
+
+ io.grpc
+ grpc-netty-shaded
+ ${grpc.version}
+
+
+ io.grpc
+ grpc-protobuf
+ ${grpc.version}
+
+
+ io.grpc
+ grpc-stub
+ ${grpc.version}
+
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+
+
+
+
+ ${basedir}/src/main/java
+
+
+ src/main/resources
+
+
+ src/main/proto
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ ${os.plugin.version}
+
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ ${protobuf.plugin.version}
+ true
+
+
+ com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
+
+ grpc-java
+
+ io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
+
+
+ ${project.basedir}/src/main/proto
+
+
+ ${project.basedir}/src/main/java
+
+ false
+
+
+
+
+
+ generate-sources
+
+
+ compile
+
+ compile-custom
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.3.0
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+ ${basedir}/src/main/java
+ ${basedir}/src/main/dev
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ src/main/java
+
+
+
+
+
+
+ initialize
+
+ clean
+
+
+
+
+
+
+
diff --git a/hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/HgStoreStreamGrpc.java b/hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/HgStoreStreamGrpc.java
new file mode 100644
index 0000000000..bd7a2a2b33
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/HgStoreStreamGrpc.java
@@ -0,0 +1,560 @@
+/*
+ * 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.store.grpc.stream;
+
+import static io.grpc.MethodDescriptor.generateFullMethodName;
+
+/**
+ *
+ **
+ * In order to improve performance, reuse memory, and reduce gc recycling, the KvStream.writeTo method needs to be rewritten.
+ *
+ *
+ * bool over = 2;
+ * @return The over.
+ */
+ boolean getOver();
+
+ /**
+ * uint32 version = 4;
+ * @return The version.
+ */
+ int getVersion();
+
+ /**
+ * bytes stream = 5;
+ * @return The stream.
+ */
+ ByteBuffer getStream();
+ /**
+ * .KvStreamType type = 6;
+ * @return The enum numeric value on the wire for type.
+ */
+ int getTypeValue();
+ /**
+ * .KvStreamType type = 6;
+ * @return The type.
+ */
+ org.apache.hugegraph.store.grpc.stream.KvStreamType getType();
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/store_stream.proto b/hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/store_stream.proto
new file mode 100644
index 0000000000..7ea840d9f7
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/dev/org/apache/hugegraph/store/grpc/stream/store_stream.proto
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+import "store_common.proto";
+import "store_stream_meta.proto";
+option java_multiple_files = true;
+option java_package = "org.apache.hugegraph.store.grpc.stream";
+option java_outer_classname = "HgStoreStreamProto";
+
+/**
+ In order to improve performance, reuse memory, and reduce gc recycling, the KvStream.writeTo method needs to be overwrite.
+ */
+service HgStoreStream {
+
+ rpc Scan(stream ScanStreamReq) returns (stream KvPageRes) {}
+ rpc ScanOneShot(ScanStreamReq) returns (KvPageRes) {}
+ rpc ScanBatch(stream ScanStreamBatchReq) returns (stream KvPageRes) {}
+ rpc ScanBatch2(stream ScanStreamBatchReq) returns (stream KvStream) {}
+ rpc ScanBatchOneShot(ScanStreamBatchReq) returns (KvPageRes) {}
+}
+
+
+message KvStream {
+ int32 seq_no = 1; //query times.
+ bool over = 2; //true=no more data
+ uint32 version = 4;
+ bytes stream = 5;
+ KvStreamType type = 6;
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/proto/graphpb.proto b/hugegraph-store/hg-store-grpc/src/main/proto/graphpb.proto
new file mode 100644
index 0000000000..a245002f85
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/proto/graphpb.proto
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+package graph_pb;
+
+option java_package = "org.apache.hugegraph.store.grpc";
+
+service GraphStore {
+ rpc ScanPartition(stream ScanPartitionRequest) returns (stream ScanResponse){}
+}
+
+message ScanPartitionRequest{
+ enum ScanType{
+ SCAN_UNKNOWN = 0;
+ SCAN_VERTEX = 1;
+ SCAN_EDGE = 2;
+ }
+ // 请求参数
+ message Request{
+ ScanType scan_type = 1;
+ string graph_name = 2;
+ uint32 partition_id = 3;
+ uint32 start_code = 4;
+ uint32 end_code = 5;
+ // 过滤条件
+ string condition = 6;
+ string table = 7;
+ int64 limit = 8;
+ int32 boundary = 9;
+ bytes position = 10;
+ // 返回条件
+ repeated int64 properties = 11;
+ }
+
+
+ message Reply{
+ int32 seq_no = 1;
+ }
+ RequestHeader header = 1;
+ oneof request {
+ Request scan_request = 2;
+ // 每消费一个数据包,通知服务端一次,返回消息序号
+ Reply reply_request = 4;
+ }
+}
+
+message ScanResponse{
+ ResponseHeader header = 1;
+ // 消息序号
+ int32 seq_no = 2;
+ repeated Vertex vertex = 3;
+ repeated Edge edge = 4;
+}
+
+
+message Property{
+ uint64 label = 1;
+ Variant value = 2;
+}
+
+message Vertex{
+ int64 label = 1; // 点类型
+ Variant id = 2; // 点ID
+ repeated Property properties = 3; //点属性
+}
+
+message Edge{
+ int64 label = 1; // 边类型
+ int64 sourceLabel = 2;
+ int64 targetLabel = 3;
+ Variant source_id = 4; // 源点ID
+ Variant target_id = 5; // 目标点ID
+
+ repeated Property properties = 6; //边属性
+}
+
+message Variant {
+ optional VariantType type = 1;
+ optional int32 value_int32 = 2;
+ optional int64 value_int64 = 3;
+ optional float value_float = 4;
+ optional double value_double = 5;
+ optional string value_string = 6;
+ optional bytes value_bytes = 7;
+ optional string value_datetime = 8;
+ optional bool value_boolean = 9;
+}
+
+enum VariantType {
+ VT_UNKNOWN = 0;
+ VT_BOOLEAN = 1;
+ VT_INT = 2;
+ VT_LONG = 3;
+ VT_FLOAT = 4;
+ VT_DOUBLE = 7;
+ VT_STRING = 8;
+ VT_BYTES = 9;
+ VT_DATETIME = 10;
+}
+
+
+
+message RequestHeader {
+ // 发送者 ID.
+ uint64 sender_id = 2;
+}
+
+message ResponseHeader {
+ uint64 sender_id = 1;
+ Error error = 2;
+}
+
+
+enum ErrorType {
+ OK = 0;
+ UNKNOWN = 1;
+}
+
+message Error {
+ ErrorType type = 1;
+ string message = 2;
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/proto/healthy.proto b/hugegraph-store/hg-store-grpc/src/main/proto/healthy.proto
new file mode 100644
index 0000000000..ca6ba06bb6
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/proto/healthy.proto
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "org.apache.hugegraph.store.grpc";
+
+import "google/protobuf/empty.proto";
+
+service Healthy {
+ rpc IsOk(google.protobuf.Empty) returns (StringReply) {}
+}
+
+message StringReply {
+ string message = 1;
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/proto/store_common.proto b/hugegraph-store/hg-store-grpc/src/main/proto/store_common.proto
new file mode 100644
index 0000000000..fc9934dec4
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/proto/store_common.proto
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.apache.hugegraph.store.grpc.common";
+option java_outer_classname = "HgStoreCommonProto";
+
+message Header {
+ string graph = 1;
+}
+message Tkv {
+ string table = 1;
+ bytes key = 2;
+ bytes value = 3;
+ int32 code = 9;
+
+}
+
+message Tk {
+ string table = 1;
+ bytes key = 2;
+ int32 code = 9;
+}
+
+message Tp {
+ string table = 1;
+ bytes prefix = 2;
+ int32 code = 9;
+}
+
+message Tse {
+ string table = 1;
+ Key start = 2;
+ Key end = 3;
+}
+
+message Key {
+ bytes key = 1;
+ int32 code = 9;
+}
+
+message Kv {
+ bytes key = 1;
+ bytes value = 2;
+ int32 code = 9;
+}
+
+message ResStatus {
+ ResCode code = 1;
+ string msg = 2;
+}
+
+/*--- enum ---*/
+enum ResCode {
+ RES_CODE_OK = 0;
+ RES_CODE_FAIL = 1;
+ RES_CODE_NOT_EXIST = 2;
+ RES_CODE_EXCESS = 3;
+}
+
+enum ScanMethod {
+ UNKNOWN_SCAN_TYPE = 0;
+ ALL = 1;
+ PREFIX = 2;
+ RANGE = 3;
+}
+
+enum ScanOrderType{
+ // 批量接口下,返回顺序的要求
+ ORDER_NONE = 0; // 允许无序
+ ORDER_WITHIN_VERTEX = 1; // 一个点内的边不会被打断,单不同点之间为无序
+ ORDER_STRICT = 2; // 保证原始的输入点顺序
+}
+
+enum OpType {
+ OP_TYPE_UNKNOWN = 0;
+ OP_TYPE_PUT = 1;
+ OP_TYPE_DEL = 2;
+ OP_TYPE_DEL_SINGLE = 3;
+ OP_TYPE_DEL_PREFIX = 4;
+ OP_TYPE_DEL_RANGE = 5;
+ OP_TYPE_MERGE = 6;
+}
+
+enum TableMethod{
+ TABLE_METHOD_UNKNOWN = 0;
+ TABLE_METHOD_EXISTS = 1;
+ TABLE_METHOD_CREATE = 2;
+ TABLE_METHOD_DELETE = 3;
+ TABLE_METHOD_DROP = 4;
+ TABLE_METHOD_TRUNCATE = 5;
+}
+
+enum GraphMethod{
+ GRAPH_METHOD_UNKNOWN = 0;
+ GRAPH_METHOD_DELETE = 3;
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/proto/store_session.proto b/hugegraph-store/hg-store-grpc/src/main/proto/store_session.proto
new file mode 100644
index 0000000000..b659645a63
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/proto/store_session.proto
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.apache.hugegraph.store.grpc.session";
+option java_outer_classname = "HgStoreSessionProto";
+
+import "store_common.proto";
+import "store_stream_meta.proto";
+
+service HgStoreSession {
+ rpc Get2(GetReq) returns (FeedbackRes) {}
+ rpc BatchGet2(BatchGetReq) returns (FeedbackRes) {}
+ rpc Batch(BatchReq) returns (FeedbackRes){}
+ rpc Table(TableReq) returns (FeedbackRes){};
+ rpc Graph(GraphReq) returns (FeedbackRes){};
+ rpc Clean(CleanReq) returns (FeedbackRes) {}
+ rpc Count(ScanStreamReq) returns (Agg) {}
+}
+
+message TableReq{
+ Header header = 1;
+ TableMethod method = 2;
+ string table_name = 3;
+}
+
+message GraphReq{
+ Header header = 1;
+ GraphMethod method = 2;
+ string graph_name = 3;
+}
+
+message BatchReq{
+ Header header = 1;
+ string batch_id = 2;
+ oneof requests{
+ BatchWriteReq write_req = 10;
+ BatchCommitReq commit_req = 11;
+ BatchRollbackReq rollback_req = 12;
+ }
+}
+
+message BatchWriteReq{
+ repeated BatchEntry entry = 1;
+}
+
+message BatchCommitReq{}
+
+message BatchRollbackReq{}
+
+message BatchEntry{
+ OpType op_type = 1;
+ int32 table = 2;
+ Key start_key = 3;
+ Key end_key = 4;
+ bytes value = 5;
+}
+
+message BatchGetReq {
+ Header header = 1;
+ string table = 2;
+ repeated Key key = 3;
+ int32 partition = 9;
+}
+
+message GetReq {
+ Header header = 1;
+ Tk tk = 2;
+}
+
+message CleanReq{
+ Header header = 1;
+ int32 partition = 2;
+}
+
+
+message FeedbackRes {
+ ResStatus status = 1;
+
+ oneof responses{
+ PartitionFaultResponse partition_fault_response = 10;
+ ValueResponse value_response = 11;
+ KeyValueResponse key_value_response = 12;
+ }
+
+}
+
+message ValueResponse {
+ bytes value = 1;
+}
+
+message KeyValueResponse {
+ repeated Kv kv = 1;
+}
+
+message PartitionFaultResponse{
+ PartitionFaultType fault_type = 1;
+ repeated PartitionLeader partition_leaders = 2;
+ repeated int32 partition_ids = 3;
+}
+
+message PartitionLeader {
+ int32 partitionId = 2;
+ int64 leaderId = 3;
+}
+
+enum PartitionFaultType{
+ PARTITION_FAULT_TYPE_UNKNOWN = 0;
+ // 当前不是Leader,返回Leader所在store
+ PARTITION_FAULT_TYPE_NOT_LEADER = 1;
+ // 等待Leader超时,可能raft group创建失败
+ PARTITION_FAULT_TYPE_WAIT_LEADER_TIMEOUT = 2;
+ // 分区不属于本机
+ PARTITION_FAULT_TYPE_NOT_LOCAL = 3;
+
+}
+message Agg {
+ Header header = 1;
+ int64 count = 2;
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/proto/store_state.proto b/hugegraph-store/hg-store-grpc/src/main/proto/store_state.proto
new file mode 100644
index 0000000000..d2b0aa3613
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/proto/store_state.proto
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+import "google/protobuf/empty.proto";
+import "store_common.proto";
+
+option java_multiple_files = true;
+option java_package = "org.apache.hugegraph.store.grpc.state";
+option java_outer_classname = "HgStoreStateProto";
+
+service HgStoreState {
+
+ // Subscribe Store Node state publishing.
+ rpc SubState(SubStateReq) returns (stream NodeStateRes) {}
+
+ // Unsubscribe Store Node state publishing.
+ rpc UnsubState(SubStateReq) returns (google.protobuf.Empty){}
+ rpc getScanState(SubStateReq) returns (ScanState){}
+
+}
+
+message SubStateReq{
+ string subId = 1;
+}
+
+message NodeStateRes {
+ NodeStateType state = 1;
+}
+
+message ScanState{
+ string address = 1;
+ uint64 taskCount = 2;
+ uint64 completedTaskCount = 3;
+ uint32 activeCount = 4;
+ uint32 largestPoolSize = 5;
+ uint32 poolSize = 6;
+ int32 maximumPoolSize = 7;
+ int32 queueSize = 8;
+ int32 queueRemainingCapacity = 9;
+}
+
+enum NodeStateType {
+ UNKNOWN_STATE_TYPE = 0;
+ STARTING = 10;
+ STANDBY = 20;
+ ONLINE = 30;
+ PAUSE = 40;
+ PENDING = 50;
+ STOPPING = 60;
+ HALTED = 70;
+ ERROR = 90;
+ ZOMBIE = 99;
+}
+
+message QuotaRequest {
+ map limits = 1;
+}
diff --git a/hugegraph-store/hg-store-grpc/src/main/proto/store_stream_meta.proto b/hugegraph-store/hg-store-grpc/src/main/proto/store_stream_meta.proto
new file mode 100644
index 0000000000..7c2211cab7
--- /dev/null
+++ b/hugegraph-store/hg-store-grpc/src/main/proto/store_stream_meta.proto
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+import "store_common.proto";
+
+option java_multiple_files = true;
+option java_package = "org.apache.hugegraph.store.grpc.stream";
+option java_outer_classname = "HgStoreStreamMetaProto";
+
+
+message ScanStreamBatchReq {
+ Header header = 1;
+ oneof query {
+ ScanQueryRequest query_request = 10;
+ ScanPagingRequest paging_request = 11;
+ ScanPauseRequest pause_request = 12;
+ ScanCancelRequest cancel_request = 13;
+ ScanReceiptRequest receipt_request = 14;
+ }
+ int64 logId = 15;
+}
+
+message ScanQueryRequest {
+ ScanMethod method = 2;
+ string table = 3;
+ int64 limit = 4;
+ int64 pageSize = 5;
+ int32 scanType = 6;
+ bytes query = 7;
+ bytes position = 8;
+ repeated ScanCondition condition = 9;
+ int64 perKeyLimit = 10;
+ int64 skipDegree = 11;
+ ScanOrderType orderType = 12;
+ int64 perKeyMax = 13;
+}
+
+message ScanPagingRequest {
+ int64 pageSize = 1;
+}
+message ScanPauseRequest {}
+message ScanCancelRequest {}
+message ScanReceiptRequest {
+ uint32 times = 1;
+}
+
+message ScanCondition {
+ int32 code = 1; // owner key hashcode
+ bytes prefix = 2; // key prefix
+ bytes start = 3; // start key
+ bytes end = 4; // end key
+ int32 serialNo = 5; // serial no
+}
+
+message ScanStreamReq {
+ Header header = 1;
+ ScanMethod method = 2;
+ string table = 3;
+ int32 code = 4; // partitionId
+ bytes prefix = 5; // key prefix
+ bytes start = 6; //start key
+ bytes end = 7; //end key
+ int64 limit = 8;
+ int32 scanType = 9;
+ bytes query = 10;
+ int32 pageSize = 11;
+ bytes position = 12;
+ uint32 closeFlag = 13;
+ SelectParam selects = 14;
+}
+
+message SelectParam {
+ bytes filter = 1;
+ bool withNoProperties = 2;
+ repeated int32 properties = 3;
+}
+
+message KvPageRes {
+ int32 times = 1; //query times.
+ bool over = 2; //true=no more data
+ repeated Kv data = 3;
+ uint32 version = 4;
+ bytes stream = 5;
+}
+
+enum KvStreamType {
+ STREAM_TYPE_NONE = 0;
+ STREAM_TYPE_KV = 1;
+ STREAM_TYPE_K = 2;
+ STREAM_TYPE_SKV = 3;
+ STREAM_TYPE_SK = 4;
+}
From 17a3735c62e7f9bae1841357117896adc7c2785e Mon Sep 17 00:00:00 2001
From: Peng Junzhi <201250214@smail.nju.edu.cn>
Date: Fri, 5 Apr 2024 11:54:33 +0800
Subject: [PATCH 4/6] feat(store): integrate `store-client` submodule
---
hugegraph-store/hg-store-client/pom.xml | 107 +++
.../org/apache/hugegraph/store/HgKvEntry.java | 29 +
.../apache/hugegraph/store/HgKvIterator.java | 35 +
.../hugegraph/store/HgKvOrderedIterator.java | 26 +
.../hugegraph/store/HgKvPagingIterator.java | 25 +
.../org/apache/hugegraph/store/HgKvStore.java | 125 +++
.../apache/hugegraph/store/HgOwnerKey.java | 151 +++
.../apache/hugegraph/store/HgPageSize.java | 32 +
.../org/apache/hugegraph/store/HgPrivate.java | 31 +
.../apache/hugegraph/store/HgScanQuery.java | 331 +++++++
.../apache/hugegraph/store/HgSeekAble.java | 28 +
.../hugegraph/store/HgSessionManager.java | 55 ++
.../hugegraph/store/HgSessionProvider.java | 29 +
.../apache/hugegraph/store/HgStoreClient.java | 97 ++
.../hugegraph/store/HgStoreSession.java | 39 +
.../apache/hugegraph/store/HgTkvEntry.java | 27 +
.../apache/hugegraph/store/HgTokvEntry.java | 27 +
.../store/client/HgNodePartition.java | 103 ++
.../client/HgNodePartitionerBuilder.java | 70 ++
.../hugegraph/store/client/HgPrivate.java | 35 +
.../hugegraph/store/client/HgStoreNode.java | 60 ++
.../store/client/HgStoreNodeBuilder.java | 36 +
.../store/client/HgStoreNodeCandidates.java | 41 +
.../store/client/HgStoreNodeManager.java | 264 ++++++
.../store/client/HgStoreNodeNotifier.java | 36 +
.../store/client/HgStoreNodePartitioner.java | 66 ++
.../client/HgStoreNodePartitionerImpl.java | 199 ++++
.../store/client/HgStoreNodeProvider.java | 34 +
.../store/client/HgStoreNodeSession.java | 43 +
.../hugegraph/store/client/HgStoreNotice.java | 100 ++
.../store/client/HgStoreService.java | 31 +
.../store/client/HgStoreSessionProvider.java | 37 +
.../store/client/HgTkvEntryImpl.java | 84 ++
.../store/client/HgTokvEntryImpl.java | 84 ++
.../store/client/MultiNodeSessionFactory.java | 54 ++
.../hugegraph/store/client/NodeTkv.java | 125 +++
.../store/client/NodeTxExecutor.java | 431 +++++++++
.../store/client/NodeTxSessionProxy.java | 887 ++++++++++++++++++
.../store/client/SequencedIterator.java | 149 +++
.../store/client/ShiftWorkIteratorProxy.java | 163 ++++
.../store/client/TopWorkIteratorProxy.java | 148 +++
.../store/client/grpc/AbstractGrpcClient.java | 176 ++++
.../store/client/grpc/GrpcKvEntryImpl.java | 78 ++
.../store/client/grpc/GrpcKvIteratorImpl.java | 161 ++++
.../client/grpc/GrpcNodeHealthyClient.java | 92 ++
.../client/grpc/GrpcStoreNodeBuilder.java | 77 ++
.../store/client/grpc/GrpcStoreNodeImpl.java | 98 ++
.../client/grpc/GrpcStoreNodeSessionImpl.java | 545 +++++++++++
.../client/grpc/GrpcStoreSessionClient.java | 158 ++++
.../client/grpc/GrpcStoreStateClient.java | 75 ++
.../client/grpc/GrpcStoreStreamClient.java | 217 +++++
.../hugegraph/store/client/grpc/GrpcUtil.java | 148 +++
.../client/grpc/KvBatchOneShotScanner.java | 124 +++
.../store/client/grpc/KvBatchScanner.java | 410 ++++++++
.../store/client/grpc/KvBatchScanner5.java | 454 +++++++++
.../client/grpc/KvBatchScannerMerger.java | 334 +++++++
.../store/client/grpc/KvBatchUtil.java | 156 +++
.../client/grpc/KvCloseableIterator.java | 30 +
.../store/client/grpc/KvListIterator.java | 48 +
.../store/client/grpc/KvOneShotScanner.java | 213 +++++
.../store/client/grpc/KvPageScanner.java | 311 ++++++
.../store/client/grpc/NotifyingExecutor.java | 253 +++++
.../hugegraph/store/client/grpc/ScanUtil.java | 52 +
.../store/client/grpc/SeekAbleIterator.java | 70 ++
.../store/client/grpc/SwitchingExecutor.java | 53 ++
.../store/client/type/HgNodeStatus.java | 43 +
.../client/type/HgStoreClientException.java | 48 +
.../hugegraph/store/client/util/Base58.java | 170 ++++
.../store/client/util/ExecutorPool.java | 62 ++
.../hugegraph/store/client/util/HgAssert.java | 134 +++
.../store/client/util/HgBufferProxy.java | 162 ++++
.../client/util/HgStoreClientConfig.java | 191 ++++
.../store/client/util/HgStoreClientConst.java | 50 +
.../store/client/util/HgStoreClientUtil.java | 175 ++++
.../hugegraph/store/client/util/HgUuid.java | 41 +
.../hugegraph/store/client/util/MetricX.java | 108 +++
.../store/client/util/PropertyUtil.java | 97 ++
.../main/resources/hg-store-client.properties | 23 +
.../src/main/resources/log4j2.xml | 102 ++
79 files changed, 10213 insertions(+)
create mode 100644 hugegraph-store/hg-store-client/pom.xml
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvEntry.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvOrderedIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvPagingIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvStore.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgOwnerKey.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPageSize.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPrivate.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgScanQuery.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSeekAble.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionManager.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionProvider.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreClient.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreSession.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTkvEntry.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTokvEntry.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartition.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartitionerBuilder.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgPrivate.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNode.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeBuilder.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeCandidates.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeManager.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeNotifier.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitioner.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitionerImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeProvider.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeSession.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNotice.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreService.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreSessionProvider.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTkvEntryImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTokvEntryImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/MultiNodeSessionFactory.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTkv.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxSessionProxy.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/SequencedIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/ShiftWorkIteratorProxy.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/TopWorkIteratorProxy.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/AbstractGrpcClient.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcKvEntryImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcKvIteratorImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcNodeHealthyClient.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcStoreNodeBuilder.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcStoreNodeImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcStoreNodeSessionImpl.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcStoreSessionClient.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcStoreStateClient.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcStoreStreamClient.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/GrpcUtil.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchOneShotScanner.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScanner.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScanner5.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScannerMerger.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchUtil.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvCloseableIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvListIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvOneShotScanner.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvPageScanner.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/NotifyingExecutor.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/ScanUtil.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/SeekAbleIterator.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/SwitchingExecutor.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/type/HgNodeStatus.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/type/HgStoreClientException.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/Base58.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/ExecutorPool.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgAssert.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgBufferProxy.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgStoreClientConfig.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgStoreClientConst.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgStoreClientUtil.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgUuid.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/MetricX.java
create mode 100644 hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/PropertyUtil.java
create mode 100644 hugegraph-store/hg-store-client/src/main/resources/hg-store-client.properties
create mode 100644 hugegraph-store/hg-store-client/src/main/resources/log4j2.xml
diff --git a/hugegraph-store/hg-store-client/pom.xml b/hugegraph-store/hg-store-client/pom.xml
new file mode 100644
index 0000000000..2c402d37aa
--- /dev/null
+++ b/hugegraph-store/hg-store-client/pom.xml
@@ -0,0 +1,107 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.hugegraph
+ hugegraph-store
+ ${revision}
+ ../pom.xml
+
+
+ hg-store-client
+
+
+ 11
+ 11
+ true
+ 2.15.0
+ 1.18.20
+
+
+
+
+ org.apache.hugegraph
+ hg-store-grpc
+ ${revision}
+
+
+ org.apache.hugegraph
+ hg-store-common
+ ${revision}
+
+
+ org.apache.hugegraph
+ hg-pd-client
+ ${revision}
+
+
+ org.apache.hugegraph
+ hg-pd-grpc
+ ${revision}
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j2.version}
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+ com.google.protobuf
+ protobuf-java-util
+ 3.17.2
+
+
+
+ commons-io
+ commons-io
+ 2.7
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.0
+ test
+
+
+ commons-codec
+ commons-codec
+ 1.15
+ test
+
+
+
+
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvEntry.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvEntry.java
new file mode 100644
index 0000000000..ff44db008e
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvEntry.java
@@ -0,0 +1,29 @@
+/*
+ * 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.store;
+
+public interface HgKvEntry {
+
+ byte[] key();
+
+ byte[] value();
+
+ default int code() {
+ return -1;
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvIterator.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvIterator.java
new file mode 100644
index 0000000000..38c8b0039b
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvIterator.java
@@ -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.
+ */
+
+package org.apache.hugegraph.store;
+
+import java.io.Closeable;
+import java.util.Iterator;
+
+/**
+ * created on 2021/10/21
+ */
+public interface HgKvIterator extends Iterator, HgSeekAble, Closeable {
+
+ byte[] key();
+
+ byte[] value();
+
+ @Override
+ void close();
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvOrderedIterator.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvOrderedIterator.java
new file mode 100644
index 0000000000..52df012ef2
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvOrderedIterator.java
@@ -0,0 +1,26 @@
+/*
+ * 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.store;
+
+/**
+ * created on 2022/03/10
+ */
+public interface HgKvOrderedIterator extends HgKvIterator, Comparable {
+
+ long getSequence();
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvPagingIterator.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvPagingIterator.java
new file mode 100644
index 0000000000..ba9fa33981
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvPagingIterator.java
@@ -0,0 +1,25 @@
+/*
+ * 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.store;
+
+/**
+ * created on 2021/10/24
+ */
+public interface HgKvPagingIterator extends HgKvIterator, HgPageSize {
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvStore.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvStore.java
new file mode 100644
index 0000000000..db640592f3
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgKvStore.java
@@ -0,0 +1,125 @@
+/*
+ * 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.store;
+
+import java.util.List;
+
+import org.apache.hugegraph.store.client.grpc.KvCloseableIterator;
+import org.apache.hugegraph.store.grpc.stream.ScanStreamReq;
+
+/**
+ * @version 0.2.0
+ */
+public interface HgKvStore {
+
+ /**
+ * CAUTION: THE CONST BELOW MUST KEEP CONSISTENCE TO ScanIterator.Trait.
+ */
+ int SCAN_ANY = 0x80;
+ int SCAN_PREFIX_BEGIN = 0x01;
+ int SCAN_PREFIX_END = 0x02;
+ int SCAN_GT_BEGIN = 0x04;
+ int SCAN_GTE_BEGIN = 0x0c;
+ int SCAN_LT_END = 0x10;
+ int SCAN_LTE_END = 0x30;
+ int SCAN_KEYONLY = 0x40;
+ int SCAN_HASHCODE = 0x100;
+
+ boolean put(String table, HgOwnerKey ownerKey, byte[] value);
+
+ /**
+ * 该版本被store内部使用。向分区写入数据,
+ * partitionId与key.keyCode必须与pd存储的分区信息保持一致。
+ */
+ boolean directPut(String table, int partitionId, HgOwnerKey key, byte[] value);
+
+ byte[] get(String table, HgOwnerKey ownerKey);
+
+ boolean clean(int partId);
+
+ boolean delete(String table, HgOwnerKey ownerKey);
+
+ boolean deleteSingle(String table, HgOwnerKey ownerKey);
+
+ boolean deletePrefix(String table, HgOwnerKey prefix);
+
+ boolean deleteRange(String table, HgOwnerKey start, HgOwnerKey end);
+
+ boolean merge(String table, HgOwnerKey key, byte[] value);
+
+ @Deprecated
+ List batchGetOwner(String table, List keyList);
+
+ HgKvIterator scanIterator(String table);
+
+ HgKvIterator scanIterator(String table, byte[] query);
+
+ HgKvIterator scanIterator(String table, long limit);
+
+ HgKvIterator scanIterator(String table, long limit, byte[] query);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey keyPrefix);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey keyPrefix, long limit);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey keyPrefix, long limit,
+ byte[] query);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey startKey, HgOwnerKey endKey);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey startKey, HgOwnerKey endKey,
+ long limit);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey startKey, HgOwnerKey endKey,
+ long limit, byte[] query);
+
+ HgKvIterator scanIterator(String table, HgOwnerKey startKey, HgOwnerKey endKey,
+ long limit, int scanType, byte[] query);
+
+ HgKvIterator scanIterator(String table, int codeFrom, int codeTo, int scanType,
+ byte[] query);
+
+ // HgKvIterator scanIterator(ScanStreamReq scanReq);
+
+ HgKvIterator scanIterator(ScanStreamReq.Builder scanReqBuilder);
+
+ long count(String table);
+
+ boolean truncate();
+
+ default boolean existsTable(String table) {
+ return false;
+ }
+
+ boolean createTable(String table);
+
+ boolean deleteTable(String table);
+
+ boolean dropTable(String table);
+
+ boolean deleteGraph(String graph);
+
+ List> scanBatch(HgScanQuery scanQuery);
+
+ KvCloseableIterator> scanBatch2(HgScanQuery scanQuery);
+
+ KvCloseableIterator> scanBatch3(HgScanQuery scanQuery,
+ KvCloseableIterator iterator);
+
+ HgKvIterator batchPrefix(String table, List prefixList);
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgOwnerKey.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgOwnerKey.java
new file mode 100644
index 0000000000..e9245b3a39
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgOwnerKey.java
@@ -0,0 +1,151 @@
+/*
+ * 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.store;
+
+import static org.apache.hugegraph.store.client.util.HgStoreClientConst.EMPTY_BYTES;
+import static org.apache.hugegraph.store.client.util.HgStoreClientConst.EMPTY_OWNER_KEY;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.hugegraph.store.client.util.HgStoreClientUtil;
+
+/**
+ * created on 2021/10/14
+ *
+ * @version 1.3.0 add canceled assert
+ */
+public class HgOwnerKey implements Serializable {
+
+ private final byte[] owner; // TODO: consider remove? since it seems to be useless
+ private int keyCode = 0;// TODO: Be here OK?
+ private byte[] key;
+ // Sequence number, used for batch queries to ensure the order of returned results
+ private int serialNo;
+
+ /**
+ * @param owner
+ * @param key
+ * @see HgOwnerKey:of(byte[] owner, byte[] key)
+ */
+ @Deprecated
+ public HgOwnerKey(byte[] owner, byte[] key) {
+ if (owner == null) {
+ owner = EMPTY_BYTES;
+ }
+ if (key == null) {
+ key = EMPTY_BYTES;
+ }
+ this.owner = owner;
+ this.key = key;
+ }
+
+ public HgOwnerKey(int code, byte[] key) {
+ if (key == null) {
+ key = EMPTY_BYTES;
+ }
+ this.owner = EMPTY_BYTES;
+ this.key = key;
+ this.keyCode = code;
+ }
+
+ public static HgOwnerKey emptyOf() {
+ return EMPTY_OWNER_KEY;
+ }
+
+ public static HgOwnerKey newEmpty() {
+ return HgOwnerKey.of(EMPTY_BYTES, EMPTY_BYTES);
+ }
+
+ public static HgOwnerKey ownerOf(byte[] owner) {
+ return new HgOwnerKey(owner, EMPTY_BYTES);
+ }
+
+ public static HgOwnerKey codeOf(int code) {
+ return HgOwnerKey.of(EMPTY_BYTES, EMPTY_BYTES).setKeyCode(code);
+ }
+
+ public static HgOwnerKey of(byte[] owner, byte[] key) {
+ return new HgOwnerKey(owner, key);
+ }
+
+ public static HgOwnerKey of(int keyCode, byte[] key) {
+ return new HgOwnerKey(keyCode, key);
+ }
+
+ public byte[] getOwner() {
+ return owner;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public int getKeyCode() {
+ return keyCode;
+ }
+
+ public HgOwnerKey setKeyCode(int keyCode) {
+ this.keyCode = keyCode;
+ return this;
+ }
+
+ public HgOwnerKey codeToKey(int keyCode) {
+ this.keyCode = keyCode;
+ this.key = HgStoreClientUtil.toIntBytes(keyCode);
+ return this;
+ }
+
+ public int getSerialNo() {
+ return this.serialNo;
+ }
+
+ public HgOwnerKey setSerialNo(int serialNo) {
+ this.serialNo = serialNo;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ HgOwnerKey that = (HgOwnerKey) o;
+ return Arrays.equals(owner, that.owner) && Arrays.equals(key, that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Arrays.hashCode(owner);
+ result = 31 * result + Arrays.hashCode(key);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "HgOwnerKey{" +
+ "owner=" + Arrays.toString(owner) +
+ ", key=" + Arrays.toString(key) +
+ ", code=" + keyCode +
+ '}';
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPageSize.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPageSize.java
new file mode 100644
index 0000000000..38163d568f
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPageSize.java
@@ -0,0 +1,32 @@
+/*
+ * 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.store;
+
+/**
+ * Return the amount of records returned by one query in pageable-query.
+ *
+ * created on 2021/10/24
+ */
+public interface HgPageSize {
+
+ long getPageSize();
+
+ default boolean isPageEmpty() {
+ return false;
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPrivate.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPrivate.java
new file mode 100644
index 0000000000..80cdb77471
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgPrivate.java
@@ -0,0 +1,31 @@
+/*
+ * 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.store;
+
+public final class HgPrivate {
+
+ private static final HgPrivate INSTANCE = new HgPrivate();
+
+ private HgPrivate() {
+ }
+
+ static HgPrivate of() {
+ return INSTANCE;
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgScanQuery.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgScanQuery.java
new file mode 100644
index 0000000000..cc64ba945b
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgScanQuery.java
@@ -0,0 +1,331 @@
+/*
+ * 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.store;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.hugegraph.store.client.util.HgAssert;
+import org.apache.hugegraph.store.grpc.common.ScanOrderType;
+
+/**
+ * 2022/3/4
+ *
+ * @version 0.5.0
+ */
+public interface HgScanQuery {
+
+ static HgScanQuery tableOf(String table) {
+ return ScanBuilder.tableOf(table).build();
+ }
+
+ static HgScanQuery rangeOf(String table, List startList, List endList) {
+ return ScanBuilder.rangeOf(table, startList, endList).build();
+ }
+
+ static HgScanQuery prefixOf(String table, List prefixList) {
+ return ScanBuilder.prefixOf(table, prefixList).build();
+ }
+
+ static HgScanQuery prefixOf(String table, List prefixList,
+ ScanOrderType orderType) {
+ return ScanBuilder.prefixOf(table, prefixList).setOrderType(orderType).build();
+ }
+
+ static HgScanQuery prefixIteratorOf(String table, Iterator prefixItr) {
+ return ScanBuilder.prefixIteratorOf(table, prefixItr).build();
+ }
+
+ static HgScanQuery prefixIteratorOf(String table, Iterator prefixItr,
+ ScanOrderType orderType) {
+ return ScanBuilder.prefixIteratorOf(table, prefixItr).setOrderType(orderType).build();
+ }
+
+ String getTable();
+
+ HgScanQuery.ScanMethod getScanMethod();
+
+ List getPrefixList();
+
+ Iterator getPrefixItr();
+
+ List getStartList();
+
+ List getEndList();
+
+ long getLimit();
+
+ long getPerKeyLimit();
+
+ long getPerKeyMax();
+
+ long getSkipDegree();
+
+ int getScanType();
+
+ ScanOrderType getOrderType();
+
+ boolean isOnlyKey();
+
+ byte[] getQuery();
+
+ ScanBuilder builder();
+
+ enum ScanMethod {
+ ALL,
+ PREFIX,
+ RANGE
+ }
+
+ enum SortType {
+ UNSORTED,
+ SORT_BY_EDGE,
+ SORT_BY_VERTEX
+ }
+
+ class ScanBuilder {
+
+ private final String table;
+ private final HgScanQuery.ScanMethod sanMethod;
+ private long limit = Integer.MAX_VALUE;
+ private long perKeyLimit = Integer.MAX_VALUE;
+ private long perKeyMax = Integer.MAX_VALUE;
+ private int scanType;
+ private ScanOrderType orderType;
+
+ private long skipDegree;
+
+ private boolean onlyKey;
+ private byte[] query;
+ private List prefixList;
+ private List startList;
+ private List endList;
+ private Iterator prefixItr;
+
+ ScanBuilder(HgScanQuery.ScanMethod sanMethod, String table) {
+ this.table = table;
+ this.sanMethod = sanMethod;
+ this.orderType = ScanOrderType.ORDER_NONE;
+ }
+
+ public static ScanBuilder rangeOf(String table, List startList,
+ List endList) {
+ HgAssert.isArgumentValid(table, "table");
+ HgAssert.isArgumentValid(startList, "startList");
+ HgAssert.isArgumentValid(endList, "endList");
+ HgAssert.isTrue(startList.size() == endList.size()
+ , "The size of startList not equals endList's.");
+
+ ScanBuilder res = new ScanBuilder(HgScanQuery.ScanMethod.RANGE, table);
+ res.startList = startList;
+ res.endList = endList;
+ res.scanType = HgKvStore.SCAN_GTE_BEGIN | HgKvStore.SCAN_LTE_END;
+ return res;
+ }
+
+ public static ScanBuilder prefixOf(String table, List prefixList) {
+ HgAssert.isArgumentValid(table, "table");
+ HgAssert.isArgumentValid(prefixList, "prefixList");
+
+ ScanBuilder res = new ScanBuilder(HgScanQuery.ScanMethod.PREFIX, table);
+ res.prefixList = prefixList;
+ return res;
+
+ }
+
+ public static ScanBuilder prefixIteratorOf(String table, Iterator prefixItr) {
+ HgAssert.isArgumentValid(table, "table");
+
+ ScanBuilder res = new ScanBuilder(HgScanQuery.ScanMethod.PREFIX, table);
+ res.prefixItr = prefixItr;
+ return res;
+
+ }
+
+ public static ScanBuilder tableOf(String table) {
+ HgAssert.isArgumentValid(table, "table");
+
+ return new ScanBuilder(HgScanQuery.ScanMethod.ALL, table);
+ }
+
+ public ScanBuilder setLimit(long limit) {
+ this.limit = limit;
+ return this;
+ }
+
+ public ScanBuilder setPerKeyLimit(long limit) {
+ this.perKeyLimit = limit;
+ return this;
+ }
+
+ public ScanBuilder setPerKeyMax(long max) {
+ this.perKeyMax = max;
+ return this;
+ }
+
+ public ScanBuilder setScanType(int scanType) {
+ this.scanType = scanType;
+ return this;
+ }
+
+ public ScanBuilder setOrderType(ScanOrderType orderType) {
+ this.orderType = orderType;
+ return this;
+ }
+
+ public ScanBuilder setQuery(byte[] query) {
+ this.query = query;
+ return this;
+ }
+
+ public ScanBuilder setSkipDegree(long skipDegree) {
+ this.skipDegree = skipDegree;
+ return this;
+ }
+
+ public ScanBuilder setOnlyKey(boolean onlyKey) {
+ this.onlyKey = onlyKey;
+ return this;
+ }
+
+ public HgScanQuery build() {
+ return this.new BatchScanQuery();
+ }
+
+ private class BatchScanQuery implements HgScanQuery {
+
+ @Override
+ public String getTable() {
+ return table;
+ }
+
+ @Override
+ public HgScanQuery.ScanMethod getScanMethod() {
+ return sanMethod;
+ }
+
+ @Override
+ public List getPrefixList() {
+ if (prefixList == null) {
+ return Collections.EMPTY_LIST;
+ } else {
+ return Collections.unmodifiableList(prefixList);
+ }
+ }
+
+ @Override
+ public Iterator getPrefixItr() {
+ return prefixItr;
+ }
+
+ @Override
+ public List getStartList() {
+ if (startList == null) {
+ return Collections.EMPTY_LIST;
+ } else {
+ return Collections.unmodifiableList(startList);
+ }
+ }
+
+ @Override
+ public List getEndList() {
+ if (endList == null) {
+ return Collections.EMPTY_LIST;
+ } else {
+ return Collections.unmodifiableList(endList);
+ }
+ }
+
+ @Override
+ public long getLimit() {
+ return limit;
+ }
+
+ @Override
+ public long getPerKeyLimit() {
+ return perKeyLimit;
+ }
+
+ @Override
+ public long getPerKeyMax() {
+ return perKeyMax;
+ }
+
+ @Override
+ public long getSkipDegree() {
+ return skipDegree;
+ }
+
+ @Override
+ public int getScanType() {
+ return scanType;
+ }
+
+ @Override
+ public ScanOrderType getOrderType() {
+ return orderType;
+ }
+
+ @Override
+ public boolean isOnlyKey() {
+ return onlyKey;
+ }
+
+ @Override
+ public byte[] getQuery() {
+ return query;
+ }
+
+ @Override
+ public ScanBuilder builder() {
+ return ScanBuilder.this;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("HgScanQuery{");
+ sb.append("table='").append(getTable()).append('\'');
+ sb.append(", scanMethod=").append(getScanMethod());
+ sb.append(", prefixList=").append(getPrefixList());
+ sb.append(", startList=").append(getStartList());
+ sb.append(", endList=").append(getEndList());
+ sb.append(", limit=").append(getLimit());
+ sb.append(", perKeyLimit=").append(getPerKeyLimit());
+ sb.append(", perKeyMax=").append(getPerKeyMax());
+ sb.append(", skipDegree=").append(getSkipDegree());
+ sb.append(", scanType=").append(getScanType());
+ sb.append(", orderType=").append(getOrderType());
+ sb.append(", onlyKey=").append(isOnlyKey());
+ sb.append(", query=");
+ if (query == null) {
+ sb.append("null");
+ } else {
+ sb.append('[');
+ for (int i = 0; i < query.length; ++i) {
+ sb.append(i == 0 ? "" : ", ").append(query[i]);
+ }
+ sb.append(']');
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSeekAble.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSeekAble.java
new file mode 100644
index 0000000000..fe6a580a1c
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSeekAble.java
@@ -0,0 +1,28 @@
+/*
+ * 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.store;
+
+/**
+ * created on 2022/03/11
+ */
+public interface HgSeekAble {
+
+ byte[] position();
+
+ void seek(byte[] position);
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionManager.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionManager.java
new file mode 100644
index 0000000000..37c2184c80
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionManager.java
@@ -0,0 +1,55 @@
+/*
+ * 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.store;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.hugegraph.store.client.HgStoreSessionProvider;
+
+/**
+ * Maintain HgStoreSession instances.
+ * HgStore-clusters.
+ */
+
+@ThreadSafe
+public final class HgSessionManager {
+
+ // TODO: Holding more than one HgSessionManager is available,if you want to connect multi
+ private final static HgSessionManager INSTANCE = new HgSessionManager();
+ private final HgSessionProvider sessionProvider;
+
+ private HgSessionManager() {
+ // TODO: constructed by SPI
+ this.sessionProvider = new HgStoreSessionProvider();
+ }
+
+ public static HgSessionManager getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Retrieve or create a HgStoreSession.
+ *
+ * @param graphName
+ * @return
+ */
+ public HgStoreSession openSession(String graphName) {
+ return this.sessionProvider.createSession(graphName);
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionProvider.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionProvider.java
new file mode 100644
index 0000000000..7049c27b01
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgSessionProvider.java
@@ -0,0 +1,29 @@
+/*
+ * 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.store;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * created on 2021/10/12
+ */
+@ThreadSafe
+public interface HgSessionProvider {
+
+ HgStoreSession createSession(String graphName);
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreClient.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreClient.java
new file mode 100644
index 0000000000..0f8ebb929f
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreClient.java
@@ -0,0 +1,97 @@
+/*
+ * 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.store;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.hugegraph.pd.client.PDClient;
+import org.apache.hugegraph.pd.client.PDConfig;
+import org.apache.hugegraph.store.client.HgStoreNodeManager;
+import org.apache.hugegraph.store.client.HgStoreNodePartitionerImpl;
+import org.apache.hugegraph.store.client.HgStoreSessionProvider;
+
+/**
+ * Maintain HgStoreSession instances.
+ * HgStore-clusters.
+ */
+
+@ThreadSafe
+public final class HgStoreClient {
+
+ // TODO: Holding more than one HgSessionManager is available,if you want to connect multi
+ private final HgSessionProvider sessionProvider;
+ private PDClient pdClient;
+
+ public HgStoreClient() {
+ this.sessionProvider = new HgStoreSessionProvider();
+ }
+
+ public HgStoreClient(PDConfig config) {
+ this.sessionProvider = new HgStoreSessionProvider();
+ pdClient = PDClient.create(config);
+ setPdClient(pdClient);
+ }
+
+ public HgStoreClient(PDClient pdClient) {
+ this.sessionProvider = new HgStoreSessionProvider();
+ setPdClient(pdClient);
+ }
+
+ public static HgStoreClient create(PDConfig config) {
+ return new HgStoreClient(config);
+ }
+
+ public static HgStoreClient create(PDClient pdClient) {
+ return new HgStoreClient(pdClient);
+ }
+
+ public static HgStoreClient create() {
+ return new HgStoreClient();
+ }
+
+ public void setPDConfig(PDConfig config) {
+ pdClient = PDClient.create(config);
+ setPdClient(pdClient);
+ }
+
+ /**
+ * Retrieve or create a HgStoreSession.
+ *
+ * @param graphName
+ * @return
+ */
+ public HgStoreSession openSession(String graphName) {
+ return this.sessionProvider.createSession(graphName);
+ }
+
+ public PDClient getPdClient() {
+ return pdClient;
+ }
+
+ public void setPdClient(PDClient client) {
+ this.pdClient = client;
+ HgStoreNodeManager nodeManager =
+ HgStoreNodeManager.getInstance();
+
+ HgStoreNodePartitionerImpl p = new HgStoreNodePartitionerImpl(pdClient, nodeManager);
+ nodeManager.setNodeProvider(p);
+ nodeManager.setNodePartitioner(p);
+ nodeManager.setNodeNotifier(p);
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreSession.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreSession.java
new file mode 100644
index 0000000000..2e595e1ba1
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgStoreSession.java
@@ -0,0 +1,39 @@
+/*
+ * 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.store;
+
+import org.apache.hugegraph.store.client.type.HgStoreClientException;
+
+public interface HgStoreSession extends HgKvStore {
+
+ void beginTx();
+
+ /**
+ * @throws IllegalStateException when the tx hasn't been beginning.
+ * @throws HgStoreClientException when failed to commit .
+ */
+ void commit();
+
+ /**
+ * @throws IllegalStateException when the tx hasn't been beginning.
+ * @throws HgStoreClientException when failed to rollback.
+ */
+ void rollback();
+
+ boolean isTx();
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTkvEntry.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTkvEntry.java
new file mode 100644
index 0000000000..8e08ab656e
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTkvEntry.java
@@ -0,0 +1,27 @@
+/*
+ * 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.store;
+
+public interface HgTkvEntry {
+
+ String table();
+
+ byte[] key();
+
+ byte[] value();
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTokvEntry.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTokvEntry.java
new file mode 100644
index 0000000000..57ca4d4a91
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/HgTokvEntry.java
@@ -0,0 +1,27 @@
+/*
+ * 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.store;
+
+public interface HgTokvEntry {
+
+ String table();
+
+ HgOwnerKey ownerKey();
+
+ byte[] value();
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartition.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartition.java
new file mode 100644
index 0000000000..6fa354edec
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartition.java
@@ -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.
+ */
+
+package org.apache.hugegraph.store.client;
+
+import java.util.Objects;
+
+/**
+ * Immutable Object Pattern
+ *
+ * created on 2021/10/26
+ */
+public final class HgNodePartition {
+
+ private final Long nodeId;
+ //当前key的hashcode
+ private final Integer keyCode;
+
+ //分区的开始结束范围
+ private final Integer startKey;
+ private final Integer endKey;
+ private int hash = -1;
+
+ HgNodePartition(Long nodeId, Integer keyCode) {
+ this.nodeId = nodeId;
+ this.keyCode = keyCode;
+ this.startKey = this.endKey = keyCode;
+ }
+
+ HgNodePartition(Long nodeId, Integer keyCode, Integer startKey, Integer endKey) {
+ this.nodeId = nodeId;
+ this.keyCode = keyCode;
+ this.startKey = startKey;
+ this.endKey = endKey;
+ }
+
+ public static HgNodePartition of(Long nodeId, Integer keyCode) {
+ return new HgNodePartition(nodeId, keyCode);
+ }
+
+ public static HgNodePartition of(Long nodeId, Integer keyCode, Integer startKey,
+ Integer endKey) {
+ return new HgNodePartition(nodeId, keyCode, startKey, endKey);
+ }
+
+ public Long getNodeId() {
+ return nodeId;
+ }
+
+ public Integer getKeyCode() {
+ return keyCode;
+ }
+
+ public Integer getStartKey() {
+ return startKey;
+ }
+
+ public Integer getEndKey() {
+ return endKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ HgNodePartition that = (HgNodePartition) o;
+ return Objects.equals(nodeId, that.nodeId) && Objects.equals(keyCode, that.keyCode);
+ }
+
+ @Override
+ public int hashCode() {
+ if (this.hash == -1) {
+ this.hash = Objects.hash(nodeId, keyCode);
+ }
+ return this.hash;
+ }
+
+ @Override
+ public String toString() {
+ return "HgNodePartition{" +
+ "nodeId=" + nodeId +
+ ", partitionId=" + keyCode +
+ '}';
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartitionerBuilder.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartitionerBuilder.java
new file mode 100644
index 0000000000..4bb0705b74
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgNodePartitionerBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * 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.store.client;
+
+import static org.apache.hugegraph.store.client.util.HgAssert.isFalse;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * created on 2021/10/26
+ *
+ * @version 1.0.0
+ */
+@NotThreadSafe
+public final class HgNodePartitionerBuilder {
+
+ private Set partitions = null;
+
+ static HgNodePartitionerBuilder resetAndGet() {
+ return new HgNodePartitionerBuilder();
+ }
+
+ /**
+ * @param nodeId
+ * @param keyCode
+ * @return
+ * @see HgNodePartitionerBuilder:setPartitions(Set partitions)
+ */
+ @Deprecated
+ public HgNodePartitionerBuilder add(Long nodeId, Integer keyCode) {
+ isFalse(nodeId == null, "The argument is invalid: nodeId");
+ isFalse(keyCode == null, "The argument is invalid: keyCode");
+
+ if (this.partitions == null) {
+ this.partitions = new HashSet<>(16, 1);
+ }
+
+ this.partitions.add(HgNodePartition.of(nodeId, keyCode));
+ return this;
+ }
+
+ Collection getPartitions() {
+ return this.partitions;
+ }
+
+ public void setPartitions(Set partitions) {
+ isFalse(partitions == null, "The argument is invalid: partitions");
+ this.partitions = partitions;
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgPrivate.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgPrivate.java
new file mode 100644
index 0000000000..ee73485469
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgPrivate.java
@@ -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.
+ */
+
+package org.apache.hugegraph.store.client;
+
+/**
+ * created on 2021/10/26
+ */
+public class HgPrivate {
+
+ private final static HgPrivate instance = new HgPrivate();
+
+ private HgPrivate() {
+
+ }
+
+ static HgPrivate getInstance() {
+ return instance;
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNode.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNode.java
new file mode 100644
index 0000000000..31438c0a53
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNode.java
@@ -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.
+ */
+
+package org.apache.hugegraph.store.client;
+
+import org.apache.hugegraph.store.HgStoreSession;
+
+/**
+ * created on 2021/10/11
+ *
+ * @version 0.2.0
+ */
+public interface HgStoreNode {
+
+ /**
+ * Return boolean value of being online or not
+ *
+ * @return
+ */
+ default boolean isHealthy() {
+ return true;
+ }
+
+ /**
+ * Return the unique ID of store-node.
+ *
+ * @return
+ */
+ Long getNodeId();
+
+ /**
+ * A string value concatenated by host and port: "host:port"
+ *
+ * @return
+ */
+ String getAddress();
+
+ /**
+ * Return a new HgStoreSession instance, that is not Thread safe.
+ * Return null when the node is not in charge of the graph that was passed from argument.
+ *
+ * @return
+ */
+ HgStoreSession openSession(String graphName);
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeBuilder.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeBuilder.java
new file mode 100644
index 0000000000..c35b5e9343
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeBuilder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.store.client;
+
+/**
+ * created on 2021/10/11
+ */
+public interface HgStoreNodeBuilder {
+
+ HgStoreNodeBuilder setNodeId(Long nodeId);
+
+ HgStoreNodeBuilder setAddress(String address);
+
+ /**
+ * To build a HgStoreNode instance.
+ *
+ * @return
+ */
+ HgStoreNode build();
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeCandidates.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeCandidates.java
new file mode 100644
index 0000000000..d8735cdc6e
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeCandidates.java
@@ -0,0 +1,41 @@
+/*
+ * 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.store.client;
+
+import java.util.List;
+
+/**
+ * created on 2021/10/12
+ */
+public final class HgStoreNodeCandidates {
+
+ List nodeList;
+
+ HgStoreNodeCandidates(List nodeList) {
+ this.nodeList = nodeList;
+ }
+
+ public int size() {
+ return this.nodeList.size();
+ }
+
+ public HgStoreNode getNode(int index) {
+ return this.nodeList.get(index);
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeManager.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeManager.java
new file mode 100644
index 0000000000..84709f19a9
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeManager.java
@@ -0,0 +1,264 @@
+/*
+ * 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.store.client;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.hugegraph.store.client.grpc.GrpcStoreNodeBuilder;
+import org.apache.hugegraph.store.client.type.HgNodeStatus;
+import org.apache.hugegraph.store.client.type.HgStoreClientException;
+import org.apache.hugegraph.store.client.util.HgAssert;
+import org.apache.hugegraph.store.client.util.HgStoreClientConst;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * // TODO: Mapping to Store-Node-Cluster, one to one.
+ *
+ * created on 2021/10/11
+ *
+ * @version 0.2.0
+ */
+@ThreadSafe
+@Slf4j
+public final class HgStoreNodeManager {
+
+ private final static Set CLUSTER_ID_SET = new HashSet<>();
+ private final static HgStoreNodeManager instance = new HgStoreNodeManager();
+
+ private final String clusterId;
+ private final Map addressMap = new ConcurrentHashMap<>();
+ private final Map nodeIdMap = new ConcurrentHashMap<>();
+ private final Map> graphNodesMap = new ConcurrentHashMap<>();
+
+ private HgStoreNodeProvider nodeProvider;
+ private HgStoreNodePartitioner nodePartitioner;
+ private HgStoreNodeNotifier nodeNotifier;
+
+ private HgStoreNodeManager() {
+ this.clusterId = HgStoreClientConst.DEFAULT_NODE_CLUSTER_ID;
+ }
+
+ private HgStoreNodeManager(String clusterId) {
+ synchronized (CLUSTER_ID_SET) {
+ if (CLUSTER_ID_SET.contains(clusterId)) {
+ throw new RuntimeException("The cluster [" + clusterId + "] has been existing.");
+ }
+ CLUSTER_ID_SET.add(clusterId);
+ this.clusterId = clusterId;
+ }
+ }
+
+ public static HgStoreNodeManager getInstance() {
+ return instance;
+ }
+
+ /**
+ * Return the HgStoreNodeBuilder
+ *
+ * @return
+ */
+ public HgStoreNodeBuilder getNodeBuilder() {
+ // TODO: Constructed by a provider that retrieved by SPI
+ return new GrpcStoreNodeBuilder(this, HgPrivate.getInstance());
+ }
+
+ /**
+ * Return an instance of HgStoreNode whose ID is matched to the argument.
+ *
+ * @param nodeId
+ * @return null when none of instance is matched to the argument,or argument is invalid.
+ */
+ public HgStoreNode getStoreNode(Long nodeId) {
+ if (nodeId == null) {
+ return null;
+ }
+ return this.nodeIdMap.get(nodeId);
+ }
+
+ /**
+ * Apply a HgStoreNode instance with graph-name and node-id.
+ * CAUTION:
+ * It won't work when user haven't set a HgStoreNodeProvider via setNodeProvider method.
+ *
+ * @param graphName
+ * @param nodeId
+ * @return
+ */
+ HgStoreNode applyNode(String graphName, Long nodeId) {
+ HgStoreNode node = this.nodeIdMap.get(nodeId);
+
+ if (node != null) {
+ return node;
+ }
+
+ if (this.nodeProvider == null) {
+ return null;
+ }
+
+ node = this.nodeProvider.apply(graphName, nodeId);
+
+ if (node == null) {
+
+ log.warn("Failed to apply a HgStoreNode instance form the nodeProvider [ "
+ + this.nodeProvider.getClass().getName() + " ].");
+ notifying(graphName, nodeId, HgNodeStatus.NOT_EXIST);
+ return null;
+ }
+
+ this.addNode(graphName, node);
+
+ return node;
+ }
+
+ private void notifying(String graphName, Long nodeId, HgNodeStatus status) {
+ if (this.nodeNotifier != null) {
+ try {
+ this.nodeNotifier.notice(graphName, HgStoreNotice.of(nodeId, status));
+ } catch (Throwable t) {
+ log.error("Failed to invoke " + this.nodeNotifier.getClass().getSimpleName() +
+ ":notice(" + nodeId + "," + status + ")", t);
+ }
+ }
+ }
+
+ /**
+ * @param graphName
+ * @param notice
+ * @return null: when there is no HgStoreNodeNotifier in the nodeManager;
+ * @throws HgStoreClientException
+ */
+ public Integer notifying(String graphName, HgStoreNotice notice) {
+
+ if (this.nodeNotifier != null) {
+
+ synchronized (Thread.currentThread()) {
+ try {
+ return this.nodeNotifier.notice(graphName, notice);
+ } catch (Throwable t) {
+ String msg =
+ "Failed to invoke " + this.nodeNotifier.getClass().getSimpleName() +
+ ", notice: [ " + notice + " ]";
+ log.error(msg, t);
+ throw new HgStoreClientException(msg);
+ }
+ }
+
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a collection of HgStoreNode who is in charge of the graph passed in the argument.
+ *
+ * @param graphName
+ * @return null when none matched to argument or any argument is invalid.
+ */
+ public List getStoreNodes(String graphName) {
+ if (HgAssert.isInvalid(graphName)) {
+ return null;
+ }
+
+ return this.graphNodesMap.get(graphName);
+ }
+
+ /**
+ * Adding a new Store-Node, return the argument's value if the host+port was not existing,
+ * otherwise return the HgStoreNode-instance added early.
+ *
+ * @param storeNode
+ * @return
+ * @throws IllegalArgumentException when any argument is invalid.
+ */
+ public HgStoreNode addNode(HgStoreNode storeNode) {
+ HgAssert.isFalse(storeNode == null, "the argument: storeNode is null.");
+
+ Long nodeId = storeNode.getNodeId();
+
+ HgStoreNode node = null;
+
+ synchronized (this.nodeIdMap) {
+ node = this.addressMap.get(nodeId);
+ if (node == null) {
+ node = storeNode;
+ this.nodeIdMap.put(nodeId, node);
+ this.addressMap.put(storeNode.getAddress(), node);
+ }
+ }
+
+ return node;
+ }
+
+ /**
+ * @param graphName
+ * @param storeNode
+ * @return
+ * @throws IllegalArgumentException when any argument is invalid.
+ */
+ public HgStoreNode addNode(String graphName, HgStoreNode storeNode) {
+ HgAssert.isFalse(HgAssert.isInvalid(graphName), "the argument is invalid: graphName");
+ HgStoreNode node = this.addNode(storeNode);
+
+ List nodes = null;
+
+ synchronized (this.graphNodesMap) {
+ nodes = this.graphNodesMap.get(graphName);
+ if (nodes == null) {
+ nodes = new ArrayList<>();
+ this.graphNodesMap.put(graphName, nodes);
+ }
+ nodes.add(node);
+ }
+
+ return node;
+ }
+
+ public HgStoreNodePartitioner getNodePartitioner() {
+ return nodePartitioner;
+ }
+
+ public HgStoreNodeManager setNodePartitioner(HgStoreNodePartitioner nodePartitioner) {
+ HgAssert.isFalse(nodePartitioner == null, "the argument is invalid: nodePartitioner");
+ this.nodePartitioner = nodePartitioner;
+ return this;
+ }
+
+ public HgStoreNodeNotifier getNodeNotifier() {
+ return nodeNotifier;
+ }
+
+ public HgStoreNodeManager setNodeNotifier(HgStoreNodeNotifier nodeNotifier) {
+ HgAssert.isFalse(nodeNotifier == null, "the argument is invalid: nodeNotifier");
+ this.nodeNotifier = nodeNotifier;
+ return this;
+ }
+
+ public HgStoreNodeManager setNodeProvider(HgStoreNodeProvider nodeProvider) {
+ this.nodeProvider = nodeProvider;
+ return this;
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeNotifier.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeNotifier.java
new file mode 100644
index 0000000000..0319d6c4de
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeNotifier.java
@@ -0,0 +1,36 @@
+/*
+ * 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.store.client;
+
+/**
+ * created on 2021/10/12
+ *
+ * @version 1.0.0
+ */
+public interface HgStoreNodeNotifier {
+
+ /**
+ * It will be invoked by NodeManager, when some exception or issue was happened.
+ *
+ * @param graphName
+ * @param storeNotice
+ * @return return 0 please, for no matter what.
+ */
+ int notice(String graphName, HgStoreNotice storeNotice);
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitioner.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitioner.java
new file mode 100644
index 0000000000..d540f68aa7
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitioner.java
@@ -0,0 +1,66 @@
+/*
+ * 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.store.client;
+
+import org.apache.hugegraph.store.client.util.HgStoreClientConst;
+
+/**
+ * created on 2021/10/12
+ *
+ * @version 1.0.0
+ */
+public interface HgStoreNodePartitioner {
+
+ /**
+ * The partition algorithm implementation, that specialized by user.
+ *
+ * @param builder The builder of HgNodePartitionerBuilder. It's supposed to be invoked
+ * directly by user.
+ * e.g. builder.add(nodeId,address,partitionId);
+ * @param graphName
+ * @param startKey
+ * @param endKey
+ * @return status:
+ *
+ *
0: The partitioner is OK.
+ *
10: The partitioner is not work.
+ *
+ */
+ int partition(HgNodePartitionerBuilder builder, String graphName, byte[] startKey,
+ byte[] endKey);
+
+ /**
+ * @param builder
+ * @param graphName
+ * @param startCode hash code
+ * @param endCode hash code
+ * @return
+ */
+ default int partition(HgNodePartitionerBuilder builder, String graphName, int startCode,
+ int endCode) {
+ return this.partition(builder, graphName
+ , HgStoreClientConst.ALL_PARTITION_OWNER
+ , HgStoreClientConst.ALL_PARTITION_OWNER);
+ }
+
+ default int partition(HgNodePartitionerBuilder builder, String graphName, int partitionId) {
+ return this.partition(builder, graphName
+ , HgStoreClientConst.ALL_PARTITION_OWNER
+ , HgStoreClientConst.ALL_PARTITION_OWNER);
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitionerImpl.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitionerImpl.java
new file mode 100644
index 0000000000..dba939ec86
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodePartitionerImpl.java
@@ -0,0 +1,199 @@
+/*
+ * 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.store.client;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.hugegraph.pd.client.PDClient;
+import org.apache.hugegraph.pd.common.KVPair;
+import org.apache.hugegraph.pd.common.PDException;
+import org.apache.hugegraph.pd.common.PartitionUtils;
+import org.apache.hugegraph.pd.grpc.Metapb;
+import org.apache.hugegraph.store.client.type.HgNodeStatus;
+import org.apache.hugegraph.store.client.util.HgStoreClientConst;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class HgStoreNodePartitionerImpl implements HgStoreNodePartitioner,
+ HgStoreNodeProvider,
+ HgStoreNodeNotifier {
+
+ private PDClient pdClient;
+ private HgStoreNodeManager nodeManager;
+
+ protected HgStoreNodePartitionerImpl() {
+ }
+
+ public HgStoreNodePartitionerImpl(PDClient pdClient, HgStoreNodeManager nodeManager) {
+ this.pdClient = pdClient;
+ this.nodeManager = nodeManager;
+ }
+
+ /**
+ * 查询分区信息,结果通过HgNodePartitionerBuilder返回
+ */
+ @Override
+ public int partition(HgNodePartitionerBuilder builder, String graphName,
+ byte[] startKey, byte[] endKey) {
+ try {
+ HashSet partitions = null;
+ if (HgStoreClientConst.ALL_PARTITION_OWNER == startKey) {
+ List stores = pdClient.getActiveStores(graphName);
+ partitions = new HashSet<>(stores.size());
+ for (Metapb.Store store : stores) {
+ partitions.add(HgNodePartition.of(store.getId(), -1));
+ }
+
+ } else if (endKey == HgStoreClientConst.EMPTY_BYTES
+ || startKey == endKey || Arrays.equals(startKey, endKey)) {
+ KVPair partShard =
+ pdClient.getPartition(graphName, startKey);
+ Metapb.Shard leader = partShard.getValue();
+ partitions = new HashSet<>();
+ partitions.add(HgNodePartition.of(leader.getStoreId(),
+ pdClient.keyToCode(graphName, startKey)));
+ } else {
+ log.warn(
+ "StartOwnerkey is not equal to endOwnerkey, which is meaningless!!, It is" +
+ " a error!!");
+ List stores = pdClient.getActiveStores(graphName);
+ partitions = new HashSet<>(stores.size());
+ for (Metapb.Store store : stores) {
+ partitions.add(HgNodePartition.of(store.getId(), -1));
+ }
+ }
+ builder.setPartitions(partitions);
+ } catch (PDException e) {
+ log.error("An error occurred while getting partition information :{}", e.getMessage());
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ return 0;
+ }
+
+ @Override
+ public int partition(HgNodePartitionerBuilder builder, String graphName,
+ int startKey, int endKey) {
+ try {
+ HashSet partitions = new HashSet<>();
+ Metapb.Partition partition = null;
+ while ((partition == null || partition.getEndKey() < endKey)
+ && startKey < PartitionUtils.MAX_VALUE) {
+ KVPair partShard =
+ pdClient.getPartitionByCode(graphName, startKey);
+ if (partShard != null) {
+ partition = partShard.getKey();
+ Metapb.Shard leader = partShard.getValue();
+ partitions.add(HgNodePartition.of(leader.getStoreId(), startKey,
+ (int) partition.getStartKey(),
+ (int) partition.getEndKey()));
+ startKey = (int) partition.getEndKey();
+ } else {
+ break;
+ }
+ }
+ builder.setPartitions(partitions);
+ } catch (PDException e) {
+ log.error("An error occurred while getting partition information :{}", e.getMessage());
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ return 0;
+ }
+
+ @Override
+ public int partition(HgNodePartitionerBuilder builder, String graphName,
+ int partitionId) {
+ try {
+ HashSet partitions = new HashSet<>();
+ Metapb.Partition partition = null;
+
+ KVPair partShard =
+ pdClient.getPartitionById(graphName, partitionId);
+ if (partShard != null) {
+ partition = partShard.getKey();
+ Metapb.Shard leader = partShard.getValue();
+ partitions.add(
+ HgNodePartition.of(leader.getStoreId(), (int) partition.getStartKey()));
+ }
+ builder.setPartitions(partitions);
+ } catch (PDException e) {
+ log.error("An error occurred while getting partition information :{}", e.getMessage());
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ return 0;
+ }
+
+ /**
+ * 查询hgstore信息
+ *
+ * @return hgstore
+ */
+ @Override
+ public HgStoreNode apply(String graphName, Long nodeId) {
+ try {
+ Metapb.Store store = pdClient.getStore(nodeId);
+ return nodeManager.getNodeBuilder().setNodeId(store.getId())
+ .setAddress(store.getAddress()).build();
+ } catch (PDException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 通知更新缓存
+ */
+ @Override
+ public int notice(String graphName, HgStoreNotice storeNotice) {
+ log.warn(storeNotice.toString());
+ if (storeNotice.getPartitionLeaders() != null) {
+ storeNotice.getPartitionLeaders().forEach((partId, leader) -> {
+ pdClient.updatePartitionLeader(graphName, partId, leader);
+ log.warn("updatePartitionLeader:{}-{}-{}",
+ graphName, partId, leader);
+ });
+ }
+ if (storeNotice.getPartitionIds() != null) {
+ storeNotice.getPartitionIds().forEach(partId -> {
+ pdClient.invalidPartitionCache(graphName, partId);
+ });
+ }
+ if (!storeNotice.getNodeStatus().equals(
+ HgNodeStatus.PARTITION_COMMON_FAULT)
+ && !storeNotice.getNodeStatus().equals(
+ HgNodeStatus.NOT_PARTITION_LEADER)) {
+ pdClient.invalidPartitionCache();
+ log.warn("invalidPartitionCache:{} ", storeNotice.getNodeStatus());
+ }
+ return 0;
+ }
+
+ public Metapb.Graph delGraph(String graphName) {
+ try {
+ return pdClient.delGraph(graphName);
+ } catch (PDException e) {
+ log.error("delGraph {} exception, {}", graphName, e.getMessage());
+ }
+ return null;
+ }
+
+ public void setNodeManager(HgStoreNodeManager nodeManager) {
+ this.nodeManager = nodeManager;
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeProvider.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeProvider.java
new file mode 100644
index 0000000000..2d0a7b5ed5
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeProvider.java
@@ -0,0 +1,34 @@
+/*
+ * 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.store.client;
+
+/**
+ * created on 2021/10/27
+ */
+public interface HgStoreNodeProvider {
+
+ /**
+ * Applying a new HgStoreNode instance
+ *
+ * @param graphName
+ * @param nodeId
+ * @return
+ */
+ HgStoreNode apply(String graphName, Long nodeId);
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeSession.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeSession.java
new file mode 100644
index 0000000000..17387eebc1
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNodeSession.java
@@ -0,0 +1,43 @@
+/*
+ * 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.store.client;
+
+import org.apache.hugegraph.store.HgStoreSession;
+
+/**
+ * created on 2021/10/11
+ *
+ * @version 0.1.0
+ */
+public interface HgStoreNodeSession extends HgStoreSession {
+
+ /**
+ * Return the name of graph.
+ *
+ * @return
+ */
+ String getGraphName();
+
+ /**
+ * Return an instance of HgStoreNode, which provided the connection of Store-Node machine.
+ *
+ * @return
+ */
+ HgStoreNode getStoreNode();
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNotice.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNotice.java
new file mode 100644
index 0000000000..083cb8d381
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreNotice.java
@@ -0,0 +1,100 @@
+/*
+ * 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.store.client;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+import org.apache.hugegraph.store.client.type.HgNodeStatus;
+import org.apache.hugegraph.store.client.util.HgAssert;
+
+/**
+ * 2021/11/16
+ */
+@NotThreadSafe
+public class HgStoreNotice {
+
+ private final Long nodeId;
+ private final HgNodeStatus nodeStatus;
+ private final String message;
+ private Map partitionLeaders;
+ private List partitionIds;
+
+ private HgStoreNotice(Long nodeId, HgNodeStatus nodeStatus, String message) {
+ this.nodeId = nodeId;
+ this.nodeStatus = nodeStatus;
+ this.message = message;
+ }
+
+ public static HgStoreNotice of(Long nodeId, HgNodeStatus nodeStatus) {
+ HgAssert.isArgumentNotNull(nodeId, "nodeId");
+ HgAssert.isArgumentNotNull(nodeStatus, "nodeStatus");
+ return new HgStoreNotice(nodeId, nodeStatus, "");
+ }
+
+ public static HgStoreNotice of(Long nodeId, HgNodeStatus nodeStatus, String message) {
+ HgAssert.isArgumentNotNull(nodeId, "nodeId");
+ HgAssert.isArgumentNotNull(nodeStatus, "nodeStatus");
+ HgAssert.isArgumentNotNull(message, "message");
+
+ return new HgStoreNotice(nodeId, nodeStatus, message);
+ }
+
+ public Long getNodeId() {
+ return nodeId;
+ }
+
+ public HgNodeStatus getNodeStatus() {
+ return nodeStatus;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Map getPartitionLeaders() {
+ return partitionLeaders;
+ }
+
+ public HgStoreNotice setPartitionLeaders(Map partitionLeaders) {
+ this.partitionLeaders = partitionLeaders;
+ return this;
+ }
+
+ public List getPartitionIds() {
+ return partitionIds;
+ }
+
+ public HgStoreNotice setPartitionIds(List partitionIds) {
+ this.partitionIds = partitionIds;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "HgStoreNotice{" +
+ "nodeId=" + nodeId +
+ ", nodeStatus=" + nodeStatus +
+ ", message='" + message + '\'' +
+ ", partitionLeaders=" + partitionLeaders +
+ ", partitionIds=" + partitionIds +
+ '}';
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreService.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreService.java
new file mode 100644
index 0000000000..c0e2be6b59
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.store.client;
+
+public class HgStoreService {
+
+ private static final HgStoreService instance = new HgStoreService();
+
+ private HgStoreService() {
+ }
+
+ static HgStoreService of() {
+ return instance;
+ }
+
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreSessionProvider.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreSessionProvider.java
new file mode 100644
index 0000000000..37fa51cb4a
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgStoreSessionProvider.java
@@ -0,0 +1,37 @@
+/*
+ * 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.store.client;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.hugegraph.store.HgSessionProvider;
+import org.apache.hugegraph.store.HgStoreSession;
+
+/**
+ * created on 2021/10/12
+ */
+@ThreadSafe
+public class HgStoreSessionProvider implements HgSessionProvider {
+
+ private final MultiNodeSessionFactory sessionFactory = MultiNodeSessionFactory.getInstance();
+
+ @Override
+ public HgStoreSession createSession(String graphName) {
+ return this.sessionFactory.createStoreSession(graphName);
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTkvEntryImpl.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTkvEntryImpl.java
new file mode 100644
index 0000000000..ab0c7fdce9
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTkvEntryImpl.java
@@ -0,0 +1,84 @@
+/*
+ * 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.store.client;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import org.apache.hugegraph.store.HgTkvEntry;
+
+/**
+ * created on 2021/10/14
+ */
+class HgTkvEntryImpl implements HgTkvEntry {
+
+ private final String table;
+ private final byte[] key;
+ private final byte[] value;
+
+ HgTkvEntryImpl(String table, byte[] key, byte[] value) {
+ this.table = table;
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public String table() {
+ return this.table;
+ }
+
+ @Override
+ public byte[] key() {
+ return this.key;
+ }
+
+ @Override
+ public byte[] value() {
+ return this.value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ HgTkvEntryImpl that = (HgTkvEntryImpl) o;
+ return Objects.equals(table, that.table) && Arrays.equals(key, that.key) &&
+ Arrays.equals(value, that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(table);
+ result = 31 * result + Arrays.hashCode(key);
+ result = 31 * result + Arrays.hashCode(value);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "HgTkvEntryImpl{" +
+ "table='" + table + '\'' +
+ ", key=" + Arrays.toString(key) +
+ ", value=" + Arrays.toString(value) +
+ '}';
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTokvEntryImpl.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTokvEntryImpl.java
new file mode 100644
index 0000000000..932864a55b
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/HgTokvEntryImpl.java
@@ -0,0 +1,84 @@
+/*
+ * 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.store.client;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import org.apache.hugegraph.store.HgOwnerKey;
+import org.apache.hugegraph.store.HgTokvEntry;
+
+/**
+ * created on 2021/10/14
+ */
+class HgTokvEntryImpl implements HgTokvEntry {
+
+ private final String table;
+ private final HgOwnerKey ownerKey;
+ private final byte[] value;
+
+ HgTokvEntryImpl(String table, HgOwnerKey ownerKey, byte[] value) {
+ this.table = table;
+ this.ownerKey = ownerKey;
+ this.value = value;
+ }
+
+ @Override
+ public String table() {
+ return this.table;
+ }
+
+ @Override
+ public HgOwnerKey ownerKey() {
+ return this.ownerKey;
+ }
+
+ @Override
+ public byte[] value() {
+ return this.value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ HgTokvEntryImpl that = (HgTokvEntryImpl) o;
+ return Objects.equals(table, that.table) && Objects.equals(ownerKey, that.ownerKey) &&
+ Arrays.equals(value, that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(table, ownerKey);
+ result = 31 * result + Arrays.hashCode(value);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "HgTokvEntryImpl{" +
+ "table='" + table + '\'' +
+ ", okv=" + ownerKey +
+ ", value=" + Arrays.toString(value) +
+ '}';
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/MultiNodeSessionFactory.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/MultiNodeSessionFactory.java
new file mode 100644
index 0000000000..ff7cde0db8
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/MultiNodeSessionFactory.java
@@ -0,0 +1,54 @@
+/*
+ * 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.store.client;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.hugegraph.store.HgStoreSession;
+
+/**
+ * created on 2021/10/12
+ */
+@ThreadSafe
+public final class MultiNodeSessionFactory {
+
+ // TODO multi-instance ?
+ private final static MultiNodeSessionFactory INSTANCE = new MultiNodeSessionFactory();
+ // TODO multi-instance ?
+ private final HgStoreNodeManager nodeManager = HgStoreNodeManager.getInstance();
+ // TODO: to be a chain assigned to each graph
+ //private HgStoreNodeDispatcher storeNodeDispatcher;
+
+ private MultiNodeSessionFactory() {
+ }
+
+ static MultiNodeSessionFactory getInstance() {
+ return INSTANCE;
+ }
+
+ HgStoreSession createStoreSession(String graphName) {
+ return buildProxy(graphName);
+ }
+
+ private HgStoreSession buildProxy(String graphName) {
+ //return new MultiNodeSessionProxy(graphName, nodeManager, storeNodeDispatcher);
+ //return new NodePartitionSessionProxy(graphName,nodeManager);
+ //return new NodeRetrySessionProxy(graphName,nodeManager);
+ return new NodeTxSessionProxy(graphName, nodeManager);
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTkv.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTkv.java
new file mode 100644
index 0000000000..e78ced4c10
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTkv.java
@@ -0,0 +1,125 @@
+/*
+ * 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.store.client;
+
+import java.util.Objects;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.hugegraph.store.HgOwnerKey;
+import org.apache.hugegraph.store.HgStoreSession;
+
+/**
+ * created on 2021/10/26
+ */
+@ThreadSafe
+class NodeTkv {
+
+ private final HgNodePartition nodePartition;
+ private final String table;
+ private final HgOwnerKey key;
+ private final HgOwnerKey endKey;
+ private HgStoreSession session;
+
+ NodeTkv(HgNodePartition nodePartition, String table, HgOwnerKey key) {
+ this.nodePartition = nodePartition;
+ this.table = table;
+ this.key = key;
+ this.endKey = key;
+ this.key.setKeyCode(this.nodePartition.getKeyCode());
+ }
+
+ NodeTkv(HgNodePartition nodePartition, String table, HgOwnerKey key, int keyCode) {
+ this.nodePartition = nodePartition;
+ this.table = table;
+ this.key = key;
+ this.endKey = key;
+
+ this.key.setKeyCode(keyCode);
+ }
+
+ NodeTkv(HgNodePartition nodePartition, String table, HgOwnerKey startKey,
+ HgOwnerKey endKey) {
+ this.nodePartition = nodePartition;
+ this.table = table;
+ this.key = startKey;
+ this.endKey = endKey;
+ this.key.setKeyCode(nodePartition.getStartKey());
+ this.endKey.setKeyCode(nodePartition.getEndKey());
+ }
+
+ public Long getNodeId() {
+ return this.nodePartition.getNodeId();
+ }
+
+ public String getTable() {
+ return table;
+ }
+
+ public HgOwnerKey getKey() {
+ return key;
+ }
+
+ public HgOwnerKey getEndKey() {
+ return endKey;
+ }
+
+ public NodeTkv setKeyCode(int code) {
+ this.key.setKeyCode(code);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ NodeTkv nptKv = (NodeTkv) o;
+ return Objects.equals(nodePartition, nptKv.nodePartition) &&
+ Objects.equals(table, nptKv.table)
+ && Objects.equals(key, nptKv.key)
+ && Objects.equals(endKey, nptKv.endKey);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(nodePartition, table, key, endKey);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "NptKv{" +
+ "nodePartition=" + nodePartition +
+ ", table='" + table + '\'' +
+ ", key=" + key +
+ ", endKey=" + endKey +
+ '}';
+ }
+
+ public HgStoreSession getSession() {
+ return session;
+ }
+
+ public void setSession(HgStoreSession session) {
+ this.session = session;
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java
new file mode 100644
index 0000000000..01eea1af79
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java
@@ -0,0 +1,431 @@
+/*
+ * 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.store.client;
+
+import static org.apache.hugegraph.store.client.util.HgStoreClientConst.EMPTY_LIST;
+import static org.apache.hugegraph.store.client.util.HgStoreClientConst.NODE_MAX_RETRYING_TIMES;
+import static org.apache.hugegraph.store.client.util.HgStoreClientConst.TX_SESSIONS_MAP_CAPACITY;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+import org.apache.hugegraph.store.HgOwnerKey;
+import org.apache.hugegraph.store.HgStoreSession;
+import org.apache.hugegraph.store.client.type.HgStoreClientException;
+import org.apache.hugegraph.store.client.util.HgAssert;
+import org.apache.hugegraph.store.client.util.HgStoreClientConst;
+import org.apache.hugegraph.store.term.HgPair;
+import org.apache.hugegraph.store.term.HgTriple;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 2021/11/18
+ */
+@Slf4j
+@NotThreadSafe
+final class NodeTxExecutor {
+
+ private static final String maxTryMsg =
+ "the number of retries reached the upper limit : " + NODE_MAX_RETRYING_TIMES +
+ ",caused by:";
+ private static final String msg =
+ "Not all tx-data delivered to real-node-session successfully.";
+
+ static {
+ System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism",
+ String.valueOf(Runtime.getRuntime().availableProcessors() * 2));
+ }
+
+ private final String graphName;
+ NodeTxSessionProxy proxy;
+ Collector>> collector = Collectors.groupingBy(
+ nkv -> nkv.getNodeId(), Collectors.mapping(NodeTkv::getKey, Collectors.toList()));
+ private Map sessions = new HashMap<>(TX_SESSIONS_MAP_CAPACITY, 1);
+ private boolean isTx;
+ private List,
+ Function>> entries = new LinkedList<>();
+
+ private NodeTxExecutor(String graphName, NodeTxSessionProxy proxy) {
+ this.graphName = graphName;
+ this.proxy = proxy;
+ }
+
+ static NodeTxExecutor graphOf(String graphName, NodeTxSessionProxy proxy) {
+ return new NodeTxExecutor(graphName, proxy);
+ }
+
+ public boolean isTx() {
+ return isTx;
+ }
+
+ void setTx(boolean tx) {
+ isTx = tx;
+ }
+
+ void commitTx() {
+ if (!this.isTx) {
+ throw new IllegalStateException("It's not in tx state");
+ }
+
+ this.doCommit();
+ }
+
+ void rollbackTx() {
+ if (!this.isTx) {
+ return;
+ }
+ try {
+ this.sessions.values().stream().filter(HgStoreSession::isTx)
+ .forEach(HgStoreSession::rollback);
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ this.isTx = false;
+ this.sessions.clear();
+ }
+ }
+
+ void doCommit() {
+ try {
+ this.retryingInvoke(() -> {
+ if (this.entries.isEmpty()) {
+ return true;
+ }
+ AtomicBoolean allSuccess = new AtomicBoolean(true);
+ for (HgPair, Function> e :
+ this.entries) {
+ doAction(e.getKey(), e.getValue());
+ }
+ if (!allSuccess.get()) {
+ throw HgStoreClientException.of(msg);
+ }
+ AtomicReference throwable = new AtomicReference<>();
+ Collection sessions = this.sessions.values();
+ sessions.parallelStream().forEach(e -> {
+ if (e.isTx()) {
+ try {
+ e.commit();
+ } catch (Throwable t) {
+ throwable.compareAndSet(null, t);
+ allSuccess.set(false);
+ }
+ }
+ });
+ if (!allSuccess.get()) {
+ if (isTx) {
+ try {
+ sessions.stream().forEach(HgStoreSession::rollback);
+ } catch (Exception e) {
+
+ }
+ }
+ Throwable cause = throwable.get();
+ if (cause.getCause() != null) {
+ cause = cause.getCause();
+ }
+ if (cause instanceof HgStoreClientException) {
+ throw (HgStoreClientException) cause;
+ }
+ throw HgStoreClientException.of(cause);
+ }
+ return true;
+ });
+
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ this.isTx = false;
+ this.entries = new LinkedList<>();
+ this.sessions = new HashMap<>(TX_SESSIONS_MAP_CAPACITY, 1);
+ }
+ }
+
+ // private Function,
+ // List>> nodeStreamWrapper = nodeParams -> {
+ // if (nodeParams.getZ() == null) {
+ // return this.proxy.getNode(nodeParams.getX(),
+ // nodeParams.getY());
+ // } else {
+ // if (nodeParams.getZ() instanceof HgOwnerKey) {
+ // return this.proxy.getNode(nodeParams.getX(),
+ // nodeParams.getY(),
+ // (HgOwnerKey) nodeParams.getZ());
+ // } if ( nodeParams.getZ() instanceof Integer ){
+ // return this.proxy.doPartition(nodeParams.getX(), (Integer) nodeParams.getZ())
+ // .stream()
+ // .map(e -> new NodeTkv(e, nodeParams.getX(), nodeParams.getY(),
+ // nodeParams.getY()
+ // .getKeyCode()))
+ // .map(
+ // e -> new HgPair<>(this.proxy.getStoreNode(e.getNodeId
+ // ()), e)
+ // );
+ // }else {
+ // HgAssert.isTrue(nodeParams.getZ() instanceof byte[],
+ // "Illegal parameter to get node id");
+ // throw new NotImplementedException();
+ // }
+ // }
+ // };
+
+ // private Function,
+ // List>> nodeStreamWrapper = nodeParams -> {
+ // if (nodeParams.getZ() == null) {
+ // return this.proxy.getNode(nodeParams.getX(), nodeParams.getY());
+ // } else {
+ // if (nodeParams.getZ() instanceof HgOwnerKey) {
+ // return this.proxy.getNode(nodeParams.getX(), nodeParams.getY(),
+ // (HgOwnerKey) nodeParams.getZ());
+ // }
+ // if (nodeParams.getZ() instanceof Integer) {
+ // Collection nodePartitions = this.proxy.doPartition(nodeParams
+ // .getX(),
+ // (Integer)
+ // nodeParams
+ // .getZ());
+ // ArrayList> hgPairs = new ArrayList<>
+ // (nodePartitions.size());
+ // for (HgNodePartition nodePartition : nodePartitions) {
+ // NodeTkv nodeTkv = new NodeTkv(nodePartition, nodeParams.getX(), nodeParams
+ // .getY(),
+ // nodeParams.getY().getKeyCode());
+ // hgPairs.add(new HgPair<>(this.proxy.getStoreNode(nodeTkv.getNodeId()),
+ // nodeTkv));
+ //
+ // }
+ // return hgPairs;
+ // } else {
+ // HgAssert.isTrue(nodeParams.getZ() instanceof byte[], "Illegal parameter to get
+ // node id");
+ // throw new RuntimeException("not implemented");
+ // }
+ // }
+ // };
+
+ private boolean doAction(HgTriple nodeParams,
+ Function action) {
+ if (nodeParams.getZ() == null) {
+ return this.proxy.doAction(nodeParams.getX(), nodeParams.getY(), nodeParams.getY(),
+ action);
+ } else {
+ if (nodeParams.getZ() instanceof HgOwnerKey) {
+ boolean result = this.proxy.doAction(nodeParams.getX(), nodeParams.getY(),
+ (HgOwnerKey) nodeParams.getZ(), action);
+ return result;
+ }
+ if (nodeParams.getZ() instanceof Integer) {
+ return this.proxy.doAction(nodeParams.getX(), nodeParams.getY(),
+ (Integer) nodeParams.getZ(), action);
+ } else {
+ HgAssert.isTrue(nodeParams.getZ() instanceof byte[],
+ "Illegal parameter to get node id");
+ throw new RuntimeException("not implemented");
+ }
+ }
+ }
+
+ boolean prepareTx(HgTriple nodeParams,
+ Function sessionMapper) {
+ if (this.isTx) {
+ return this.entries.add(new HgPair(nodeParams, sessionMapper));
+ } else {
+ return this.isAllTrue(nodeParams, sessionMapper);
+ }
+ }
+
+ public HgStoreSession openNodeSession(HgStoreNode node) {
+ HgStoreSession res = this.sessions.get(node.getNodeId());
+ if (res == null) {
+ this.sessions.put(node.getNodeId(), (res = node.openSession(this.graphName)));
+ }
+ if (this.isTx) {
+ res.beginTx();
+ }
+
+ return res;
+ }
+
+ R limitOne(
+ Supplier>> nodeStreamSupplier,
+ Function, R> sessionMapper, R emptyObj) {
+
+ Optional res = retryingInvoke(
+ () -> nodeStreamSupplier.get()
+ .parallel()
+ .map(
+ pair -> new SessionData(
+ openNodeSession(pair.getKey()),
+ pair.getValue())
+ ).map(sessionMapper)
+ .filter(
+ r -> isValid(r)
+ )
+ .findAny()
+ .orElseGet(() -> emptyObj)
+ );
+ return res.orElse(emptyObj);
+ }
+
+ List toList(Function nodeFunction
+ , List keyList
+ , Function> flatMapper
+ , Function>, List> sessionMapper) {
+ Optional> res = retryingInvoke(
+ () -> keyList.stream()
+ .flatMap(flatMapper)
+ .collect(collector)
+ .entrySet()
+ .stream()
+ .map(
+ e -> new SessionData<>
+ (
+ openNodeSession(
+ nodeFunction.apply(e.getKey())),
+ e.getValue()
+ )
+ )
+ .parallel()
+ .map(sessionMapper)
+ .flatMap(
+ e -> e.stream()
+ )
+ //.distinct()
+ .collect(Collectors.toList())
+ );
+
+ return res.orElse(EMPTY_LIST);
+ }
+
+ private boolean isAllTrue(HgTriple nodeParams,
+ Function action) {
+ Optional res = retryingInvoke(() -> doAction(nodeParams, action));
+ return res.orElse(false);
+ }
+
+ boolean isAllTrue(Supplier>> dataSource,
+ Function, Boolean> action) {
+ Optional res = retryingInvoke(
+ () -> dataSource.get()
+ .parallel()
+ .map(
+ pair -> new SessionData(
+ openNodeSession(pair.getKey()),
+ pair.getValue())
+ ).map(action)
+ .allMatch(Boolean::booleanValue)
+ );
+
+ return res.orElse(false);
+ }
+
+ boolean ifAnyTrue(Supplier>> nodeStreamSupplier
+ , Function, Boolean> sessionMapper) {
+
+ Optional res = retryingInvoke(
+ () -> nodeStreamSupplier.get()
+ .parallel()
+ .map(
+ pair -> new SessionData(
+ openNodeSession(pair.getKey()),
+ pair.getValue())
+ )
+ .map(sessionMapper)
+ .anyMatch(Boolean::booleanValue)
+ );
+
+ return res.orElse(false);
+ }
+
+ Optional retryingInvoke(Supplier supplier) {
+ return IntStream.rangeClosed(0, NODE_MAX_RETRYING_TIMES).boxed()
+ .map(
+ i -> {
+ T buffer = null;
+ try {
+ buffer = supplier.get();
+ } catch (Throwable t) {
+ if (i + 1 <= NODE_MAX_RETRYING_TIMES) {
+ try {
+ int sleepTime;
+ // 前三次每隔一秒做一次尝试
+ if (i < 3) {
+ sleepTime = 1;
+ } else {
+ // 后面逐次递增
+ sleepTime = i - 1;
+ }
+ log.info("Waiting {} seconds " +
+ "for the next try.",
+ sleepTime);
+ Thread.sleep(sleepTime * 1000L);
+ } catch (InterruptedException e) {
+ log.error("Failed to sleep", e);
+ }
+ } else {
+ log.error(maxTryMsg, t);
+ throw HgStoreClientException.of(
+ t.getMessage(), t);
+ }
+ }
+ return buffer;
+ }
+ )
+ .filter(e -> e != null)
+ .findFirst();
+
+ }
+
+ private boolean isValid(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (HgStoreClientConst.EMPTY_BYTES.equals(obj)) {
+ return false;
+ }
+
+ return !EMPTY_LIST.equals(obj);
+ }
+
+ class SessionData {
+
+ HgStoreSession session;
+ T data;
+
+ SessionData(HgStoreSession session, T data) {
+ this.session = session;
+ this.data = data;
+ }
+
+ }
+}
diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxSessionProxy.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxSessionProxy.java
new file mode 100644
index 0000000000..066f96893d
--- /dev/null
+++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxSessionProxy.java
@@ -0,0 +1,887 @@
+/*
+ * 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.store.client;
+
+import static java.util.stream.Collectors.groupingBy;
+import static org.apache.hugegraph.store.client.util.HgAssert.isArgumentNotNull;
+import static org.apache.hugegraph.store.client.util.HgAssert.isArgumentValid;
+import static org.apache.hugegraph.store.client.util.HgAssert.isFalse;
+import static org.apache.hugegraph.store.client.util.HgStoreClientConst.EMPTY_STRING;
+import static org.apache.hugegraph.store.client.util.HgStoreClientUtil.err;
+import static org.apache.hugegraph.store.client.util.HgStoreClientUtil.toStr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+import org.apache.hugegraph.store.HgKvEntry;
+import org.apache.hugegraph.store.HgKvIterator;
+import org.apache.hugegraph.store.HgKvOrderedIterator;
+import org.apache.hugegraph.store.HgOwnerKey;
+import org.apache.hugegraph.store.HgScanQuery;
+import org.apache.hugegraph.store.HgStoreSession;
+import org.apache.hugegraph.store.client.grpc.KvBatchScanner;
+import org.apache.hugegraph.store.client.grpc.KvCloseableIterator;
+import org.apache.hugegraph.store.client.util.HgAssert;
+import org.apache.hugegraph.store.client.util.HgStoreClientConst;
+import org.apache.hugegraph.store.client.util.HgStoreClientUtil;
+import org.apache.hugegraph.store.grpc.stream.ScanStreamReq.Builder;
+import org.apache.hugegraph.store.term.HgPair;
+import org.apache.hugegraph.store.term.HgTriple;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * created on 2022/01/19
+ *
+ * @version 0.6.0 added batch scan on 2022/03/03
+ */
+@Slf4j
+@NotThreadSafe
+class NodeTxSessionProxy implements HgStoreSession {
+
+ private final HgStoreNodeManager nodeManager;
+ private final HgStoreNodePartitioner nodePartitioner;
+ private final String graphName;
+ private final NodeTxExecutor txExecutor;
+
+ NodeTxSessionProxy(String graphName, HgStoreNodeManager nodeManager) {
+ this.nodeManager = nodeManager;
+ this.graphName = graphName;
+ this.nodePartitioner = this.nodeManager.getNodePartitioner();
+ this.txExecutor = NodeTxExecutor.graphOf(this.graphName, this);
+
+ isFalse(this.nodePartitioner == null,
+ "Failed to retrieve the node-partitioner from node-manager.");
+ }
+
+ @Override
+ public void beginTx() {
+ this.txExecutor.setTx(true);
+ }
+
+ @Override
+ public void commit() {
+ this.txExecutor.commitTx();
+ }
+
+ @Override
+ public void rollback() {
+ this.txExecutor.rollbackTx();
+ }
+
+ @Override
+ public boolean isTx() {
+ return this.txExecutor.isTx();
+ }
+
+ @Override
+ public boolean put(String table, HgOwnerKey ownerKey, byte[] value) {
+ // isArgumentValid(table, "table");
+ // isArgumentNotNull(ownerKey, "ownerKey");
+ // log.info("put -> graph: {}, table: {}, key: {}, value: {}",
+ // graphName, table, ownerKey, toByteStr(value));
+ // return this.txExecutor.prepareTx(
+ // () -> getNodeStream(table, ownerKey),
+ // e -> e.session.put(table, e.data.getKey(), value)
+ // );
+ return this.txExecutor.prepareTx(new HgTriple(table, ownerKey, null),
+ e -> e.getSession().put(table,
+ e.getKey(),
+ value));
+ }
+
+ @Override
+ public boolean directPut(String table, int partitionId, HgOwnerKey ownerKey, byte[] value) {
+ isArgumentValid(table, "table");
+ isArgumentNotNull(ownerKey, "ownerKey");
+
+ return this.txExecutor.prepareTx(
+ new HgTriple(table, ownerKey, partitionId),
+ e -> e.getSession().put(table, e.getKey(), value)
+ );
+ }
+
+ @Override
+ public boolean delete(String table, HgOwnerKey ownerKey) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(ownerKey == null, "The argument is invalid: ownerKey");
+
+ if (log.isDebugEnabled()) {
+ log.debug("delete -> graph: {}, table: {}, key: {}"
+ , graphName, table, toStr(ownerKey));
+ }
+
+ return this.txExecutor
+ .prepareTx(
+ new HgTriple(table, ownerKey, null),
+ e -> e.getSession().delete(table, e.getKey())
+ );
+ }
+
+ @Override
+ public boolean deleteSingle(String table, HgOwnerKey ownerKey) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(ownerKey == null, "The argument is invalid: ownerKey");
+
+ if (log.isDebugEnabled()) {
+ log.debug("deleteSingle -> graph: {}, table: {}, key: {}"
+ , graphName, table, toStr(ownerKey));
+ }
+
+ return this.txExecutor
+ .prepareTx(
+ new HgTriple(table, ownerKey, null),
+ e -> e.getSession().deleteSingle(table, e.getKey())
+ );
+ }
+
+ @Override
+ public boolean deletePrefix(String table, HgOwnerKey prefix) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(prefix == null, "The argument is invalid: prefix");
+
+ if (log.isDebugEnabled()) {
+ log.debug("deletePrefix -> graph: {}, table: {}, prefix: {}"
+ , graphName, table, toStr(prefix));
+ }
+
+ return this.txExecutor
+ .prepareTx(
+ new HgTriple(table, prefix, null),
+ e -> e.getSession().deletePrefix(table, e.getKey())
+ );
+ }
+
+ @Override
+ public boolean deleteRange(String table, HgOwnerKey start, HgOwnerKey end) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(start == null, "The argument is invalid: start");
+ HgAssert.isFalse(end == null, "The argument is invalid: end");
+
+ if (log.isDebugEnabled()) {
+ log.debug("deleteRange -> graph: {}, table: {}, start: {}, end: {}"
+ , graphName, table, toStr(start), toStr(end));
+ }
+
+ return this.txExecutor
+ .prepareTx(
+ new HgTriple(table, start, end),
+ e -> e.getSession().deleteRange(table, e.getKey(), e.getEndKey())
+ );
+ }
+
+ @Override
+ public boolean merge(String table, HgOwnerKey key, byte[] value) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(key == null, "The argument is invalid: key");
+ HgAssert.isFalse(value == null, "The argument is invalid: value");
+
+ if (log.isDebugEnabled()) {
+ log.debug("merge -> graph: {}, table: {}, key: {}, value: {}"
+ , graphName, table, toStr(key), toStr(value));
+ }
+
+ return this.txExecutor
+ .prepareTx(
+ new HgTriple(table, key, value),
+ e -> e.getSession().merge(table, e.getKey(), value)
+ );
+ }
+
+ /*--- tx end ---*/
+
+ @Override
+ public byte[] get(String table, HgOwnerKey ownerKey) {
+ isArgumentValid(table, "table");
+ isArgumentNotNull(ownerKey, "ownerKey");
+
+ return this.txExecutor
+ .limitOne(
+ () -> this.getNodeStream(table, ownerKey),
+ e -> e.session.get(table, e.data.getKey()), HgStoreClientConst.EMPTY_BYTES
+ );
+ }
+
+ @Override
+ public boolean clean(int partId) {
+ Collection nodes = this.doPartition("", partId);
+ return nodes.parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .clean(partId)
+ ).findFirst().get();
+ }
+
+ @Override
+ @Deprecated
+ public List batchGetOwner(String table, List keyList) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(HgAssert.isInvalid(keyList), "The argument is invalid: keyList");
+
+ return this.txExecutor
+ .toList(
+ (l) -> this.getStoreNode(l),
+ keyList,
+ key -> this.toNodeTkvList(table, key, key).stream(),
+ e -> e.session.batchGetOwner(table, e.data)
+ );
+ }
+
+ @Override
+ public HgKvIterator batchPrefix(String table, List keyList) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(HgAssert.isInvalid(keyList), "The argument is invalid: keyList");
+ return this.toHgKvIteratorProxy(
+ this.txExecutor
+ .toList(
+ (l) -> this.getStoreNode(l),
+ keyList,
+ key -> this.toNodeTkvList(table, key, key).stream(),
+ e -> Collections.singletonList(e.session.batchPrefix(table, e.data))
+ )
+ , Long.MAX_VALUE);
+ }
+
+ @Override
+ public boolean truncate() {
+ return this.txExecutor
+ .isAllTrue(
+ () -> this.getNodeStream(EMPTY_STRING),
+ e -> e.session.truncate()
+ );
+ }
+
+ @Override
+ public boolean existsTable(String table) {
+ return this.txExecutor
+ .ifAnyTrue(
+ () -> this.getNodeStream(EMPTY_STRING),
+ e -> e.session.existsTable(table)
+ );
+ }
+
+ @Override
+ public boolean createTable(String table) {
+ return this.txExecutor
+ .isAllTrue(
+ () -> this.getNodeStream(EMPTY_STRING),
+ e -> e.session.createTable(table)
+ );
+ }
+
+ @Override
+ public boolean deleteTable(String table) {
+ return this.txExecutor
+ .isAllTrue(
+ () -> this.getNodeStream(EMPTY_STRING),
+ e -> e.session.deleteTable(table)
+ );
+ }
+
+ @Override
+ public boolean dropTable(String table) {
+ return this.txExecutor
+ .isAllTrue(
+ () -> this.getNodeStream(table),
+ e -> e.session.dropTable(table)
+ );
+ }
+
+ @Override
+ public boolean deleteGraph(String graph) {
+ return this.txExecutor
+ .isAllTrue(
+ () -> this.getNodeStream(EMPTY_STRING),
+ e -> e.session.deleteGraph(graph)
+ );
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table) {
+ return scanIterator(table, 0);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, byte[] query) {
+ return scanIterator(table, 0, query);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, long limit) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), limit)
+ )
+ .collect(Collectors.toList())
+ , limit);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, long limit, byte[] query) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), e.getKey(), limit, query)
+ )
+ .collect(Collectors.toList())
+ , limit);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey keyPrefix) {
+ return scanIterator(table, keyPrefix, 0);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey keyPrefix, long limit) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(keyPrefix == null, "The argument is invalid: keyPrefix");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table, keyPrefix)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), e.getKey(), limit)
+ )
+ .collect(Collectors.toList())
+ , limit);
+
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey keyPrefix, long limit,
+ byte[] query) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(keyPrefix == null, "The argument is invalid: keyPrefix");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table, keyPrefix)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), e.getKey(), limit, query)
+ )
+ .collect(Collectors.toList())
+ , limit);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey startKey,
+ HgOwnerKey endKey) {
+ return this.scanIterator(table, startKey, endKey, 0, null);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey startKey,
+ HgOwnerKey endKey, long limit) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(startKey == null, "The argument is invalid: startKey");
+ HgAssert.isFalse(endKey == null, "The argument is invalid: endKey");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table, startKey, endKey)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), e.getKey(), e.getEndKey(), limit)
+ )
+ .collect(Collectors.toList())
+ , limit);
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey startKey, HgOwnerKey endKey
+ , long limit, byte[] query) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(startKey == null, "The argument is invalid: startKey");
+ HgAssert.isFalse(endKey == null, "The argument is invalid: endKey");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table, startKey, endKey)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), e.getKey(), e.getEndKey(), limit,
+ query)
+ )
+ .collect(Collectors.toList())
+ , limit);
+
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, HgOwnerKey startKey, HgOwnerKey endKey
+ , long limit, int scanType, byte[] query) {
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ HgAssert.isFalse(startKey == null, "The argument is invalid: startKey");
+ HgAssert.isFalse(endKey == null, "The argument is invalid: endKey");
+
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table, startKey, endKey)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable(), e.getKey(), e.getEndKey(), limit,
+ scanType, query)
+ )
+ .collect(Collectors.toList())
+ , limit);
+
+ }
+
+ @Override
+ public HgKvIterator scanIterator(String table, int codeFrom, int codeTo,
+ int scanType, byte[] query) {
+ if (log.isDebugEnabled()) {
+ log.debug("graph: {}, table: {}, codeFrom: {}, codeTo: {}, scanType: {}, query: {}"
+ , graphName, table, codeFrom, codeTo, scanType, HgStoreClientUtil.toStr(query));
+ }
+
+ HgAssert.isFalse(HgAssert.isInvalid(table), "The argument is invalid: table");
+ return this.toHgKvIteratorProxy(
+ this.toNodeTkvList(table, codeFrom, codeTo)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .scanIterator(e.getTable()
+ , e.getKey().getKeyCode()
+ , e.getEndKey().getKeyCode(),
+ scanType, query)
+ )
+ .collect(Collectors.toList())
+ , 0);
+
+ }
+
+ @Override
+ public HgKvIterator scanIterator(Builder scanReqBuilder) {
+ List nodeTKvs = this.toNodeTkvList(scanReqBuilder);
+ Function> hgKvIteratorFunction = e -> {
+ HgStoreSession session = this.getStoreNode(e.getNodeId())
+ .openSession(this.graphName);
+ return session.scanIterator(scanReqBuilder);
+ };
+ List iterators = nodeTKvs.parallelStream()
+ .map(hgKvIteratorFunction)
+ .collect(Collectors.toList());
+ return this.toHgKvIteratorProxy(iterators, scanReqBuilder.getLimit());
+ }
+
+ @Override
+ public long count(String table) {
+ return this.toNodeTkvList(table)
+ .parallelStream()
+ .map(
+ e -> this.getStoreNode(e.getNodeId()).openSession(this.graphName)
+ .count(e.getTable())
+ )
+ .collect(Collectors.summingLong(l -> l));
+ }
+
+ @Override
+ public List> scanBatch(HgScanQuery scanQuery) {
+ HgAssert.isArgumentNotNull(scanQuery, "scanQuery");
+
+ return this.toTkvMapFunc(scanQuery.getScanMethod())
+ .apply(scanQuery)
+ .entrySet()
+ .stream()
+ .map(e ->
+ this.getStoreNode(e.getKey())
+ .openSession(this.graphName)
+ .scanBatch(toScanQueryFunc(scanQuery.getScanMethod())
+ .apply(scanQuery.getTable(), e.getValue())
+ .setQuery(scanQuery.getQuery())
+ .setLimit(scanQuery.getLimit())
+ .setPerKeyLimit(scanQuery.getPerKeyLimit())
+ .setPerKeyMax((scanQuery.getPerKeyMax()))
+ .setScanType(scanQuery.getScanType())
+ .build()
+ )
+ )
+ //.peek(e->log.info("{}",e))
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
+
+ }
+
+ @Override
+ public KvCloseableIterator> scanBatch2(HgScanQuery scanQuery) {
+ return scanBatch3(scanQuery, null);
+ }
+
+ @Override
+ public KvCloseableIterator> scanBatch3(HgScanQuery scanQuery,
+ KvCloseableIterator iterator) {
+ KvCloseableIterator notifierWrap = KvBatchScanner.ofMerger(scanQuery, (query, notifier) -> {
+ Map> nodeTkvs = this.toTkvMapFunc(scanQuery.getScanMethod())
+ .apply(query);
+
+ nodeTkvs.forEach((storeId, tkvs) -> {
+ this.getStoreNode(storeId)
+ .openSession(this.graphName)
+ .scanBatch3(toScanQueryFunc(scanQuery.getScanMethod())
+ .apply(scanQuery.getTable(), tkvs)
+ .setQuery(scanQuery.getQuery())
+ .setLimit(scanQuery.getLimit())
+ .setSkipDegree(scanQuery.getSkipDegree())
+ .setPerKeyLimit(scanQuery.getPerKeyLimit())
+ .setPerKeyMax((scanQuery.getPerKeyMax()))
+ .setScanType(scanQuery.getScanType())
+ .setOrderType(scanQuery.getOrderType())
+ .build(), notifier
+ );
+ });
+ return true;
+ });
+ return notifierWrap;
+ }
+
+ private Function>> toTkvMapFunc(
+ HgScanQuery.ScanMethod scanMethod) {
+ switch (scanMethod) {
+ case RANGE:
+ return scanQuery -> {
+ List starts = scanQuery.getStartList();
+ List ends = scanQuery.getEndList();
+ int size = starts.size();
+ return IntStream.range(0, size)
+ .boxed()
+ .map(i -> this.toNodeTkvList(scanQuery.getTable(),
+ starts.get(i), ends.get(i)))
+ .flatMap(List::stream)
+ .collect(groupingBy(NodeTkv::getNodeId));
+ };
+ case PREFIX:
+ return scanQuery ->
+ scanQuery.getPrefixList()
+ .stream()
+ .map(keyPrefix -> this.toNodeTkvList(scanQuery.getTable(),
+ keyPrefix))
+ .flatMap(List::stream)
+ .collect(groupingBy(NodeTkv::getNodeId));
+
+ default:
+ return scanQuery -> this.toNodeTkvList(scanQuery.getTable())
+ .stream()
+ .collect(groupingBy(NodeTkv::getNodeId));
+ }
+ }
+
+ private BiFunction, HgScanQuery.ScanBuilder> toScanQueryFunc(
+ HgScanQuery.ScanMethod scanMethod) {
+ switch (scanMethod) {
+ case RANGE:
+ return (table, tkvList) -> {
+ List startList = new LinkedList();
+ List endList = new LinkedList();
+
+ tkvList.stream().forEach(e -> {
+ startList.add(e.getKey());
+ endList.add(e.getEndKey());
+ });
+
+ return HgScanQuery.ScanBuilder.rangeOf(table, startList, endList);
+ };
+ case PREFIX:
+ return (table, tkvList) ->
+ HgScanQuery.ScanBuilder.prefixOf(table,
+ tkvList.stream()
+ .map(e -> e.getKey())
+ .collect(Collectors.toList())
+ );
+ default:
+ return (table, tkvList) -> HgScanQuery.ScanBuilder.tableOf(table);
+ }
+
+ }
+
+ /*-- common --*/
+ private HgKvIterator toHgKvIteratorProxy(List iteratorList, long limit) {
+ boolean isAllOrderedLimiter = iteratorList.stream()
+ .allMatch(
+ e -> e instanceof HgKvOrderedIterator);
+
+ HgKvIterator iterator;
+ if (isAllOrderedLimiter) {
+ iterator = new SequencedIterator(iteratorList.stream()
+ .map(e -> (HgKvOrderedIterator) e)
+ .collect(Collectors.toList()), limit);
+ } else {
+ iterator = new TopWorkIteratorProxy(iteratorList, limit);
+ }
+
+ return iterator;
+ }
+
+ HgStoreNode getStoreNode(Long nodeId) {
+ HgStoreNode res = this.nodeManager.applyNode(this.graphName, nodeId);
+
+ if (res == null) {
+ throw err("Failed to apply for an instance of HgStoreNode from node-manager.");
+ }
+
+ return res;
+ }
+
+ public boolean doAction(String table, HgOwnerKey startKey, HgOwnerKey endKey,
+ Function action) {
+ Collection partitions =
+ doPartition(table, startKey.getOwner(), endKey.getOwner());
+ for (HgNodePartition partition : partitions) {
+ HgStoreNode storeNode = this.getStoreNode(partition.getNodeId());
+ HgStoreSession session = this.txExecutor.openNodeSession(storeNode);
+ NodeTkv data = new NodeTkv(partition, table, startKey, endKey);
+ data.setSession(session);
+ if (!action.apply(data)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean doAction(String table, HgOwnerKey startKey, Integer code,
+ Function action) {
+ Collection partitions = this.doPartition(table, code);
+ for (HgNodePartition partition : partitions) {
+ HgStoreNode storeNode = this.getStoreNode(partition.getNodeId());
+ HgStoreSession session = this.txExecutor.openNodeSession(storeNode);
+ NodeTkv data = new NodeTkv(partition, table, startKey, code);
+ data.setSession(session);
+ if (!action.apply(data)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private List toNodeTkvList(Builder scanReqBuilder) {
+ // TODO 使用builder获取owner
+ String table = scanReqBuilder.getTable();
+ HgOwnerKey ownerKey = HgStoreClientConst.ALL_PARTITION_OWNER_KEY;
+ byte[] allOwner = ownerKey.getOwner();
+ Collection partitions = doPartition(table,
+ allOwner,
+ allOwner);
+ List nodeTkvs = new ArrayList<>(partitions.size());
+ for (HgNodePartition partition : partitions) {
+ nodeTkvs.add(new NodeTkv(partition, table, ownerKey, ownerKey));
+ }
+ return nodeTkvs;
+ }
+
+ private List toNodeTkvList(String table) {
+ Collection partitions = doPartition(table,
+ HgStoreClientConst.ALL_PARTITION_OWNER_KEY.getOwner(),
+ HgStoreClientConst.ALL_PARTITION_OWNER_KEY.getOwner());
+ ArrayList nodeTkvs = new ArrayList<>(partitions.size());
+ for (HgNodePartition partition : partitions) {
+ nodeTkvs.add(new NodeTkv(partition, table, HgStoreClientConst.ALL_PARTITION_OWNER_KEY,
+ HgStoreClientConst.ALL_PARTITION_OWNER_KEY));
+ }
+ return nodeTkvs;
+ }
+
+ private List toNodeTkvList(String table, HgOwnerKey ownerKey) {
+ Collection partitions =
+ doPartition(table, ownerKey.getOwner(), ownerKey.getOwner());
+ ArrayList nodeTkvs = new ArrayList<>(partitions.size());
+ for (HgNodePartition partition : partitions) {
+ nodeTkvs.add(new NodeTkv(partition, table, ownerKey, ownerKey));
+ }
+
+ return nodeTkvs;
+ }
+
+ private List toNodeTkvList(String table, HgOwnerKey startKey, HgOwnerKey endKey) {
+ Collection partitions =
+ doPartition(table, startKey.getOwner(), endKey.getOwner());
+ ArrayList nodeTkvs = new ArrayList<>(partitions.size());
+ for (HgNodePartition partition : partitions) {
+ nodeTkvs.add(new NodeTkv(partition, table, startKey, endKey));
+ }
+ return nodeTkvs;
+ }
+
+ private List toNodeTkvList(String table, int startCode, int endCode) {
+ Collection partitions = this.doPartition(table, startCode, endCode);
+ ArrayList nodeTkvs = new ArrayList<>(partitions.size());
+ for (HgNodePartition partition : partitions) {
+ nodeTkvs.add(
+ new NodeTkv(partition, table, HgOwnerKey.codeOf(startCode),
+ HgOwnerKey.codeOf(endCode)));
+ }
+ return nodeTkvs;
+ }
+
+ /**
+ * @return not null
+ */
+ private Collection doPartition(String table, byte[] startKey, byte[] endKey) {
+ HgNodePartitionerBuilder partitionerBuilder = HgNodePartitionerBuilder.resetAndGet();
+
+ int status = this.nodePartitioner.partition(partitionerBuilder, this.graphName, startKey,
+ endKey);
+
+ if (status != 0) {
+ throw err("The node-partitioner is not work.");
+ }
+
+ Collection