You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2022/01/01 12:57:04 UTC
[hbase] branch branch-2.5 updated: HBASE-26635 Optimize decodeNumeric in OrderedBytes (#3986)
This is an automated email from the ASF dual-hosted git repository.
zhangduo pushed a commit to branch branch-2.5
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-2.5 by this push:
new ede518c HBASE-26635 Optimize decodeNumeric in OrderedBytes (#3986)
ede518c is described below
commit ede518c295b7415b36c4560f0c6feeba1b4bef2e
Author: Yutong Xiao <yu...@gmail.com>
AuthorDate: Sat Jan 1 20:42:57 2022 +0800
HBASE-26635 Optimize decodeNumeric in OrderedBytes (#3986)
Signed-off-by: Duo Zhang <zh...@apache.org>
---
.../org/apache/hadoop/hbase/util/OrderedBytes.java | 25 +++++++++++++---------
.../apache/hadoop/hbase/util/TestOrderedBytes.java | 22 +++++++++++++++++++
2 files changed, 37 insertions(+), 10 deletions(-)
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/OrderedBytes.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/OrderedBytes.java
index c82d6ee..46a7fae 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/OrderedBytes.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/OrderedBytes.java
@@ -21,7 +21,6 @@ import static org.apache.hadoop.hbase.util.Order.ASCENDING;
import static org.apache.hadoop.hbase.util.Order.DESCENDING;
import java.math.BigDecimal;
-import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.nio.charset.Charset;
@@ -561,8 +560,8 @@ public class OrderedBytes {
byte[] a = src.getBytes();
final int start = src.getPosition(), offset = src.getOffset(), remaining = src.getRemaining();
Order ord = comp ? DESCENDING : ASCENDING;
- BigDecimal m = BigDecimal.ZERO;
- e--;
+ BigDecimal m;
+ StringBuilder sb = new StringBuilder();
for (int i = 0;; i++) {
if (i > remaining) {
// we've exceeded this range's window
@@ -571,18 +570,23 @@ public class OrderedBytes {
"Read exceeds range before termination byte found. offset: " + offset + " position: "
+ (start + i));
}
+ // one byte -> 2 digits
// base-100 digits are encoded as val * 2 + 1 except for the termination digit.
- m = m.add( // m +=
- new BigDecimal(BigInteger.ONE, e * -2).multiply( // 100 ^ p * [decoded digit]
- BigDecimal.valueOf((ord.apply(a[offset + start + i]) & 0xff) / 2)));
- e--;
+ int twoDigits = (ord.apply(a[offset + start + i]) & 0xff) / 2;
+ sb.append(String.format("%02d", twoDigits));
// detect termination digit
- if ((ord.apply(a[offset + start + i]) & 1) == 0) {
+ // Besides, as we will normalise the return value at last,
+ // we only need to decode at most MAX_PRECISION + 2 digits here.
+ if ((ord.apply(a[offset + start + i]) & 1) == 0 || sb.length() > MAX_PRECISION + 1) {
src.setPosition(start + i + 1);
break;
}
}
- return normalize(m);
+ m = new BigDecimal(sb.toString());
+ int stepsMoveLeft = sb.charAt(0) != '0' ? m.precision() : m.precision() + 1;
+ stepsMoveLeft -= e * 2;
+
+ return normalize(m.movePointLeft(stepsMoveLeft));
}
/**
@@ -743,7 +747,8 @@ public class OrderedBytes {
/**
* Encode a value val in [0.01, 1.0) into Centimals.
- * Util function for {@link this.encodeNumericLarge()} and {@link this.encodeNumericSmall()}
+ * Util function for {@link OrderedBytes#encodeNumericLarge(PositionedByteRange, BigDecimal)
+ * and {@link OrderedBytes#encodeNumericSmall(PositionedByteRange, BigDecimal)}
* @param dst The destination to which encoded digits are written.
* @param val A BigDecimal after the normalization. The value must be in [0.01, 1.0).
*/
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestOrderedBytes.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestOrderedBytes.java
index 943038f..7c9c962 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestOrderedBytes.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestOrderedBytes.java
@@ -25,6 +25,7 @@ import static org.junit.Assert.fail;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
+import java.util.concurrent.ThreadLocalRandom;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.testclassification.MiscTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
@@ -1319,4 +1320,25 @@ public class TestOrderedBytes {
OrderedBytes.skip(buff);
}
}
+
+ /**
+ * Test if the data encoded by our encoding function can be decoded correctly.
+ */
+ @Test
+ public void testEncodeDecodeMatch() {
+ int samplesQuantity = 200;
+ for (int i = 0; i < samplesQuantity; i++) {
+ BigDecimal randomData = BigDecimal.valueOf(ThreadLocalRandom.current().nextDouble() +
+ ThreadLocalRandom.current().nextLong());
+ PositionedByteRange tmp = new SimplePositionedMutableByteRange(100);
+ Order ord = ThreadLocalRandom.current().nextBoolean() ? Order.DESCENDING : Order.ASCENDING;
+
+ OrderedBytes.encodeNumeric(tmp, randomData, ord);
+ tmp.setPosition(0);
+
+ BigDecimal left = OrderedBytes.normalize(randomData);
+ BigDecimal right = OrderedBytes.decodeNumericAsBigDecimal(tmp);
+ assertEquals(0, left.compareTo(right));
+ }
+ }
}