Răsfoiți Sursa

use compact BigDecimal

jianghang.loujh 2 ani în urmă
părinte
comite
afef45500e

+ 170 - 2
dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/LogBuffer.java

@@ -16,6 +16,8 @@ import java.util.BitSet;
  */
 public class LogBuffer {
 
+    static final BigDecimal DECIMAL_ZERO_1_SCALE = BigDecimal.valueOf(0, 1);
+    static final BigDecimal DECIMAL_ONE_1_SCALE = BigDecimal.valueOf(10, 1);
     protected byte[] buffer;
 
     protected int    origin, limit;
@@ -1263,6 +1265,15 @@ public class LogBuffer {
             throw new IllegalArgumentException("limit excceed: " + (position + binSize - origin));
         }
 
+        if (precision <= 20 && intg <= 18 && frac <= 9) {
+            // use compact BigDecimal
+            BigDecimal compactDecimal = getBigDecimalCompact(precision, scale, intg, frac, intg0x);
+            if (compactDecimal != null) {
+                position += binSize;
+                return compactDecimal;
+            }
+        }
+
         BigDecimal decimal = getDecimal0(position, intg, frac, // NL
             intg0,
             frac0,
@@ -1272,6 +1283,162 @@ public class LogBuffer {
         return decimal;
     }
 
+    /**
+     * use compact BigDecimal
+     */
+    private BigDecimal getBigDecimalCompact(int precision, int scale, int intg, int frac, int intg0x) {
+        if (precision > 20 || intg > 18 && frac > 9) {
+            return null;
+        }
+
+        BigDecimal compactDecimal = null;
+        long longValue = 0;
+        int small = 0;
+        int pos = position;
+        byte b0 = buffer[position];
+        final int mask = ((b0 & 0x80) == 0x80) ? 0 : -1;
+        b0 ^= 0x80;
+
+        switch (intg0x) {
+            case 0:
+                if (intg == 0) {
+                    longValue = 0;
+                } else {
+                    longValue = (b0 << 24)
+                                | ((0xff & buffer[pos + 1]) << 16)
+                                | ((0xff & buffer[pos + 2]) << 8)
+                                | (0xff & buffer[pos + 3]);
+                    longValue ^= mask;
+                    pos += 4;
+                }
+                break;
+            case 1:
+            case 2:
+                longValue = b0;
+                longValue ^= mask;
+                pos += 1;
+                break;
+            case 3:
+            case 4:
+                longValue = (b0 << 8) | (0xff & buffer[pos + 1]);
+                longValue ^= mask;
+                pos += 2;
+                break;
+            case 5:
+            case 6:
+                longValue = (b0 << 16) | ((0xff & buffer[pos + 1]) << 8) | (0xff & buffer[pos + 2]);
+                longValue ^= mask;
+                pos += 3;
+                break;
+            case 7:
+            case 8:
+                longValue = (b0 << 24)
+                            | ((0xff & buffer[pos + 1]) << 16)
+                            | ((0xff & buffer[pos + 2]) << 8)
+                            | (0xff & buffer[pos + 3]);
+                longValue ^= mask;
+                pos += 4;
+                break;
+            default:
+                break;
+        }
+
+        if (intg > 9) {
+            int value = getInt32BE(buffer, pos);
+            value ^= mask;
+            longValue *= 1_000_000_000;
+            longValue += value;
+            pos += 4;
+        }
+
+        int power = 1;
+        if (pos != position) {
+            b0 = buffer[pos];
+        }
+        switch (frac) {
+            case 0:
+                small = 0;
+                break;
+            case 1:
+            case 2:
+                power = frac == 1 ? 10 : 100;
+                small = b0;
+                small ^= mask;
+                break;
+            case 3:
+            case 4:
+                power = frac == 3 ? 1_000 : 10_000;
+                small = (b0 << 8) | (0xff & buffer[pos + 1]);
+                small ^= mask;
+                break;
+            case 5:
+            case 6:
+                power = frac == 5 ? 100_000 : 1_000_000;
+                small = (b0 << 16) | ((0xff & buffer[pos + 1]) << 8) | (0xff & buffer[pos + 2]);
+                small ^= mask;
+                break;
+            case 7:
+            case 8:
+            case 9:
+                power = frac == 7 ? 10_000_000 : frac == 8 ? 100_000_000 : 1_000_000_000;
+                small = (b0 << 24)
+                        | ((0xff & buffer[pos + 1]) << 16)
+                        | ((0xff & buffer[pos + 2]) << 8)
+                        | (0xff & buffer[pos + 3]);
+                small ^= mask;
+                break;
+            default:
+                break;
+        }
+
+        if (small == 0) {
+            if (frac == 0) {
+                if (mask != 0) {
+                    longValue = -longValue;
+                }
+                compactDecimal = BigDecimal.valueOf(longValue, 0);
+            } else if (longValue == 0) {
+                if (scale < 9) {
+                    compactDecimal = DECIMAL_ZERO_1_SCALE;
+                } else {
+                    compactDecimal = BigDecimal.valueOf(longValue, scale);
+                }
+            } else {
+                if (scale < 9) {
+                    long unscaleValue = longValue * 10;
+                    if (unscaleValue >= longValue) {
+                        if (mask != 0) {
+                            unscaleValue = -unscaleValue;
+                        }
+                        if (unscaleValue == 10) {
+                            compactDecimal = DECIMAL_ONE_1_SCALE;
+                        } else {
+                            compactDecimal = BigDecimal.valueOf(unscaleValue, 1);
+                        }
+                    }
+                } else {
+                    long unscaleValue = longValue * power;
+                    if (unscaleValue >= longValue) {
+                        if (mask != 0) {
+                            unscaleValue = -unscaleValue;
+                        }
+                        compactDecimal = BigDecimal.valueOf(unscaleValue, scale);
+                    }
+                }
+            }
+        } else {
+            long unscaleValue = longValue * power + small;
+            if (unscaleValue >= longValue) {
+                if (mask != 0) {
+                    unscaleValue = -unscaleValue;
+                }
+                compactDecimal = BigDecimal.valueOf(unscaleValue, scale);
+            }
+        }
+
+        return compactDecimal;
+    }
+
     /**
      * Return big decimal from buffer.
      * 
@@ -1445,8 +1612,9 @@ public class LogBuffer {
         }
 
         d_copy[begin] ^= 0x80; /* restore sign */
-        String decimal = String.valueOf(buf, 0, pos);
-        return new BigDecimal(decimal);
+        // String decimal = String.valueOf(buf, 0, pos);
+        // return new BigDecimal(decimal);
+        return new BigDecimal(buf, 0, pos);
     }
 
     /**