Merge pull request #2571 from chenBright/opt_stream_overcrowded

Ignore eovercrowded for streaming control frame
diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml
index 4e98aa3..c23885d 100644
--- a/.github/workflows/ci-macos.yml
+++ b/.github/workflows/ci-macos.yml
@@ -27,9 +27,9 @@
 
     - name: config_brpc
       run: |
-           GETOPT_PATH=$(find "/usr/local/Cellar/" -name "getopt" -type f -perm +111 -exec dirname {} \;)
+           GETOPT_PATH=$(brew --prefix gnu-getopt)/bin
            export PATH=$GETOPT_PATH:$PATH
-           ./config_brpc.sh --header="/usr/local/include" --libs="/usr/local/lib"
+           ./config_brpc.sh --header="$(brew --prefix)/include" --libs="$(brew --prefix)/lib"
 
     - name: compile
       run: |
@@ -44,7 +44,7 @@
     - name: install dependences
       run: |
            brew install ./homebrew-formula/protobuf.rb 
-           brew install openssl gnu-getopt coreutils gflags leveldb
+           brew install openssl gflags leveldb
 
     - name: cmake
       run: |
@@ -56,3 +56,44 @@
       run: |
            cd build
            make -j ${{env.proc_num}}
+
+  compile-with-make-protobuf22:
+    runs-on: macos-latest # https://github.com/actions/runner-images
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: install dependences
+        run: |
+          brew install protobuf openssl gnu-getopt coreutils gflags leveldb
+
+      - name: config_brpc
+        run: |
+          GETOPT_PATH=$(brew --prefix gnu-getopt)/bin
+          export PATH=$GETOPT_PATH:$PATH
+           ./config_brpc.sh --header="$(brew --prefix)/include" --libs="$(brew --prefix)/lib"
+
+      - name: compile
+        run: |
+          make -j ${{env.proc_num}}
+
+  compile-with-cmake-protobuf22:
+    runs-on: macos-latest
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: install dependences
+        run: |
+          brew install protobuf openssl gflags leveldb
+
+      - name: cmake
+        run: |
+          mkdir build
+          cd build
+          cmake ..
+
+      - name: compile
+        run: |
+          cd build
+          make -j ${{env.proc_num}}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2eeec04..40eff79 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-cmake_minimum_required(VERSION 2.8.10)
+cmake_minimum_required(VERSION 2.8.12)
 project(brpc C CXX)
 
 option(WITH_GLOG "With glog" OFF)
@@ -140,8 +140,6 @@
 endif()
 endmacro(use_cxx11)
 
-use_cxx11()
-
 if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     #required by butil/crc32.cc to boost performance for 10x
     if((CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4))
@@ -156,6 +154,50 @@
 endif()
 
 find_package(Protobuf REQUIRED)
+if(Protobuf_VERSION GREATER 4.21)
+    # required by absl
+    set(CMAKE_CXX_STANDARD 17)
+
+    find_package(absl REQUIRED CONFIG)
+    set(protobuf_ABSL_USED_TARGETS
+        absl::absl_check
+        absl::absl_log
+        absl::algorithm
+        absl::base
+        absl::bind_front
+        absl::bits
+        absl::btree
+        absl::cleanup
+        absl::cord
+        absl::core_headers
+        absl::debugging
+        absl::die_if_null
+        absl::dynamic_annotations
+        absl::flags
+        absl::flat_hash_map
+        absl::flat_hash_set
+        absl::function_ref
+        absl::hash
+        absl::layout
+        absl::log_initialize
+        absl::log_severity
+        absl::memory
+        absl::node_hash_map
+        absl::node_hash_set
+        absl::optional
+        absl::span
+        absl::status
+        absl::statusor
+        absl::strings
+        absl::synchronization
+        absl::time
+        absl::type_traits
+        absl::utility
+        absl::variant
+    )
+else()
+    use_cxx11()
+endif()
 find_package(Threads REQUIRED)
 
 find_path(LEVELDB_INCLUDE_PATH NAMES leveldb/db.h)
