This is an automated email from the ASF dual-hosted git repository.

caiconghui pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f5b06a  [Bug][Optimize] Fix race condition problem and optimize 
do_money_format function (#6350)
2f5b06a is described below

commit 2f5b06ae701e1274824c1768fd5bb1a739b6906c
Author: caiconghui <55968745+caicong...@users.noreply.github.com>
AuthorDate: Fri Aug 6 16:29:34 2021 +0800

    [Bug][Optimize] Fix race condition problem and optimize do_money_format 
function (#6350)
    
    * [Bug][Optimize] Fix race condition problem and optimize do_money_format 
function
    
    Co-authored-by: caiconghui <caicong...@xiaomi.com>
---
 be/src/exprs/string_functions.cpp       | 16 +++----
 be/src/exprs/string_functions.h         | 34 ++++++---------
 be/src/gutil/strings/numbers.cc         | 76 ++++++++++++++++++++++++---------
 be/src/gutil/strings/numbers.h          |  3 ++
 be/test/exprs/string_functions_test.cpp | 34 ++++++++++-----
 5 files changed, 101 insertions(+), 62 deletions(-)

diff --git a/be/src/exprs/string_functions.cpp 
b/be/src/exprs/string_functions.cpp
index 0ede46e..8822065 100644
--- a/be/src/exprs/string_functions.cpp
+++ b/be/src/exprs/string_functions.cpp
@@ -880,8 +880,10 @@ StringVal StringFunctions::money_format(FunctionContext* 
context, const DoubleVa
         return StringVal::null();
     }
 
-    double v_cent = MathFunctions::my_double_round(v.val, 2, false, false) * 
100;
-    return do_money_format(context, std::to_string(v_cent));
+    double v_cent = MathFunctions::my_double_round(v.val, 2, false, false);
+    bool negative = v_cent < 0;
+    int32_t frac_value = negative ? ((int64_t) (-v_cent * 100)) % 100 : 
((int64_t)(v_cent * 100)) % 100;
+    return do_money_format<int64_t, 26>(context, (int64_t) v_cent , 
frac_value);
 }
 
 StringVal StringFunctions::money_format(FunctionContext* context, const 
DecimalV2Val& v) {
@@ -891,25 +893,21 @@ StringVal StringFunctions::money_format(FunctionContext* 
context, const DecimalV
 
     DecimalV2Value rounded(0);
     DecimalV2Value::from_decimal_val(v).round(&rounded, 2, HALF_UP);
-    DecimalV2Value tmp(std::string_view("100"));
-    DecimalV2Value result = rounded * tmp;
-    return do_money_format(context, result.to_string());
+    return do_money_format<int64_t, 26>(context, rounded.int_value(), 
abs(rounded.frac_value()));
 }
 
 StringVal StringFunctions::money_format(FunctionContext* context, const 
BigIntVal& v) {
     if (v.is_null) {
         return StringVal::null();
     }
-
-    return do_money_format(context, fmt::format("{}00", v.val, "00"));
+    return do_money_format<int64_t, 26>(context, v.val);
 }
 
 StringVal StringFunctions::money_format(FunctionContext* context, const 
LargeIntVal& v) {
     if (v.is_null) {
         return StringVal::null();
     }
-
-    return do_money_format(context, fmt::format("{}00", v.val, "00"));
+    return do_money_format<__int128_t, 52>(context, v.val);
 }
 
 static int index_of(const uint8_t* source, int source_offset, int source_count,
diff --git a/be/src/exprs/string_functions.h b/be/src/exprs/string_functions.h
index 05a548d..dbd8cee 100644
--- a/be/src/exprs/string_functions.h
+++ b/be/src/exprs/string_functions.h
@@ -26,6 +26,7 @@
 #include <string_view>
 
 #include "anyval_util.h"
+#include "gutil/strings/numbers.h"
 #include "runtime/string_search.hpp"
 #include "runtime/string_value.h"
 
@@ -148,28 +149,17 @@ public:
     static doris_udf::StringVal money_format(doris_udf::FunctionContext* 
context,
                                              const doris_udf::LargeIntVal& v);
 
-    struct CommaMoneypunct : std::moneypunct<char> {
-        pattern do_pos_format() const override { return {{none, sign, none, 
value}}; }
-        pattern do_neg_format() const override { return {{none, sign, none, 
value}}; }
-        int do_frac_digits() const override { return 2; }
-        char_type do_thousands_sep() const override { return ','; }
-        string_type do_grouping() const override { return "\003"; }
-        string_type do_negative_sign() const override { return "-"; }
-    };
-
-    static StringVal do_money_format(FunctionContext* context, const 
std::string& v) {
-        static std::locale comma_locale(std::locale(), new CommaMoneypunct());
-        static std::stringstream ss;
-        static bool ss_init = false;
-        if (UNLIKELY(!ss_init)) {
-            ss.imbue(comma_locale);
-            ss_init = true;
-        }
-        static std::string empty_string;
-        ss.str(empty_string);
-
-        ss << std::put_money(v);
-        return AnyValUtil::from_string_temp(context, ss.str());
+    template <typename T, size_t N> static StringVal 
do_money_format(FunctionContext* context, const T int_value,
+            const int32_t frac_value = 0) {
+        char local[N];
+        char* p = SimpleItoaWithCommas(int_value, local, sizeof(local));
+        int32_t string_val_len = local + sizeof(local) - p + 3;
+        StringVal result = StringVal::create_temp_string_val(context, 
string_val_len);
+        memcpy(result.ptr, p, string_val_len - 3);
+        *(result.ptr + string_val_len - 3) = '.';
+        *(result.ptr + string_val_len - 2) = '0' + (frac_value / 10);
+        *(result.ptr + string_val_len - 1) = '0' + (frac_value % 10);
+        return result;
     };
 
     static StringVal split_part(FunctionContext* context, const StringVal& 
content,
diff --git a/be/src/gutil/strings/numbers.cc b/be/src/gutil/strings/numbers.cc
index 83fd47a..65ae119 100644
--- a/be/src/gutil/strings/numbers.cc
+++ b/be/src/gutil/strings/numbers.cc
@@ -1335,7 +1335,39 @@ string SimpleItoaWithCommas(uint32 i) {
 string SimpleItoaWithCommas(int64 i) {
     // 19 digits, 6 commas, and sign are good for 64-bit or smaller ints.
     char local[26];
+    char* p = SimpleItoaWithCommas(i, local, sizeof(local));
+    return string(p, local + sizeof(local));
+}
+
+// We need this overload because otherwise SimpleItoaWithCommas(5ULL) wouldn't
+// compile.
+string SimpleItoaWithCommas(uint64 i) {
+    // 20 digits and 6 commas are good for 64-bit or smaller ints.
+    // Longest is 18,446,744,073,709,551,615.
+    char local[26];
     char* p = local + sizeof(local);
+    *--p = '0' + i % 10; // this case deals with the number "0"
+    i /= 10;
+    while (i) {
+        *--p = '0' + i % 10;
+        i /= 10;
+        if (i == 0) break;
+
+        *--p = '0' + i % 10;
+        i /= 10;
+        if (i == 0) break;
+
+        *--p = ',';
+        *--p = '0' + i % 10;
+        i /= 10;
+        // For this unrolling, we check if i == 0 in the main while loop
+    }
+    return string(p, local + sizeof(local));
+}
+
+char* SimpleItoaWithCommas(int64_t i, char* buffer, int32_t buffer_size) {
+    // 19 digits, 6 commas, and sign are good for 64-bit or smaller ints.
+    char* p = buffer + buffer_size;
     // Need to use uint64 instead of int64 to correctly handle
     // -9,223,372,036,854,775,808.
     uint64 n = i;
@@ -1357,35 +1389,37 @@ string SimpleItoaWithCommas(int64 i) {
         // For this unrolling, we check if n == 0 in the main while loop
     }
     if (i < 0) *--p = '-';
-    return string(p, local + sizeof(local));
+    return p;
 }
 
-// We need this overload because otherwise SimpleItoaWithCommas(5ULL) wouldn't
-// compile.
-string SimpleItoaWithCommas(uint64 i) {
-    // 20 digits and 6 commas are good for 64-bit or smaller ints.
-    // Longest is 18,446,744,073,709,551,615.
-    char local[26];
-    char* p = local + sizeof(local);
-    *--p = '0' + i % 10; // this case deals with the number "0"
-    i /= 10;
-    while (i) {
-        *--p = '0' + i % 10;
-        i /= 10;
-        if (i == 0) break;
+char* SimpleItoaWithCommas(__int128_t i, char* buffer, int32_t buffer_size) {
+    // 39 digits, 12 commas, and sign are good for 128-bit or smaller ints.
+    char* p = buffer + buffer_size;
+    // Need to use uint128 instead of int128 to correctly handle
+    // -170,141,183,460,469,231,731,687,303,715,884,105,728.
+    __uint128_t n = i;
+    if (i < 0) n = 0 - n;
+    *--p = '0' + n % 10; // this case deals with the number "0"
+    n /= 10;
+    while (n) {
+        *--p = '0' + n % 10;
+        n /= 10;
+        if (n == 0) break;
 
-        *--p = '0' + i % 10;
-        i /= 10;
-        if (i == 0) break;
+        *--p = '0' + n % 10;
+        n /= 10;
+        if (n == 0) break;
 
         *--p = ',';
-        *--p = '0' + i % 10;
-        i /= 10;
-        // For this unrolling, we check if i == 0 in the main while loop
+        *--p = '0' + n % 10;
+        n /= 10;
+        // For this unrolling, we check if n == 0 in the main while loop
     }
-    return string(p, local + sizeof(local));
+    if (i < 0) *--p = '-';
+    return p;
 }
 
+
 // ----------------------------------------------------------------------
 // ItoaKMGT()
 //    Description: converts an integer to a string
diff --git a/be/src/gutil/strings/numbers.h b/be/src/gutil/strings/numbers.h
index 5f2acb2..931a1c2 100644
--- a/be/src/gutil/strings/numbers.h
+++ b/be/src/gutil/strings/numbers.h
@@ -461,6 +461,9 @@ string SimpleItoaWithCommas(uint32 i);
 string SimpleItoaWithCommas(int64 i);
 string SimpleItoaWithCommas(uint64 i);
 
+char* SimpleItoaWithCommas(int64_t i, char* buffer, int32_t buffer_size);
+char* SimpleItoaWithCommas(__int128_t i, char* buffer, int32_t buffer_size);
+
 // ----------------------------------------------------------------------
 // ItoaKMGT()
 //    Description: converts an integer to a string
diff --git a/be/test/exprs/string_functions_test.cpp 
b/be/test/exprs/string_functions_test.cpp
index a5240c3..99532b6 100644
--- a/be/test/exprs/string_functions_test.cpp
+++ b/be/test/exprs/string_functions_test.cpp
@@ -18,9 +18,9 @@
 #include "exprs/string_functions.h"
 
 #include <gtest/gtest.h>
-
 #include <iostream>
 #include <string>
+#include <fmt/os.h>
 
 #include "exprs/anyval_util.h"
 #include "test_util/test_util.h"
@@ -44,13 +44,26 @@ private:
     FunctionContext* ctx;
 };
 
-TEST_F(StringFunctionsTest, do_money_format_bench) {
+TEST_F(StringFunctionsTest, do_money_format_for_bigint_bench) {
     doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
     StringVal expected =
             AnyValUtil::from_string_temp(context, 
std::string("9,223,372,036,854,775,807.00"));
+    BigIntVal bigIntVal(9223372036854775807);
     for (int i = 0; i < LOOP_LESS_OR_MORE(10, 10000000); i++) {
-        StringVal result =
-                StringFunctions::do_money_format(context, 
"922337203685477580700"); // cent
+        StringVal result = StringFunctions::money_format(context, bigIntVal);
+        ASSERT_EQ(expected, result);
+    }
+    delete context;
+}
+
+TEST_F(StringFunctionsTest, do_money_format_for_decimalv2_bench) {
+    doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
+    StringVal expected = AnyValUtil::from_string_temp(context, 
std::string("9,223,372,085.85"));
+    DecimalV2Value dv1(std::string("9223372085.8678"));
+    DecimalV2Val decimalV2Val;
+    dv1.to_decimal_val(&decimalV2Val);
+    for (int i = 0; i < LOOP_LESS_OR_MORE(10, 10000000); i++) {
+        StringVal result = StringFunctions::money_format(context, 
decimalV2Val);
         ASSERT_EQ(expected, result);
     }
     delete context;
@@ -75,16 +88,17 @@ TEST_F(StringFunctionsTest, money_format_bigint) {
 
 TEST_F(StringFunctionsTest, money_format_large_int) {
     doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
-
-    std::string str("170141183460469231731687303715884105727");
-    std::stringstream ss;
-    ss << str;
-    __int128 value;
-    ss >> value;
+    __int128 value = MAX_INT128;
     StringVal result = StringFunctions::money_format(context, 
doris_udf::LargeIntVal(value));
     StringVal expected = AnyValUtil::from_string_temp(
             context, 
std::string("170,141,183,460,469,231,731,687,303,715,884,105,727.00"));
     ASSERT_EQ(expected, result);
+
+    value = MIN_INT128;
+    result = StringFunctions::money_format(context, 
doris_udf::LargeIntVal(value));
+    expected = AnyValUtil::from_string_temp(
+                context, 
std::string("-170,141,183,460,469,231,731,687,303,715,884,105,728.00"));
+    ASSERT_EQ(expected, result);
     delete context;
 }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to