From bda73eb630fa4ad3b2b79a003debdc608c2ef9d9 Mon Sep 17 00:00:00 2001 From: V_Galaxy Date: Wed, 23 Oct 2024 21:48:41 +0800 Subject: [PATCH] minor improve --- .../store/client/grpc/KvBatchScanner5.java | 4 +- .../hugegraph/store/client/util/Base58.java | 166 ------- .../hugegraph/store/client/util/HgUuid.java | 4 +- .../apache/hugegraph/store/term/HgPair.java | 66 ++- .../hugegraph/store/util/Base58Encoder.java | 165 +++++++ .../store/util/CopyOnWriteCache.java | 124 ++++- .../hugegraph/store/util/UnsafeUtil.java | 452 ++++++++++++++++-- .../store/node/grpc/ScanBatchResponse3.java | 4 +- .../node/metrics/RocksDBMetricsConst.java | 274 ++++++----- .../hugegraph/store/node/util/Base58.java | 167 ------- 10 files changed, 881 insertions(+), 545 deletions(-) delete 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-common/src/main/java/org/apache/hugegraph/store/util/Base58Encoder.java delete mode 100644 hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/util/Base58.java diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScanner5.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScanner5.java index 2ee91f62b7..9f95eeb510 100644 --- a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScanner5.java +++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/grpc/KvBatchScanner5.java @@ -35,7 +35,7 @@ import org.apache.hugegraph.store.HgScanQuery; import org.apache.hugegraph.store.client.HgStoreNodeSession; import org.apache.hugegraph.store.client.type.HgStoreClientException; -import org.apache.hugegraph.store.client.util.Base58; +import org.apache.hugegraph.store.util.Base58Encoder; import org.apache.hugegraph.store.client.util.HgStoreClientConfig; import org.apache.hugegraph.store.grpc.common.Kv; import org.apache.hugegraph.store.grpc.stream.HgStoreStreamGrpc; @@ -107,7 +107,7 @@ private static class OrderBroker { if (log.isDebugEnabled()) { if (scanQuery.getPrefixList() != null && scanQuery.getPrefixList().size() > 0) { - brokerId = Base58.encode(scanQuery.getPrefixList().get(0).getKey()); + brokerId = Base58Encoder.convertToBase58(scanQuery.getPrefixList().get(0).getKey()); log.debug( "[ANALYSIS START] [{}] firstKey: {}, keyLength: {}, table: {}, node: {}" diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/Base58.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/Base58.java deleted file mode 100644 index 11d90c6f7e..0000000000 --- a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/Base58.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hugegraph.store.client.util; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -public class Base58 { - - public static final char[] ALPHABET = - "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); - private static final int[] INDEXES = new int[128]; - - static { - Arrays.fill(INDEXES, -1); - for (int i = 0; i < ALPHABET.length; i++) { - INDEXES[ALPHABET[i]] = i; - } - } - - /** - * Encodes the given bytes in base58. No checksum is appended. - */ - public static String encode(byte[] input) { - if (input.length == 0) { - return ""; - } - input = copyOfRange(input, 0, input.length); - // Count leading zeroes. - int zeroCount = 0; - while (zeroCount < input.length && input[zeroCount] == 0) { - ++zeroCount; - } - // The actual encoding. - byte[] temp = new byte[input.length * 2]; - int j = temp.length; - - int startAt = zeroCount; - while (startAt < input.length) { - byte mod = divmod58(input, startAt); - if (input[startAt] == 0) { - ++startAt; - } - temp[--j] = (byte) ALPHABET[mod]; - } - - // Strip extra '1' if there are some after decoding. - while (j < temp.length && temp[j] == ALPHABET[0]) { - ++j; - } - // Add as much leading '1' as there were leading zeros. - while (--zeroCount >= 0) { - temp[--j] = (byte) ALPHABET[0]; - } - - byte[] output = copyOfRange(temp, j, temp.length); - return new String(output, StandardCharsets.US_ASCII); - } - - public static byte[] decode(String input) throws IllegalArgumentException { - if (input.isEmpty()) { - return new byte[0]; - } - byte[] input58 = new byte[input.length()]; - // Transform the String to a base58 byte sequence - for (int i = 0; i < input.length(); ++i) { - char c = input.charAt(i); - - int digit58 = -1; - if (c < 128) { - digit58 = INDEXES[c]; - } - if (digit58 < 0) { - throw new IllegalArgumentException("Illegal character " + c + " at " + i); - } - - input58[i] = (byte) digit58; - } - // Count leading zeroes - int zeroCount = 0; - while (zeroCount < input58.length && input58[zeroCount] == 0) { - ++zeroCount; - } - // The encoding - byte[] temp = new byte[input.length()]; - int j = temp.length; - - int startAt = zeroCount; - while (startAt < input58.length) { - byte mod = divmod256(input58, startAt); - if (input58[startAt] == 0) { - ++startAt; - } - - temp[--j] = mod; - } - // Do no add extra leading zeroes, move j to first non-null byte. - while (j < temp.length && temp[j] == 0) { - ++j; - } - - return copyOfRange(temp, j - zeroCount, temp.length); - } - - public static BigInteger decodeToBigInteger(String input) throws IllegalArgumentException { - return new BigInteger(1, decode(input)); - } - - // - // number -> number / 58, returns number % 58 - // - private static byte divmod58(byte[] number, int startAt) { - int remainder = 0; - for (int i = startAt; i < number.length; i++) { - int digit256 = (int) number[i] & 0xFF; - int temp = remainder * 256 + digit256; - - number[i] = (byte) (temp / 58); - - remainder = temp % 58; - } - - return (byte) remainder; - } - - // - // number -> number / 256, returns number % 256 - // - private static byte divmod256(byte[] number58, int startAt) { - int remainder = 0; - for (int i = startAt; i < number58.length; i++) { - int digit58 = (int) number58[i] & 0xFF; - int temp = remainder * 58 + digit58; - - number58[i] = (byte) (temp / 256); - - remainder = temp % 256; - } - - return (byte) remainder; - } - - private static byte[] copyOfRange(byte[] source, int from, int to) { - byte[] range = new byte[to - from]; - System.arraycopy(source, from, range, 0, range.length); - - return range; - } - -} diff --git a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgUuid.java b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgUuid.java index fd83fef20a..0933837a13 100644 --- a/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgUuid.java +++ b/hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/util/HgUuid.java @@ -20,13 +20,15 @@ import java.nio.ByteBuffer; import java.util.UUID; +import org.apache.hugegraph.store.util.Base58Encoder; + public final class HgUuid { private static String encode(UUID uuid) { ByteBuffer bb = ByteBuffer.wrap(new byte[16]); bb.putLong(uuid.getMostSignificantBits()); bb.putLong(uuid.getLeastSignificantBits()); - return Base58.encode(bb.array()); + return Base58Encoder.convertToBase58(bb.array()); } /** 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 index b2b09291bf..4601468361 100644 --- 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 @@ -23,11 +23,12 @@ public class HgPair implements Serializable { /** - * Key of this Pair. + * This is the key associated with this Pair. */ private K key; + /** - * Value of this Pair. + * This is the value associated with this Pair. */ private V value; @@ -36,10 +37,10 @@ public HgPair() { } /** - * Creates a new pair + * Initializes a new pair with the specified key and value. * - * @param key The key for this pair - * @param value The value to use for this pair + * @param key The key to be associated with this pair + * @param value The value to be associated with this pair */ public HgPair(K key, V value) { this.key = key; @@ -47,9 +48,9 @@ public HgPair(K key, V value) { } /** - * Gets the key for this pair. + * Retrieves the key associated with this pair. * - * @return key for this pair + * @return the key of this pair */ public K getKey() { return key; @@ -60,9 +61,9 @@ public void setKey(K key) { } /** - * Gets the value for this pair. + * Retrieves the value associated with this pair. * - * @return value for this pair + * @return the value of this pair */ public V getValue() { return value; @@ -73,12 +74,11 @@ public void setValue(V value) { } /** - *

String representation of this - * Pair.

+ * Provides a String representation of this Pair. * - *

The default name/value delimiter '=' is always used.

+ *

The default delimiter between name and value is '='.

* - * @return String representation of this Pair + * @return a String representation of this Pair */ @Override public String toString() { @@ -86,38 +86,33 @@ public String toString() { } /** - *

Generate a hash code for this Pair.

+ * Generates a hash code for this Pair. * - *

The hash code is calculated using both the name and + *

The hash code is computed using both the key and * the value of the Pair.

* - * @return hash code for this Pair + * @return the 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 + // The hashCode of the key is multiplied by a prime number (13) + // to ensure uniqueness between different key-value combinations: + // key: a value: aa + // key: aa value: a return key.hashCode() * 13 + (value == null ? 0 : value.hashCode()); } /** - *

Test this Pair for equality with another - * Object.

+ * Checks if this Pair is equal to another Object. * - *

If the Object to be tested is not a - * Pair or is null, then this method - * returns false.

+ *

This method returns false if the tested + * Object is not a Pair or is null.

* - *

Two Pairs are considered equal if and only if - * both the names and values are equal.

+ *

Two Pairs are equal if their keys and values are both 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 + * @param o the Object to compare with this Pair + * @return true if the specified Object is + * equal to this Pair, otherwise false */ @Override public boolean equals(Object o) { @@ -125,11 +120,8 @@ public boolean equals(Object 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); + HgPair pair = (HgPair) o; + return Objects.equals(key, pair.key) && Objects.equals(value, pair.value); } return false; } diff --git a/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/util/Base58Encoder.java b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/util/Base58Encoder.java new file mode 100644 index 0000000000..617f6dd28f --- /dev/null +++ b/hugegraph-store/hg-store-common/src/main/java/org/apache/hugegraph/store/util/Base58Encoder.java @@ -0,0 +1,165 @@ +/* + * 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.util; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public class Base58Encoder { + + public static final char[] CHAR_SET = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); + private static final int[] CHAR_INDEXES = new int[128]; + + static { + Arrays.fill(CHAR_INDEXES, -1); + for (int i = 0; i < CHAR_SET.length; i++) { + CHAR_INDEXES[CHAR_SET[i]] = i; + } + } + + /** + * Converts the input bytes to a Base58 encoded string without checksum. + */ + public static String convertToBase58(byte[] byteArray) { + if (byteArray.length == 0) { + return ""; + } + byteArray = getSubArray(byteArray, 0, byteArray.length); + // Count leading zeros. + int leadingZeroCount = 0; + while (leadingZeroCount < byteArray.length && byteArray[leadingZeroCount] == 0) { + ++leadingZeroCount; + } + // Actual encoding process. + byte[] intermediate = new byte[byteArray.length * 2]; + int index = intermediate.length; + + int position = leadingZeroCount; + while (position < byteArray.length) { + byte remainder = divideAndModulo58(byteArray, position); + if (byteArray[position] == 0) { + ++position; + } + intermediate[--index] = (byte) CHAR_SET[remainder]; + } + + // Remove extra leading '1's. + while (index < intermediate.length && intermediate[index] == CHAR_SET[0]) { + ++index; + } + // Add leading '1's based on the count of leading zeros. + while (--leadingZeroCount >= 0) { + intermediate[--index] = (byte) CHAR_SET[0]; + } + + byte[] result = getSubArray(intermediate, index, intermediate.length); + return new String(result, StandardCharsets.US_ASCII); + } + + public static byte[] convertFromBase58(String encodedStr) throws IllegalArgumentException { + if (encodedStr.isEmpty()) { + return new byte[0]; + } + byte[] encodedBytes = new byte[encodedStr.length()]; + // Transform the string into a byte array based on Base58 + for (int i = 0; i < encodedStr.length(); ++i) { + char character = encodedStr.charAt(i); + + int value58 = -1; + if (character < 128) { + value58 = CHAR_INDEXES[character]; + } + if (value58 < 0) { + throw new IllegalArgumentException("Invalid character " + character + " at " + i); + } + + encodedBytes[i] = (byte) value58; + } + // Count leading zeros + int leadingZeroCount = 0; + while (leadingZeroCount < encodedBytes.length && encodedBytes[leadingZeroCount] == 0) { + ++leadingZeroCount; + } + // Decoding process + byte[] intermediate = new byte[encodedStr.length()]; + int index = intermediate.length; + + int position = leadingZeroCount; + while (position < encodedBytes.length) { + byte remainder = divideAndModulo256(encodedBytes, position); + if (encodedBytes[position] == 0) { + ++position; + } + + intermediate[--index] = remainder; + } + // Avoid adding extra leading zeros, adjust index to first non-zero byte. + while (index < intermediate.length && intermediate[index] == 0) { + ++index; + } + + return getSubArray(intermediate, index - leadingZeroCount, intermediate.length); + } + + public static BigInteger convertToBigInt(String encodedStr) throws IllegalArgumentException { + return new BigInteger(1, convertFromBase58(encodedStr)); + } + + // + // number -> number / 58, returns number % 58 + // + private static byte divideAndModulo58(byte[] number, int startIndex) { + int remainder = 0; + for (int i = startIndex; i < number.length; i++) { + int byteValue = (int) number[i] & 0xFF; + int temp = remainder * 256 + byteValue; + + number[i] = (byte) (temp / 58); + + remainder = temp % 58; + } + + return (byte) remainder; + } + + // + // number -> number / 256, returns number % 256 + // + private static byte divideAndModulo256(byte[] number58, int startIndex) { + int remainder = 0; + for (int i = startIndex; i < number58.length; i++) { + int byteValue58 = (int) number58[i] & 0xFF; + int temp = remainder * 58 + byteValue58; + + number58[i] = (byte) (temp / 256); + + remainder = temp % 256; + } + + return (byte) remainder; + } + + private static byte[] getSubArray(byte[] sourceArray, int start, int end) { + byte[] resultArray = new byte[end - start]; + System.arraycopy(sourceArray, start, resultArray, 0, resultArray.length); + + return resultArray; + } +} diff --git a/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/CopyOnWriteCache.java b/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/CopyOnWriteCache.java index e20e5fb3fa..59dd7c2d82 100644 --- a/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/CopyOnWriteCache.java +++ b/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/CopyOnWriteCache.java @@ -29,66 +29,142 @@ import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.jetbrains.annotations.NotNull; + public class CopyOnWriteCache implements ConcurrentMap { - ScheduledExecutorService scheduledExecutor; + // Scheduled executor service for periodically clearing the cache. + private ScheduledExecutorService scheduledExecutor; + + // The underlying map used to store key-value pairs in this cache. private volatile Map map; + /** + * Constructs a new CopyOnWriteCache with a specified effective time. + * + * @param effectiveTime The time interval in milliseconds after which the cache will be cleared. + */ public CopyOnWriteCache(long effectiveTime) { + // Initialize the map as an empty map at the beginning. this.map = Collections.emptyMap(); + // Create a single-threaded scheduled executor to manage cache clearing. scheduledExecutor = Executors.newScheduledThreadPool(1); - scheduledExecutor.scheduleWithFixedDelay(this::clear, effectiveTime, effectiveTime, - TimeUnit.MILLISECONDS); + // Schedule the clear task to run at fixed intervals defined by effectiveTime. + scheduledExecutor.scheduleWithFixedDelay( + this::clear, effectiveTime, effectiveTime, TimeUnit.MILLISECONDS); } + /** + * Checks if the specified key is present in the cache. + * + * @param k The key to check for existence. + * @return true if the key is found in the cache; otherwise, false. + */ @Override public boolean containsKey(Object k) { return map.containsKey(k); } + /** + * Checks if the specified value is present in the cache. + * + * @param v The value to check for existence. + * @return true if the value is found in the cache; otherwise, false. + */ @Override public boolean containsValue(Object v) { return map.containsValue(v); } + /** + * Returns a set view of the mappings contained in this cache. + * + * @return a set of entries representing the key-value pairs in the cache. + */ @NotNull @Override public Set> entrySet() { return map.entrySet(); } + /** + * Retrieves the value associated with the specified key. + * + * @param k The key whose associated value is to be returned. + * @return the value associated with the key, or null if the key is not found. + */ @Override public V get(Object k) { return map.get(k); } + /** + * Checks if the cache is empty. + * + * @return true if the cache contains no key-value mappings; otherwise, false. + */ @Override public boolean isEmpty() { return map.isEmpty(); } + /** + * Returns a set view of the keys contained in this cache. + * + * @return a set of keys present in the cache. + */ @NotNull @Override public Set keySet() { return map.keySet(); } + /** + * Returns the number of key-value pairs in the cache. + * + * @return the size of the cache. + */ @Override public int size() { return map.size(); } + /** + * Returns a collection view of the values contained in this cache. + * + * @return a collection of values present in the cache. + */ @NotNull @Override public Collection values() { return map.values(); } + /** + * Clears all entries from the cache, resetting it to an empty state. + */ @Override public synchronized void clear() { this.map = Collections.emptyMap(); } + /** + * Associates the specified value with the specified key in the cache. + * If the key already exists, the previous value is replaced. + * + * @param k The key with which the specified value is to be associated. + * @param v The value to be associated with the specified key. + * @return the previous value associated with the key, or null if there was no mapping for the key. + */ @Override public synchronized V put(K k, V v) { Map copy = new HashMap<>(this.map); @@ -97,6 +173,11 @@ public synchronized V put(K k, V v) { return prev; } + /** + * Copies all of the mappings from the specified map to this cache. + * + * @param entries The map whose mappings are to be copied. + */ @Override public synchronized void putAll(@NotNull Map entries) { Map copy = new HashMap<>(this.map); @@ -104,6 +185,12 @@ public synchronized void putAll(@NotNull Map entries) this.map = Collections.unmodifiableMap(copy); } + /** + * Removes the mapping for the specified key from this cache if present. + * + * @param key The key whose mapping is to be removed from the cache. + * @return the previous value associated with the key, or null if there was no mapping for the key. + */ @Override public synchronized V remove(Object key) { Map copy = new HashMap<>(this.map); @@ -112,6 +199,14 @@ public synchronized V remove(Object key) { return prev; } + /** + * If the specified key is not already associated with a value, associates it with the given value. + * Otherwise, returns the current value associated with the key. + * + * @param k The key with which the specified value is to be associated. + * @param v The value to be associated with the specified key. + * @return the previous value associated with the key, or null if there was no mapping for the key. + */ @Override public synchronized V putIfAbsent(K k, V v) { if (!containsKey(k)) { @@ -121,6 +216,13 @@ public synchronized V putIfAbsent(K k, V v) { } } + /** + * Removes the entry for the specified key only if it is currently mapped to the specified value. + * + * @param k The key whose mapping is to be removed. + * @param v The value expected to be associated with the key. + * @return true if the mapping was removed; otherwise, false. + */ @Override public synchronized boolean remove(Object k, Object v) { if (containsKey(k) && get(k).equals(v)) { @@ -131,6 +233,14 @@ public synchronized boolean remove(Object k, Object v) { } } + /** + * Replaces the entry for the specified key only if it is currently mapped to the specified original value. + * + * @param k The key whose mapping is to be replaced. + * @param original The expected value to be associated with the key. + * @param replacement The value to be associated with the key if the original value is present. + * @return true if the mapping was replaced; otherwise, false. + */ @Override public synchronized boolean replace(@NotNull K k, @NotNull V original, @NotNull V replacement) { if (containsKey(k) && get(k).equals(original)) { @@ -141,6 +251,13 @@ public synchronized boolean replace(@NotNull K k, @NotNull V original, @NotNull } } + /** + * Replaces the entry for the specified key with the given value. + * + * @param k The key whose mapping is to be replaced. + * @param v The new value to be associated with the key. + * @return the previous value associated with the key, or null if there was no mapping for the key. + */ @Override public synchronized V replace(K k, V v) { if (containsKey(k)) { @@ -149,5 +266,4 @@ public synchronized V replace(K k, V v) { return null; } } - } diff --git a/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/UnsafeUtil.java b/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/UnsafeUtil.java index fd2c450388..f25569db99 100644 --- a/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/UnsafeUtil.java +++ b/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/util/UnsafeUtil.java @@ -25,314 +25,692 @@ @Slf4j public class UnsafeUtil { + // Static field holding an instance of Unsafe, initialized via getUnsafe0() method private static final Object UNSAFE = getUnsafe0(); + + // Static field for accessing Unsafe methods through the UnsafeAccessor class private static final UnsafeAccessor UNSAFE_ACCESSOR = getUnsafeAccessor0(); + // Offsets used for direct access to specific array and string fields private static final long BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(byte[].class); private static final long STRING_VALUE_OFFSET = objectFieldOffset(stringValueField()); + /** + * Checks if the Unsafe class is available for use. + * + * @return true if Unsafe is available, false otherwise. + */ public static boolean hasUnsafe() { return UNSAFE != null; } + /** + * Attempts to obtain an instance of sun.misc.Unsafe. + * + * @return the Unsafe instance, or null if not available. + */ public static Object getUnsafe0() { Object unsafe; try { + // Accessing the Unsafe class and its singleton instance final Class unsafeClass = Class.forName("sun.misc.Unsafe"); final Field unsafeField = unsafeClass.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - unsafe = unsafeField.get(null); + unsafeField.setAccessible(true); // Bypass access checks + unsafe = unsafeField.get(null); // Get the Unsafe instance } catch (final Throwable t) { + // Log a warning if Unsafe is not available if (log.isWarnEnabled()) { log.warn("sun.misc.Unsafe.theUnsafe: unavailable.", t); } unsafe = null; } - return unsafe; + return unsafe; // Return the Unsafe instance or null } + /** + * Writes a byte value to a specified index in a byte array. + * + * @param target the target byte array. + * @param index the index to write to. + * @param value the byte value to write. + */ public static void putByte(final byte[] target, final long index, final byte value) { - assert UNSAFE_ACCESSOR != null; - UNSAFE_ACCESSOR.putByte(target, BYTE_ARRAY_BASE_OFFSET + index, value); + assert UNSAFE_ACCESSOR != null; // Ensure UnsafeAccessor is available + UNSAFE_ACCESSOR.putByte(target, BYTE_ARRAY_BASE_OFFSET + index, value); // Write the byte } + /** + * Reads a byte value from a specified index in a byte array. + * + * @param target the target byte array. + * @param index the index to read from. + * @return the byte value at the specified index. + */ public static byte getByte(final byte[] target, final long index) { - assert UNSAFE_ACCESSOR != null; - return UNSAFE_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index); + assert UNSAFE_ACCESSOR != null; // Ensure UnsafeAccessor is available + return UNSAFE_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index); // Read the byte } + /** + * Returns the base offset of the specified array class. + * + * @param clazz the class of the array. + * @return the base offset of the array, or -1 if Unsafe is not available. + */ public static int arrayBaseOffset(final Class clazz) { if (hasUnsafe()) { - assert UNSAFE_ACCESSOR != null; - return UNSAFE_ACCESSOR.arrayBaseOffset(clazz); + assert UNSAFE_ACCESSOR != null; // Ensure UnsafeAccessor is available + return UNSAFE_ACCESSOR.arrayBaseOffset(clazz); // Get the array base offset } else { - return -1; + return -1; // Return -1 if Unsafe is not available } } + /** + * Creates a String instance from a character array without copying the characters. + * + * @param chars the character array. + * @return the String created from the character array. + */ public static String moveToString(final char[] chars) { if (STRING_VALUE_OFFSET == -1) { - // In the off-chance that this JDK does not implement String as we'd expect, just do - // a copy. + // If STRING_VALUE_OFFSET is invalid, create a String by copying characters return new String(chars); } final String str; try { - assert UNSAFE_ACCESSOR != null; + assert UNSAFE_ACCESSOR != null; // Ensure UnsafeAccessor is available + // Allocate an instance of String without calling its constructor str = (String) UNSAFE_ACCESSOR.allocateInstance(String.class); } catch (final InstantiationException e) { - // This should never happen, but return a copy as a fallback just in case. + // Fallback to creating a String by copying characters if allocation fails return new String(chars); } + // Directly set the value field of the String to the character array UNSAFE_ACCESSOR.putObject(str, STRING_VALUE_OFFSET, chars); - return str; + return str; // Return the created String } + /** + * Returns the offset of a given field in an object. + * + * @param field the field to get the offset for. + * @return the offset of the field, or -1 if Unsafe is not available. + */ public static long objectFieldOffset(final Field field) { if (field == null || hasUnsafe()) { - assert UNSAFE_ACCESSOR != null; - return UNSAFE_ACCESSOR.objectFieldOffset(field); + assert UNSAFE_ACCESSOR != null; // Ensure UnsafeAccessor is available + return UNSAFE_ACCESSOR.objectFieldOffset(field); // Get the field offset } else { - return -1; + return -1; // Return -1 if Unsafe is not available } } + /** + * Retrieves the Field object for the "value" field of the String class. + * + * @return the Field representing the value field in String. + */ private static Field stringValueField() { - return field(String.class, "value", char[].class); + return field(String.class, "value", char[].class); // Get the field for the character array } + /** + * Gets a declared field from a class by name and checks its type. + * + * @param clazz the class to search in. + * @param fieldName the name of the field to retrieve. + * @param expectedType the expected type of the field. + * @return the Field object if found and type matches, otherwise null. + */ private static Field field(final Class clazz, final String fieldName, - final Class expectedType) { + final Class expectedType) { Field field; try { - field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); + field = clazz.getDeclaredField(fieldName); // Get the declared field + field.setAccessible(true); // Bypass access checks if (!field.getType().equals(expectedType)) { - return null; + return null; // Return null if type does not match } } catch (final Throwable t) { - // Failed to access the fields. + // Failed to access the field; return null field = null; } - return field; + return field; // Return the Field object or null } + /** + * Initializes the UnsafeAccessor if Unsafe is available. + * + * @return an UnsafeAccessor instance if Unsafe is available, null otherwise. + */ private static UnsafeAccessor getUnsafeAccessor0() { - return hasUnsafe() ? new UnsafeAccessor(UNSAFE) : null; + return hasUnsafe() ? new UnsafeAccessor(UNSAFE) : null; // Return UnsafeAccessor } @Getter public static class UnsafeAccessor { /** - * -- GETTER -- - * Returns the instance. + * An instance of {@link sun.misc.Unsafe}, which provides low-level, unsafe operations + * that are generally not available in standard Java. */ private final sun.misc.Unsafe unsafe; + /** + * Constructs an instance of {@link UnsafeAccessor} with the specified Unsafe object. + * + * @param unsafe the Unsafe instance to be used for accessing low-level operations. + */ public UnsafeAccessor(Object unsafe) { this.unsafe = (sun.misc.Unsafe) unsafe; } + /** + * Retrieves a byte value from the specified object at the given memory offset. + * + * @param target the object from which to read the byte value. + * @param offset the memory offset from which to read the byte value. + * @return the byte value at the specified offset in the target object. + */ public byte getByte(final Object target, final long offset) { return this.unsafe.getByte(target, offset); } + /** + * Writes a byte value to the specified object at the given memory offset. + * + * @param target the object to which to write the byte value. + * @param offset the memory offset at which to write the byte value. + * @param value the byte value to be written to the target object. + */ public void putByte(final Object target, final long offset, final byte value) { this.unsafe.putByte(target, offset, value); } + /** + * Retrieves a short value from the specified object at the given memory offset. + * + * @param target the object from which to read the short value. + * @param offset the memory offset from which to read the short value. + * @return the short value at the specified offset in the target object. + */ public short getShort(final Object target, final long offset) { return this.unsafe.getShort(target, offset); } + /** + * Writes a short value to the specified object at the given memory offset. + * + * @param target the object to which to write the short value. + * @param offset the memory offset at which to write the short value. + * @param value the short value to be written to the target object. + */ public void putShort(final Object target, final long offset, final short value) { this.unsafe.putShort(target, offset, value); } + /** + * Retrieves an integer value from the specified object at the given memory offset. + * + * @param target the object from which to read the integer value. + * @param offset the memory offset from which to read the integer value. + * @return the integer value at the specified offset in the target object. + */ public int getInt(final Object target, final long offset) { return this.unsafe.getInt(target, offset); } + /** + * Writes an integer value to the specified object at the given memory offset. + * + * @param target the object to which to write the integer value. + * @param offset the memory offset at which to write the integer value. + * @param value the integer value to be written to the target object. + */ public void putInt(final Object target, final long offset, final int value) { this.unsafe.putInt(target, offset, value); } + /** + * Retrieves a long value from the specified object at the given memory offset. + * + * @param target the object from which to read the long value. + * @param offset the memory offset from which to read the long value. + * @return the long value at the specified offset in the target object. + */ public long getLong(final Object target, final long offset) { return this.unsafe.getLong(target, offset); } + /** + * Writes a long value to the specified object at the given memory offset. + * + * @param target the object to which to write the long value. + * @param offset the memory offset at which to write the long value. + * @param value the long value to be written to the target object. + */ public void putLong(final Object target, final long offset, final long value) { this.unsafe.putLong(target, offset, value); } + /** + * Retrieves a boolean value from the specified object at the given memory offset. + * + * @param target the object from which to read the boolean value. + * @param offset the memory offset from which to read the boolean value. + * @return the boolean value at the specified offset in the target object. + */ public boolean getBoolean(final Object target, final long offset) { return this.unsafe.getBoolean(target, offset); } + /** + * Writes a boolean value to the specified object at the given memory offset. + * + * @param target the object to which to write the boolean value. + * @param offset the memory offset at which to write the boolean value. + * @param value the boolean value to be written to the target object. + */ public void putBoolean(final Object target, final long offset, final boolean value) { this.unsafe.putBoolean(target, offset, value); } + /** + * Retrieves a float value from the specified object at the given memory offset. + * + * @param target the object from which to read the float value. + * @param offset the memory offset from which to read the float value. + * @return the float value at the specified offset in the target object. + */ public float getFloat(final Object target, final long offset) { return this.unsafe.getFloat(target, offset); } + /** + * Writes a float value to the specified object at the given memory offset. + * + * @param target the object to which to write the float value. + * @param offset the memory offset at which to write the float value. + * @param value the float value to be written to the target object. + */ public void putFloat(final Object target, final long offset, final float value) { this.unsafe.putFloat(target, offset, value); } + /** + * Retrieves a double value from the specified object at the given memory offset. + * + * @param target the object from which to read the double value. + * @param offset the memory offset from which to read the double value. + * @return the double value at the specified offset in the target object. + */ public double getDouble(final Object target, final long offset) { return this.unsafe.getDouble(target, offset); } + /** + * Writes a double value to the specified object at the given memory offset. + * + * @param target the object to which to write the double value. + * @param offset the memory offset at which to write the double value. + * @param value the double value to be written to the target object. + */ public void putDouble(final Object target, final long offset, final double value) { this.unsafe.putDouble(target, offset, value); } + /** + * Retrieves an object reference from the specified object at the given memory offset. + * + * @param target the object from which to read the object reference. + * @param offset the memory offset from which to read the object reference. + * @return the object reference at the specified offset in the target object. + */ public Object getObject(final Object target, final long offset) { return this.unsafe.getObject(target, offset); } + /** + * Writes an object reference to the specified object at the given memory offset. + * + * @param target the object to which to write the object reference. + * @param offset the memory offset at which to write the object reference. + * @param value the object reference to be written to the target object. + */ public void putObject(final Object target, final long offset, final Object value) { this.unsafe.putObject(target, offset, value); } + /** + * Retrieves a byte value from a specific memory address. + * + * @param address the memory address from which to read the byte value. + * @return the byte value at the specified memory address. + */ public byte getByte(final long address) { return this.unsafe.getByte(address); } + /** + * Writes a byte value to a specific memory address. + * + * @param address the memory address at which to write the byte value. + * @param value the byte value to be written to the specified memory address. + */ public void putByte(final long address, final byte value) { this.unsafe.putByte(address, value); } + /** + * Retrieves a short value from a specific memory address. + * + * @param address the memory address from which to read the short value. + * @return the short value at the specified memory address. + */ public short getShort(final long address) { return this.unsafe.getShort(address); } + /** + * Writes a short value to a specific memory address. + * + * @param address the memory address at which to write the short value. + * @param value the short value to be written to the specified memory address. + */ public void putShort(final long address, final short value) { this.unsafe.putShort(address, value); } + /** + * Retrieves an integer value from a specific memory address. + * + * @param address the memory address from which to read the integer value. + * @return the integer value at the specified memory address. + */ public int getInt(final long address) { return this.unsafe.getInt(address); } + /** + * Writes an integer value to a specific memory address. + * + * @param address the memory address at which to write the integer value. + * @param value the integer value to be written to the specified memory address. + */ public void putInt(final long address, final int value) { this.unsafe.putInt(address, value); } + /** + * Retrieves a long value from a specific memory address. + * + * @param address the memory address from which to read the long value. + * @return the long value at the specified memory address. + */ public long getLong(final long address) { return this.unsafe.getLong(address); } + /** + * Writes a long value to a specific memory address. + * + * @param address the memory address at which to write the long value. + * @param value the long value to be written to the specified memory address. + */ public void putLong(final long address, final long value) { this.unsafe.putLong(address, value); } + /** + * Copies a block of memory from one location to another. + * + * @param srcBase the source object from which to copy memory. + * @param srcOffset the offset in the source object from which to start copying. + * @param dstBase the destination object to which to copy memory. + * @param dstOffset the offset in the destination object at which to start writing. + * @param bytes the number of bytes to copy. + */ public void copyMemory(final Object srcBase, final long srcOffset, final Object dstBase, - final long dstOffset, - final long bytes) { + final long dstOffset, + final long bytes) { this.unsafe.copyMemory(srcBase, srcOffset, dstBase, dstOffset, bytes); } + /** + * Copies a block of memory from one address to another. + * + * @param srcAddress the source memory address from which to copy. + * @param dstAddress the destination memory address to which to copy. + * @param bytes the number of bytes to copy. + */ public void copyMemory(final long srcAddress, final long dstAddress, final long bytes) { this.unsafe.copyMemory(srcAddress, dstAddress, bytes); } + /** + * Retrieves a volatile byte value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile byte value. + * @param offset the memory offset from which to read the volatile byte value. + * @return the volatile byte value at the specified offset in the target object. + */ public byte getByteVolatile(final Object target, final long offset) { return this.unsafe.getByteVolatile(target, offset); } + /** + * Writes a volatile byte value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile byte value. + * @param offset the memory offset at which to write the volatile byte value. + * @param value the volatile byte value to be written to the target object. + */ public void putByteVolatile(final Object target, final long offset, final byte value) { this.unsafe.putByteVolatile(target, offset, value); } + /** + * Retrieves a volatile short value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile short value. + * @param offset the memory offset from which to read the volatile short value. + * @return the volatile short value at the specified offset in the target object. + */ public short getShortVolatile(final Object target, final long offset) { return this.unsafe.getShortVolatile(target, offset); } + /** + * Writes a volatile short value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile short value. + * @param offset the memory offset at which to write the volatile short value. + * @param value the volatile short value to be written to the target object. + */ public void putShortVolatile(final Object target, final long offset, final short value) { this.unsafe.putShortVolatile(target, offset, value); } + /** + * Retrieves a volatile integer value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile integer value. + * @param offset the memory offset from which to read the volatile integer value. + * @return the volatile integer value at the specified offset in the target object. + */ public int getIntVolatile(final Object target, final long offset) { return this.unsafe.getIntVolatile(target, offset); } + /** + * Writes a volatile integer value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile integer value. + * @param offset the memory offset at which to write the volatile integer value. + * @param value the volatile integer value to be written to the target object. + */ public void putIntVolatile(final Object target, final long offset, final int value) { this.unsafe.putIntVolatile(target, offset, value); } + /** + * Retrieves a volatile long value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile long value. + * @param offset the memory offset from which to read the volatile long value. + * @return the volatile long value at the specified offset in the target object. + */ public long getLongVolatile(final Object target, final long offset) { return this.unsafe.getLongVolatile(target, offset); } + /** + * Writes a volatile long value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile long value. + * @param offset the memory offset at which to write the volatile long value. + * @param value the volatile long value to be written to the target object. + */ public void putLongVolatile(final Object target, final long offset, final long value) { this.unsafe.putLongVolatile(target, offset, value); } + /** + * Retrieves a volatile boolean value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile boolean value. + * @param offset the memory offset from which to read the volatile boolean value. + * @return the volatile boolean value at the specified offset in the target object. + */ public boolean getBooleanVolatile(final Object target, final long offset) { return this.unsafe.getBooleanVolatile(target, offset); } + /** + * Writes a volatile boolean value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile boolean value. + * @param offset the memory offset at which to write the volatile boolean value. + * @param value the volatile boolean value to be written to the target object. + */ public void putBooleanVolatile(final Object target, final long offset, - final boolean value) { + final boolean value) { this.unsafe.putBooleanVolatile(target, offset, value); } + /** + * Retrieves a volatile float value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile float value. + * @param offset the memory offset from which to read the volatile float value. + * @return the volatile float value at the specified offset in the target object. + */ public float getFloatVolatile(final Object target, final long offset) { return this.unsafe.getFloatVolatile(target, offset); } + /** + * Writes a volatile float value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile float value. + * @param offset the memory offset at which to write the volatile float value. + * @param value the volatile float value to be written to the target object. + */ public void putFloatVolatile(final Object target, final long offset, final float value) { this.unsafe.putFloatVolatile(target, offset, value); } + /** + * Retrieves a volatile double value from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile double value. + * @param offset the memory offset from which to read the volatile double value. + * @return the volatile double value at the specified offset in the target object. + */ public double getDoubleVolatile(final Object target, final long offset) { return this.unsafe.getDoubleVolatile(target, offset); } + /** + * Writes a volatile double value to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile double value. + * @param offset the memory offset at which to write the volatile double value. + * @param value the volatile double value to be written to the target object. + */ public void putDoubleVolatile(final Object target, final long offset, final double value) { this.unsafe.putDoubleVolatile(target, offset, value); } + /** + * Retrieves a volatile object reference from the specified object at the given memory offset. + * + * @param target the object from which to read the volatile object reference. + * @param offset the memory offset from which to read the volatile object reference. + * @return the volatile object reference at the specified offset in the target object. + */ public Object getObjectVolatile(final Object target, final long offset) { return this.unsafe.getObjectVolatile(target, offset); } + /** + * Writes a volatile object reference to the specified object at the given memory offset. + * + * @param target the object to which to write the volatile object reference. + * @param offset the memory offset at which to write the volatile object reference. + * @param value the volatile object reference to be written to the target object. + */ public void putObjectVolatile(final Object target, final long offset, final Object value) { this.unsafe.putObjectVolatile(target, offset, value); } /** - * Reports the offset of the first element in the storage allocation of a - * given array class. + * Reports the offset of the first element in the storage allocation of a given array class. + * + * @param clazz the class of the array for which to report the base offset. + * @return the offset of the first element in the storage allocation of the given array class. */ public int arrayBaseOffset(final Class clazz) { return this.unsafe != null ? this.unsafe.arrayBaseOffset(clazz) : -1; } /** - * Reports the scale factor for addressing elements in the storage - * allocation of a given array class. + * Reports the scale factor for addressing elements in the storage allocation of a given array class. + * + * @param clazz the class of the array for which to report the index scale. + * @return the scale factor for addressing elements in the storage allocation of the given array class. */ public int arrayIndexScale(final Class clazz) { return this.unsafe != null ? this.unsafe.arrayIndexScale(clazz) : -1; } /** - * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not - * available. + * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not available. + * + * @param field the field for which to get the offset. + * @return the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not available. */ public long objectFieldOffset(final Field field) { return field == null || this.unsafe == null ? -1 : this.unsafe.objectFieldOffset(field); } + /** + * Allocates a new instance of the specified class without invoking any constructor. + * + * @param clazz the class for which to allocate an instance. + * @return a new instance of the specified class. + * @throws InstantiationException if the allocation fails. + */ public Object allocateInstance(final Class clazz) throws InstantiationException { return this.unsafe.allocateInstance(clazz); } + /** + * Throws the specified throwable as an exception. + * + * @param t the throwable to be thrown as an exception. + */ public void throwException(final Throwable t) { this.unsafe.throwException(t); } diff --git a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/grpc/ScanBatchResponse3.java b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/grpc/ScanBatchResponse3.java index fac1c35820..2369dffd95 100644 --- a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/grpc/ScanBatchResponse3.java +++ b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/grpc/ScanBatchResponse3.java @@ -34,7 +34,7 @@ import org.apache.hugegraph.store.grpc.stream.ScanCondition; import org.apache.hugegraph.store.grpc.stream.ScanQueryRequest; import org.apache.hugegraph.store.grpc.stream.ScanStreamBatchReq; -import org.apache.hugegraph.store.node.util.Base58; +import org.apache.hugegraph.store.util.Base58Encoder; import org.apache.hugegraph.store.node.util.HgAssert; import org.apache.hugegraph.store.node.util.HgGrpc; import org.apache.hugegraph.store.node.util.HgStoreConst; @@ -133,7 +133,7 @@ private void makeADeal(ScanQueryRequest request) { if (conditions.size() > 0) { ScanCondition c = conditions.get(0); if (c.getPrefix() != null && c.getPrefix().size() > 0) { - deliverId = Base58.encode(c.getPrefix().toByteArray()); + deliverId = Base58Encoder.convertToBase58(c.getPrefix().toByteArray()); log.info("[ANALYSIS DEAL] [{}] prefixLength: {}", deliverId, conditions.size()); } diff --git a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java index 84f93a5629..c22b36ad3c 100644 --- a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java +++ b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/RocksDBMetricsConst.java @@ -20,144 +20,160 @@ import org.rocksdb.HistogramType; import org.rocksdb.TickerType; +/** + * Final class containing constants related to RocksDB metrics. + * This class provides constants for metric prefixes, labels, and + * arrays of tickers and histograms for monitoring RocksDB performance. + * Metrics include both counters (tickers) and summaries (histograms). + */ public final class RocksDBMetricsConst { + // Prefix used for all RocksDB statistics. public static final String PREFIX = "rocks.stats"; + + // Labels used for metrics, primarily for quantile information. public static final String LABELS = "quantile"; + + // Specific quantile labels, representing the 50th, 95th, and 99th percentiles. public static final String LABEL_50 = "0.5"; public static final String LABEL_95 = "0.95"; public static final String LABEL_99 = "0.99"; - // Tickers - RocksDB equivalent of counters + /** + * Array of TickerType representing various RocksDB counters. + * Tickers track the number of times a particular event has occurred (e.g., cache hits). + * Useful for monitoring and debugging purposes, giving insights into database performance. + */ public static final TickerType[] TICKERS = { - TickerType.BLOCK_CACHE_ADD, - TickerType.BLOCK_CACHE_HIT, - TickerType.BLOCK_CACHE_ADD_FAILURES, - TickerType.BLOCK_CACHE_INDEX_MISS, - TickerType.BLOCK_CACHE_INDEX_HIT, - TickerType.BLOCK_CACHE_INDEX_ADD, - TickerType.BLOCK_CACHE_INDEX_BYTES_INSERT, - TickerType.BLOCK_CACHE_INDEX_BYTES_EVICT, - TickerType.BLOCK_CACHE_FILTER_MISS, - TickerType.BLOCK_CACHE_FILTER_HIT, - TickerType.BLOCK_CACHE_FILTER_ADD, - TickerType.BLOCK_CACHE_FILTER_BYTES_INSERT, - TickerType.BLOCK_CACHE_FILTER_BYTES_EVICT, - TickerType.BLOCK_CACHE_DATA_MISS, - TickerType.BLOCK_CACHE_DATA_HIT, - TickerType.BLOCK_CACHE_DATA_ADD, - TickerType.BLOCK_CACHE_DATA_BYTES_INSERT, - TickerType.BLOCK_CACHE_BYTES_READ, - TickerType.BLOCK_CACHE_BYTES_WRITE, - TickerType.BLOOM_FILTER_USEFUL, - TickerType.PERSISTENT_CACHE_HIT, - TickerType.PERSISTENT_CACHE_MISS, - TickerType.SIM_BLOCK_CACHE_HIT, - TickerType.SIM_BLOCK_CACHE_MISS, - TickerType.MEMTABLE_HIT, - TickerType.MEMTABLE_MISS, - TickerType.GET_HIT_L0, - TickerType.GET_HIT_L1, - TickerType.GET_HIT_L2_AND_UP, - TickerType.COMPACTION_KEY_DROP_NEWER_ENTRY, - TickerType.COMPACTION_KEY_DROP_OBSOLETE, - TickerType.COMPACTION_KEY_DROP_RANGE_DEL, - TickerType.COMPACTION_KEY_DROP_USER, - TickerType.COMPACTION_RANGE_DEL_DROP_OBSOLETE, - TickerType.NUMBER_KEYS_WRITTEN, - TickerType.NUMBER_KEYS_READ, - TickerType.NUMBER_KEYS_UPDATED, - TickerType.BYTES_WRITTEN, - TickerType.BYTES_READ, - TickerType.NUMBER_DB_SEEK, - TickerType.NUMBER_DB_NEXT, - TickerType.NUMBER_DB_PREV, - TickerType.NUMBER_DB_SEEK_FOUND, - TickerType.NUMBER_DB_NEXT_FOUND, - TickerType.NUMBER_DB_PREV_FOUND, - TickerType.ITER_BYTES_READ, - TickerType.NO_FILE_CLOSES, - TickerType.NO_FILE_OPENS, - TickerType.NO_FILE_ERRORS, - // TickerType.STALL_L0_SLOWDOWN_MICROS, - // TickerType.STALL_MEMTABLE_COMPACTION_MICROS, - // TickerType.STALL_L0_NUM_FILES_MICROS, - TickerType.STALL_MICROS, - TickerType.DB_MUTEX_WAIT_MICROS, - TickerType.RATE_LIMIT_DELAY_MILLIS, - TickerType.NO_ITERATORS, - TickerType.NUMBER_MULTIGET_BYTES_READ, - TickerType.NUMBER_MULTIGET_KEYS_READ, - TickerType.NUMBER_MULTIGET_CALLS, - TickerType.NUMBER_FILTERED_DELETES, - TickerType.NUMBER_MERGE_FAILURES, - TickerType.BLOOM_FILTER_PREFIX_CHECKED, - TickerType.BLOOM_FILTER_PREFIX_USEFUL, - TickerType.NUMBER_OF_RESEEKS_IN_ITERATION, - TickerType.GET_UPDATES_SINCE_CALLS, - TickerType.BLOCK_CACHE_COMPRESSED_MISS, - TickerType.BLOCK_CACHE_COMPRESSED_HIT, - TickerType.BLOCK_CACHE_COMPRESSED_ADD, - TickerType.BLOCK_CACHE_COMPRESSED_ADD_FAILURES, - TickerType.WAL_FILE_SYNCED, - TickerType.WAL_FILE_BYTES, - TickerType.WRITE_DONE_BY_SELF, - TickerType.WRITE_DONE_BY_OTHER, - TickerType.WRITE_TIMEDOUT, - TickerType.WRITE_WITH_WAL, - TickerType.COMPACT_READ_BYTES, - TickerType.COMPACT_WRITE_BYTES, - TickerType.FLUSH_WRITE_BYTES, - TickerType.NUMBER_DIRECT_LOAD_TABLE_PROPERTIES, - TickerType.NUMBER_SUPERVERSION_ACQUIRES, - TickerType.NUMBER_SUPERVERSION_RELEASES, - TickerType.NUMBER_SUPERVERSION_CLEANUPS, - TickerType.NUMBER_BLOCK_COMPRESSED, - TickerType.NUMBER_BLOCK_DECOMPRESSED, - TickerType.NUMBER_BLOCK_NOT_COMPRESSED, - TickerType.MERGE_OPERATION_TOTAL_TIME, - TickerType.FILTER_OPERATION_TOTAL_TIME, - TickerType.ROW_CACHE_HIT, - TickerType.ROW_CACHE_MISS, - TickerType.READ_AMP_ESTIMATE_USEFUL_BYTES, - TickerType.READ_AMP_TOTAL_READ_BYTES, - TickerType.NUMBER_RATE_LIMITER_DRAINS, - TickerType.NUMBER_ITER_SKIP, - TickerType.NUMBER_MULTIGET_KEYS_FOUND, - }; + TickerType.BLOCK_CACHE_ADD, // Number of blocks added to the cache. + TickerType.BLOCK_CACHE_HIT, // Number of cache hits. + TickerType.BLOCK_CACHE_ADD_FAILURES, // Failures in adding blocks to the cache. + TickerType.BLOCK_CACHE_INDEX_MISS, // Index cache misses. + TickerType.BLOCK_CACHE_INDEX_HIT, // Index cache hits. + TickerType.BLOCK_CACHE_INDEX_ADD, // Index blocks added to cache. + TickerType.BLOCK_CACHE_INDEX_BYTES_INSERT, // Bytes inserted into index cache. + TickerType.BLOCK_CACHE_INDEX_BYTES_EVICT, // Bytes evicted from index cache. + TickerType.BLOCK_CACHE_FILTER_MISS, // Filter cache misses. + TickerType.BLOCK_CACHE_FILTER_HIT, // Filter cache hits. + TickerType.BLOCK_CACHE_FILTER_ADD, // Filter blocks added to cache. + TickerType.BLOCK_CACHE_FILTER_BYTES_INSERT, // Bytes inserted in filter cache. + TickerType.BLOCK_CACHE_FILTER_BYTES_EVICT, // Bytes evicted from filter cache. + TickerType.BLOCK_CACHE_DATA_MISS, // Data cache misses. + TickerType.BLOCK_CACHE_DATA_HIT, // Data cache hits. + TickerType.BLOCK_CACHE_DATA_ADD, // Data blocks added to cache. + TickerType.BLOCK_CACHE_DATA_BYTES_INSERT, // Bytes inserted into data cache. + TickerType.BLOCK_CACHE_BYTES_READ, // Bytes read from cache. + TickerType.BLOCK_CACHE_BYTES_WRITE, // Bytes written to cache. + TickerType.BLOOM_FILTER_USEFUL, // Bloom filter passes. + TickerType.PERSISTENT_CACHE_HIT, // Hits in persistent cache. + TickerType.PERSISTENT_CACHE_MISS, // Misses in persistent cache. + TickerType.SIM_BLOCK_CACHE_HIT, // Simulated block cache hits. + TickerType.SIM_BLOCK_CACHE_MISS, // Simulated block cache misses. + TickerType.MEMTABLE_HIT, // Hits in the memtable. + TickerType.MEMTABLE_MISS, // Misses in the memtable. + TickerType.GET_HIT_L0, // Level 0 get hits. + TickerType.GET_HIT_L1, // Level 1 get hits. + TickerType.GET_HIT_L2_AND_UP, // Level 2 and above get hits. + TickerType.COMPACTION_KEY_DROP_NEWER_ENTRY, // Keys dropped due to newer entry during compaction. + TickerType.COMPACTION_KEY_DROP_OBSOLETE, // Obsolete keys dropped during compaction. + TickerType.COMPACTION_KEY_DROP_RANGE_DEL, // Range deletion keys dropped during compaction. + TickerType.COMPACTION_KEY_DROP_USER, // User keys dropped during compaction. + TickerType.COMPACTION_RANGE_DEL_DROP_OBSOLETE, // Obsolete range deletes dropped. + TickerType.NUMBER_KEYS_WRITTEN, // Total keys written. + TickerType.NUMBER_KEYS_READ, // Total keys read. + TickerType.NUMBER_KEYS_UPDATED, // Total keys updated. + TickerType.BYTES_WRITTEN, // Number of bytes written. + TickerType.BYTES_READ, // Number of bytes read. + TickerType.NUMBER_DB_SEEK, // Number of seek operations. + TickerType.NUMBER_DB_NEXT, // Number of next operations. + TickerType.NUMBER_DB_PREV, // Number of previous operations. + TickerType.NUMBER_DB_SEEK_FOUND, // Number of successful seek operations. + TickerType.NUMBER_DB_NEXT_FOUND, // Number of successful next operations. + TickerType.NUMBER_DB_PREV_FOUND, // Number of successful previous operations. + TickerType.ITER_BYTES_READ, // Bytes read by iterators. + TickerType.NO_FILE_CLOSES, // Number of file close operations. + TickerType.NO_FILE_OPENS, // Number of file open operations. + TickerType.NO_FILE_ERRORS, // Number of file errors. + TickerType.STALL_MICROS, // Time spent in a stall micro. + TickerType.DB_MUTEX_WAIT_MICROS, // Time spent waiting on a mutex. + TickerType.RATE_LIMIT_DELAY_MILLIS, // Rate limiting delay in milliseconds. + TickerType.NO_ITERATORS, // Number of iterators created. + TickerType.NUMBER_MULTIGET_BYTES_READ, // Bytes read by multi-get operations. + TickerType.NUMBER_MULTIGET_KEYS_READ, // Keys read in multi-get operations. + TickerType.NUMBER_MULTIGET_CALLS, // Number of multi-get operations. + TickerType.NUMBER_FILTERED_DELETES, // Number of deletes filtered. + TickerType.NUMBER_MERGE_FAILURES, // Number of merge failures. + TickerType.BLOOM_FILTER_PREFIX_CHECKED, // Number of prefix bloom filter checks. + TickerType.BLOOM_FILTER_PREFIX_USEFUL, // Number of useful prefix bloom filter checks. + TickerType.NUMBER_OF_RESEEKS_IN_ITERATION, // Number of reseeks in iteration. + TickerType.GET_UPDATES_SINCE_CALLS, // Number of get updates since calls. + TickerType.BLOCK_CACHE_COMPRESSED_MISS, // Misses in compressed block cache. + TickerType.BLOCK_CACHE_COMPRESSED_HIT, // Hits in compressed block cache. + TickerType.BLOCK_CACHE_COMPRESSED_ADD, // Compressed blocks added to cache. + TickerType.BLOCK_CACHE_COMPRESSED_ADD_FAILURES, // Failures adding compressed blocks. + TickerType.WAL_FILE_SYNCED, // Number of synced WAL files. + TickerType.WAL_FILE_BYTES, // Bytes written to WAL files. + TickerType.WRITE_DONE_BY_SELF, // Writes completed by self. + TickerType.WRITE_DONE_BY_OTHER, // Writes completed by others. + TickerType.WRITE_TIMEDOUT, // Number of write timeouts. + TickerType.WRITE_WITH_WAL, // Writes involving WAL. + TickerType.COMPACT_READ_BYTES, // Bytes read during compaction. + TickerType.COMPACT_WRITE_BYTES, // Bytes written during compaction. + TickerType.FLUSH_WRITE_BYTES, // Bytes written during flush. + TickerType.NUMBER_DIRECT_LOAD_TABLE_PROPERTIES, // Number of direct load table properties. + TickerType.NUMBER_SUPERVERSION_ACQUIRES, // Acquired superversions. + TickerType.NUMBER_SUPERVERSION_RELEASES, // Released superversions. + TickerType.NUMBER_SUPERVERSION_CLEANUPS, // Cleanups of superversions. + TickerType.NUMBER_BLOCK_COMPRESSED, // Number of blocks compressed. + TickerType.NUMBER_BLOCK_DECOMPRESSED, // Number of blocks decompressed. + TickerType.NUMBER_BLOCK_NOT_COMPRESSED, // Number of blocks not compressed. + TickerType.MERGE_OPERATION_TOTAL_TIME, // Time spent in merge operations. + TickerType.FILTER_OPERATION_TOTAL_TIME, // Time spent in filter operations. + TickerType.ROW_CACHE_HIT, // Hits in row cache. + TickerType.ROW_CACHE_MISS, // Misses in row cache. + TickerType.READ_AMP_ESTIMATE_USEFUL_BYTES, // Estimated useful bytes read due to read amplification. + TickerType.READ_AMP_TOTAL_READ_BYTES, // Total bytes read due to read amplification. + TickerType.NUMBER_RATE_LIMITER_DRAINS, // Number of times rate limiter is drained. + TickerType.NUMBER_ITER_SKIP, // Number of iterator skips. + TickerType.NUMBER_MULTIGET_KEYS_FOUND, // Number of keys found by multi-get operations. + }; - // Histograms - treated as prometheus summaries + /** + * Array of HistogramType representing various RocksDB histograms. + * Histograms track the distribution of certain metrics (e.g., latencies). + * Useful for performance analysis by providing quantiles and averages. + */ public static final HistogramType[] HISTOGRAMS = { - HistogramType.DB_GET, - HistogramType.DB_WRITE, - HistogramType.COMPACTION_TIME, - HistogramType.SUBCOMPACTION_SETUP_TIME, - HistogramType.TABLE_SYNC_MICROS, - HistogramType.COMPACTION_OUTFILE_SYNC_MICROS, - HistogramType.WAL_FILE_SYNC_MICROS, - HistogramType.MANIFEST_FILE_SYNC_MICROS, - HistogramType.TABLE_OPEN_IO_MICROS, - HistogramType.DB_MULTIGET, - HistogramType.READ_BLOCK_COMPACTION_MICROS, - HistogramType.READ_BLOCK_GET_MICROS, - HistogramType.WRITE_RAW_BLOCK_MICROS, - HistogramType.STALL_L0_SLOWDOWN_COUNT, - HistogramType.STALL_MEMTABLE_COMPACTION_COUNT, - HistogramType.STALL_L0_NUM_FILES_COUNT, - HistogramType.HARD_RATE_LIMIT_DELAY_COUNT, - HistogramType.SOFT_RATE_LIMIT_DELAY_COUNT, - HistogramType.NUM_FILES_IN_SINGLE_COMPACTION, - HistogramType.DB_SEEK, - HistogramType.WRITE_STALL, - HistogramType.SST_READ_MICROS, - HistogramType.NUM_SUBCOMPACTIONS_SCHEDULED, - HistogramType.BYTES_PER_READ, - HistogramType.BYTES_PER_WRITE, - HistogramType.BYTES_PER_MULTIGET, - HistogramType.BYTES_COMPRESSED, - HistogramType.BYTES_DECOMPRESSED, - HistogramType.COMPRESSION_TIMES_NANOS, - HistogramType.DECOMPRESSION_TIMES_NANOS, - HistogramType.READ_NUM_MERGE_OPERANDS, - }; + HistogramType.DB_GET, // Latency of database get operations. + HistogramType.DB_WRITE, // Latency of database write operations. + HistogramType.COMPACTION_TIME, // Time spent in compactions. + HistogramType.SUBCOMPACTION_SETUP_TIME, // Time spent setting up subcompactions. + HistogramType.TABLE_SYNC_MICROS, // Time spent synchronizing tables. + HistogramType.COMPACTION_OUTFILE_SYNC_MICROS, // Time spent syncing compaction output files. + HistogramType.WAL_FILE_SYNC_MICROS, // Time spent syncing WAL files. + HistogramType.MANIFEST_FILE_SYNC_MICROS, // Time spent syncing manifest files. + HistogramType.TABLE_OPEN_IO_MICROS, // Time spent opening tables (I/O). + HistogramType.DB_MULTIGET, // Latency of database multi-get operations. + HistogramType.READ_BLOCK_COMPACTION_MICROS, // Time spent reading blocks during compaction. + HistogramType.READ_BLOCK_GET_MICROS, // Time spent reading blocks during get. + HistogramType.WRITE_RAW_BLOCK_MICROS, // Time spent writing raw blocks. + HistogramType.STALL_L0_SLOWDOWN_COUNT, // Count of stalls due to L0 slowdown. + HistogramType.STALL_MEMTABLE_COMPACTION_COUNT, // Count of stalls due to memtable compaction. + HistogramType.STALL_L0_NUM_FILES_COUNT, // Count of stalls due to number of files at L0. + HistogramType.HARD_RATE_LIMIT_DELAY_COUNT, // Count of delays due to hard rate limits. + HistogramType.SOFT_RATE_LIMIT_DELAY_COUNT, // Count of delays due to soft rate limits. + HistogramType.NUM_FILES_IN_SINGLE_COMPACTION, // Number of files in a single compaction. + HistogramType.DB_SEEK, // Latency of database seek operations. + HistogramType.WRITE_STALL, // Time spent in write stalls. + HistogramType.SST_READ_MICROS, // Time spent reading SST files. + HistogramType.NUM_SUBCOMPACTIONS_SCHEDULED, // Number of subcompactions scheduled. + HistogramType.BYTES_PER_READ, // Distribution of bytes read per operation. + HistogramType.BYTES_PER_WRITE, // Distribution of bytes written per operation. + HistogramType.BYTES_PER_MULTIGET, // Distribution of bytes read per multi-get operation. + HistogramType.BYTES_COMPRESSED, // Distribution of compressed bytes. + HistogramType.BYTES_DECOMPRESSED, // Distribution of decompressed bytes. + HistogramType.COMPRESSION_TIMES_NANOS, // Time spent in compression operations. + HistogramType.DECOMPRESSION_TIMES_NANOS, // Time spent in decompression operations. + HistogramType.READ_NUM_MERGE_OPERANDS, // Distribution of number of merge operands read. + }; } diff --git a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/util/Base58.java b/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/util/Base58.java deleted file mode 100644 index bca9e54175..0000000000 --- a/hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/util/Base58.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hugegraph.store.node.util; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -public class Base58 { - - public static final char[] ALPHABET = - "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); - private static final int[] INDEXES = new int[128]; - - static { - Arrays.fill(INDEXES, -1); - for (int i = 0; i < ALPHABET.length; i++) { - INDEXES[ALPHABET[i]] = i; - } - } - - /** - * Encodes the given bytes in base58. No checksum is appended. - */ - public static String encode(byte[] input) { - if (input.length == 0) { - return ""; - } - input = copyOfRange(input, 0, input.length); - // Count leading zeroes. - int zeroCount = 0; - while (zeroCount < input.length && input[zeroCount] == 0) { - ++zeroCount; - } - // The actual encoding. - byte[] temp = new byte[input.length * 2]; - int j = temp.length; - - int startAt = zeroCount; - while (startAt < input.length) { - byte mod = divmod58(input, startAt); - if (input[startAt] == 0) { - ++startAt; - } - temp[--j] = (byte) ALPHABET[mod]; - } - - // Strip extra '1' if there are some after decoding. - while (j < temp.length && temp[j] == ALPHABET[0]) { - ++j; - } - // Add as much leading '1' as there were leading zeros. - while (--zeroCount >= 0) { - temp[--j] = (byte) ALPHABET[0]; - } - - byte[] output = copyOfRange(temp, j, temp.length); - return new String(output, StandardCharsets.US_ASCII); - } - - public static byte[] decode(String input) throws IllegalArgumentException { - if (input.isEmpty()) { - return new byte[0]; - } - byte[] input58 = new byte[input.length()]; - // Transform the String to a base58 byte sequence - for (int i = 0; i < input.length(); ++i) { - char c = input.charAt(i); - - int digit58 = -1; - if (c < 128) { - digit58 = INDEXES[c]; - } - if (digit58 < 0) { - throw new IllegalArgumentException("Illegal character " + c + " at " + i); - } - - input58[i] = (byte) digit58; - } - // Count leading zeroes - int zeroCount = 0; - while (zeroCount < input58.length && input58[zeroCount] == 0) { - ++zeroCount; - } - // The encoding - byte[] temp = new byte[input.length()]; - int j = temp.length; - - int startAt = zeroCount; - while (startAt < input58.length) { - byte mod = divmod256(input58, startAt); - if (input58[startAt] == 0) { - ++startAt; - } - - temp[--j] = mod; - } - // Do no add extra leading zeroes, move j to first non-null byte. - while (j < temp.length && temp[j] == 0) { - ++j; - } - - return copyOfRange(temp, j - zeroCount, temp.length); - } - - public static BigInteger decodeToBigInteger(String input) throws IllegalArgumentException { - return new BigInteger(1, decode(input)); - } - - // - // number -> number / 58, returns number % 58 - // - private static byte divmod58(byte[] number, int startAt) { - int remainder = 0; - for (int i = startAt; i < number.length; i++) { - int digit256 = (int) number[i] & 0xFF; - int temp = remainder * 256 + digit256; - - number[i] = (byte) (temp / 58); - - remainder = temp % 58; - } - - return (byte) remainder; - } - - // - // number -> number / 256, returns number % 256 - // - private static byte divmod256(byte[] number58, int startAt) { - int remainder = 0; - for (int i = startAt; i < number58.length; i++) { - int digit58 = (int) number58[i] & 0xFF; - int temp = remainder * 58 + digit58; - - number58[i] = (byte) (temp / 256); - - remainder = temp % 256; - } - - return (byte) remainder; - } - - private static byte[] copyOfRange(byte[] source, int from, int to) { - byte[] range = new byte[to - from]; - System.arraycopy(source, from, range, 0, range.length); - - return range; - } - -} -