@@ -229,7 +271,7 @@
 
 set(DYNAMIC_LIB
     ${GFLAGS_LIBRARY}
-    ${PROTOBUF_LIBRARIES}
+    ${PROTOBUF_LIBRARIES} ${protobuf_ABSL_USED_TARGETS}
     ${LEVELDB_LIB}
     ${PROTOC_LIB}
     ${CMAKE_THREAD_LIBS_INIT}
diff --git a/Makefile b/Makefile
index 0ed8a35..04d0a24 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@
 # 2. Removed -Werror: Not block compilation for non-vital warnings, especially when the
 #    code is tested on newer systems. If the code is used in production, add -Werror back
 CPPFLAGS+=-DBTHREAD_USE_FAST_PTHREAD_MUTEX -D_GNU_SOURCE -DUSE_SYMBOLIZE -DNO_TCMALLOC -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -DNDEBUG -DBRPC_REVISION=\"$(shell ./tools/get_brpc_revision.sh .)\"
-CXXFLAGS=$(CPPFLAGS) -O2 -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-invalid-offsetof -Wno-unused-parameter -fno-omit-frame-pointer -std=c++0x
+CXXFLAGS+=$(CPPFLAGS) -O2 -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-invalid-offsetof -Wno-unused-parameter -fno-omit-frame-pointer
 CFLAGS=$(CPPFLAGS) -O2 -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-unused-parameter -fno-omit-frame-pointer
 DEBUG_CXXFLAGS = $(filter-out -DNDEBUG,$(CXXFLAGS)) -DUNIT_TEST -DBVAR_NOT_LINK_DEFAULT_VARIABLES
 DEBUG_CFLAGS = $(filter-out -DNDEBUG,$(CFLAGS)) -DUNIT_TEST
@@ -243,9 +243,9 @@
 protoc-gen-mcpack: src/idl_options.pb.cc src/mcpack2pb/generator.o libbrpc.a
 	@echo "> Linking $@"
 ifeq ($(SYSTEM),Linux)
-	$(CXX) -o $@ $(CXXFLAGS) $(HDRPATHS) $(LIBPATHS) -std=c++0x -Xlinker "-(" $^ -Wl,-Bstatic $(STATIC_LINKINGS) -Wl,-Bdynamic -Xlinker "-)" $(DYNAMIC_LINKINGS)
+	$(CXX) -o $@ $(CXXFLAGS) $(HDRPATHS) $(LIBPATHS) -Xlinker "-(" $^ -Wl,-Bstatic $(STATIC_LINKINGS) -Wl,-Bdynamic -Xlinker "-)" $(DYNAMIC_LINKINGS)
 else ifeq ($(SYSTEM),Darwin)
-	$(CXX) -o $@ $(CXXFLAGS) $(HDRPATHS) $(LIBPATHS) -std=c++0x $^ $(STATIC_LINKINGS) $(DYNAMIC_LINKINGS)
+	$(CXX) -o $@ $(CXXFLAGS) $(HDRPATHS) $(LIBPATHS) $^ $(STATIC_LINKINGS) $(DYNAMIC_LINKINGS)
 endif
 
 # force generation of pb headers before compiling to avoid fail-to-import issues in compiling pb.cc
diff --git a/community/newcommitter_cn.md b/community/newcommitter_cn.md
index 1385eb3..25b27d0 100644
--- a/community/newcommitter_cn.md
+++ b/community/newcommitter_cn.md
@@ -11,7 +11,7 @@
 1. 提名者在private@brpc中发起讨论和投票,投票通过即OK (最少3+1, +1 > -1),[邮件模版](https://community.apache.org/newcommitter.html#committer-vote-template)
 2. 提名者发送close vote邮件给private@brpc, 标题可以为subject [RESULT][VOTE],[邮件模版](https://community.apache.org/newcommitter.html#close-vote)
 3. 提名者给被提名者发invite letter([邮件模板](https://community.apache.org/newcommitter.html#committer-invite-template)),并得到回复后再提示他提交ICLA([邮件模板](https://community.apache.org/newcommitter.html#committer-accept-template))
-4. 被提名者填写[CLA](https://www.apache.org/licenses/contributor-agreements.html), 个人贡献者需要下载[ICLA](https://www.apache.org/licenses/icla.pdf)填写个人信息并签名,发送电子版给 secretary@apache.org。(注意:ICLA需要填写信息完全,包括邮寄地址和签名,否则会被ASF的秘书打回)个人信息填写项(除签名外)可以使用 PDF 阅读器或浏览器填写,填写后保存进行签名。签名方式支持:
+4. 被提名者填写[CLA](https://www.apache.org/licenses/contributor-agreements.html), 个人贡献者需要下载[ICLA](https://www.apache.org/licenses/icla.pdf)填写个人信息并签名,发送电子版给 secretary@apache.org。(注意:1. ICLA需要填写信息完全,包括邮寄地址和签名,否则会被ASF的秘书打回, 2. ICLA中的preffered Apache id和notify project虽然是optional,但最好填上,这样秘书会帮新commiter申请好apache id,否则就需要PMC chair或者ASF member去申请)个人信息填写项(除签名外)可以使用 PDF 阅读器或浏览器填写,填写后保存进行签名。签名方式支持:
    - 打印 该pdf 文件,手工填写表单(姓名、邮箱、邮寄地址),然后手写签名,最后扫描为电子版;
    - 使用支持手写的设备进行电子签名;
    - 使用 `gpg` 进行电子签名,即对填写好个人基本信息的 pdf 文件进行操作(需要提前生成与登记邮箱匹配的公钥/密钥对):`gpg --armor --detach-sign icla.pdf`;
diff --git a/config_brpc.sh b/config_brpc.sh
index 7e459b7..cc945d3 100755
--- a/config_brpc.sh
+++ b/config_brpc.sh
@@ -89,7 +89,7 @@
     exit 1
 fi
 
-GCC_VERSION=$($CXX tools/print_gcc_version.cc -o print_gcc_version && ./print_gcc_version && rm ./print_gcc_version)
+GCC_VERSION=$(CXX=$CXX tools/print_gcc_version.sh)
 if [ $GCC_VERSION -gt 0 ] && [ $GCC_VERSION -lt 40800 ]; then
     >&2 $ECHO "GCC is too old, please install a newer version supporting C++11"
     exit 1
@@ -262,10 +262,89 @@
 fi
 
 PROTOBUF_HDR=$(find_dir_of_header_or_die google/protobuf/message.h)
+PROTOBUF_VERSION=$(grep '#define GOOGLE_PROTOBUF_VERSION [0-9]\+' $PROTOBUF_HDR/google/protobuf/stubs/common.h | awk '{print $3}')
+if [ "$PROTOBUF_VERSION" -ge 4022000 ]; then
+    ABSL_HDR=$(find_dir_of_header_or_die absl/base/config.h)
+    ABSL_LIB=$(find_dir_of_lib_or_die absl_strings)
+    ABSL_LIB_NAMES="
+        absl_bad_optional_access
+        absl_bad_variant_access
+        absl_base
+        absl_city
+        absl_civil_time
+        absl_cord
+        absl_cord_internal
+        absl_cordz_functions
+        absl_cordz_handle
+        absl_cordz_info
+        absl_crc32c
+        absl_crc_cord_state
+        absl_crc_cpu_detect
+        absl_crc_internal
+        absl_debugging_internal
+        absl_demangle_internal
+        absl_die_if_null
+        absl_examine_stack
+        absl_exponential_biased
+        absl_flags
+        absl_flags_commandlineflag
+        absl_flags_commandlineflag_internal
+        absl_flags_config
+        absl_flags_internal
+        absl_flags_marshalling
+        absl_flags_private_handle_accessor
+        absl_flags_program_name
+        absl_flags_reflection
+        absl_graphcycles_internal
+        absl_hash
+        absl_hashtablez_sampler
+        absl_int128
+        absl_kernel_timeout_internal
+        absl_leak_check
+        absl_log_entry
+        absl_log_globals
+        absl_log_initialize
+        absl_log_internal_check_op
+        absl_log_internal_conditions
+        absl_log_internal_format
+        absl_log_internal_globals
+        absl_log_internal_log_sink_set
+        absl_log_internal_message
+        absl_log_internal_nullguard
+        absl_log_internal_proto
+        absl_log_severity
+        absl_log_sink
+        absl_low_level_hash
+        absl_malloc_internal
+        absl_raw_hash_set
+        absl_raw_logging_internal
+        absl_spinlock_wait
+        absl_stacktrace
+        absl_status
+        absl_statusor
+        absl_str_format_internal
+        absl_strerror
+        absl_string_view
+        absl_strings
+        absl_strings_internal
+        absl_symbolize
+        absl_synchronization
+        absl_throw_delegate
+        absl_time
+        absl_time_zone
+    "
+    for i in $ABSL_LIB_NAMES; do
+         append_linking "$ABSL_LIB" "$i"
+    done
+    CXXFLAGS="-std=c++17"
+else
+    CXXFLAGS="-std=c++0x"
+fi
+
 LEVELDB_HDR=$(find_dir_of_header_or_die leveldb/db.h)
 
-HDRS=$($ECHO "$GFLAGS_HDR\n$PROTOBUF_HDR\n$LEVELDB_HDR\n$OPENSSL_HDR" | sort | uniq)
-LIBS=$($ECHO "$GFLAGS_LIB\n$PROTOBUF_LIB\n$LEVELDB_LIB\n$OPENSSL_LIB\n$SNAPPY_LIB" | sort | uniq)
+HDRS=$($ECHO "$GFLAGS_HDR\n$PROTOBUF_HDR\n$ABSL_HDR\n$LEVELDB_HDR\n$OPENSSL_HDR" | sort | uniq)
+LIBS=$($ECHO "$GFLAGS_LIB\n$PROTOBUF_LIB\n$ABSL_LIB\n$LEVELDB_LIB\n$OPENSSL_LIB\n$SNAPPY_LIB" | sort | uniq)
 
 absent_in_the_list() {
     TMP=`$ECHO "$1\n$2" | sort | uniq`
@@ -390,6 +469,8 @@
 endif
 "
 
+append_to_output "CXXFLAGS=${CXXFLAGS}"
+
 append_to_output "ifeq (\$(NEED_LIBPROTOC), 1)"
 PROTOC_LIB=$(find $PROTOBUF_LIB -name "libprotoc.*" | head -n1)
 if [ -z "$PROTOC_LIB" ]; then
diff --git a/src/brpc/esp_message.h b/src/brpc/esp_message.h
index 279f7b6..aecc837 100644
--- a/src/brpc/esp_message.h
+++ b/src/brpc/esp_message.h
@@ -72,7 +72,7 @@
             ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE;
     ::google::protobuf::uint8* SerializeWithCachedSizesToArray(
             ::google::protobuf::uint8* output) const PB_310_OVERRIDE;
-    int GetCachedSize() const override { return ByteSize(); }
+    int GetCachedSize() const PB_422_OVERRIDE { return ByteSize(); }
 
 protected:
     ::google::protobuf::Metadata GetMetadata() const override;
diff --git a/src/brpc/global.cpp b/src/brpc/global.cpp
index 121b9d9..d45c67f 100644
--- a/src/brpc/global.cpp
+++ b/src/brpc/global.cpp
@@ -297,6 +297,7 @@
     return NULL;
 }
 
+#if GOOGLE_PROTOBUF_VERSION < 3022000
 static void BaiduStreamingLogHandler(google::protobuf::LogLevel level,
                                      const char* filename, int line,
                                      const std::string& message) {
@@ -316,6 +317,7 @@
     }
     CHECK(false) << filename << ':' << line << ' ' << message;
 }
+#endif
 
 static void GlobalInitializeOrDieImpl() {
     //////////////////////////////////////////////////////////////////
@@ -331,8 +333,10 @@
         CHECK(SIG_ERR != signal(SIGPIPE, SIG_IGN));
     }
 
+#if GOOGLE_PROTOBUF_VERSION < 3022000
     // Make GOOGLE_LOG print to comlog device
     SetLogHandler(&BaiduStreamingLogHandler);
+#endif
 
     // Set bthread create span function
     bthread_set_create_span_func(CreateBthreadSpan);
diff --git a/src/brpc/memcache.h b/src/brpc/memcache.h
index c6fd2b9..014f075 100644
--- a/src/brpc/memcache.h
+++ b/src/brpc/memcache.h
@@ -107,7 +107,7 @@
     void SerializeWithCachedSizes(
         ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE;
     ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const PB_310_OVERRIDE;
-    int GetCachedSize() const override { return _cached_size_; }
+    int GetCachedSize() const PB_422_OVERRIDE { return _cached_size_; }
     
     static const ::google::protobuf::Descriptor* descriptor();
 
@@ -125,7 +125,7 @@
 
     void SharedCtor();
     void SharedDtor();
-    void SetCachedSize(int size) const override;
+    void SetCachedSize(int size) const PB_422_OVERRIDE;
 
     int _pipelined_count;
     butil::IOBuf _buf;
@@ -220,7 +220,7 @@
     void SerializeWithCachedSizes(
         ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE;
     ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const PB_310_OVERRIDE;
-    int GetCachedSize() const override { return _cached_size_; }
+    int GetCachedSize() const PB_422_OVERRIDE { return _cached_size_; }
 
     static const ::google::protobuf::Descriptor* descriptor();
 
@@ -233,7 +233,7 @@
 
     void SharedCtor();
     void SharedDtor();
-    void SetCachedSize(int size) const override;
+    void SetCachedSize(int size) const PB_422_OVERRIDE;
 
     std::string _err;
     butil::IOBuf _buf;
diff --git a/src/brpc/nshead_message.h b/src/brpc/nshead_message.h
index 11cc1c6..6cd06ca 100644
--- a/src/brpc/nshead_message.h
+++ b/src/brpc/nshead_message.h
@@ -67,7 +67,7 @@
     void SerializeWithCachedSizes(
         ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE;
     ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const PB_310_OVERRIDE;
-    int GetCachedSize() const override { return ByteSize(); }
+    int GetCachedSize() const PB_422_OVERRIDE { return ByteSize(); }
 
 protected:
     ::google::protobuf::Metadata GetMetadata() const override;
diff --git a/src/brpc/pb_compat.h b/src/brpc/pb_compat.h
index 70faeb5..d089530 100644
--- a/src/brpc/pb_compat.h
+++ b/src/brpc/pb_compat.h
@@ -19,6 +19,12 @@
 #ifndef BRPC_PB_COMPAT_H
 #define BRPC_PB_COMPAT_H
 
+#if GOOGLE_PROTOBUF_VERSION < 4022000
+# define PB_422_OVERRIDE override
+#else
+# define PB_422_OVERRIDE
+#endif
+
 #if GOOGLE_PROTOBUF_VERSION < 3021000
 # define PB_321_OVERRIDE override
 #else
diff --git a/src/brpc/protocol.cpp b/src/brpc/protocol.cpp
index 5f39939..e0468c2 100644
--- a/src/brpc/protocol.cpp
+++ b/src/brpc/protocol.cpp
@@ -18,6 +18,8 @@
 
 // Since kDefaultTotalBytesLimit is private, we need some hacks to get the limit.
 // Works for pb 2.4, 2.6, 3.0
+#include "google/protobuf/stubs/common.h"
+#if GOOGLE_PROTOBUF_VERSION < 4022000
 #define private public
 #include <google/protobuf/io/coded_stream.h>
 const int PB_TOTAL_BYETS_LIMITS_RAW =
@@ -25,6 +27,12 @@
 const uint64_t PB_TOTAL_BYETS_LIMITS =
     PB_TOTAL_BYETS_LIMITS_RAW < 0 ? (uint64_t)-1LL : PB_TOTAL_BYETS_LIMITS_RAW;
 #undef private
+#else
+#include <google/protobuf/io/coded_stream.h>
+const int PB_TOTAL_BYETS_LIMITS_RAW = INT_MAX;
+const uint64_t PB_TOTAL_BYETS_LIMITS =
+    PB_TOTAL_BYETS_LIMITS_RAW < 0 ? (uint64_t)-1LL : PB_TOTAL_BYETS_LIMITS_RAW;
+#endif
 
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/text_format.h>
diff --git a/src/brpc/redis.h b/src/brpc/redis.h
index d02e894..6b949ea 100644
--- a/src/brpc/redis.h
+++ b/src/brpc/redis.h
@@ -125,7 +125,7 @@
     void SerializeWithCachedSizes(
         ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE;
     ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const PB_310_OVERRIDE;
-    int GetCachedSize() const override { return _cached_size_; }
+    int GetCachedSize() const PB_422_OVERRIDE { return _cached_size_; }
 
     static const ::google::protobuf::Descriptor* descriptor();
     
@@ -137,7 +137,7 @@
 private:
     void SharedCtor();
     void SharedDtor();
-    void SetCachedSize(int size) const override;
+    void SetCachedSize(int size) const PB_422_OVERRIDE;
     bool AddCommandWithArgs(const char* fmt, ...);
 
     int _ncommand;    // # of valid commands
@@ -198,7 +198,7 @@
     void SerializeWithCachedSizes(
         ::google::protobuf::io::CodedOutputStream* output) const PB_310_OVERRIDE;
     ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const PB_310_OVERRIDE;
-    int GetCachedSize() const override { return _cached_size_; }
+    int GetCachedSize() const PB_422_OVERRIDE { return _cached_size_; }
 
     static const ::google::protobuf::Descriptor* descriptor();
 
@@ -208,7 +208,7 @@
 private:
     void SharedCtor();
     void SharedDtor();
-    void SetCachedSize(int size) const override;
+    void SetCachedSize(int size) const PB_422_OVERRIDE;
 
     RedisReply _first_reply;
     RedisReply* _other_replies;
diff --git a/src/brpc/serialized_request.h b/src/brpc/serialized_request.h
index 0fbf76b..5b68262 100644
--- a/src/brpc/serialized_request.h
+++ b/src/brpc/serialized_request.h
@@ -53,7 +53,7 @@
     void Clear() override;
     bool IsInitialized() const override;
     int ByteSize() const;
-    int GetCachedSize() const override { return (int)_serialized.size(); }
+    int GetCachedSize() const PB_422_OVERRIDE { return (int)_serialized.size(); }
     butil::IOBuf& serialized_data() { return _serialized; }
     const butil::IOBuf& serialized_data() const { return _serialized; }
 
@@ -71,7 +71,7 @@
     void MergeFrom(const SerializedRequest& from);
     void SharedCtor();
     void SharedDtor();
-    void SetCachedSize(int size) const override;
+    void SetCachedSize(int size) const PB_422_OVERRIDE;
   
 private:
     butil::IOBuf _serialized;
diff --git a/src/butil/iobuf.cpp b/src/butil/iobuf.cpp
index b4d6ce3..3418f67 100644
--- a/src/butil/iobuf.cpp
+++ b/src/butil/iobuf.cpp
@@ -164,8 +164,13 @@
 void* (*blockmem_allocate)(size_t) = ::malloc;
 void  (*blockmem_deallocate)(void*) = ::free;
 
+void remove_tls_block_chain();
+
 // Use default function pointers
 void reset_blockmem_allocate_and_deallocate() {
+    // There maybe block allocated by previous hooks, it's wrong to free them using
+    // mismatched hook.
+    remove_tls_block_chain();
     blockmem_allocate = ::malloc;
     blockmem_deallocate = ::free;
 }
diff --git a/src/butil/logging.cc b/src/butil/logging.cc
index 032a544..6a43eaf 100644
--- a/src/butil/logging.cc
+++ b/src/butil/logging.cc
@@ -135,6 +135,8 @@
 
 DEFINE_bool(log_pid, false, "Log process id");
 
+DEFINE_bool(log_bid, true, "Log bthread id");
+
 DEFINE_int32(minloglevel, 0, "Any log at or above this level will be "
              "displayed. Anything below this level will be silently ignored. "
              "0=INFO 1=NOTICE 2=WARNING 3=ERROR 4=FATAL");
@@ -809,6 +811,9 @@
     }
     os << ' ' << std::setfill(' ') << std::setw(5)
        << butil::PlatformThread::CurrentId() << std::setfill('0');
+    if (FLAGS_log_bid && bthread_self) {
+        os << ' ' << std::setfill(' ') << std::setw(5) << bthread_self();
+    }
     if (FLAGS_log_hostname) {
         butil::StringPiece hostname(butil::my_hostname());
         if (hostname.ends_with(".baidu.com")) { // make it shorter
diff --git a/src/json2pb/json_to_pb.cpp b/src/json2pb/json_to_pb.cpp
index 6a6f46c..60ba4fd 100644
--- a/src/json2pb/json_to_pb.cpp
+++ b/src/json2pb/json_to_pb.cpp
@@ -534,8 +534,12 @@
     for (int i = 0; i < descriptor->extension_range_count(); ++i) {
         const google::protobuf::Descriptor::ExtensionRange*
             ext_range = descriptor->extension_range(i);
-        for (int tag_number = ext_range->start; tag_number < ext_range->end;
-             ++tag_number) {
+#if GOOGLE_PROTOBUF_VERSION < 4025000
+        for (int tag_number = ext_range->start; tag_number < ext_range->end; ++tag_number)
+#else
+        for (int tag_number = ext_range->start_number(); tag_number < ext_range->end_number(); ++tag_number)
+#endif
+        {
             const google::protobuf::FieldDescriptor* field =
                 reflection->FindKnownExtensionByNumber(tag_number);
             if (field) {
diff --git a/src/json2pb/pb_to_json.cpp b/src/json2pb/pb_to_json.cpp
index c6ce183..b0066dc 100644
--- a/src/json2pb/pb_to_json.cpp
+++ b/src/json2pb/pb_to_json.cpp
@@ -75,8 +75,12 @@
     for (int i = 0; i < ext_range_count; ++i) {
         const google::protobuf::Descriptor::ExtensionRange*
             ext_range = descriptor->extension_range(i);
-        for (int tag_number = ext_range->start;
-             tag_number < ext_range->end; ++tag_number) {
+#if GOOGLE_PROTOBUF_VERSION < 4025000
+        for (int tag_number = ext_range->start; tag_number < ext_range->end; ++tag_number)
+#else
+        for (int tag_number = ext_range->start_number(); tag_number < ext_range->end_number(); ++tag_number)
+#endif
+        {
             const google::protobuf::FieldDescriptor* field =
                     reflection->FindKnownExtensionByNumber(tag_number);
             if (field) {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index da59abe..fe9bb42 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -173,6 +173,7 @@
     ${PROJECT_SOURCE_DIR}/test/object_pool_unittest.cpp
     ${PROJECT_SOURCE_DIR}/test/test_switches.cc
     ${PROJECT_SOURCE_DIR}/test/scoped_locale.cc
+    ${PROJECT_SOURCE_DIR}/test/scope_guard_unittest.cc
     ${PROJECT_SOURCE_DIR}/test/butil_unittest_main.cpp
     ${PROJECT_SOURCE_DIR}/test/butil_unittest_main.cpp
 	)
diff --git a/test/Makefile b/test/Makefile
index 82efc38..97bde8f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -145,7 +145,8 @@
     scoped_locale.cc \
     popen_unittest.cpp \
     bounded_queue_unittest.cc \
-    butil_unittest_main.cpp
+    butil_unittest_main.cpp \
+    scope_guard_unittest.cc
 
 ifeq ($(SYSTEM), Linux)
     TEST_BUTIL_SOURCES += test_file_util_linux.cc \
diff --git a/tools/print_gcc_version.cc b/test/scope_guard_unittest.cc
similarity index 62%
rename from tools/print_gcc_version.cc
rename to test/scope_guard_unittest.cc
index cfd615c..085162f 100644
--- a/tools/print_gcc_version.cc
+++ b/test/scope_guard_unittest.cc
@@ -15,20 +15,25 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include <stdio.h>
-int main() {
-#if defined(__clang__)
-    const int major_v = __GNUC__;
-    int minor_v = __GNUC_MINOR__;
-    if (major_v == 4 && minor_v <= 8) {
-        // Make version of clang >= 4.8 so that it's not rejected by config_brpc.sh
-        minor_v = 8;
+
+#include <gtest/gtest.h>
+#include "butil/memory/scope_guard.h"
+
+TEST(ScopedGuardTest, sanity) {
+    bool flag = false;
+    {
+        auto guard = butil::MakeScopeGuard([&flag] {
+            flag = true;
+        });
     }
-    printf("%d\n", (major_v * 10000 + minor_v * 100));
-#elif defined(__GNUC__)
-    printf("%d\n", (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__));
-#else
-    printf("0\n");
-#endif
-    return 0;
+    ASSERT_TRUE(flag);
+
+    flag = false;
+    {
+        auto guard = butil::MakeScopeGuard([&flag] {
+            flag = true;
+        });
+        guard.dismiss();
+    }
+    ASSERT_FALSE(flag);
 }
diff --git a/tools/print_gcc_version.sh b/tools/print_gcc_version.sh
new file mode 100755
index 0000000..00abf6c
--- /dev/null
+++ b/tools/print_gcc_version.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+while read -r line; do
+    val=$(echo "$line" | awk '{print $3}')
+    if   [[ $line =~ __clang__ ]]; then
+        CLANG=${val}
+    elif [[ $line =~ __GNUC__ ]]; then
+        GNUC=${val}
+    elif [[ $line =~ __GNUC_MINOR__ ]]; then
+        GNUC_MINOR=${val}
+    elif [[ $line =~ __GNUC_PATCHLEVEL__ ]]; then
+        GNUC_PATCHLEVEL=${val}
+    fi
+done < <("${CXX:-c++}" -dM -E - < /dev/null | grep "__clang__\|__GNUC__\|__GNUC_MINOR__\|__GNUC_PATCHLEVEL__")
+
+if [ -n "$GNUC" ] && [ -n "$GNUC_MINOR" ] && [ -n "$GNUC_PATCHLEVEL" ]; then
+    # Calculate GCC/Clang version
+    GCC_VERSION=$((GNUC * 10000 + GNUC_MINOR * 100 + GNUC_PATCHLEVEL))
+    if [ -n "$CLANG" ] && [ "40000" -lt $GCC_VERSION ] && [ $GCC_VERSION -lt "40800" ]; then
+        # Make version of clang >= 4.8 so that it's not rejected by config_brpc.sh
+        GCC_VERSION=40800
+    fi
+    echo $GCC_VERSION
+else
+    echo 0
+fi