You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pegasus.apache.org by wa...@apache.org on 2022/12/26 06:18:08 UTC

[incubator-pegasus] branch master updated: feat: decide whether two C strings are equal and support CHECK_STREQ* and CHECK_STRNE* (#1300)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 86f7e02ab feat: decide whether two C strings are equal and support CHECK_STREQ* and CHECK_STRNE* (#1300)
86f7e02ab is described below

commit 86f7e02aba866a33a660815a30bf463c77870cf7
Author: Dan Wang <wa...@apache.org>
AuthorDate: Mon Dec 26 14:18:01 2022 +0800

    feat: decide whether two C strings are equal and support CHECK_STREQ* and CHECK_STRNE* (#1300)
---
 src/aio/test/aio.cpp                             |  13 ++-
 src/block_service/test/fds_service_test.cpp      |  15 +--
 src/block_service/test/hdfs_service_test.cpp     |  16 +--
 src/failure_detector/test/failure_detector.cpp   |   4 +-
 src/http/http_message_parser.cpp                 |  16 +--
 src/http/pprof_http_service.cpp                  |  25 +++--
 src/meta/meta_state_service_simple.cpp           |   9 +-
 src/meta/server_state.cpp                        |  32 +++---
 src/meta/test/dump_file.cpp                      |   4 +-
 src/meta/test/json_compacity.cpp                 |   2 +-
 src/meta/test/state_sync_test.cpp                |  31 +++---
 src/perf_counter/perf_counter.cpp                |   7 +-
 src/perf_counter/perf_counters.cpp               |  11 +-
 src/redis_protocol/proxy/main.cpp                |   9 +-
 src/redis_protocol/proxy_lib/redis_parser.cpp    |  22 ++--
 src/redis_protocol/proxy_ut/redis_proxy_test.cpp |  19 ++--
 src/replica/storage/simple_kv/test/case.cpp      |   2 +-
 src/replica/storage/simple_kv/test/checker.cpp   |   4 +-
 src/replica/test/mutation_log_learn_test.cpp     |  16 +--
 src/reporter/pegasus_counter_reporter.cpp        |  25 +++--
 src/runtime/global_config.cpp                    |   2 +-
 src/runtime/rpc/rpc_address.cpp                  |   3 +-
 src/runtime/rpc/thrift_message_parser.cpp        |  17 +--
 src/runtime/service_api_c.cpp                    |  42 +++----
 src/runtime/test/main.cpp                        |   5 +-
 src/runtime/test/netprovider.cpp                 |   2 +-
 src/runtime/test/rpc_message.cpp                 |   4 +-
 src/server/compaction_filter_rule.cpp            |  15 +--
 src/server/main.cpp                              |  30 +++--
 src/server/pegasus_server_impl.cpp               |  35 +++---
 src/server/pegasus_write_service_impl.h          |  21 ++--
 src/shell/args.h                                 |   5 +-
 src/shell/command_helper.h                       |  44 ++++----
 src/shell/command_utils.h                        |  23 +---
 src/shell/commands/detect_hotkey.cpp             |  23 ++--
 src/shell/commands/global_properties.cpp         |   5 +-
 src/shell/main.cpp                               |  14 ++-
 src/test/kill_test/main.cpp                      |   7 +-
 src/utils/fmt_logging.h                          |  61 +++++++++++
 src/utils/long_adder_bench/long_adder_bench.cpp  |   9 +-
 src/utils/metrics.cpp                            |  13 ++-
 src/utils/metrics.h                              |  17 +--
 src/utils/simple_logger.cpp                      |   3 +-
 src/utils/string_view.cpp                        |  10 +-
 src/utils/string_view.h                          |   4 +-
 src/utils/strings.cpp                            |  76 +++++++++++++
 src/utils/strings.h                              |  23 ++++
 src/utils/test/flag_test.cpp                     |   2 +-
 src/utils/test/metrics_test.cpp                  |   4 +-
 src/utils/test/utils.cpp                         | 134 +++++++++++++++++++++++
 50 files changed, 623 insertions(+), 312 deletions(-)

diff --git a/src/aio/test/aio.cpp b/src/aio/test/aio.cpp
index bb1bfb777..a7e13cbee 100644
--- a/src/aio/test/aio.cpp
+++ b/src/aio/test/aio.cpp
@@ -24,12 +24,13 @@
  * THE SOFTWARE.
  */
 
+#include <gtest/gtest.h>
+
 #include "runtime/task/async_calls.h"
+#include "utils/fail_point.h"
 #include "utils/filesystem.h"
 #include "utils/smart_pointers.h"
-#include "utils/fail_point.h"
-
-#include <gtest/gtest.h>
+#include "utils/strings.h"
 
 using namespace ::dsn;
 
@@ -121,7 +122,7 @@ TEST(core, aio)
 
         t->wait();
         EXPECT_TRUE(t->get_transferred_size() == (size_t)len);
-        EXPECT_TRUE(memcmp(buffer, buffer2, len) == 0);
+        EXPECT_TRUE(dsn::utils::mequals(buffer, buffer2, len));
     }
 
     err = file::close(fp);
@@ -178,12 +179,12 @@ TEST(core, operation_failed)
     t = ::dsn::file::read(fp2, buffer, 512, 0, LPC_AIO_TEST, nullptr, io_callback, 0);
     t->wait();
     EXPECT_TRUE(*err == ERR_OK && *count == strlen(str));
-    EXPECT_TRUE(strncmp(buffer, str, 10) == 0);
+    EXPECT_TRUE(dsn::utils::equals(buffer, str, 10));
 
     t = ::dsn::file::read(fp2, buffer, 5, 0, LPC_AIO_TEST, nullptr, io_callback, 0);
     t->wait();
     EXPECT_TRUE(*err == ERR_OK && *count == 5);
-    EXPECT_TRUE(strncmp(buffer, str, 5) == 0);
+    EXPECT_TRUE(dsn::utils::equals(buffer, str, 5));
 
     t = ::dsn::file::read(fp2, buffer, 512, 100, LPC_AIO_TEST, nullptr, io_callback, 0);
     t->wait();
diff --git a/src/block_service/test/fds_service_test.cpp b/src/block_service/test/fds_service_test.cpp
index 8d939fb7e..ea47cc019 100644
--- a/src/block_service/test/fds_service_test.cpp
+++ b/src/block_service/test/fds_service_test.cpp
@@ -17,18 +17,19 @@
 
 #include "block_service/fds/fds_service.h"
 
-#include <fcntl.h>
-
 #include <array>
+#include <fcntl.h>
 #include <fstream>
-#include <gtest/gtest.h>
 #include <memory>
 
+#include <gtest/gtest.h>
+
 #include "block_service/block_service.h"
-#include "utils/fmt_logging.h"
 #include "utils/filesystem.h"
+#include "utils/fmt_logging.h"
 #include "utils/rand.h"
 #include "utils/safe_strerror_posix.h"
+#include "utils/strings.h"
 #include "utils/utils.h"
 
 using namespace dsn;
@@ -65,7 +66,7 @@ static void file_eq_compare(const std::string &fname1, const std::string &fname2
         int up_to_bytes = length < (l - i) ? length : (l - i);
         ifile1.read(buf1, up_to_bytes);
         ifile2.read(buf2, up_to_bytes);
-        ASSERT_TRUE(memcmp(buf1, buf2, up_to_bytes) == 0);
+        ASSERT_TRUE(dsn::utils::mequals(buf1, buf2, up_to_bytes));
     }
 }
 
@@ -507,7 +508,7 @@ TEST_F(FDSClientTest, test_basic_operation)
 
         ASSERT_EQ(dsn::ERR_OK, r_resp.err);
         ASSERT_EQ(length, r_resp.buffer.length());
-        ASSERT_EQ(0, memcmp(r_resp.buffer.data(), test_buffer, length));
+        ASSERT_TRUE(dsn::utils::mequals(r_resp.buffer.data(), test_buffer, length));
 
         // partitial read
         cf_resp.file_handle
@@ -519,7 +520,7 @@ TEST_F(FDSClientTest, test_basic_operation)
 
         ASSERT_EQ(dsn::ERR_OK, r_resp.err);
         ASSERT_EQ(10, r_resp.buffer.length());
-        ASSERT_EQ(0, memcmp(r_resp.buffer.data(), test_buffer + 5, 10));
+        ASSERT_TRUE(dsn::utils::mequals(r_resp.buffer.data(), test_buffer + 5, 10));
     }
 
     // then test remove path
diff --git a/src/block_service/test/hdfs_service_test.cpp b/src/block_service/test/hdfs_service_test.cpp
index f1bd5d559..ed386dd98 100644
--- a/src/block_service/test/hdfs_service_test.cpp
+++ b/src/block_service/test/hdfs_service_test.cpp
@@ -15,15 +15,17 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include "block_service/block_service.h"
-#include "utils/filesystem.h"
-#include "utils/flags.h"
-#include "utils/rand.h"
 #include <fstream>
-#include <gtest/gtest.h>
 #include <memory>
 
+#include <gtest/gtest.h>
+
+#include "block_service/block_service.h"
 #include "block_service/hdfs/hdfs_service.h"
+#include "utils/filesystem.h"
+#include "utils/flags.h"
+#include "utils/rand.h"
+#include "utils/strings.h"
 
 using namespace dsn;
 using namespace dsn::dist::block_service;
@@ -219,7 +221,7 @@ TEST_F(HDFSClientTest, test_basic_operation)
         ->wait();
     ASSERT_EQ(dsn::ERR_OK, r_resp.err);
     ASSERT_EQ(length, r_resp.buffer.length());
-    ASSERT_EQ(0, memcmp(r_resp.buffer.data(), test_buffer, length));
+    ASSERT_TRUE(dsn::utils::mequals(r_resp.buffer.data(), test_buffer, length));
 
     // test partitial read.
     cf_resp.file_handle
@@ -230,7 +232,7 @@ TEST_F(HDFSClientTest, test_basic_operation)
         ->wait();
     ASSERT_EQ(dsn::ERR_OK, r_resp.err);
     ASSERT_EQ(10, r_resp.buffer.length());
-    ASSERT_EQ(0, memcmp(r_resp.buffer.data(), test_buffer + 5, 10));
+    ASSERT_TRUE(dsn::utils::mequals(r_resp.buffer.data(), test_buffer + 5, 10));
 
     // clean up local test files.
     utils::filesystem::remove_path(local_test_file);
diff --git a/src/failure_detector/test/failure_detector.cpp b/src/failure_detector/test/failure_detector.cpp
index af969098c..1fb19f0bd 100644
--- a/src/failure_detector/test/failure_detector.cpp
+++ b/src/failure_detector/test/failure_detector.cpp
@@ -263,11 +263,11 @@ bool get_worker_and_master(test_worker *&worker, std::vector<test_master *> &mas
     worker = nullptr;
 
     for (int i = 0; i != apps.size(); ++i) {
-        if (strcmp(apps[i]->info().type.c_str(), "worker") == 0) {
+        if (apps[i]->info().type == "worker") {
             if (worker != nullptr)
                 return false;
             worker = reinterpret_cast<test_worker *>(apps[i]);
-        } else if (strcmp(apps[i]->info().type.c_str(), "master") == 0) {
+        } else if (apps[i]->info().type == "master") {
             int index = apps[i]->info().index - 1;
             if (index >= masters.size() || masters[index] != nullptr)
                 return false;
diff --git a/src/http/http_message_parser.cpp b/src/http/http_message_parser.cpp
index 11653b4e4..d4bea0b4a 100644
--- a/src/http/http_message_parser.cpp
+++ b/src/http/http_message_parser.cpp
@@ -26,14 +26,16 @@
 
 #include "http_message_parser.h"
 
-#include "utils/fmt_logging.h"
-#include "utils/ports.h"
-#include "utils/crc.h"
+#include <iomanip>
+
+#include "http_server.h"
+#include "runtime/api_layer1.h"
 #include "runtime/rpc/rpc_message.h"
 #include "runtime/rpc/serialization.h"
-#include "runtime/api_layer1.h"
-#include "http_server.h"
-#include <iomanip>
+#include "utils/crc.h"
+#include "utils/fmt_logging.h"
+#include "utils/ports.h"
+#include "utils/strings.h"
 
 namespace dsn {
 
@@ -98,7 +100,7 @@ http_message_parser::http_message_parser()
         [](http_parser *parser, const char *at, size_t length) -> int {
         http_message_parser *msg_parser = static_cast<parser_context *>(parser->data)->parser;
         msg_parser->_stage = HTTP_ON_HEADER_FIELD;
-        if (strncmp(at, "Content-Type", length) == 0) {
+        if (utils::equals(at, "Content-Type", length)) {
             msg_parser->_is_field_content_type = true;
         }
         return 0;
diff --git a/src/http/pprof_http_service.cpp b/src/http/pprof_http_service.cpp
index 4b9d99003..4f11dc69b 100644
--- a/src/http/pprof_http_service.cpp
+++ b/src/http/pprof_http_service.cpp
@@ -17,25 +17,26 @@
 
 #ifdef DSN_ENABLE_GPERF
 
-#include <fcntl.h>
+#include "pprof_http_service.h"
 
-#include <cstdlib>
 #include <chrono>
+#include <cstdlib>
+#include <fcntl.h>
 #include <fstream>
 #include <sstream>
 
-#include "pprof_http_service.h"
+#include <gperftools/heap-profiler.h>
+#include <gperftools/malloc_extension.h>
+#include <gperftools/profiler.h>
 
-#include "utils/fmt_logging.h"
 #include "runtime/api_layer1.h"
+#include "utils/defer.h"
+#include "utils/fmt_logging.h"
 #include "utils/process_utils.h"
 #include "utils/string_conv.h"
-#include "utils/defer.h"
-#include "utils/timer.h"
 #include "utils/string_splitter.h"
-#include <gperftools/heap-profiler.h>
-#include <gperftools/malloc_extension.h>
-#include <gperftools/profiler.h>
+#include "utils/strings.h"
+#include "utils/timer.h"
 
 namespace dsn {
 
@@ -109,9 +110,9 @@ static int extract_symbols_from_binary(std::map<uintptr_t, std::string> &addr_ma
             continue;
         }
         const char *name_begin = sp.field();
-        if (strncmp(name_begin, "typeinfo ", 9) == 0 || strncmp(name_begin, "VTT ", 4) == 0 ||
-            strncmp(name_begin, "vtable ", 7) == 0 || strncmp(name_begin, "global ", 7) == 0 ||
-            strncmp(name_begin, "guard ", 6) == 0) {
+        if (utils::equals(name_begin, "typeinfo ", 9) || utils::equals(name_begin, "VTT ", 4) ||
+            utils::equals(name_begin, "vtable ", 7) || utils::equals(name_begin, "global ", 7) ||
+            utils::equals(name_begin, "guard ", 6)) {
             addr_map[addr] = std::string();
             continue;
         }
diff --git a/src/meta/meta_state_service_simple.cpp b/src/meta/meta_state_service_simple.cpp
index 9e8a8a408..fdc7af2bc 100644
--- a/src/meta/meta_state_service_simple.cpp
+++ b/src/meta/meta_state_service_simple.cpp
@@ -27,7 +27,6 @@
 #include "meta_state_service_simple.h"
 
 #include <fcntl.h>
-
 #include <stack>
 #include <utility>
 
@@ -35,6 +34,7 @@
 #include "runtime/task/task.h"
 #include "utils/filesystem.h"
 #include "utils/fmt_logging.h"
+#include "utils/strings.h"
 
 namespace dsn {
 namespace dist {
@@ -349,7 +349,7 @@ task_ptr meta_state_service_simple::submit_transaction(
                 op._node.push_back('/');
                 std::set<std::string>::iterator iter = snapshot.lower_bound(op._node);
                 if (iter != snapshot.end() && (*iter).length() >= op._node.length() &&
-                    memcmp((*iter).c_str(), op._node.c_str(), op._node.length()) == 0) {
+                    utils::mequals((*iter).c_str(), op._node.c_str(), op._node.length())) {
                     // op._node is the prefix of some path, so we regard this directory as not empty
                     op._result = ERR_INVALID_PARAMETERS;
                 } else {
@@ -507,5 +507,6 @@ meta_state_service_simple::~meta_state_service_simple()
     }
     _quick_map.clear();
 }
-}
-}
+
+} // namespace dist
+} // namespace dsn
diff --git a/src/meta/server_state.cpp b/src/meta/server_state.cpp
index 8751d6b3f..2c81cb881 100644
--- a/src/meta/server_state.cpp
+++ b/src/meta/server_state.cpp
@@ -34,24 +34,25 @@
  *     2016-04-25, Weijie Sun(sunweijie at xiaomi.com), refactor
  */
 
-#include "utils/fmt_logging.h"
-#include "common/replica_envs.h"
-#include "utils/factory_store.h"
-#include "utils/string_conv.h"
-#include "utils/strings.h"
-#include "runtime/task/task.h"
-#include "utils/command_manager.h"
-#include "runtime/task/async_calls.h"
-#include <sstream>
 #include <cinttypes>
+#include <sstream>
 #include <string>
+
 #include <boost/lexical_cast.hpp>
 
-#include "server_state.h"
-#include "server_load_balancer.h"
-#include "dump_file.h"
 #include "app_env_validator.h"
+#include "common/replica_envs.h"
+#include "dump_file.h"
 #include "meta_bulk_load_service.h"
+#include "runtime/task/async_calls.h"
+#include "runtime/task/task.h"
+#include "server_load_balancer.h"
+#include "server_state.h"
+#include "utils/command_manager.h"
+#include "utils/factory_store.h"
+#include "utils/fmt_logging.h"
+#include "utils/string_conv.h"
+#include "utils/strings.h"
 
 using namespace dsn;
 
@@ -112,8 +113,7 @@ void server_state::register_cli_commands()
             } else {
                 const char *target_file = nullptr;
                 for (int i = 0; i < args.size(); i += 2) {
-                    if (strcmp(args[i].c_str(), "-t") == 0 ||
-                        strcmp(args[i].c_str(), "--target") == 0)
+                    if (args[i] == "-t" || args[i] == "--target")
                         target_file = args[i + 1].c_str();
                 }
                 if (target_file == nullptr) {
@@ -382,7 +382,7 @@ error_code server_state::restore_from_local_storage(const char *local_path)
     CHECK_EQ_MSG(file->read_next_buffer(data), 1, "read format header failed");
     _all_apps.clear();
 
-    CHECK_EQ(memcmp(data.data(), "binary", 6), 0);
+    CHECK_TRUE(utils::mequals(data.data(), "binary", 6));
     while (true) {
         int ans = file->read_next_buffer(data);
         CHECK_NE_MSG(ans, -1, "read file failed");
@@ -434,7 +434,7 @@ error_code server_state::initialize_default_apps()
     app_info default_app;
     for (int i = 0; i < sections.size(); i++) {
         if (strstr(sections[i], "meta_server.apps") == sections[i] ||
-            strcmp(sections[i], "replication.app") == 0) {
+            utils::equals(sections[i], "replication.app")) {
             const char *s = sections[i];
 
             default_app.status = app_status::AS_CREATING;
diff --git a/src/meta/test/dump_file.cpp b/src/meta/test/dump_file.cpp
index 50ccab62e..bf502a9d0 100644
--- a/src/meta/test/dump_file.cpp
+++ b/src/meta/test/dump_file.cpp
@@ -25,7 +25,9 @@
  */
 
 #include <gtest/gtest.h>
+
 #include "meta/dump_file.h"
+#include "utils/strings.h"
 
 TEST(dump_file, read_write)
 {
@@ -78,7 +80,7 @@ TEST(dump_file, read_write)
         }
 
         ASSERT_EQ(block_offset, length_blocks.size());
-        ASSERT_EQ(memcmp(out_buffer.get(), buffer.get(), total_length), 0);
+        ASSERT_TRUE(dsn::utils::mequals(out_buffer.get(), buffer.get(), total_length));
     }
 
     // corrupted end
diff --git a/src/meta/test/json_compacity.cpp b/src/meta/test/json_compacity.cpp
index 60fb7739b..da5349cfb 100644
--- a/src/meta/test/json_compacity.cpp
+++ b/src/meta/test/json_compacity.cpp
@@ -97,7 +97,7 @@ void meta_service_test_app::json_compacity()
     ASSERT_EQ(234, pc.ballot);
     ASSERT_TRUE(pc.primary.is_invalid());
     ASSERT_EQ(1, pc.secondaries.size());
-    ASSERT_EQ(0, strcmp(pc.secondaries[0].to_string(), "127.0.0.1:6"));
+    ASSERT_STREQ("127.0.0.1:6", pc.secondaries[0].to_string());
     ASSERT_EQ(157, pc.last_committed_decree);
     ASSERT_EQ(0, pc.partition_flags);
 
diff --git a/src/meta/test/state_sync_test.cpp b/src/meta/test/state_sync_test.cpp
index 0a9c9be22..a30c635d9 100644
--- a/src/meta/test/state_sync_test.cpp
+++ b/src/meta/test/state_sync_test.cpp
@@ -26,30 +26,29 @@
 
 #include <cmath>
 #include <fstream>
-#include <vector>
 #include <iostream>
+#include <vector>
 
 #include <gtest/gtest.h>
-#include "runtime/api_task.h"
+
+#include "common/gpid.h"
+#include "meta/meta_service.h"
+#include "meta/server_state.h"
+#include "meta/test/misc/misc.h"
+#include "meta_service_test_app.h"
 #include "runtime/api_layer1.h"
+#include "runtime/api_task.h"
 #include "runtime/app_model.h"
-#include "utils/api_utilities.h"
-#include "utils/error_code.h"
-#include "utils/threadpool_code.h"
-#include "runtime/task/task_code.h"
-#include "common/gpid.h"
-#include "runtime/rpc/serialization.h"
 #include "runtime/rpc/rpc_stream.h"
+#include "runtime/rpc/serialization.h"
 #include "runtime/serverlet.h"
 #include "runtime/service_app.h"
+#include "runtime/task/task_code.h"
 #include "runtime/rpc/rpc_address.h"
-
-#include "meta/meta_service.h"
-#include "meta/server_state.h"
-
-#include "meta/test/misc/misc.h"
-
-#include "meta_service_test_app.h"
+#include "utils/api_utilities.h"
+#include "utils/error_code.h"
+#include "utils/strings.h"
+#include "utils/threadpool_code.h"
 
 namespace dsn {
 namespace replication {
@@ -105,7 +104,7 @@ static void file_data_compare(const char *fname1, const char *fname2)
         int up_to_bytes = length < (l - i) ? length : (l - i);
         ifile1.read(buf1, up_to_bytes);
         ifile2.read(buf2, up_to_bytes);
-        ASSERT_TRUE(memcmp(buf1, buf2, up_to_bytes) == 0);
+        ASSERT_TRUE(utils::mequals(buf1, buf2, up_to_bytes));
     }
 }
 
diff --git a/src/perf_counter/perf_counter.cpp b/src/perf_counter/perf_counter.cpp
index 302383bb4..128d19973 100644
--- a/src/perf_counter/perf_counter.cpp
+++ b/src/perf_counter/perf_counter.cpp
@@ -24,9 +24,10 @@
  * THE SOFTWARE.
  */
 
-#include <cstring>
 #include "perf_counter/perf_counter.h"
 
+#include "utils/strings.h"
+
 static const char *ctypes[] = {
     "NUMBER", "VOLATILE_NUMBER", "RATE", "PERCENTILE", "INVALID_COUNTER"};
 const char *dsn_counter_type_to_string(dsn_perf_counter_type_t t)
@@ -39,7 +40,7 @@ const char *dsn_counter_type_to_string(dsn_perf_counter_type_t t)
 dsn_perf_counter_type_t dsn_counter_type_from_string(const char *str)
 {
     for (int i = 0; i < COUNTER_TYPE_COUNT; ++i) {
-        if (strcmp(str, ctypes[i]) == 0)
+        if (dsn::utils::equals(str, ctypes[i]))
             return (dsn_perf_counter_type_t)i;
     }
     return COUNTER_TYPE_INVALID;
@@ -56,7 +57,7 @@ const char *dsn_percentile_type_to_string(dsn_perf_counter_percentile_type_t t)
 dsn_perf_counter_percentile_type_t dsn_percentile_type_from_string(const char *str)
 {
     for (int i = 0; i < COUNTER_PERCENTILE_COUNT; ++i) {
-        if (strcmp(str, ptypes[i]) == 0)
+        if (dsn::utils::equals(str, ptypes[i]))
             return (dsn_perf_counter_percentile_type_t)i;
     }
     return COUNTER_PERCENTILE_INVALID;
diff --git a/src/perf_counter/perf_counters.cpp b/src/perf_counter/perf_counters.cpp
index afe910978..c85bd8785 100644
--- a/src/perf_counter/perf_counters.cpp
+++ b/src/perf_counter/perf_counters.cpp
@@ -31,14 +31,15 @@
 
 #include "builtin_counters.h"
 #include "common/json_helper.h"
+#include "perf_counter/perf_counter.h"
 #include "perf_counter/perf_counter_atomic.h"
 #include "perf_counter/perf_counter_utils.h"
-#include "perf_counter/perf_counter.h"
 #include "runtime/service_app.h"
 #include "runtime/service_engine.h"
 #include "runtime/task/task.h"
 #include "utils/command_manager.h"
 #include "utils/string_view.h"
+#include "utils/strings.h"
 #include "utils/time_utils.h"
 
 namespace dsn {
@@ -139,7 +140,7 @@ perf_counters::perf_counters()
             return perf_counters::instance().list_snapshot_by_literal(
                 args, [](const std::string &arg, const counter_snapshot &cs) {
                     return cs.name.size() >= arg.size() &&
-                           ::memcmp(cs.name.c_str(), arg.c_str(), arg.size()) == 0;
+                           utils::mequals(cs.name.c_str(), arg.c_str(), arg.size());
                 });
         }));
     _cmds.emplace_back(command_manager::instance().register_command(
@@ -150,9 +151,9 @@ perf_counters::perf_counters()
             return perf_counters::instance().list_snapshot_by_literal(
                 args, [](const std::string &arg, const counter_snapshot &cs) {
                     return cs.name.size() >= arg.size() &&
-                           ::memcmp(cs.name.c_str() + cs.name.size() - arg.size(),
-                                    arg.c_str(),
-                                    arg.size()) == 0;
+                           utils::mequals(cs.name.c_str() + cs.name.size() - arg.size(),
+                                          arg.c_str(),
+                                          arg.size());
                 });
         }));
 
diff --git a/src/redis_protocol/proxy/main.cpp b/src/redis_protocol/proxy/main.cpp
index 811ad3179..b704053bc 100644
--- a/src/redis_protocol/proxy/main.cpp
+++ b/src/redis_protocol/proxy/main.cpp
@@ -18,14 +18,15 @@
  */
 
 #include <atomic>
-#include <unistd.h>
 #include <memory>
 #include <signal.h>
+#include <unistd.h>
 
 #include <pegasus/version.h>
 
-#include "reporter/pegasus_counter_reporter.h"
 #include "redis_parser.h"
+#include "reporter/pegasus_counter_reporter.h"
+#include "utils/strings.h"
 
 namespace pegasus {
 namespace proxy {
@@ -73,8 +74,8 @@ void signal_handler(int signal_id)
 int main(int argc, char **argv)
 {
     for (int i = 1; i < argc; ++i) {
-        if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-version") == 0 ||
-            strcmp(argv[i], "--version") == 0) {
+        if (dsn::utils::equals(argv[i], "-v") || dsn::utils::equals(argv[i], "-version") ||
+            dsn::utils::equals(argv[i], "--version")) {
             printf("Pegasus Redis Proxy %s\n", PEGASUS_VERSION);
             return 0;
         }
diff --git a/src/redis_protocol/proxy_lib/redis_parser.cpp b/src/redis_protocol/proxy_lib/redis_parser.cpp
index 135540df9..08b76ee5e 100644
--- a/src/redis_protocol/proxy_lib/redis_parser.cpp
+++ b/src/redis_protocol/proxy_lib/redis_parser.cpp
@@ -21,10 +21,10 @@
 
 #include <rocksdb/status.h>
 
-#include <rrdb/rrdb.client.h>
 #include <pegasus/error.h>
 #include <pegasus_key_schema.h>
 #include <pegasus_utils.h>
+#include <rrdb/rrdb.client.h>
 
 #include "base/pegasus_const.h"
 #include "common/replication_other_types.h"
@@ -939,7 +939,7 @@ void redis_parser::counter_internal(message_entry &entry)
     CHECK_GT(entry.request.sub_requests[0].length, 0);
     const char *command = entry.request.sub_requests[0].data.data();
     int64_t increment = 1;
-    if (strcasecmp(command, "INCR") == 0 || strcasecmp(command, "DECR") == 0) {
+    if (dsn::utils::iequals(command, "INCR") || dsn::utils::iequals(command, "DECR")) {
         if (entry.request.sub_requests.size() != 2) {
             LOG_WARNING_F("{}: command {} seqid({}) with invalid arguments count: {}",
                           _remote_address.to_string(),
@@ -949,7 +949,7 @@ void redis_parser::counter_internal(message_entry &entry)
             simple_error_reply(entry, fmt::format("wrong number of arguments for '{}'", command));
             return;
         }
-    } else if (strcasecmp(command, "INCRBY") == 0 || strcasecmp(command, "DECRBY") == 0) {
+    } else if (dsn::utils::iequals(command, "INCRBY") || dsn::utils::iequals(command, "DECRBY")) {
         if (entry.request.sub_requests.size() != 3) {
             LOG_WARNING_F("{}: command {} seqid({}) with invalid arguments count: {}",
                           _remote_address.to_string(),
@@ -972,7 +972,7 @@ void redis_parser::counter_internal(message_entry &entry)
     } else {
         LOG_FATAL_F("command not support: {}", command);
     }
-    if (strncasecmp(command, "DECR", 4) == 0) {
+    if (dsn::utils::iequals(command, "DECR", 4)) {
         increment = -increment;
     }
 
@@ -1017,7 +1017,7 @@ void redis_parser::parse_set_parameters(const std::vector<redis_bulk_string> &op
     ttl_seconds = 0;
     for (int i = 3; i < opts.size(); ++i) {
         const std::string &opt = opts[i].data.to_string();
-        if (strcasecmp(opt.c_str(), "EX") == 0 && i + 1 < opts.size()) {
+        if (dsn::utils::iequals(opt, "EX") && i + 1 < opts.size()) {
             const std::string &str_ttl_seconds = opts[i + 1].data.to_string();
             if (!dsn::buf2int32(str_ttl_seconds, ttl_seconds)) {
                 LOG_WARNING_F("'EX {}' option is error, use {}", str_ttl_seconds, ttl_seconds);
@@ -1067,20 +1067,20 @@ void redis_parser::parse_geo_radius_parameters(const std::vector<redis_bulk_stri
     // [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]
     while (base_index < opts.size()) {
         const std::string &opt = opts[base_index].data.to_string();
-        if (strcasecmp(opt.c_str(), "WITHCOORD") == 0) {
+        if (dsn::utils::iequals(opt, "WITHCOORD")) {
             WITHCOORD = true;
-        } else if (strcasecmp(opt.c_str(), "WITHDIST") == 0) {
+        } else if (dsn::utils::iequals(opt, "WITHDIST")) {
             WITHDIST = true;
-        } else if (strcasecmp(opt.c_str(), "WITHHASH") == 0) {
+        } else if (dsn::utils::iequals(opt, "WITHHASH")) {
             WITHHASH = true;
-        } else if (strcasecmp(opt.c_str(), "COUNT") == 0 && base_index + 1 < opts.size()) {
+        } else if (dsn::utils::iequals(opt, "COUNT") && base_index + 1 < opts.size()) {
             const std::string &str_count = opts[base_index + 1].data.to_string();
             if (!dsn::buf2int32(str_count, count)) {
                 LOG_ERROR_F("'COUNT {}' option is error, use {}", str_count, count);
             }
-        } else if (strcasecmp(opt.c_str(), "ASC") == 0) {
+        } else if (dsn::utils::iequals(opt, "ASC")) {
             sort_type = geo::geo_client::SortType::asc;
-        } else if (strcasecmp(opt.c_str(), "DESC") == 0) {
+        } else if (dsn::utils::iequals(opt, "DESC")) {
             sort_type = geo::geo_client::SortType::desc;
         }
         base_index++;
diff --git a/src/redis_protocol/proxy_ut/redis_proxy_test.cpp b/src/redis_protocol/proxy_ut/redis_proxy_test.cpp
index 1f1c950cc..e2b312a27 100644
--- a/src/redis_protocol/proxy_ut/redis_proxy_test.cpp
+++ b/src/redis_protocol/proxy_ut/redis_proxy_test.cpp
@@ -20,16 +20,18 @@
 #include <algorithm>
 #include <memory>
 #include <string>
-#include <boost/asio.hpp>
-
-#include "utils/string_conv.h"
-#include "utils/rand.h"
 
+#include <boost/asio.hpp>
 #include <gtest/gtest.h>
-#include <rrdb/rrdb.client.h>
+
 #include <pegasus_utils.h>
+#include <rrdb/rrdb.client.h>
+
 #include "proxy_layer.h"
 #include "redis_parser.h"
+#include "utils/string_conv.h"
+#include "utils/strings.h"
+#include "utils/rand.h"
 
 using namespace boost::asio;
 using namespace ::pegasus::proxy;
@@ -128,7 +130,8 @@ protected:
             ASSERT_EQ(bs1.length, bs2.length);
             if (bs1.length > 0) {
                 ASSERT_EQ(bs1.data.length(), bs2.data.length());
-                ASSERT_EQ(0, memcmp(bs1.data.data(), bs2.data.data(), bs2.data.length()));
+                ASSERT_TRUE(
+                    dsn::utils::mequals(bs1.data.data(), bs2.data.data(), bs2.data.length()));
             }
         }
 
@@ -572,8 +575,8 @@ TEST(proxy, connection)
             boost::asio::read(client_socket, boost::asio::buffer(got_reply, strlen(resps1)));
         got_reply[got_length] = 0;
         ASSERT_EQ(got_length, strlen(resps1));
-        ASSERT_TRUE(strncmp(got_reply, resps1, got_length) == 0 ||
-                    strncmp(got_reply, resps2, got_length) == 0);
+        ASSERT_TRUE(dsn::utils::equals(got_reply, resps1, got_length) ||
+                    dsn::utils::equals(got_reply, resps2, got_length));
     }
 
     {
diff --git a/src/replica/storage/simple_kv/test/case.cpp b/src/replica/storage/simple_kv/test/case.cpp
index 7ca5add5e..b78ac29e4 100644
--- a/src/replica/storage/simple_kv/test/case.cpp
+++ b/src/replica/storage/simple_kv/test/case.cpp
@@ -884,7 +884,7 @@ dsn::replication::config_type::type
 client_case_line::parse_config_command(const std::string &command_name) const
 {
     for (int i = 0; s_replica_config_commands[i] != nullptr; ++i) {
-        if (boost::iequals(command_name.c_str(), s_replica_config_commands[i])) {
+        if (boost::iequals(command_name, s_replica_config_commands[i])) {
             return (dsn::replication::config_type::type)i;
         }
     }
diff --git a/src/replica/storage/simple_kv/test/checker.cpp b/src/replica/storage/simple_kv/test/checker.cpp
index 91f3f5fb8..79d445bbe 100644
--- a/src/replica/storage/simple_kv/test/checker.cpp
+++ b/src/replica/storage/simple_kv/test/checker.cpp
@@ -171,13 +171,13 @@ bool test_checker::init(const std::string &name, const std::vector<service_app *
         PROVIDER_TYPE_MAIN);
 
     for (auto &app : _apps) {
-        if (0 == strcmp(app->info().type.c_str(), "meta")) {
+        if (app->info().type == "meta") {
             meta_service_app *meta_app = (meta_service_app *)app;
             meta_app->_service->_state->set_config_change_subscriber_for_test(
                 std::bind(&test_checker::on_config_change, this, std::placeholders::_1));
             meta_app->_service->_meta_opts.partition_guardian_type = "checker_partition_guardian";
             _meta_servers.push_back(meta_app);
-        } else if (0 == strcmp(app->info().type.c_str(), "replica")) {
+        } else if (app->info().type == "replica") {
             replication_service_app *replica_app = (replication_service_app *)app;
             replica_app->_stub->set_replica_state_subscriber_for_test(
                 std::bind(&test_checker::on_replica_state_change,
diff --git a/src/replica/test/mutation_log_learn_test.cpp b/src/replica/test/mutation_log_learn_test.cpp
index 862e57a81..38f4cedc7 100644
--- a/src/replica/test/mutation_log_learn_test.cpp
+++ b/src/replica/test/mutation_log_learn_test.cpp
@@ -24,13 +24,15 @@
  * THE SOFTWARE.
  */
 
+#include <chrono>
+#include <condition_variable>
+
+#include <gtest/gtest.h>
+
 #include "replica/mutation_log.h"
 #include "replica_test_base.h"
-
 #include "utils/filesystem.h"
-#include <gtest/gtest.h>
-#include <chrono>
-#include <condition_variable>
+#include "utils/strings.h"
 
 namespace dsn {
 namespace replication {
@@ -149,9 +151,9 @@ TEST_F(mutation_log_test, learn)
                 EXPECT_TRUE(wmu->data.updates.size() == mu->data.updates.size());
                 EXPECT_TRUE(wmu->data.updates[0].data.length() ==
                             mu->data.updates[0].data.length());
-                EXPECT_TRUE(memcmp((const void *)wmu->data.updates[0].data.data(),
-                                   (const void *)mu->data.updates[0].data.data(),
-                                   mu->data.updates[0].data.length()) == 0);
+                EXPECT_TRUE(utils::mequals(wmu->data.updates[0].data.data(),
+                                           mu->data.updates[0].data.data(),
+                                           mu->data.updates[0].data.length()));
                 EXPECT_TRUE(wmu->data.updates[0].code == mu->data.updates[0].code);
                 EXPECT_TRUE(wmu->client_requests.size() == mu->client_requests.size());
 
diff --git a/src/reporter/pegasus_counter_reporter.cpp b/src/reporter/pegasus_counter_reporter.cpp
index ead2a8e0c..a2f2d8315 100644
--- a/src/reporter/pegasus_counter_reporter.cpp
+++ b/src/reporter/pegasus_counter_reporter.cpp
@@ -19,27 +19,28 @@
 
 #include "pegasus_counter_reporter.h"
 
-#include <regex>
-#include <ios>
+#include <chrono>
 #include <iomanip>
+#include <ios>
 #include <iostream>
-#include <unistd.h>
-#include <chrono>
 #include <map>
 #include <memory>
+#include <regex>
 #include <string>
-#include <event2/event.h>
+#include <unistd.h>
+
 #include <event2/buffer.h>
+#include <event2/event.h>
 #include <event2/http.h>
 #include <event2/keyvalq_struct.h>
 
-#include "runtime/service_app.h"
-#include "common/common.h"
-#include "utils/fmt_logging.h"
-#include "utils/flags.h"
-
 #include "base/pegasus_utils.h"
+#include "common/common.h"
 #include "pegasus_io_service.h"
+#include "runtime/service_app.h"
+#include "utils/flags.h"
+#include "utils/fmt_logging.h"
+#include "utils/strings.h"
 
 using namespace ::dsn;
 
@@ -141,9 +142,9 @@ void pegasus_counter_reporter::start()
 
     _last_report_time_ms = dsn_now_ms();
 
-    if (strcmp("prometheus", FLAGS_perf_counter_sink) == 0) {
+    if (dsn::utils::iequals("prometheus", FLAGS_perf_counter_sink)) {
         _perf_counter_sink = perf_counter_sink_t::PROMETHEUS;
-    } else if (strcmp("falcon", FLAGS_perf_counter_sink) == 0) {
+    } else if (dsn::utils::iequals("falcon", FLAGS_perf_counter_sink)) {
         _perf_counter_sink = perf_counter_sink_t::FALCON;
     } else {
         _perf_counter_sink = perf_counter_sink_t::INVALID;
diff --git a/src/runtime/global_config.cpp b/src/runtime/global_config.cpp
index bb128f5ff..3eb06e2e0 100644
--- a/src/runtime/global_config.cpp
+++ b/src/runtime/global_config.cpp
@@ -326,7 +326,7 @@ bool service_spec::init_app_specs()
             all_section_names.push_back("apps.mimic");
         } else {
             auto type = dsn_config_get_value_string("apps.mimic", "type", "", "");
-            if (strcmp(type, mimic_app_role_name) != 0) {
+            if (!utils::equals(type, mimic_app_role_name)) {
                 printf("invalid config value '%s' for [apps.mimic] type", type);
                 return false;
             }
diff --git a/src/runtime/rpc/rpc_address.cpp b/src/runtime/rpc/rpc_address.cpp
index 50ed9db06..664ea1785 100644
--- a/src/runtime/rpc/rpc_address.cpp
+++ b/src/runtime/rpc/rpc_address.cpp
@@ -41,6 +41,7 @@
 #include "utils/safe_strerror_posix.h"
 #include "utils/string_conv.h"
 #include "utils/string_view.h"
+#include "utils/strings.h"
 
 namespace dsn {
 
@@ -100,7 +101,7 @@ uint32_t rpc_address::ipv4_from_network_interface(const char *network_interface)
             if (i->ifa_name != nullptr && i->ifa_addr != nullptr &&
                 i->ifa_addr->sa_family == AF_INET) {
                 uint32_t ip_val = ((struct sockaddr_in *)i->ifa_addr)->sin_addr.s_addr;
-                if (strcmp(i->ifa_name, network_interface) == 0 ||
+                if (utils::equals(i->ifa_name, network_interface) ||
                     (network_interface[0] == '\0' && !is_docker_netcard(i->ifa_name, ip_val) &&
                      is_site_local_address(ip_val))) {
                     ret = (uint32_t)ntohl(ip_val);
diff --git a/src/runtime/rpc/thrift_message_parser.cpp b/src/runtime/rpc/thrift_message_parser.cpp
index c806ba257..dd24ab6e3 100644
--- a/src/runtime/rpc/thrift_message_parser.cpp
+++ b/src/runtime/rpc/thrift_message_parser.cpp
@@ -26,18 +26,19 @@
 
 #include "thrift_message_parser.h"
 
-#include "runtime/api_task.h"
+#include "common/serialization_helper/dsn.layer2_types.h"
+#include "common/serialization_helper/thrift_helper.h"
 #include "runtime/api_layer1.h"
+#include "runtime/api_task.h"
 #include "runtime/app_model.h"
-#include "utils/api_utilities.h"
-#include "common/serialization_helper/thrift_helper.h"
-#include "common/serialization_helper/dsn.layer2_types.h"
 #include "runtime/message_utils.h"
-#include "utils/fmt_logging.h"
-#include "utils/ports.h"
+#include "runtime/rpc/rpc_message.h"
+#include "utils/api_utilities.h"
 #include "utils/crc.h"
 #include "utils/endians.h"
-#include "runtime/rpc/rpc_message.h"
+#include "utils/fmt_logging.h"
+#include "utils/ports.h"
+#include "utils/strings.h"
 
 namespace dsn {
 
@@ -149,7 +150,7 @@ bool thrift_message_parser::parse_request_header(message_reader *reader, int &re
 
     // The first 4 bytes is "THFT"
     data_input input(buf);
-    if (memcmp(buf.data(), "THFT", 4) != 0) {
+    if (!utils::mequals(buf.data(), "THFT", 4)) {
         LOG_ERROR("hdr_type mismatch %s", message_parser::get_debug_string(buf.data()).c_str());
         read_next = -1;
         return false;
diff --git a/src/runtime/service_api_c.cpp b/src/runtime/service_api_c.cpp
index e2ecd55d5..6ecf14141 100644
--- a/src/runtime/service_api_c.cpp
+++ b/src/runtime/service_api_c.cpp
@@ -24,37 +24,31 @@
  * THE SOFTWARE.
  */
 
-#include "service_engine.h"
-#include "utils/coredump.h"
-#include "runtime/rpc/rpc_engine.h"
-#include "runtime/task/task_engine.h"
-#include "runtime/security/init.h"
-
 #include <fstream>
 
-#include "runtime/api_task.h"
-#include "runtime/api_layer1.h"
-#include "runtime/app_model.h"
-#include "utils/api_utilities.h"
-#include "runtime/tool_api.h"
-#include "utils/command_manager.h"
-#include "runtime/rpc/serialization.h"
-#include "utils/filesystem.h"
-#include "utils/process_utils.h"
-#include "utils/flags.h"
-#include "utils/time_utils.h"
-#include "utils/errors.h"
-#include "utils/fmt_logging.h"
-
 #ifdef DSN_ENABLE_GPERF
 #include <gperftools/malloc_extension.h>
 #endif
 
-#include "service_engine.h"
+#include "runtime/api_layer1.h"
+#include "runtime/api_task.h"
+#include "runtime/app_model.h"
 #include "runtime/rpc/rpc_engine.h"
+#include "runtime/rpc/serialization.h"
+#include "runtime/security/init.h"
+#include "runtime/security/negotiation_manager.h"
+#include "runtime/service_engine.h"
 #include "runtime/task/task_engine.h"
+#include "runtime/tool_api.h"
+#include "utils/api_utilities.h"
+#include "utils/command_manager.h"
 #include "utils/coredump.h"
-#include "runtime/security/negotiation_manager.h"
+#include "utils/errors.h"
+#include "utils/filesystem.h"
+#include "utils/flags.h"
+#include "utils/fmt_logging.h"
+#include "utils/time_utils.h"
+#include "utils/process_utils.h"
 
 namespace dsn {
 namespace security {
@@ -253,13 +247,13 @@ void dsn_run(int argc, char **argv, bool is_server)
     std::string app_list = "";
 
     for (int i = 2; i < argc;) {
-        if (0 == strcmp(argv[i], "-cargs")) {
+        if (dsn::utils::equals(argv[i], "-cargs")) {
             if (++i < argc) {
                 config_args = std::string(argv[i++]);
             }
         }
 
-        else if (0 == strcmp(argv[i], "-app_list")) {
+        else if (dsn::utils::equals(argv[i], "-app_list")) {
             if (++i < argc) {
                 app_list = std::string(argv[i++]);
             }
diff --git a/src/runtime/test/main.cpp b/src/runtime/test/main.cpp
index 2526e253e..d7ec9d2e9 100644
--- a/src/runtime/test/main.cpp
+++ b/src/runtime/test/main.cpp
@@ -35,7 +35,9 @@
 
 #include <iostream>
 #include "gtest/gtest.h"
+
 #include "test_utils.h"
+#include "utils/strings.h"
 
 int g_test_count = 0;
 int g_test_ret = 0;
@@ -62,7 +64,8 @@ GTEST_API_ int main(int argc, char **argv)
         return g_test_ret;
     }
 
-    if (strcmp("simulator", dsn_config_get_value_string("core", "tool", "simulator", "")) != 0) {
+    if (!dsn::utils::equals("simulator",
+                            dsn_config_get_value_string("core", "tool", "simulator", ""))) {
         // run out-rDSN tests in other threads
         std::cout << "=========================================================== " << std::endl;
         std::cout << "================== run in non-rDSN threads ================ " << std::endl;
diff --git a/src/runtime/test/netprovider.cpp b/src/runtime/test/netprovider.cpp
index 62705d121..8e91337ac 100644
--- a/src/runtime/test/netprovider.cpp
+++ b/src/runtime/test/netprovider.cpp
@@ -94,7 +94,7 @@ void response_handler(dsn::error_code ec,
         std::string response_string;
         char *request_str = (char *)(request_buf);
         ::dsn::unmarshall(resp, response_string);
-        ASSERT_TRUE(strcmp(response_string.c_str(), request_str) == 0);
+        ASSERT_EQ(response_string, request_str);
     } else {
         LOG_INFO("error msg: %s", ec.to_string());
     }
diff --git a/src/runtime/test/rpc_message.cpp b/src/runtime/test/rpc_message.cpp
index 555a18d3d..54cab925e 100644
--- a/src/runtime/test/rpc_message.cpp
+++ b/src/runtime/test/rpc_message.cpp
@@ -202,7 +202,7 @@ TEST(rpc_message, create_receive_message_with_standalone_header)
 
     message_ptr msg = message_ex::create_receive_message_with_standalone_header(data);
     ASSERT_EQ(msg->buffers.size(), 2);
-    ASSERT_EQ(0, strcmp(msg->buffers[1].data(), data.data()));
+    ASSERT_STREQ(msg->buffers[1].data(), data.data());
     ASSERT_EQ(msg->header->body_length, data.length());
 }
 
@@ -214,7 +214,7 @@ TEST(rpc_message, copy_message_no_reply)
 
     auto msg = message_ex::copy_message_no_reply(*old_msg);
     ASSERT_EQ(msg->buffers.size(), old_msg->buffers.size());
-    ASSERT_EQ(0, strcmp(msg->buffers[1].data(), old_msg->buffers[1].data()));
+    ASSERT_STREQ(msg->buffers[1].data(), old_msg->buffers[1].data());
     ASSERT_EQ(msg->header->body_length, old_msg->header->body_length);
     ASSERT_EQ(msg->local_rpc_code, old_msg->local_rpc_code);
 
diff --git a/src/server/compaction_filter_rule.cpp b/src/server/compaction_filter_rule.cpp
index 8d6e93aa9..ec5deee7f 100644
--- a/src/server/compaction_filter_rule.cpp
+++ b/src/server/compaction_filter_rule.cpp
@@ -19,11 +19,12 @@
 
 #include "compaction_filter_rule.h"
 
-#include "utils/fmt_logging.h"
-#include "utils/string_view.h"
-#include "utils/api_utilities.h"
 #include "base/pegasus_utils.h"
 #include "base/pegasus_value_schema.h"
+#include "utils/api_utilities.h"
+#include "utils/fmt_logging.h"
+#include "utils/string_view.h"
+#include "utils/strings.h"
 
 namespace pegasus {
 namespace server {
@@ -40,11 +41,11 @@ bool string_pattern_match(dsn::string_view value,
     case string_match_type::SMT_MATCH_ANYWHERE:
         return value.find(filter_pattern) != dsn::string_view::npos;
     case string_match_type::SMT_MATCH_PREFIX:
-        return memcmp(value.data(), filter_pattern.data(), filter_pattern.length()) == 0;
+        return dsn::utils::mequals(value.data(), filter_pattern.data(), filter_pattern.length());
     case string_match_type::SMT_MATCH_POSTFIX:
-        return memcmp(value.data() + value.length() - filter_pattern.length(),
-                      filter_pattern.data(),
-                      filter_pattern.length()) == 0;
+        return dsn::utils::mequals(value.data() + value.length() - filter_pattern.length(),
+                                   filter_pattern.data(),
+                                   filter_pattern.length());
     default:
         LOG_ERROR_F("invalid match type {}", type);
         return false;
diff --git a/src/server/main.cpp b/src/server/main.cpp
index 344db2f69..f9ed0d81f 100644
--- a/src/server/main.cpp
+++ b/src/server/main.cpp
@@ -17,20 +17,6 @@
  * under the License.
  */
 
-#include "pegasus_server_impl.h"
-#include "pegasus_service_app.h"
-#include "info_collector_app.h"
-#include "compaction_operation.h"
-
-#include <pegasus/version.h>
-#include <pegasus/git_commit.h>
-
-#include "runtime/tool_api.h"
-#include "utils/command_manager.h"
-
-#include "replica/replication_service_app.h"
-#include "meta/meta_service_app.h"
-
 #include <cstdio>
 #include <cstring>
 #include <chrono>
@@ -38,6 +24,18 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <pegasus/version.h>
+#include <pegasus/git_commit.h>
+
+#include "compaction_operation.h"
+#include "info_collector_app.h"
+#include "meta/meta_service_app.h"
+#include "pegasus_server_impl.h"
+#include "pegasus_service_app.h"
+#include "replica/replication_service_app.h"
+#include "runtime/tool_api.h"
+#include "utils/command_manager.h"
+
 #define STR_I(var) #var
 #define STR(var) STR_I(var)
 #ifndef DSN_BUILD_TYPE
@@ -75,8 +73,8 @@ void dsn_app_registration_pegasus()
 int main(int argc, char **argv)
 {
     for (int i = 1; i < argc; ++i) {
-        if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-version") == 0 ||
-            strcmp(argv[i], "--version") == 0) {
+        if (utils::equals(argv[i], "-v") || utils::equals(argv[i], "-version") ||
+            utils::equals(argv[i], "--version")) {
             printf("Pegasus Server %s (%s) %s\n",
                    PEGASUS_VERSION,
                    PEGASUS_GIT_COMMIT,
diff --git a/src/server/pegasus_server_impl.cpp b/src/server/pegasus_server_impl.cpp
index 29e7abc46..2a9d28bc7 100644
--- a/src/server/pegasus_server_impl.cpp
+++ b/src/server/pegasus_server_impl.cpp
@@ -20,27 +20,29 @@
 #include "pegasus_server_impl.h"
 
 #include <algorithm>
+
 #include <boost/lexical_cast.hpp>
 #include <rocksdb/convenience.h>
 #include <rocksdb/utilities/checkpoint.h>
 #include <rocksdb/utilities/options_util.h>
-#include "utils/chrono_literals.h"
-#include "utils/utils.h"
-#include "utils/filesystem.h"
-#include "utils/string_conv.h"
-#include "utils/fmt_logging.h"
-#include "common/replication.codes.h"
-#include "utils/flags.h"
-#include "utils/token_bucket_throttling_controller.h"
-#include "common//duplication_common.h"
 
 #include "base/pegasus_key_schema.h"
-#include "base/pegasus_value_schema.h"
 #include "base/pegasus_utils.h"
+#include "base/pegasus_value_schema.h"
 #include "capacity_unit_calculator.h"
-#include "pegasus_server_write.h"
-#include "meta_store.h"
+#include "common/duplication_common.h"
+#include "common/replication.codes.h"
 #include "hotkey_collector.h"
+#include "meta_store.h"
+#include "pegasus_server_write.h"
+#include "utils/chrono_literals.h"
+#include "utils/filesystem.h"
+#include "utils/flags.h"
+#include "utils/fmt_logging.h"
+#include "utils/string_conv.h"
+#include "utils/strings.h"
+#include "utils/token_bucket_throttling_controller.h"
+#include "utils/utils.h"
 
 using namespace dsn::literals::chrono_literals;
 
@@ -2258,11 +2260,12 @@ bool pegasus_server_impl::validate_filter(::dsn::apps::filter_type::type filter_
         if (filter_type == ::dsn::apps::filter_type::FT_MATCH_ANYWHERE) {
             return dsn::string_view(value).find(filter_pattern) != dsn::string_view::npos;
         } else if (filter_type == ::dsn::apps::filter_type::FT_MATCH_PREFIX) {
-            return ::memcmp(value.data(), filter_pattern.data(), filter_pattern.length()) == 0;
+            return dsn::utils::mequals(
+                value.data(), filter_pattern.data(), filter_pattern.length());
         } else { // filter_type == ::dsn::apps::filter_type::FT_MATCH_POSTFIX
-            return ::memcmp(value.data() + value.length() - filter_pattern.length(),
-                            filter_pattern.data(),
-                            filter_pattern.length()) == 0;
+            return dsn::utils::mequals(value.data() + value.length() - filter_pattern.length(),
+                                       filter_pattern.data(),
+                                       filter_pattern.length());
         }
     }
     default:
diff --git a/src/server/pegasus_write_service_impl.h b/src/server/pegasus_write_service_impl.h
index 6fb15a0c5..16108b852 100644
--- a/src/server/pegasus_write_service_impl.h
+++ b/src/server/pegasus_write_service_impl.h
@@ -19,18 +19,18 @@
 
 #pragma once
 
-#include "pegasus_write_service.h"
-#include "pegasus_server_impl.h"
-#include "logging_utils.h"
+#include <gtest/gtest_prod.h>
 
 #include "base/pegasus_key_schema.h"
+#include "logging_utils.h"
 #include "meta_store.h"
+#include "pegasus_server_impl.h"
+#include "pegasus_write_service.h"
 #include "rocksdb_wrapper.h"
-
+#include "utils/defer.h"
 #include "utils/filesystem.h"
 #include "utils/string_conv.h"
-#include <gtest/gtest_prod.h>
-#include "utils/defer.h"
+#include "utils/strings.h"
 
 namespace pegasus {
 namespace server {
@@ -611,11 +611,12 @@ private:
             if (check_type == ::dsn::apps::cas_check_type::CT_VALUE_MATCH_ANYWHERE) {
                 return dsn::string_view(value).find(check_operand) != dsn::string_view::npos;
             } else if (check_type == ::dsn::apps::cas_check_type::CT_VALUE_MATCH_PREFIX) {
-                return ::memcmp(value.data(), check_operand.data(), check_operand.length()) == 0;
+                return dsn::utils::mequals(
+                    value.data(), check_operand.data(), check_operand.length());
             } else { // check_type == ::dsn::apps::cas_check_type::CT_VALUE_MATCH_POSTFIX
-                return ::memcmp(value.data() + value.length() - check_operand.length(),
-                                check_operand.data(),
-                                check_operand.length()) == 0;
+                return dsn::utils::mequals(value.data() + value.length() - check_operand.length(),
+                                           check_operand.data(),
+                                           check_operand.length());
             }
         }
         case ::dsn::apps::cas_check_type::CT_VALUE_BYTES_LESS:
diff --git a/src/shell/args.h b/src/shell/args.h
index 595f2fa0b..34baf1676 100644
--- a/src/shell/args.h
+++ b/src/shell/args.h
@@ -19,11 +19,12 @@
 
 #pragma once
 
-#include "runtime/app_model.h"
-#include "utils/defer.h"
+#include <string>
 
 #include "linenoise/linenoise.h"
+#include "runtime/app_model.h"
 #include "sds/sds.h"
+#include "utils/defer.h"
 
 inline sds *scanfCommand(int *argc)
 {
diff --git a/src/shell/command_helper.h b/src/shell/command_helper.h
index aff9b2adf..030cc4a04 100644
--- a/src/shell/command_helper.h
+++ b/src/shell/command_helper.h
@@ -20,37 +20,38 @@
 #pragma once
 
 #include <getopt.h>
-#include <thread>
-#include <iomanip>
 #include <fstream>
+#include <iomanip>
 #include <queue>
+#include <thread>
+
 #include <boost/algorithm/string.hpp>
 #include <rocksdb/db.h>
-#include <rocksdb/sst_dump_tool.h>
 #include <rocksdb/env.h>
+#include <rocksdb/sst_dump_tool.h>
 #include <rocksdb/statistics.h>
-#include "common/json_helper.h"
-#include "remote_cmd/remote_command.h"
-#include "client/replication_ddl_client.h"
-#include "tools/mutation_log_tool.h"
-#include "perf_counter/perf_counter_utils.h"
-#include "utils/string_view.h"
-#include "utils/synchronize.h"
-#include "utils/time_utils.h"
 
+#include <geo/lib/geo_client.h>
+#include <pegasus/error.h>
+#include <pegasus/git_commit.h>
+#include <pegasus/version.h>
 #include <rrdb/rrdb.code.definition.h>
 #include <rrdb/rrdb_types.h>
-#include <pegasus/version.h>
-#include <pegasus/git_commit.h>
-#include <pegasus/error.h>
-#include <geo/lib/geo_client.h>
 
 #include "base/pegasus_key_schema.h"
-#include "base/pegasus_value_schema.h"
 #include "base/pegasus_utils.h"
-
+#include "base/pegasus_value_schema.h"
+#include "client/replication_ddl_client.h"
 #include "command_executor.h"
 #include "command_utils.h"
+#include "common/json_helper.h"
+#include "perf_counter/perf_counter_utils.h"
+#include "remote_cmd/remote_command.h"
+#include "tools/mutation_log_tool.h"
+#include "utils/string_view.h"
+#include "utils/strings.h"
+#include "utils/synchronize.h"
+#include "utils/time_utils.h"
 
 using namespace dsn::replication;
 
@@ -250,11 +251,12 @@ inline bool validate_filter(pegasus::pegasus_client::filter_type filter_type,
         if (filter_type == pegasus::pegasus_client::FT_MATCH_ANYWHERE) {
             return dsn::string_view(value).find(filter_pattern) != dsn::string_view::npos;
         } else if (filter_type == pegasus::pegasus_client::FT_MATCH_PREFIX) {
-            return ::memcmp(value.data(), filter_pattern.data(), filter_pattern.length()) == 0;
+            return dsn::utils::mequals(
+                value.data(), filter_pattern.data(), filter_pattern.length());
         } else { // filter_type == pegasus::pegasus_client::FT_MATCH_POSTFIX
-            return ::memcmp(value.data() + value.length() - filter_pattern.length(),
-                            filter_pattern.data(),
-                            filter_pattern.length()) == 0;
+            return dsn::utils::mequals(value.data() + value.length() - filter_pattern.length(),
+                                       filter_pattern.data(),
+                                       filter_pattern.length());
         }
     }
     default:
diff --git a/src/shell/command_utils.h b/src/shell/command_utils.h
index 3550dc6dd..95771e151 100644
--- a/src/shell/command_utils.h
+++ b/src/shell/command_utils.h
@@ -20,11 +20,12 @@
 #pragma once
 
 #include <map>
-#include <string>
 #include <set>
+#include <string>
 
 #include "shell/argh.h"
 #include "utils/fmt_logging.h"
+#include "utils/strings.h"
 
 namespace dsn {
 class rpc_address;
@@ -75,31 +76,13 @@ bool validate_ip(shell_context *sc,
         }                                                                                          \
     } while (0)
 
-inline int strcmp_ignore_case(const char *left, const char *right)
-{
-    int pos = 0;
-    while (left[pos] && right[pos]) {
-        char left_c = ::tolower(left[pos]);
-        char right_c = ::tolower(right[pos]);
-        if (left_c < right_c)
-            return -1;
-        if (left_c > right_c)
-            return 1;
-        ++pos;
-    }
-    if (left[pos]) {
-        return 1;
-    }
-    return right[pos] ? -1 : 0;
-}
-
 template <typename EnumType>
 EnumType type_from_string(const std::map<int, const char *> &type_maps,
                           const std::string &type_string,
                           const EnumType &default_type)
 {
     for (auto it = type_maps.begin(); it != type_maps.end(); it++) {
-        if (strcmp_ignore_case(type_string.c_str(), it->second) == 0) {
+        if (dsn::utils::iequals(type_string, it->second)) {
             return (EnumType)it->first;
         }
     }
diff --git a/src/shell/commands/detect_hotkey.cpp b/src/shell/commands/detect_hotkey.cpp
index 094f83233..e7d8afbce 100644
--- a/src/shell/commands/detect_hotkey.cpp
+++ b/src/shell/commands/detect_hotkey.cpp
@@ -15,15 +15,16 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include "shell/commands.h"
-#include "shell/argh.h"
-#include "meta_admin_types.h"
-#include "partition_split_types.h"
-#include "duplication_types.h"
-#include "bulk_load_types.h"
 #include "backup_types.h"
+#include "bulk_load_types.h"
 #include "consensus_types.h"
+#include "duplication_types.h"
+#include "meta_admin_types.h"
+#include "partition_split_types.h"
 #include "replica_admin_types.h"
+#include "shell/argh.h"
+#include "shell/commands.h"
+#include "utils/strings.h"
 
 bool generate_hotkey_request(dsn::replication::detect_hotkey_request &req,
                              const std::string &hotkey_action,
@@ -32,9 +33,9 @@ bool generate_hotkey_request(dsn::replication::detect_hotkey_request &req,
                              int partition_index,
                              std::string &err_info)
 {
-    if (!strcasecmp(hotkey_type.c_str(), "read")) {
+    if (dsn::utils::iequals(hotkey_type, "read")) {
         req.type = dsn::replication::hotkey_type::type::READ;
-    } else if (!strcasecmp(hotkey_type.c_str(), "write")) {
+    } else if (dsn::utils::iequals(hotkey_type, "write")) {
         req.type = dsn::replication::hotkey_type::type::WRITE;
     } else {
         err_info = fmt::format("\"{}\" is an invalid hotkey type (should be 'read' or 'write')\n",
@@ -42,11 +43,11 @@ bool generate_hotkey_request(dsn::replication::detect_hotkey_request &req,
         return false;
     }
 
-    if (!strcasecmp(hotkey_action.c_str(), "start")) {
+    if (dsn::utils::iequals(hotkey_action, "start")) {
         req.action = dsn::replication::detect_action::START;
-    } else if (!strcasecmp(hotkey_action.c_str(), "stop")) {
+    } else if (dsn::utils::iequals(hotkey_action, "stop")) {
         req.action = dsn::replication::detect_action::STOP;
-    } else if (!strcasecmp(hotkey_action.c_str(), "query")) {
+    } else if (dsn::utils::iequals(hotkey_action, "query")) {
         req.action = dsn::replication::detect_action::QUERY;
     } else {
         err_info =
diff --git a/src/shell/commands/global_properties.cpp b/src/shell/commands/global_properties.cpp
index 31a57c552..b0bc9a4d1 100644
--- a/src/shell/commands/global_properties.cpp
+++ b/src/shell/commands/global_properties.cpp
@@ -18,6 +18,7 @@
  */
 
 #include "shell/commands.h"
+#include "utils/strings.h"
 
 bool use_app_as_current(command_executor *e, shell_context *sc, arguments args)
 {
@@ -44,11 +45,11 @@ bool process_escape_all(command_executor *e, shell_context *sc, arguments args)
         fprintf(stderr, "Current escape_all: %s.\n", sc->escape_all ? "true" : "false");
         return true;
     } else if (args.argc == 2) {
-        if (strcmp(args.argv[1], "true") == 0) {
+        if (dsn::utils::iequals(args.argv[1], "true")) {
             sc->escape_all = true;
             fprintf(stderr, "OK\n");
             return true;
-        } else if (strcmp(args.argv[1], "false") == 0) {
+        } else if (dsn::utils::iequals(args.argv[1], "false")) {
             sc->escape_all = false;
             fprintf(stderr, "OK\n");
             return true;
diff --git a/src/shell/main.cpp b/src/shell/main.cpp
index d877ecee4..30333fd33 100644
--- a/src/shell/main.cpp
+++ b/src/shell/main.cpp
@@ -17,15 +17,17 @@
  * under the License.
  */
 
-#include <pegasus/version.h>
-#include "utils/strings.h"
+#include <algorithm>
 #include <setjmp.h>
 #include <signal.h>
-#include <algorithm>
+
+#include <pegasus/version.h>
+
 #include "args.h"
+#include "base/pegasus_const.h"
 #include "command_executor.h"
 #include "commands.h"
-#include "base/pegasus_const.h"
+#include "utils/strings.h"
 
 std::map<std::string, command_executor *> s_commands_map;
 shell_context s_global_context;
@@ -590,7 +592,7 @@ static void completionCallback(const char *buf, linenoiseCompletions *lc)
         const command_executor &c = commands[i];
 
         size_t matchlen = strlen(buf);
-        if (strncasecmp(buf, c.name, matchlen) == 0) {
+        if (dsn::utils::iequals(buf, c.name, matchlen)) {
             linenoiseAddCompletion(lc, c.name);
         }
     }
@@ -612,7 +614,7 @@ static char *hintsCallback(const char *buf, int *color, int *bold)
     bool endWithSpace = buflen && isspace(buf[buflen - 1]);
 
     for (int i = 0; commands[i].name != nullptr; ++i) {
-        if (strcasecmp(argv[0], commands[i].name) == 0) {
+        if (dsn::utils::iequals(argv[0], commands[i].name)) {
             *color = 90;
             *bold = 0;
             sds hint = sdsnew(commands[i].option_usage);
diff --git a/src/test/kill_test/main.cpp b/src/test/kill_test/main.cpp
index 225e121fb..fc7299ad4 100644
--- a/src/test/kill_test/main.cpp
+++ b/src/test/kill_test/main.cpp
@@ -23,6 +23,7 @@
 #include "data_verifier.h"
 #include "process_kill_testor.h"
 #include "partition_kill_testor.h"
+#include "utils/strings.h"
 
 int main(int argc, const char **argv)
 {
@@ -30,13 +31,13 @@ int main(int argc, const char **argv)
         printf("invalid arguments: pegasus_kill_test configfile "
                "worker_type(verifier|process_killer|partition_killer)\n");
         return -1;
-    } else if (strcmp(argv[2], "verifier") == 0) {
+    } else if (dsn::utils::equals(argv[2], "verifier")) {
         verifier_initialize(argv[1]);
         verifier_start();
-    } else if (strcmp(argv[2], "process_killer") == 0) {
+    } else if (dsn::utils::equals(argv[2], "process_killer")) {
         pegasus::test::kill_testor *killtestor = new pegasus::test::process_kill_testor(argv[1]);
         killtestor->Run();
-    } else if (strcmp(argv[2], "partition_killer") == 0) {
+    } else if (dsn::utils::equals(argv[2], "partition_killer")) {
         pegasus::test::kill_testor *killtestor = new pegasus::test::partition_kill_testor(argv[1]);
         killtestor->Run();
     } else {
diff --git a/src/utils/fmt_logging.h b/src/utils/fmt_logging.h
index 864a69453..b3de93b0f 100644
--- a/src/utils/fmt_logging.h
+++ b/src/utils/fmt_logging.h
@@ -57,8 +57,63 @@
 #define LOG_ERROR_PREFIX(...) LOG_ERROR_F("[{}] {}", log_prefix(), fmt::format(__VA_ARGS__))
 #define LOG_FATAL_PREFIX(...) LOG_FATAL_F("[{}] {}", log_prefix(), fmt::format(__VA_ARGS__))
 
+namespace {
+
+inline const char *null_str_printer(const char *s) { return s == nullptr ? "(null)" : s; }
+
+} // anonymous namespace
+
 // Macros to check expected condition. It will abort the application
 // and log a fatal message when the condition is not met.
+
+#define CHECK_STREQ_MSG(var1, var2, ...)                                                           \
+    do {                                                                                           \
+        const auto &_v1 = (var1);                                                                  \
+        const auto &_v2 = (var2);                                                                  \
+        CHECK_EXPRESSION(var1 == var2,                                                             \
+                         dsn::utils::equals(_v1, _v2),                                             \
+                         "{} vs {} {}",                                                            \
+                         null_str_printer(_v1),                                                    \
+                         null_str_printer(_v2),                                                    \
+                         fmt::format(__VA_ARGS__));                                                \
+    } while (false)
+
+#define CHECK_STRNE_MSG(var1, var2, ...)                                                           \
+    do {                                                                                           \
+        const auto &_v1 = (var1);                                                                  \
+        const auto &_v2 = (var2);                                                                  \
+        CHECK_EXPRESSION(var1 != var2,                                                             \
+                         !dsn::utils::equals(_v1, _v2),                                            \
+                         "{} vs {} {}",                                                            \
+                         null_str_printer(_v1),                                                    \
+                         null_str_printer(_v2),                                                    \
+                         fmt::format(__VA_ARGS__));                                                \
+    } while (false)
+
+#define CHECK_STRCASEEQ_MSG(var1, var2, ...)                                                       \
+    do {                                                                                           \
+        const auto &_v1 = (var1);                                                                  \
+        const auto &_v2 = (var2);                                                                  \
+        CHECK_EXPRESSION(var1 == var2,                                                             \
+                         dsn::utils::iequals(_v1, _v2),                                            \
+                         "{} vs {} {}",                                                            \
+                         null_str_printer(_v1),                                                    \
+                         null_str_printer(_v2),                                                    \
+                         fmt::format(__VA_ARGS__));                                                \
+    } while (false)
+
+#define CHECK_STRCASENE_MSG(var1, var2, ...)                                                       \
+    do {                                                                                           \
+        const auto &_v1 = (var1);                                                                  \
+        const auto &_v2 = (var2);                                                                  \
+        CHECK_EXPRESSION(var1 != var2,                                                             \
+                         !dsn::utils::iequals(_v1, _v2),                                           \
+                         "{} vs {} {}",                                                            \
+                         null_str_printer(_v1),                                                    \
+                         null_str_printer(_v2),                                                    \
+                         fmt::format(__VA_ARGS__));                                                \
+    } while (false)
+
 #define CHECK_NE_MSG(var1, var2, ...)                                                              \
     do {                                                                                           \
         const auto &_v1 = (var1);                                                                  \
@@ -107,6 +162,9 @@
             var1 < var2, _v1 < _v2, "{} vs {} {}", _v1, _v2, fmt::format(__VA_ARGS__));            \
     } while (false)
 
+#define CHECK_STREQ(var1, var2) CHECK_STREQ_MSG(var1, var2, "")
+#define CHECK_STRNE(var1, var2) CHECK_STRNE_MSG(var1, var2, "")
+
 #define CHECK_NE(var1, var2) CHECK_NE_MSG(var1, var2, "")
 #define CHECK_EQ(var1, var2) CHECK_EQ_MSG(var1, var2, "")
 #define CHECK_GE(var1, var2) CHECK_GE_MSG(var1, var2, "")
@@ -114,6 +172,9 @@
 #define CHECK_GT(var1, var2) CHECK_GT_MSG(var1, var2, "")
 #define CHECK_LT(var1, var2) CHECK_LT_MSG(var1, var2, "")
 
+#define CHECK_TRUE(var) CHECK_EQ(var, true)
+#define CHECK_FALSE(var) CHECK_EQ(var, false)
+
 // TODO(yingchun): add CHECK_NULL(ptr), CHECK_OK(err), CHECK(cond)
 
 #define CHECK_EXPRESSION_PREFIX_MSG(expression, evaluation, ...)                                   \
diff --git a/src/utils/long_adder_bench/long_adder_bench.cpp b/src/utils/long_adder_bench/long_adder_bench.cpp
index be11784b8..9a0879c76 100644
--- a/src/utils/long_adder_bench/long_adder_bench.cpp
+++ b/src/utils/long_adder_bench/long_adder_bench.cpp
@@ -27,6 +27,7 @@
 #include "utils/long_adder.h"
 #include "utils/process_utils.h"
 #include "utils/string_conv.h"
+#include "utils/strings.h"
 
 // The simplest implementation of long adder: just wrap std::atomic<int64_t>.
 class simple_long_adder
@@ -179,13 +180,13 @@ int main(int argc, char **argv)
     }
 
     const char *long_adder_type = argv[3];
-    if (strcmp(long_adder_type, "simple_long_adder") == 0) {
+    if (dsn::utils::equals(long_adder_type, "simple_long_adder")) {
         run_bench<simple_long_adder>(num_operations, num_threads, long_adder_type);
-    } else if (strcmp(long_adder_type, "divided_long_adder") == 0) {
+    } else if (dsn::utils::equals(long_adder_type, "divided_long_adder")) {
         run_bench<divided_long_adder>(num_operations, num_threads, long_adder_type);
-    } else if (strcmp(long_adder_type, "striped_long_adder") == 0) {
+    } else if (dsn::utils::equals(long_adder_type, "striped_long_adder")) {
         run_bench<dsn::striped_long_adder>(num_operations, num_threads, long_adder_type);
-    } else if (strcmp(long_adder_type, "concurrent_long_adder") == 0) {
+    } else if (dsn::utils::equals(long_adder_type, "concurrent_long_adder")) {
         run_bench<dsn::concurrent_long_adder>(num_operations, num_threads, long_adder_type);
     } else {
         fmt::print(stderr, "Invalid long_adder_type: {}\n\n", long_adder_type);
diff --git a/src/utils/metrics.cpp b/src/utils/metrics.cpp
index df9fc9df0..d5ea0f302 100644
--- a/src/utils/metrics.cpp
+++ b/src/utils/metrics.cpp
@@ -340,12 +340,13 @@ metric_entity_ptr metric_registry::find_or_create_entity(const metric_entity_pro
         entity = new metric_entity(prototype, id, attrs);
         _entities[id] = entity;
     } else {
-        CHECK_EQ_MSG(std::strcmp(prototype->name(), iter->second->prototype()->name()),
-                     0,
-                     "new prototype '{}' is inconsistent with old prototype '{}' for entity '{}'",
-                     prototype->name(),
-                     iter->second->prototype()->name(),
-                     id);
+        CHECK_STREQ_MSG(
+            prototype->name(),
+            iter->second->prototype()->name(),
+            "new prototype '{}' is inconsistent with old prototype '{}' for entity '{}'",
+            prototype->name(),
+            iter->second->prototype()->name(),
+            id);
 
         iter->second->set_attributes(attrs);
         entity = iter->second;
diff --git a/src/utils/metrics.h b/src/utils/metrics.h
index 0d8493850..c7c1bda18 100644
--- a/src/utils/metrics.h
+++ b/src/utils/metrics.h
@@ -47,6 +47,7 @@
 #include "utils/ports.h"
 #include "utils/singleton.h"
 #include "utils/string_view.h"
+#include "utils/strings.h"
 #include "utils/synchronize.h"
 
 // A metric library (for details pls see https://github.com/apache/incubator-pegasus/issues/922)
@@ -481,14 +482,14 @@ template <typename MetricType, typename... Args>
 ref_ptr<MetricType> metric_entity::find_or_create(const metric_prototype *prototype,
                                                   Args &&... args)
 {
-    CHECK_EQ_MSG(std::strcmp(prototype->entity_type().data(), _prototype->name()),
-                 0,
-                 "the entity type '{}' of the metric '{}' is inconsistent with the prototype "
-                 "'{}' of the attached entity '{}'",
-                 prototype->entity_type().data(),
-                 prototype->name().data(),
-                 _prototype->name(),
-                 _id);
+    CHECK_STREQ_MSG(prototype->entity_type().data(),
+                    _prototype->name(),
+                    "the entity type '{}' of the metric '{}' is inconsistent with the prototype "
+                    "'{}' of the attached entity '{}'",
+                    prototype->entity_type().data(),
+                    prototype->name().data(),
+                    _prototype->name(),
+                    _id);
 
     utils::auto_write_lock l(_lock);
 
diff --git a/src/utils/simple_logger.cpp b/src/utils/simple_logger.cpp
index b00b06b50..74c130236 100644
--- a/src/utils/simple_logger.cpp
+++ b/src/utils/simple_logger.cpp
@@ -31,6 +31,7 @@
 
 #include "utils/filesystem.h"
 #include "utils/flags.h"
+#include "utils/strings.h"
 #include "utils/time_utils.h"
 
 DSN_DECLARE_string(logging_start_level);
@@ -55,7 +56,7 @@ DSN_DEFINE_string("tools.simple_logger",
                   "LOG_LEVEL_WARNING",
                   "copy log messages at or above this level to stderr in addition to logfiles");
 DSN_DEFINE_validator(stderr_start_level, [](const char *level) -> bool {
-    return strcmp(level, "LOG_LEVEL_INVALID") != 0;
+    return !utils::equals(level, "LOG_LEVEL_INVALID");
 });
 
 static void print_header(FILE *fp, dsn_log_level_t log_level)
diff --git a/src/utils/string_view.cpp b/src/utils/string_view.cpp
index fe6e6a4a9..d49fffea5 100644
--- a/src/utils/string_view.cpp
+++ b/src/utils/string_view.cpp
@@ -17,8 +17,9 @@
 
 #include <ostream>
 
-#include "blob.h"
-#include "memutil.h"
+#include "utils/blob.h"
+#include "utils/memutil.h"
+#include "utils/strings.h"
 
 namespace dsn {
 
@@ -76,10 +77,11 @@ const char *memmatch(const char *phaystack, size_t haylen, const char *pneedle,
     // A static cast is used here to work around the fact that memchr returns
     // a void* on Posix-compliant systems and const void* on Windows.
     while ((match = static_cast<const char *>(memchr(phaystack, pneedle[0], hayend - phaystack)))) {
-        if (memcmp(match, pneedle, neelen) == 0)
+        if (utils::mequals(match, pneedle, neelen)) {
             return match;
-        else
+        } else {
             phaystack = match + 1;
+        }
     }
     return nullptr;
 }
diff --git a/src/utils/string_view.h b/src/utils/string_view.h
index b83bcc13f..b8cd2255c 100644
--- a/src/utils/string_view.h
+++ b/src/utils/string_view.h
@@ -350,7 +350,7 @@ public:
     {
         auto min_length = std::min(length_, x.length_);
         if (min_length > 0) {
-            int r = memcmp(ptr_, x.ptr_, min_length);
+            int r = std::memcmp(ptr_, x.ptr_, min_length);
             if (r < 0)
                 return -1;
             if (r > 0)
@@ -417,7 +417,7 @@ inline bool operator==(string_view x, string_view y) noexcept
     if (len != y.size()) {
         return false;
     }
-    return x.data() == y.data() || len <= 0 || memcmp(x.data(), y.data(), len) == 0;
+    return x.data() == y.data() || len <= 0 || std::memcmp(x.data(), y.data(), len) == 0;
 }
 
 inline bool operator!=(string_view x, string_view y) noexcept { return !(x == y); }
diff --git a/src/utils/strings.cpp b/src/utils/strings.cpp
index fb90cf844..81f352a91 100644
--- a/src/utils/strings.cpp
+++ b/src/utils/strings.cpp
@@ -27,9 +27,11 @@
 #include <algorithm>
 #include <cstring>
 #include <sstream>
+#include <strings.h>
 #include <utility>
 
 #include <openssl/md5.h>
+
 #include "utils/api_utilities.h"
 #include "utils/fmt_logging.h"
 #include "utils/ports.h"
@@ -38,6 +40,80 @@
 namespace dsn {
 namespace utils {
 
+#define CHECK_NULL_PTR(lhs, rhs)                                                                   \
+    do {                                                                                           \
+        if (lhs == nullptr) {                                                                      \
+            return rhs == nullptr;                                                                 \
+        }                                                                                          \
+        if (rhs == nullptr) {                                                                      \
+            return false;                                                                          \
+        }                                                                                          \
+    } while (0)
+
+bool equals(const char *lhs, const char *rhs)
+{
+    CHECK_NULL_PTR(lhs, rhs);
+    return std::strcmp(lhs, rhs) == 0;
+}
+
+bool equals(const char *lhs, const char *rhs, size_t n)
+{
+    CHECK_NULL_PTR(lhs, rhs);
+    return std::strncmp(lhs, rhs, n) == 0;
+}
+
+bool iequals(const char *lhs, const char *rhs)
+{
+    CHECK_NULL_PTR(lhs, rhs);
+    return ::strcasecmp(lhs, rhs) == 0;
+}
+
+bool iequals(const char *lhs, const char *rhs, size_t n)
+{
+    CHECK_NULL_PTR(lhs, rhs);
+    return ::strncasecmp(lhs, rhs, n) == 0;
+}
+
+bool iequals(const std::string &lhs, const char *rhs)
+{
+    if (rhs == nullptr) {
+        return false;
+    }
+    return ::strcasecmp(lhs.c_str(), rhs) == 0;
+}
+
+bool iequals(const std::string &lhs, const char *rhs, size_t n)
+{
+    if (rhs == nullptr) {
+        return false;
+    }
+    return ::strncasecmp(lhs.c_str(), rhs, n) == 0;
+}
+
+bool iequals(const char *lhs, const std::string &rhs)
+{
+    if (lhs == nullptr) {
+        return false;
+    }
+    return ::strcasecmp(lhs, rhs.c_str()) == 0;
+}
+
+bool iequals(const char *lhs, const std::string &rhs, size_t n)
+{
+    if (lhs == nullptr) {
+        return false;
+    }
+    return ::strncasecmp(lhs, rhs.c_str(), n) == 0;
+}
+
+bool mequals(const void *lhs, const void *rhs, size_t n)
+{
+    CHECK_NULL_PTR(lhs, rhs);
+    return std::memcmp(lhs, rhs, n) == 0;
+}
+
+#undef CHECK_NULL_PTR
+
 std::string get_last_component(const std::string &input, const char splitters[])
 {
     int index = -1;
diff --git a/src/utils/strings.h b/src/utils/strings.h
index 79cdb7a7e..f5c03f479 100644
--- a/src/utils/strings.h
+++ b/src/utils/strings.h
@@ -38,6 +38,29 @@ namespace utils {
 
 inline bool is_empty(const char *str) { return str == nullptr || *str == '\0'; }
 
+// Decide whether two C strings are equal, even if one of them is NULL.
+// The second function is similar except it compares the only first (at most) n bytes
+// of both strings.
+bool equals(const char *lhs, const char *rhs);
+bool equals(const char *lhs, const char *rhs, size_t n);
+
+// Decide whether two C strings are equal, ignoring the case of the characters,
+// even if one of them is NULL.
+// The second function is similar except it compares the only first (at most) n bytes
+// of both strings.
+bool iequals(const char *lhs, const char *rhs);
+bool iequals(const char *lhs, const char *rhs, size_t n);
+
+// Decide whether two strings one of which is C string are equal, ignoring the
+// case of the characters, even if the C string is NULL.
+bool iequals(const std::string &lhs, const char *rhs);
+bool iequals(const std::string &lhs, const char *rhs, size_t n);
+bool iequals(const char *lhs, const std::string &rhs);
+bool iequals(const char *lhs, const std::string &rhs, size_t n);
+
+// Decide whether the first n bytes of two memory areas are equal, even if one of them is NULL.
+bool mequals(const void *lhs, const void *rhs, size_t n);
+
 // Split the `input` string by the only character `separator` into tokens. Leading and trailing
 // spaces of each token will be stripped. Once the token is empty, or become empty after
 // stripping, an empty string will be added into `output` if `keep_place_holder` is enabled.
diff --git a/src/utils/test/flag_test.cpp b/src/utils/test/flag_test.cpp
index 195ea911d..3f7c958e6 100644
--- a/src/utils/test/flag_test.cpp
+++ b/src/utils/test/flag_test.cpp
@@ -160,7 +160,7 @@ TEST(flag_test, update_config)
     // string modifications are not supported
     res = update_flag("test_string_immutable", "update_string");
     ASSERT_EQ(res.code(), ERR_INVALID_PARAMETERS);
-    ASSERT_EQ(strcmp(FLAGS_test_string_immutable, "immutable_string"), 0);
+    ASSERT_STREQ("immutable_string", FLAGS_test_string_immutable);
 
     // test flag is not exist
     res = update_flag("test_not_exist", "test_string");
diff --git a/src/utils/test/metrics_test.cpp b/src/utils/test/metrics_test.cpp
index 326415f38..649ea1430 100644
--- a/src/utils/test/metrics_test.cpp
+++ b/src/utils/test/metrics_test.cpp
@@ -2526,10 +2526,10 @@ TEST(metrics_test, http_get_metrics)
 
         gauge_ptr<int64_t> my_gauge_int64;
         counter_ptr<> my_counter;
-        if (std::strcmp(entity.prototype->name(), "my_replica") == 0) {
+        if (utils::equals(entity.prototype->name(), "my_replica")) {
             my_gauge_int64 = METRIC_test_replica_gauge_int64.instantiate(my_entity);
             my_counter = METRIC_test_replica_counter.instantiate(my_entity);
-        } else if (std::strcmp(entity.prototype->name(), "my_app") == 0) {
+        } else if (utils::equals(entity.prototype->name(), "my_app")) {
             my_gauge_int64 = METRIC_test_app_gauge_int64.instantiate(my_entity);
             my_counter = METRIC_test_app_counter.instantiate(my_entity);
         } else {
diff --git a/src/utils/test/utils.cpp b/src/utils/test/utils.cpp
index 7b8b4608e..df65ba536 100644
--- a/src/utils/test/utils.cpp
+++ b/src/utils/test/utils.cpp
@@ -33,6 +33,8 @@
  *     xxxx-xx-xx, author, fix bug about xxx
  */
 
+#include <tuple>
+
 #include <gtest/gtest.h>
 
 #include "runtime/api_layer1.h"
@@ -115,6 +117,138 @@ TEST(core, check_c_string_empty)
     }
 }
 
+using c_string_equality = std::tuple<const char *, const char *, bool, bool>;
+
+class CStringEqualityTest : public testing::TestWithParam<c_string_equality>
+{
+};
+
+TEST_P(CStringEqualityTest, CStringEquals)
+{
+    const char *lhs;
+    const char *rhs;
+    bool is_equal;
+    bool is_equal_ignore_case;
+    std::tie(lhs, rhs, is_equal, is_equal_ignore_case) = GetParam();
+
+    EXPECT_EQ(is_equal, dsn::utils::equals(lhs, rhs));
+
+    EXPECT_EQ(is_equal_ignore_case, dsn::utils::iequals(lhs, rhs));
+
+    if (rhs != nullptr) {
+        // Since NULL pointer cannot be used to construct std::string, related test cases
+        // are neglected.
+        std::string rhs_str(rhs);
+        EXPECT_EQ(is_equal_ignore_case, dsn::utils::iequals(lhs, rhs_str));
+    }
+
+    if (lhs != nullptr) {
+        // Since NULL pointer cannot be used to construct std::string, related test cases
+        // are neglected.
+        std::string lhs_str(lhs);
+        EXPECT_EQ(is_equal_ignore_case, dsn::utils::iequals(lhs_str, rhs));
+    }
+}
+
+const std::vector<c_string_equality> c_string_equality_tests = {
+    {nullptr, nullptr, true, true}, {nullptr, "", false, false}, {nullptr, "a", false, false},
+    {nullptr, "abc", false, false}, {"", nullptr, false, false}, {"a", nullptr, false, false},
+    {"abc", nullptr, false, false}, {"", "", true, true},        {"", "a", false, false},
+    {"", "abc", false, false},      {"a", "", false, false},     {"abc", "", false, false},
+    {"a", "a", true, true},         {"a", "A", false, true},     {"A", "A", true, true},
+    {"abc", "abc", true, true},     {"aBc", "abc", false, true}, {"abc", "ABC", false, true},
+    {"a", "abc", false, false},     {"A", "abc", false, false},  {"abc", "a", false, false},
+    {"Abc", "a", false, false},
+};
+
+INSTANTIATE_TEST_CASE_P(StringTest,
+                        CStringEqualityTest,
+                        testing::ValuesIn(c_string_equality_tests));
+
+using c_string_n_bytes_equality = std::tuple<const char *, const char *, size_t, bool, bool, bool>;
+
+class CStringNBytesEqualityTest : public testing::TestWithParam<c_string_n_bytes_equality>
+{
+};
+
+TEST_P(CStringNBytesEqualityTest, CStringNBytesEquals)
+{
+    const char *lhs;
+    const char *rhs;
+    size_t n;
+    bool is_equal;
+    bool is_equal_ignore_case;
+    bool is_equal_memory;
+    std::tie(lhs, rhs, n, is_equal, is_equal_ignore_case, is_equal_memory) = GetParam();
+
+    EXPECT_EQ(is_equal, dsn::utils::equals(lhs, rhs, n));
+
+    EXPECT_EQ(is_equal_ignore_case, dsn::utils::iequals(lhs, rhs, n));
+
+    if (rhs != nullptr) {
+        // Since NULL pointer cannot be used to construct std::string, related test cases
+        // are neglected.
+        std::string rhs_str(rhs);
+        EXPECT_EQ(is_equal_ignore_case, dsn::utils::iequals(lhs, rhs_str, n));
+    }
+
+    if (lhs != nullptr) {
+        // Since NULL pointer cannot be used to construct std::string, related test cases
+        // are neglected.
+        std::string lhs_str(lhs);
+        EXPECT_EQ(is_equal_ignore_case, dsn::utils::iequals(lhs_str, rhs, n));
+    }
+
+    EXPECT_EQ(is_equal_memory, dsn::utils::mequals(lhs, rhs, n));
+}
+
+const std::vector<c_string_n_bytes_equality> c_string_n_bytes_equality_tests = {
+    {nullptr, nullptr, 0, true, true, true},
+    {nullptr, nullptr, 1, true, true, true},
+    {nullptr, "", 0, false, false, false},
+    {nullptr, "", 1, false, false, false},
+    {nullptr, "a", 0, false, false, false},
+    {nullptr, "a", 1, false, false, false},
+    {nullptr, "abc", 0, false, false, false},
+    {nullptr, "abc", 1, false, false, false},
+    {"", nullptr, 0, false, false, false},
+    {"", nullptr, 1, false, false, false},
+    {"a", nullptr, 0, false, false, false},
+    {"a", nullptr, 1, false, false, false},
+    {"abc", nullptr, 0, false, false, false},
+    {"abc", nullptr, 1, false, false, false},
+    {"", "", 0, true, true, true},
+    {"", "", 1, true, true, true},
+    {"\0", "a", 1, false, false, false},
+    {"\0\0\0", "abc", 3, false, false, false},
+    {"a", "\0", 1, false, false, false},
+    {"abc", "\0\0\0", 3, false, false, false},
+    {"a", "a", 1, true, true, true},
+    {"a", "A", 1, false, true, false},
+    {"A", "A", 1, true, true, true},
+    {"abc", "abc", 3, true, true, true},
+    {"aBc", "abc", 3, false, true, false},
+    {"abc", "ABC", 3, false, true, false},
+    {"a\0\0", "abc", 3, false, false, false},
+    {"A\0\0", "abc", 3, false, false, false},
+    {"abc", "a\0\0", 3, false, false, false},
+    {"abc", "xyz", 0, true, true, true},
+    {"Abc", "a\0\0", 3, false, false, false},
+    {"a", "abc", 1, true, true, true},
+    {"a", "Abc", 1, false, true, false},
+    {"abc", "a", 1, true, true, true},
+    {"Abc", "a", 1, false, true, false},
+    {"abc", "abd", 2, true, true, true},
+    {"abc", "ABd", 2, false, true, false},
+    {"abc\0opq", "abc\0xyz", 7, true, true, false},
+    {"abc\0opq", "ABC\0xyz", 7, false, true, false},
+    {"abc\0xyz", "abc\0xyz", 7, true, true, true},
+};
+
+INSTANTIATE_TEST_CASE_P(StringTest,
+                        CStringNBytesEqualityTest,
+                        testing::ValuesIn(c_string_n_bytes_equality_tests));
+
 // For containers such as std::unordered_set, the expected result will be deduplicated
 // at initialization. Therefore, it can be used to compare with actual result safely.
 template <typename Container>


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pegasus.apache.org
For additional commands, e-mail: commits-help@pegasus.apache.org