diff --git a/.bazelignore b/.bazelignore index 1559ee6ef2..96ab212d69 100644 --- a/.bazelignore +++ b/.bazelignore @@ -1,4 +1,6 @@ ./example/build_with_bazel +./example/build_with_bazel_module +./example/build_with_old_bazel # `registry/` is brpc's self-maintained Bzlmod registry. Its overlay # BUILD.bazel files reference sources from the libunwind tarball that is diff --git a/.bazelrc b/.bazelrc index c10fb589bc..68eaee3014 100644 --- a/.bazelrc +++ b/.bazelrc @@ -87,3 +87,5 @@ build:macos-asan --copt -D_FORTIFY_SOURCE=0 build:macos-asan --dynamic_mode=off test:asan --test_env=ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=1 + +build:ubring --define BRPC_WITH_UBRING=true diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index e15d81db4f..57837ecf4e 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -65,7 +65,7 @@ jobs: run: | export CC=gcc && export CXX=g++ mkdir gcc_build_all && cd gcc_build_all - cmake -DWITH_MESALINK=OFF -DWITH_GLOG=ON -DWITH_THRIFT=ON -DWITH_RDMA=ON \ + cmake -DWITH_MESALINK=OFF -DWITH_GLOG=ON -DWITH_THRIFT=ON -DWITH_RDMA=ON -DWITH_UBRING=ON \ -DWITH_DEBUG_BTHREAD_SCHE_SAFETY=ON -DWITH_DEBUG_LOCK=ON -DWITH_BTHREAD_TRACER=ON \ -DWITH_ASAN=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. make -j ${{env.proc_num}} && make clean @@ -123,16 +123,36 @@ jobs: # real server (e.g. brpc_redis_unittest) actually run under bazel instead # of skipping. Same shared action the make-based unittest jobs use. - uses: ./.github/actions/install-essential-dependencies - - run: bazel test //test/... + - run: bazel test --config=rdma --config=ubring //test/... gcc-compile-with-bazel-all-options: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - - run: | + - run: sudo apt-get update && sudo apt-get install -y libibverbs-dev + - name: root + run: | + bazel build --define with_mesalink=false \ + --define with_glog=true \ + --define with_thrift=true \ + --define BRPC_WITH_RDMA=true \ + --define BRPC_WITH_UBRING=true \ + --define BRPC_WITH_BORINGSSL=true \ + --define with_debug_bthread_sche_safety=true \ + --define with_debug_lock=true \ + --define with_asan=true \ + --define with_bthread_tracer=true \ + --define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \ + --define with_babylon_counter=true \ + -- //:brpc //example/... + - name: external + run: | + cd example/build_with_bazel_module bazel build --define with_mesalink=false \ --define with_glog=true \ --define with_thrift=true \ + --define BRPC_WITH_RDMA=true \ + --define BRPC_WITH_UBRING=true \ --define BRPC_WITH_BORINGSSL=true \ --define with_debug_bthread_sche_safety=true \ --define with_debug_lock=true \ @@ -140,7 +160,7 @@ jobs: --define with_bthread_tracer=true \ --define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \ --define with_babylon_counter=true \ - -- //:brpc + -- //... clang-compile-with-make-protobuf: runs-on: ubuntu-22.04 @@ -182,17 +202,40 @@ jobs: - run: | bazel test --test_output=streamed \ --action_env=CC=clang \ + --config=rdma \ + --config=ubring \ //test/... clang-compile-with-bazel-all-options: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - - run: | + - run: sudo apt-get update && sudo apt-get install -y libibverbs-dev + - name: root + run: | + bazel build --action_env=CC=clang \ + --define with_mesalink=false \ + --define with_glog=true \ + --define with_thrift=true \ + --define BRPC_WITH_RDMA=true \ + --define BRPC_WITH_UBRING=true \ + --define BRPC_WITH_BORINGSSL=true \ + --define with_debug_bthread_sche_safety=true \ + --define with_debug_lock=true \ + --define with_asan=true \ + --define with_bthread_tracer=true \ + --define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \ + --define with_babylon_counter=true \ + -- //:brpc //example/... + - name: external + run: | + cd example/build_with_bazel_module bazel build --action_env=CC=clang \ --define with_mesalink=false \ --define with_glog=true \ --define with_thrift=true \ + --define BRPC_WITH_RDMA=true \ + --define BRPC_WITH_UBRING=true \ --define BRPC_WITH_BORINGSSL=true \ --define with_debug_bthread_sche_safety=true \ --define with_debug_lock=true \ @@ -200,7 +243,7 @@ jobs: --define with_bthread_tracer=true \ --define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \ --define with_babylon_counter=true \ - -- //:brpc + -- //... clang-unittest: runs-on: ubuntu-22.04 @@ -209,7 +252,7 @@ jobs: - uses: ./.github/actions/install-essential-dependencies - uses: ./.github/actions/init-ut-make-config with: - options: --with-bthread-tracer + options: --with-bthread-tracer --with-rdma - name: compile tests run: | cat config.mk @@ -245,10 +288,10 @@ jobs: clang-unittest-bazel-with-babylon-and-new-pb: runs-on: ubuntu-22.04 env: - TEST_PROTOBUF_VERSION: "34.1" - # protobuf >= 34.x uses new ProtoInfo fields (option_deps, - # extension_declarations) introduced in Bazel 8.x. The repo's - # .bazelversion (7.2.1) is too old. bazelisk honors USE_BAZEL_VERSION. + TEST_PROTOBUF_VERSION: "35.1" + # protobuf >= 34.x uses new ProtoInfo fields (option_deps, extension_declarations) + # introduced in Bazel 8.x. The repo's .bazelversion (7.2.1) is too old. bazelisk + # honors USE_BAZEL_VERSION. USE_BAZEL_VERSION: "8.3.1" steps: - uses: actions/checkout@v2 @@ -263,7 +306,7 @@ jobs: grep -qE "bazel_dep\(name = ['\"]protobuf['\"], version = ['\"]${TEST_PROTOBUF_VERSION}['\"]" MODULE.bazel \ || { echo "ERROR: failed to override protobuf version in MODULE.bazel to ${TEST_PROTOBUF_VERSION}"; exit 1; } - run: | - bazel test --action_env=CC=clang --config=rdma \ + bazel test --action_env=CC=clang --config=rdma --config=ubring \ --define with_bthread_tracer=true \ --define with_babylon_counter=true \ //test/... diff --git a/.gitignore b/.gitignore index c7b21b9350..739963a26c 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,10 @@ CTestTestfile.cmake /test/out.txt /test/recordio_ref.io +# Local design notes and Graphify artifacts. +docs/cn/urma_proposal.md +graphify-out/ + # Ignore protoc-gen-mcpack files /protoc-gen-mcpack*/ diff --git a/.licenserc.yaml b/.licenserc.yaml index 7c8bbd54bf..f471698950 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -34,6 +34,7 @@ header: - 'example/*/*.json' - 'example/*/*.pem' - 'example/*/*.port' + - 'example/build_with_bazel_module/.bazelversion' - 'src/bthread/offset_inl.list' - 'test/*.crt' - 'test/*.key' diff --git a/BUILD.bazel b/BUILD.bazel index b1676c4a62..3ea069351f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -51,6 +51,12 @@ DEFINES = [ }) + select({ "//bazel/config:brpc_with_rdma": ["BRPC_WITH_RDMA=1"], "//conditions:default": [], + }) + select({ + "//bazel/config:brpc_with_ubring": ["BRPC_WITH_UBRING=1"], + "//conditions:default": [], + }) + select({ + "//bazel/config:brpc_with_urma": ["BRPC_WITH_URMA=1"], + "//conditions:default": [], }) + select({ "//bazel/config:brpc_with_debug_bthread_sche_safety": ["BRPC_DEBUG_BTHREAD_SCHE_SAFETY=1"], "//conditions:default": ["BRPC_DEBUG_BTHREAD_SCHE_SAFETY=0"], @@ -520,6 +526,7 @@ filegroup( "src/brpc/*.proto", "src/brpc/policy/*.proto", "src/brpc/rdma/*.proto", + "src/brpc/urma/*.proto", ]), visibility = ["//visibility:public"], ) @@ -558,9 +565,7 @@ cc_library( "src/brpc/event_dispatcher_kqueue.cpp", ]), copts = COPTS, - includes = [ - "src/", - ], + includes = ["src/"], linkopts = LINKOPTS, visibility = ["//visibility:public"], deps = [ @@ -572,6 +577,11 @@ cc_library( ":mcpack2pb", "@com_github_google_leveldb//:leveldb", ] + select({ + "//bazel/config:brpc_with_urma": [ + "@umdk//:urma_headers", + ], + "//conditions:default": [], + }) + select({ "//bazel/config:brpc_with_thrift": [ "@org_apache_thrift//:thrift", ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 9419ac3a76..a2838bceaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,13 @@ option(WITH_THRIFT "With thrift framed protocol supported" OFF) option(WITH_BTHREAD_TRACER "With bthread tracer supported" OFF) option(WITH_SNAPPY "With snappy" OFF) option(WITH_RDMA "With RDMA" OFF) +option(WITH_URMA "With URMA (openEuler Unified Remote Memory Access)" OFF) +option(DOWNLOAD_URMA_HEADERS + "Download UMDK headers when WITH_URMA is enabled and headers are absent" + ON) +option(WITH_URMA_MOCK + "Explicitly allow linking brpc's URMA link-time mock when liburma is not found (WITH_URMA only). The mock cannot talk to real URMA hardware, so this must be opted into rather than silently substituted." + OFF) option(WITH_UBRING "With UB" OFF) option(WITH_DEBUG_BTHREAD_SCHE_SAFETY "With debugging bthread sche safety" OFF) option(WITH_DEBUG_LOCK "With debugging lock" OFF) @@ -121,6 +128,11 @@ if(WITH_RDMA) set(WITH_RDMA_VAL "1") endif() +set(WITH_URMA_VAL "0") +if(WITH_URMA) + set(WITH_URMA_VAL "1") +endif() + set(WITH_UBRING_VAL "0") if(WITH_UBRING) set(WITH_UBRING_VAL "1") @@ -160,6 +172,7 @@ endif() list(APPEND BRPC_COMMON_DEFINITIONS BRPC_WITH_GLOG=${WITH_GLOG_VAL} BRPC_WITH_RDMA=${WITH_RDMA_VAL} + BRPC_WITH_URMA=${WITH_URMA_VAL} BRPC_WITH_UBRING=${WITH_UBRING_VAL} BRPC_DEBUG_BTHREAD_SCHE_SAFETY=${WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL} BRPC_DEBUG_LOCK=${WITH_DEBUG_LOCK_VAL} @@ -318,6 +331,63 @@ if(WITH_RDMA) list(APPEND BRPC_COMMON_INCLUDE_DIRS ${RDMA_INCLUDE_PATH}) endif() +if(WITH_URMA) + # UrmaTransport and its link-time mock both compile against the upstream + # UMDK API. Prefer installed headers; otherwise fetch a pinned upstream + # release, following Mooncake's URMA mock setup. + find_path(URMA_INCLUDE_PATH NAMES urma_api.h + HINTS ENV URMA_ROOT + PATHS /usr/include /usr/local/include + PATH_SUFFIXES ub/umdk/urma umdk/urma urma + src/urma/lib/urma/core/include) + find_path(URMA_BOND_INCLUDE_PATH NAMES urma_ubagg.h + HINTS ENV URMA_ROOT + PATHS /usr/include /usr/local/include + PATH_SUFFIXES ub/umdk/urma umdk/urma urma + src/urma/lib/urma/bond/include) + if(NOT URMA_INCLUDE_PATH AND DOWNLOAD_URMA_HEADERS) + include(FetchContent) + FetchContent_Declare( + urma_headers + GIT_REPOSITORY https://atomgit.com/openeuler/umdk.git + GIT_TAG v26.06.0_CAM + GIT_SHALLOW TRUE) + FetchContent_GetProperties(urma_headers) + if(NOT urma_headers_POPULATED) + FetchContent_Populate(urma_headers) + endif() + set(URMA_INCLUDE_PATH + "${urma_headers_SOURCE_DIR}/src/urma/lib/urma/core/include") + set(URMA_BOND_INCLUDE_PATH + "${urma_headers_SOURCE_DIR}/src/urma/lib/urma/bond/include") + message(STATUS "Using downloaded UMDK headers: ${URMA_INCLUDE_PATH}") + endif() + if(NOT URMA_INCLUDE_PATH) + message(FATAL_ERROR + "Fail to find urma_api.h. Install UMDK headers, set URMA_ROOT, " + "or enable DOWNLOAD_URMA_HEADERS.") + endif() + + find_library(URMA_LIB NAMES urma + HINTS ENV URMA_ROOT + PATH_SUFFIXES lib lib64) + if(URMA_LIB) + message(STATUS "Found URMA library: ${URMA_LIB}") + set(URMA_USE_MOCK 0) + elseif(WITH_URMA_MOCK) + message(STATUS + "liburma not found; WITH_URMA_MOCK=ON, building with the URMA " + "link-time mock") + set(URMA_USE_MOCK 1) + else() + message(FATAL_ERROR + "Fail to find liburma. Install liburma, set URMA_ROOT, or " + "explicitly opt into brpc's link-time mock with " + "-DWITH_URMA_MOCK=ON (the mock cannot talk to real URMA " + "hardware; only enable it for CI/tests without URMA hardware).") + endif() +endif() + find_library(PROTOC_LIB NAMES protoc) if(NOT PROTOC_LIB) message(FATAL_ERROR "Fail to find protoc lib") @@ -342,6 +412,12 @@ list(APPEND BRPC_COMMON_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} ${LEVELDB_INCLUDE_PATH} ) +if(WITH_URMA) + list(APPEND BRPC_COMMON_INCLUDE_DIRS ${URMA_INCLUDE_PATH}) + if(URMA_BOND_INCLUDE_PATH) + list(APPEND BRPC_COMMON_INCLUDE_DIRS ${URMA_BOND_INCLUDE_PATH}) + endif() +endif() set(DYNAMIC_LIB ${GFLAGS_LIBRARY} @@ -370,6 +446,13 @@ if(WITH_RDMA) list(APPEND DYNAMIC_LIB ${RDMA_LIB}) endif() +if(WITH_URMA) + message(STATUS "brpc compile with URMA (mock=${URMA_USE_MOCK})") + if(NOT URMA_USE_MOCK) + list(APPEND DYNAMIC_LIB ${URMA_LIB}) + endif() +endif() + if(WITH_UBRING) message(STATUS "brpc compile with ubring") list(APPEND DYNAMIC_LIB ${UB_LIB}) @@ -575,6 +658,14 @@ file(GLOB_RECURSE BRPC_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/brpc file(GLOB_RECURSE THRIFT_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/brpc/thrift*.cpp") file(GLOB_RECURSE EXCLUDE_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/brpc/event_dispatcher_*.cpp") +# When building with the real liburma, exclude the link-time mock so its urma_* +# symbols do not clash with the library. When liburma is absent, keep it so CI +# can build and test UrmaTransport without URMA hardware. +if(WITH_URMA AND NOT URMA_USE_MOCK) + list(REMOVE_ITEM BRPC_SOURCES + "${PROJECT_SOURCE_DIR}/src/brpc/urma/mock_urma.cpp") +endif() + if(WITH_THRIFT) message("brpc compile with thrift protocol") else() @@ -615,7 +706,8 @@ set(PROTO_FILES idl_options.proto brpc/trackme.proto brpc/streaming_rpc_meta.proto brpc/proto_base.proto - brpc/rdma/rdma_handshake.proto) + brpc/rdma/rdma_handshake.proto + brpc/urma/urma_handshake.proto) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/output/include/brpc) set(PROTOC_FLAGS ${PROTOC_FLAGS} -I${PROTOBUF_INCLUDE_DIR}) compile_proto(PROTO_HDRS PROTO_SRCS ${PROJECT_BINARY_DIR} diff --git a/MODULE.bazel b/MODULE.bazel index 6f7b01a86e..bb5e05b48c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,3 +1,20 @@ +# 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. + module( name = 'brpc', version = '1.17.0', @@ -10,11 +27,10 @@ bazel_dep(name = 'bazel_skylib', version = '1.0.3') bazel_dep(name = 'boringssl', version = '0.0.0-20211025-d4f1ab9') bazel_dep(name = 'protobuf', version = '27.3', repo_name = 'com_google_protobuf') bazel_dep(name = 'gflags', version = '2.2.2', repo_name = 'com_github_gflags_gflags') -bazel_dep(name = 'glog', version = '0.5.0', repo_name = 'com_github_google_glog') +bazel_dep(name = 'glog', version = '0.7.1', repo_name = 'com_github_google_glog') bazel_dep(name = 'platforms', version = '0.0.4') bazel_dep(name = "apple_support", version = "1.22.1") bazel_dep(name = 'rules_cc', version = '0.0.1') -bazel_dep(name = 'rules_proto', version = '4.0.0') bazel_dep(name = 'zlib', version = '1.3.1.bcr.5', repo_name = 'com_github_madler_zlib') bazel_dep(name = 'babylon', version = '1.4.4') # --registry=https://raw.githubusercontent.com/apache/brpc/master/registry @@ -52,3 +68,22 @@ git_override( remote = 'https://github.com/hedronvision/bazel-compile-commands-extractor.git', commit = '1e08f8e0507b6b6b1f4416a9a22cf5c28beaba93', # Jun 28, 2024 ) + +git_repository = use_repo_rule( + '@bazel_tools//tools/build_defs/repo:git.bzl', + 'git_repository', +) +git_repository( + name = 'umdk', + build_file = '//bazel/third_party/umdk:umdk.BUILD', + remote = 'https://atomgit.com/openeuler/umdk.git', + commit = '564ee727a55523d4351a8fb3c94292b388ebb924', # v26.06.0_CAM + # umdk ships its own src/urma/BUILD.bazel, which turns src/urma into a + # separate Bazel package and silently empties the glob() in umdk.BUILD + # (glob cannot cross package boundaries). Drop it so the headers under + # src/urma/lib/urma/**/include stay part of this repository's root + # package. + patch_cmds = [ + 'rm -f src/urma/BUILD.bazel', + ], +) diff --git a/Makefile b/Makefile index 86de388448..271b518ae6 100644 --- a/Makefile +++ b/Makefile @@ -204,9 +204,15 @@ JSON2PB_SOURCES = $(foreach d,$(JSON2PB_DIRS),$(wildcard $(addprefix $(d)/*,$(SR JSON2PB_OBJS = $(addsuffix .o, $(basename $(JSON2PB_SOURCES))) BRPC_DIRS = src/brpc src/brpc/details src/brpc/builtin src/brpc/policy src/brpc/policy/mysql src/brpc/rdma +ifeq ($(WITH_URMA),1) +BRPC_DIRS += src/brpc/urma +endif THRIFT_SOURCES = $(foreach d,$(BRPC_DIRS),$(wildcard $(addprefix $(d)/thrift*,$(SRCEXTS)))) EXCLUDE_SOURCES = $(foreach d,$(BRPC_DIRS),$(wildcard $(addprefix $(d)/event_dispatcher_*,$(SRCEXTS)))) BRPC_SOURCES_ALL = $(foreach d,$(BRPC_DIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS)))) +ifeq ($(URMA_USE_MOCK),0) +BRPC_SOURCES_ALL := $(filter-out src/brpc/urma/mock_urma.cpp,$(BRPC_SOURCES_ALL)) +endif BRPC_SOURCES = $(filter-out $(THRIFT_SOURCES) $(EXCLUDE_SOURCES), $(BRPC_SOURCES_ALL)) BRPC_PROTOS = $(filter %.proto,$(BRPC_SOURCES)) BRPC_CFAMILIES = $(filter-out %.proto %.pb.cc,$(BRPC_SOURCES)) diff --git a/WORKSPACE b/WORKSPACE index 78a6c2836a..fcb1e97533 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -279,6 +279,21 @@ http_archive( urls = ["https://archive.apache.org/dist/thrift/0.15.0/thrift-0.15.0.tar.gz"], ) +git_repository( + name = "umdk", + build_file = "//bazel/third_party/umdk:umdk.BUILD", + remote = "https://atomgit.com/openeuler/umdk.git", + commit = "564ee727a55523d4351a8fb3c94292b388ebb924", # v26.06.0_CAM + # umdk ships its own src/urma/BUILD.bazel, which turns src/urma into a + # separate Bazel package and silently empties the glob() in umdk.BUILD + # (glob cannot cross package boundaries). Drop it so the headers under + # src/urma/lib/urma/**/include stay part of this repository's root + # package. + patch_cmds = [ + "rm -f src/urma/BUILD.bazel", + ], +) + # Header-only JSON library used by iobuf_unittest's IOBuf<->std::iostream # adapter tests. Keep version in sync with MODULE.bazel. http_archive( @@ -317,4 +332,4 @@ http_archive( sha256 = "3cd0e49f0f4a6d406c1d74b53b7616f5e24f5fd319eafc1bf8eee6e14124d115", ) load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup") -hedron_compile_commands_setup() \ No newline at end of file +hedron_compile_commands_setup() diff --git a/bazel/config/BUILD.bazel b/bazel/config/BUILD.bazel index fabc4be061..96cd46cbcb 100644 --- a/bazel/config/BUILD.bazel +++ b/bazel/config/BUILD.bazel @@ -110,6 +110,12 @@ config_setting( visibility = ["//visibility:public"], ) +config_setting( + name = "brpc_with_urma", + define_values = {"BRPC_WITH_URMA": "true"}, + visibility = ["//visibility:public"], +) + config_setting( name = "brpc_with_boringssl", define_values = {"BRPC_WITH_BORINGSSL": "true"}, @@ -155,4 +161,10 @@ config_setting( name = "with_babylon_counter", define_values = {"with_babylon_counter": "true"}, visibility = ["//visibility:public"], -) \ No newline at end of file +) + +config_setting( + name = "brpc_with_ubring", + define_values = {"BRPC_WITH_UBRING": "true"}, + visibility = ["//visibility:public"], +) diff --git a/bazel/third_party/umdk/BUILD.bazel b/bazel/third_party/umdk/BUILD.bazel new file mode 100644 index 0000000000..fefa6c3fea --- /dev/null +++ b/bazel/third_party/umdk/BUILD.bazel @@ -0,0 +1,17 @@ +# 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. +# +# Thie empty BUILD.bazel file is required to make Bazel treat +# this directory as a package. diff --git a/bazel/third_party/umdk/umdk.BUILD b/bazel/third_party/umdk/umdk.BUILD new file mode 100644 index 0000000000..410e6a2736 --- /dev/null +++ b/bazel/third_party/umdk/umdk.BUILD @@ -0,0 +1,28 @@ +# 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. + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "urma_headers", + hdrs = glob([ + "src/urma/lib/urma/bond/include/*.h", + "src/urma/lib/urma/core/include/*.h", + ]), + includes = [ + "src/urma/lib/urma/bond/include", + "src/urma/lib/urma/core/include", + ], +) diff --git a/bazel/tools/brpc_proto_library.bzl b/bazel/tools/brpc_proto_library.bzl index 22a3c00bee..f95033bea5 100644 --- a/bazel/tools/brpc_proto_library.bzl +++ b/bazel/tools/brpc_proto_library.bzl @@ -70,17 +70,13 @@ def brpc_proto_library( include: protoc `-I` root AND the resulting cc_library `includes` root, relative to the current package. When omitted, "" or None, the include root is the - current package itself (suitable for .proto files - sitting directly under the package root, as in `test/` - and `example/...`). The root `BUILD.bazel` of brpc must - pass `"src"` so that code can reference the protos as - `import "brpc/foo.proto"`. + current package itself. proto_deps: list of native `proto_library` dependencies (well-known protos or external .proto libraries). Defaults to `["@com_google_protobuf//:descriptor_proto"]`. - Pass `[]` explicitly to disable the default; pass - None (the default) to use it. + Pass `[]` explicitly to disable the default. + Pass None (the default) to use it. visibility: same semantics as cc_library. testonly: same semantics as cc_library. """ @@ -127,11 +123,11 @@ def brpc_proto_library( # cc_library `includes` is required, otherwise the .pb.cc # files inside this cc_library cannot find the .pb.h headers # they just generated (the headers live under - # bazel-bin///...). When include="" we pass - # "." to mean "the current package itself"; Bazel then exposes - # both `-I ` and `-I bazel-bin/` - # automatically to dependents. - includes = [real_include if real_include else "."], + # bazel-bin///...). For a non-root package + # with include="", "." exposes the current package's source + # and bazel-bin directories. The root package needs no extra + # include because those roots are already on the search path. + includes = [real_include] if real_include else (["."] if native.package_name() else []), deps = deps + ["@com_google_protobuf//:protobuf"], visibility = visibility, testonly = testonly, diff --git a/bazel/tools/proto_gen.bzl b/bazel/tools/proto_gen.bzl index 554d24df87..c2e9c3b59b 100644 --- a/bazel/tools/proto_gen.bzl +++ b/bazel/tools/proto_gen.bzl @@ -60,31 +60,46 @@ def _resolve_include_dir(ctx): ctx.label.package = "" + include = "src" -> "src" ctx.label.package = "test" + include = "" -> "test" ctx.label.package = "" + include = "" -> "." + + When the target is in an external repository, the returned path needs + to be prefixed with workspace_root. """ pkg = ctx.label.package inc = ctx.attr.include.rstrip("/") if pkg and inc: - return pkg + "/" + inc - if pkg: - return pkg - if inc: - return inc - return "." + rel_path = pkg + "/" + inc + elif pkg: + rel_path = pkg + elif inc: + rel_path = inc + else: + rel_path = "." + + workspace_root = ctx.label.workspace_root + if workspace_root: + if rel_path == ".": + return workspace_root + else: + return workspace_root + "/" + rel_path + return rel_path def _proto_gen_impl(ctx): srcs = ctx.files.srcs include_dir = _resolve_include_dir(ctx) bin_root = ctx.bin_dir.path + current_workspace_root = ctx.label.workspace_root - # `-I` flags for this target itself: the source-tree root plus - # the corresponding bin-dir root. The bin-dir entry is needed - # when a transitive dep generates .proto files into bazel-bin - # (e.g. via a custom code generator). + # Add both the source-tree include root and its bazel-bin counterpart. + # For external repositories, include_dir already starts with workspace_root, + # so appending it to bin_root addresses generated protos in that repository. own_imports = ["-I" + include_dir] - if include_dir == ".": - own_imports.append("-I" + bin_root) - else: + if current_workspace_root: own_imports.append("-I" + bin_root + "/" + include_dir) + else: + if include_dir == ".": + own_imports.append("-I" + bin_root) + else: + own_imports.append("-I" + bin_root + "/" + include_dir) # Collect transitive info from other `brpc_proto_gen` deps. dep_srcs_list = [d[BrpcProtoInfo].transitive_srcs for d in ctx.attr.deps] @@ -120,12 +135,12 @@ def _proto_gen_impl(ctx): proto_dep_src_depsets.append(pi.transitive_sources) for path in pi.transitive_proto_path.to_list(): proto_dep_imports.append("-I" + path) - wsroot = pd.label.workspace_root - if wsroot: - extra_pb_root_imports.append("-I" + wsroot) - extra_pb_root_imports.append("-I" + bin_root + "/" + wsroot) - extra_pb_root_imports.append("-I" + wsroot + "/src") - extra_pb_root_imports.append("-I" + bin_root + "/" + wsroot + "/src") + dep_workspace_root = pd.label.workspace_root + if dep_workspace_root: + extra_pb_root_imports.append("-I" + dep_workspace_root) + extra_pb_root_imports.append("-I" + bin_root + "/" + dep_workspace_root) + extra_pb_root_imports.append("-I" + dep_workspace_root + "/src") + extra_pb_root_imports.append("-I" + bin_root + "/" + dep_workspace_root + "/src") # Deduplicate the workspace-level `-I` entries so the same repo # is not listed multiple times when several proto_deps share it. proto_dep_imports.extend(depset(extra_pb_root_imports).to_list()) @@ -156,14 +171,16 @@ def _proto_gen_impl(ctx): outs.append(ctx.actions.declare_file(base + ".pb.h")) outs.append(ctx.actions.declare_file(base + ".pb.cc")) - # protoc's --cpp_out points at the include root under bin_root. - # After protoc organizes outputs by their import-relative path, - # the .pb.{h,cc} files land exactly where declare_file declared - # them above. - if include_dir == ".": - cpp_out_dir = bin_root - else: + # Point protoc at this target's include root under bazel-bin. For external + # repositories, include_dir includes workspace_root, which places generated + # files under the repository-specific portion of bazel-bin. + if current_workspace_root: cpp_out_dir = bin_root + "/" + include_dir + else: + if include_dir == ".": + cpp_out_dir = bin_root + else: + cpp_out_dir = bin_root + "/" + include_dir args = ctx.actions.args() args.add_all(all_imports.to_list()) diff --git a/config_brpc.sh b/config_brpc.sh index 85692de3cb..edfa989c49 100755 --- a/config_brpc.sh +++ b/config_brpc.sh @@ -54,10 +54,12 @@ else LDD=ldd fi -TEMP=`getopt -o v: --long headers:,libs:,cc:,cxx:,with-glog,with-thrift,with-rdma,with-mesalink,with-bthread-tracer,with-debug-bthread-sche-safety,with-debug-lock,with-asan,with-riscv-zvbc,with-riscv-zbc,with-cpu-frequency,nodebugsymbols,werror -n 'config_brpc' -- "$@"` +TEMP=`getopt -o v: --long headers:,libs:,cc:,cxx:,with-glog,with-thrift,with-rdma,with-urma,with-urma-mock,with-mesalink,with-bthread-tracer,with-debug-bthread-sche-safety,with-debug-lock,with-asan,with-riscv-zvbc,with-riscv-zbc,with-cpu-frequency,nodebugsymbols,werror -n 'config_brpc' -- "$@"` WITH_GLOG=0 WITH_THRIFT=0 WITH_RDMA=0 +WITH_URMA=0 +WITH_URMA_MOCK=0 WITH_MESALINK=0 WITH_BTHREAD_TRACER=0 WITH_ASAN=0 @@ -90,6 +92,8 @@ while true; do --with-glog ) WITH_GLOG=1; shift 1 ;; --with-thrift) WITH_THRIFT=1; shift 1 ;; --with-rdma) WITH_RDMA=1; shift 1 ;; + --with-urma) WITH_URMA=1; shift 1 ;; + --with-urma-mock) WITH_URMA_MOCK=1; shift 1 ;; --with-mesalink) WITH_MESALINK=1; shift 1 ;; --with-bthread-tracer) WITH_BTHREAD_TRACER=1; shift 1 ;; --with-debug-bthread-sche-safety ) BRPC_DEBUG_BTHREAD_SCHE_SAFETY=1; shift 1 ;; @@ -538,6 +542,29 @@ if [ $WITH_RDMA != 0 ]; then append_to_output "WITH_RDMA=1" fi +if [ $WITH_URMA != 0 ]; then + URMA_LIB=$(find_dir_of_lib urma) + URMA_HDR=$(find_dir_of_header_or_die urma_api.h) + URMA_BOND_HDR=$(find_dir_of_header urma_ubagg.h) + CPPFLAGS="${CPPFLAGS} -DBRPC_WITH_URMA=1" + append_to_output "WITH_URMA=1" + append_to_output_headers "$URMA_HDR" + if [ -n "$URMA_BOND_HDR" ]; then + append_to_output_headers "$URMA_BOND_HDR" + fi + if [ -n "$URMA_LIB" ]; then + append_to_output_libs "$URMA_LIB" + append_to_output "DYNAMIC_LINKINGS+=-lurma" + append_to_output "URMA_USE_MOCK=0" + elif [ $WITH_URMA_MOCK != 0 ]; then + append_to_output "URMA_USE_MOCK=1" + print_info "liburma not found; --with-urma-mock given, using URMA link-time mock" + else + >&2 $ECHO "Fail to find liburma. Install liburma, or explicitly opt into brpc's link-time mock with --with-urma-mock (the mock cannot talk to real URMA hardware; only use it for CI/tests without URMA hardware)." + exit 1 + fi +fi + if [ $WITH_MESALINK != 0 ]; then CPPFLAGS="${CPPFLAGS} -DUSE_MESALINK" fi @@ -674,6 +701,7 @@ print_info "System: $SYSTEM" if [ $WITH_GLOG -ne 0 ]; then print_info "With glog: yes"; fi if [ $WITH_THRIFT -ne 0 ]; then print_info "With thrift: yes"; fi if [ $WITH_RDMA -ne 0 ]; then print_info "With RDMA: yes"; fi +if [ $WITH_URMA -ne 0 ]; then print_info "With URMA: yes"; fi if [ $WITH_MESALINK -ne 0 ]; then print_info "With MesaLink: yes"; fi if [ $WITH_BTHREAD_TRACER -ne 0 ]; then print_info "With bthread tracer: yes"; fi if [ $WITH_ASAN -ne 0 ]; then print_info "With ASAN: yes"; fi diff --git a/docs/cn/ubring.md b/docs/cn/ubring.md index 6519ae3f9f..1db9909103 100644 --- a/docs/cn/ubring.md +++ b/docs/cn/ubring.md @@ -71,10 +71,13 @@ cmake --build build -j 8 ```bash # 构建 brpc 并启用 UBRing 支持 cd /path/to/brpc -bazel build //... --define=with_ubring=true +bazel build //:brpc --define=BRPC_WITH_UBRING=true # 构建 ubring_performance 示例 -bazel build //example/ubring_performance/... +bazel build \ + //example:ubring_performance_server \ + //example:ubring_performance_client \ + --define=BRPC_WITH_UBRING=true ``` ### 选择共享内存后端 diff --git a/docs/cn/urma.md b/docs/cn/urma.md new file mode 100644 index 0000000000..b1c048fae1 --- /dev/null +++ b/docs/cn/urma.md @@ -0,0 +1,175 @@ +# UrmaTransport:基于 URMA 的远程内存 RPC + +UrmaTransport 是使用 openEuler +[URMA](https://atomgit.com/openeuler/umdk)(Unified Remote Memory Access)SDK +实现的传输层。它是 +[#3217](https://github.com/apache/brpc/discussions/3217) 中提出的路线 B, +与基于 OBMM 的 UBRing 传输(路线 A, +[#3226](https://github.com/apache/brpc/issues/3226))互补,承担大包/跨节点 +高吞吐场景,共同构成路线 C(双后端)。 + +## 技术背景 + +URMA 在 UMDK 支持的设备上提供 verbs 风格接口。当前实现创建可靠消息 +(`URMA_TM_RM`)Jetty,并使用 CTP 传输路径;通过 +`urma_post_jetty_send_wr` 提交发送 WR,通过 `urma_post_jfr_wr` 提交接收 +WR。完成事件既可由 JFC 忙轮询获取,也可通过 JFCE 事件 fd 获取。 + +## 编译配置 + +### CMake 编译 + +```bash +# 带 URMA 支持编译 brpc(需要 liburma;无硬件/CI 场景见下方 mock 说明) +cmake -B build -DWITH_URMA=ON +make -C build -j$(nproc) + +# 编译 urma_performance 示例 +cd example/urma_performance +cmake -B build +make -C build -j$(nproc) +``` + +未安装 `liburma` 时(例如 CI 环境),需显式开启链接期 mock,而不是依赖 +隐式回退: + +```bash +cmake -B build -DWITH_URMA=ON -DWITH_URMA_MOCK=ON +make -C build -j$(nproc) +``` + +`WITH_URMA=ON` 使用上游 UMDK 头文件进行编译。CMake 优先使用系统安装的 +SDK;找不到头文件时,会参照 Mooncake 的 mock 构建方式下载固定版本的 +UMDK,可通过 `DOWNLOAD_URMA_HEADERS=OFF` 禁止下载。找到 `liburma` 时使用 +真实硬件数据通路;否则默认直接报错终止构建,避免静默回退到 mock 而产出 +一个看似支持 URMA、实际无法访问真实硬件的产物。需要在无硬件环境(例如 +CI)编译和测试 URMA 代码时,显式传入 `-DWITH_URMA_MOCK=ON` +(Make 对应 `config_brpc.sh --with-urma-mock`)以主动选择链接 brpc 的 +mock。 + +### Bazel 编译 + +```bash +# 带 URMA 支持编译 brpc +bazel build --define=BRPC_WITH_URMA=true //:brpc +``` + +Bazel 下的 URMA 头文件来自 `WORKSPACE` / `MODULE.bazel` 中固定 commit 的 +`umdk` `git_repository`,没有 CMake `DOWNLOAD_URMA_HEADERS` 那样的开关: +既不能改用系统已安装的 SDK 头文件,也无法禁止下载。此外 Bazel 构建目前 +未提供检测/链接真实 `liburma` 的逻辑,`src/brpc/urma/mock_urma.cpp` 会 +无条件编入,因此 Bazel 构建的 URMA 始终使用 mock 数据通路;如需链接真实 +硬件,请使用 CMake 或 Make 构建。`urma_performance` 示例目前也只有 +CMake/Make 构建脚本,尚无对应的 Bazel target。 + +## 使用 + +通过在 channel / server 上设置 `socket_mode` 选择传输层: + +```cpp +// 客户端 +brpc::ChannelOptions opt; +opt.socket_mode = brpc::SOCKET_MODE_URMA; +opt.protocol = "baidu_std"; // URMA 仅支持 baidu_std +brpc::Channel channel; +channel.Init("127.0.0.1:8003", &opt); + +// 服务端 +brpc::ServerOptions sopt; +sopt.socket_mode = brpc::SOCKET_MODE_URMA; +server.Start(port, &sopt); +``` + +若对端不支持 URMA(例如 TCP 客户端连接 URMA 服务端),在 4 字节 magic +握手后透明回退到 TCP,应用代码无需改动。 + +## 架构 + +UrmaTransport 沿用与 `RdmaTransport` / `UBShmTransport` 一致的两层设计: + +``` +UrmaTransport : public Transport (urma_transport.{h,cpp}) + +-- std::shared_ptr (回退路径) + +-- urma::UrmaEndpoint* (URMA 数据路径) + +-- UrmaState { URMA_ON, URMA_OFF, URMA_UNKNOWN } + +urma::UrmaEndpoint : public SocketUser (urma/urma_endpoint.{h,cpp}) + +-- UrmaResource { jfc, jfce, jfr, jetty, remote_jetty, remote_seg } + +-- 握手状态机(C/S 对称,在 TCP fd 上驱动) + +-- 发送路径:urma_post_jetty_send_wr(URMA_OPC_SEND) + +-- 接收路径:urma_poll_jfc -> HandleCompletion -> InputMessenger + +-- 双窗口信用流控(_remote_rq_window_size / _sq_window_size) +``` + +### 建链流程(双平面) + +与 RDMA / UBRing 一致,控制面为 TCP,数据面为 URMA: + +1. TCP 连接建立。 +2. `UrmaConnect::StartConnect` 起客户端握手 bthread。 +3. 双方在 TCP fd 上交换 `UrmaHello` 消息(v2 二进制 magic `URMA`, + v3 protobuf magic `URM3`),携带本地 EID、jetty id、recv buffer 数量、 + 以及扁平化的 buffer 池 segment。 +4. 双方先调用 `urma_import_seg` **再**调用 `urma_import_jetty`,为远端 EID + 建立传输路径(TP)路由。跳过 `import_seg` 会导致首个 SEND 被硬件以 + `URMA_CR_RNR_RETRY_CNT_EXC_ERR` 拒绝。 +5. 4 字节 ACK(`HELLO_ACK_URMA_OK = 0x1`)确认双方均要 URMA。 +6. 成功后 TCP fd 仅保留用于 epoll 生命周期和回退,数据走 URMA。 + +### 内存管理 + +申请一大段 `mmap` 内存,用 `urma_register_seg` 一次性注册,再切成固定大小 +buffer(默认 8KB)。劫持 `butil::iobuf::blockmem_allocate` 使每个 IOBuf +block 都由注册 segment 支撑,发送路径可直接从 IOBuf block refs 构建 +`urma_sge_t`,无需逐消息注册(与 RDMA `block_pool` 设计一致)。用户注册 +内存通过 `urma::RegisterMemoryForUrma` / `DeregisterMemoryForUrma` 支持。 + +## 配置 + +所有 flag 使用 `urma_` 前缀(对标 RDMA 的 `rdma_` 前缀): + +| Flag | 默认 | 用途 | +|------|------|------| +| `--urma_use_polling` | false | 轮询 JFC 而非事件模式 | +| `--urma_poller_num` | 1 | 每 bthread tag 的轮询器数(轮询模式) | +| `--urma_disable_bthread` | false | 内联处理消息(不起 bthread) | +| `--urma_sq_size` | 128 | 本地 JFS 深度 [16, 4096] | +| `--urma_rq_size` | 128 | 本地 JFR 深度 [16, 4096] | +| `--urma_cqe_poll_once` | 32 | 每次 `urma_poll_jfc` 的上限 | +| `--urma_recv_zerocopy` | true | 大于 `--urma_zerocopy_min_size` 的接收零拷贝 | +| `--urma_zerocopy_min_size` | 512 | 小于此值的接收拷贝 | +| `--urma_device` | "" | URMA 设备名(空=首个) | +| `--urma_max_sge` | 0 | 每 WR SGE 上限(0=设备上限) | +| `--urma_bonding_mode` | 0 | bonding 模式:0=standalone,1=active-backup,2=balance | +| `--urma_bonding_level` | 0 | bonding 层级:0=IODIE,1=port | +| `--urma_prepared_jetty_cnt` | 8 | 预连接 Jetty+CQ 请求数量;会根据 `RLIMIT_NOFILE` 自动限制 | +| `--urma_buffer_size` | 8192 | 池中每个 buffer 大小(字节) | +| `--urma_buffer_count` | 65536 | 池中 buffer 数量 | +| `--urma_poller_yield` | false | 忙轮询循环中主动让出 bthread | +| `--urma_client_handshake_version` | 2 | 客户端握手版本(2=二进制,3=protobuf) | + +设备名以 `bonding` 开头时,brpc 会在创建 context 后、创建 segment 和队列 +前配置 provider。默认 standalone+IODIE 配置与 UMDK 性能工具保持一致。 +bonding 支持需要 provider 扩展头文件 `urma_ubagg.h`。 + +## 与 UBRing 协同 + +UrmaTransport 推荐用于**大包和跨节点**高吞吐路径,而 UBRing +(`SOCKET_MODE_UBRING`)对**小包和同机 IPC**最优(亚微秒、零系统调用)。 +混合负载可按服务选择传输层: + +| 场景 | 建议 `socket_mode` | +|------|---------------------| +| 同机 IPC | `SOCKET_MODE_UBRING` | +| 跨节点小包(< 64KB) | `SOCKET_MODE_UBRING`(UBS-Mem)或 `SOCKET_MODE_URMA` | +| 跨节点大包(>= 64KB) | `SOCKET_MODE_URMA` | +| 传统 RoCE/IB 数据中心 | `SOCKET_MODE_URMA` 或 `SOCKET_MODE_RDMA` | + +单连接内按包大小自动分流的方案(路线 C 方案 B)作为后续演进方向。 + +## 限制 + +- 仅支持 `baidu_std` 协议(与 RDMA 一致)。SSL、RTMP、NSHEAD、MONGO 在 + `ContextInitOrDie` 阶段拒绝。 +- 硬件数据通路需要受支持的 UMDK provider 和 `liburma`。 +- 当前实现面向 Linux。 diff --git a/docs/en/ubring.md b/docs/en/ubring.md index f910facb7b..fbf87fff36 100644 --- a/docs/en/ubring.md +++ b/docs/en/ubring.md @@ -70,10 +70,13 @@ To build brpc with UBRing support using Bazel: ```bash # Build brpc with UBRing support cd /path/to/brpc -bazel build //... --define=with_ubring=true +bazel build //:brpc --define=BRPC_WITH_UBRING=true # Build the ubring_performance example -bazel build //example/ubring_performance/... +bazel build \ + //example:ubring_performance_server \ + //example:ubring_performance_client \ + --define=BRPC_WITH_UBRING=true ``` ### Select Shared Memory Backend diff --git a/docs/en/urma.md b/docs/en/urma.md new file mode 100644 index 0000000000..8556fbdf93 --- /dev/null +++ b/docs/en/urma.md @@ -0,0 +1,190 @@ +# UrmaTransport: URMA-based Remote Memory RPC + +UrmaTransport is a transport implementation that uses openEuler's +[URMA](https://atomgit.com/openeuler/umdk) (Unified Remote Memory Access) SDK +for remote-memory RPC. It is the Route B transport proposed in +[#3217](https://github.com/apache/brpc/discussions/3217) and complements the +OBMM-based UBRing transport (Route A, [#3226](https://github.com/apache/brpc/issues/3226)) +for large-packet / cross-node scenarios (Route C, "double backend"). + +## Technical Background + +URMA exposes a verbs-style API over devices supported by UMDK. This +implementation creates a reliable-message (`URMA_TM_RM`) Jetty with a CTP +transport path, posts send work requests with `urma_post_jetty_send_wr`, and +posts receive work requests with `urma_post_jfr_wr`. Completions are consumed +from a JFC either by busy polling or through a JFCE event fd. + +## Build Configuration + +### Build with CMake + +```bash +# Build brpc with URMA support (requires liburma; see below for CI/mock builds) +cmake -B build -DWITH_URMA=ON +make -C build -j$(nproc) + +# Build the urma_performance example +cd example/urma_performance +cmake -B build +make -C build -j$(nproc) +``` + +Without `liburma` installed (e.g. in CI), explicitly opt into the link-time +mock instead of relying on an implicit fallback: + +```bash +cmake -B build -DWITH_URMA=ON -DWITH_URMA_MOCK=ON +make -C build -j$(nproc) +``` + +`WITH_URMA=ON` compiles against upstream UMDK headers. CMake prefers an +installed SDK and, following Mooncake's mock setup, downloads a pinned UMDK +release when the headers are unavailable. Set `DOWNLOAD_URMA_HEADERS=OFF` to +disable downloading. +When `liburma` is found it is linked for the hardware data path. Otherwise +the build fails by default, since silently falling back to the mock could +mask a broken environment and ship a binary that looks URMA-capable but +cannot reach real hardware. Pass `-DWITH_URMA_MOCK=ON` +(`config_brpc.sh --with-urma-mock`) to explicitly opt into brpc's +link-time mock so URMA code and tests can still be built without hardware +(e.g. in CI). + +### Build with Bazel + +```bash +# Build brpc with URMA support +bazel build --define=BRPC_WITH_URMA=true //:brpc +``` + +Bazel fetches the UMDK headers from the `umdk` `git_repository` pinned to a +fixed commit in `WORKSPACE` / `MODULE.bazel`. There is no Bazel equivalent of +CMake's `DOWNLOAD_URMA_HEADERS`: Bazel can neither use a locally installed SDK +nor disable the download. Bazel builds also have no detection/linking logic +for a real `liburma` yet — `src/brpc/urma/mock_urma.cpp` is compiled in +unconditionally, so a Bazel build of URMA always uses the mock data path. Use +CMake or Make to link against real hardware. The `urma_performance` example +currently only has CMake/Make build files; there is no Bazel target for it +yet. + +## Usage + +Select the transport by setting `socket_mode` on the channel / server: + +```cpp +// Client +brpc::ChannelOptions opt; +opt.socket_mode = brpc::SOCKET_MODE_URMA; +opt.protocol = "baidu_std"; // URMA supports baidu_std only +brpc::Channel channel; +channel.Init("127.0.0.1:8003", &opt); + +// Server +brpc::ServerOptions sopt; +sopt.socket_mode = brpc::SOCKET_MODE_URMA; +server.Start(port, &sopt); +``` + +If the peer does not speak URMA (e.g. a TCP-only client connecting to a +URMA-enabled server), the transport transparently falls back to TCP after +the 4-byte magic handshake. No application code change is required. + +## Architecture + +UrmaTransport follows the same two-layer design as `RdmaTransport` and +`UBShmTransport`: + +``` +UrmaTransport : public Transport (urma_transport.{h,cpp}) + +-- std::shared_ptr (fallback path) + +-- urma::UrmaEndpoint* (URMA data path) + +-- UrmaState { URMA_ON, URMA_OFF, URMA_UNKNOWN } + +urma::UrmaEndpoint : public SocketUser (urma/urma_endpoint.{h,cpp}) + +-- UrmaResource { jfc, jfce, jfr, jetty, remote_jetty, remote_seg } + +-- handshake state machine (C/S symmetric, driven over the TCP fd) + +-- send path: urma_post_jetty_send_wr(URMA_OPC_SEND) + +-- recv path: urma_poll_jfc -> HandleCompletion -> InputMessenger + +-- two-window credit flow control + (_remote_rq_window_size / _sq_window_size) +``` + +### Connection establishment (dual-plane) + +Like RDMA / UBRing, the control plane is TCP and the data plane is URMA: + +1. TCP connect completes. +2. `UrmaConnect::StartConnect` spawns the client handshake bthread. +3. Both sides exchange a `UrmaHello` message (magic `URMA` for v2 binary, + `URM3` for v3 protobuf) over the TCP fd. The message carries the local + EID, jetty id, recv buffer count, and the flattened buffer-pool segment. +4. Each side calls `urma_import_seg` **before** `urma_import_jetty` to + establish transport-path (TP) routing for the remote EID. Skipping the + `import_seg` step causes the first SEND to be rejected by hardware with + `URMA_CR_RNR_RETRY_CNT_EXC_ERR`. +5. A 4-byte ACK (`HELLO_ACK_URMA_OK = 0x1`) confirms both sides want URMA. +6. On success, the TCP fd is kept only for the epoll lifecycle and fallback; + payloads flow through URMA. + +### Memory management + +A single large region is `mmap`-ed and registered once with +`urma_register_seg`, then sliced into fixed-size buffers (default 8 KB). +`butil::iobuf::blockmem_allocate` is hijacked so every IOBuf block is backed +by the registered segment, allowing the send path to build `urma_sge_t` +directly from IOBuf block refs without per-message registration (mirroring the +RDMA `block_pool` design). User-registered memory is supported via +`urma::RegisterMemoryForUrma` / `DeregisterMemoryForUrma`. + +## Configuration + +All flags use the `urma_` prefix (mirroring RDMA's `rdma_` prefix): + +| Flag | Default | Purpose | +|------|---------|---------| +| `--urma_use_polling` | false | Busy-poll the JFC instead of event mode | +| `--urma_poller_num` | 1 | Poller bthreads per bthread tag (polling mode) | +| `--urma_disable_bthread` | false | Run message processing inline | +| `--urma_sq_size` | 128 | Local JFS depth [16, 4096] | +| `--urma_rq_size` | 128 | Local JFR depth [16, 4096] | +| `--urma_cqe_poll_once` | 32 | Max CQEs per `urma_poll_jfc` | +| `--urma_recv_zerocopy` | true | Zero-copy receives above `--urma_zerocopy_min_size` | +| `--urma_zerocopy_min_size` | 512 | Receives smaller than this are copied | +| `--urma_device` | "" | URMA device name (empty = first) | +| `--urma_max_sge` | 0 | Max SGEs per WR (0 = device max) | +| `--urma_bonding_mode` | 0 | Bonding mode: 0=standalone, 1=active-backup, 2=balance | +| `--urma_bonding_level` | 0 | Bonding level: 0=IODIE, 1=port | +| `--urma_prepared_jetty_cnt` | 8 | Requested pre-allocated Jetty+CQ sets; automatically capped according to `RLIMIT_NOFILE` | +| `--urma_buffer_size` | 8192 | Per-buffer size in the pool (bytes) | +| `--urma_buffer_count` | 65536 | Number of buffers in the pool | +| `--urma_poller_yield` | false | Yield in the busy-poll loop | +| `--urma_client_handshake_version` | 2 | Client wire version (2=binary, 3=protobuf) | + +For a device whose name starts with `bonding`, brpc configures the provider +immediately after context creation and before creating segments or queues. +The default standalone+IODIE combination matches the UMDK performance tool. +Bonding support requires the provider extension header `urma_ubagg.h`. + +## Coexistence with UBRing + +UrmaTransport is the recommended transport for **large packets and +cross-node** high-throughput paths, while UBRing (`SOCKET_MODE_UBRING`) is +optimal for **small packets and same-node IPC** (sub-microsecond, zero +syscalls). For a mixed workload, select the transport per service: + +| Scenario | Recommended `socket_mode` | +|----------|---------------------------| +| Same-host IPC | `SOCKET_MODE_UBRING` | +| Cross-node small packets (< 64 KB) | `SOCKET_MODE_UBRING` (UBS-Mem) or `SOCKET_MODE_URMA` | +| Cross-node large packets (>= 64 KB) | `SOCKET_MODE_URMA` | +| Traditional RoCE / IB datacenter | `SOCKET_MODE_URMA` or `SOCKET_MODE_RDMA` | + +A single-connection hybrid that auto-routes by packet size (Route C, scheme B) +is tracked as a future enhancement. + +## Limitations + +- `baidu_std` protocol only (same as RDMA). SSL, RTMP, NSHEAD, MONGO are + rejected at `ContextInitOrDie`. +- A hardware data path requires a supported UMDK provider and `liburma`. +- The current implementation targets Linux. diff --git a/example/BUILD.bazel b/example/BUILD.bazel index d0115dc43a..05eda2080b 100644 --- a/example/BUILD.bazel +++ b/example/BUILD.bazel @@ -37,6 +37,9 @@ COPTS = [ }) + select({ "//bazel/config:brpc_with_rdma": ["-DBRPC_WITH_RDMA=1"], "//conditions:default": [""], +}) + select({ + "//bazel/config:brpc_with_ubring": ["-DBRPC_WITH_UBRING=1"], + "//conditions:default": [""], }) brpc_proto_library( @@ -53,6 +56,13 @@ brpc_proto_library( proto_deps = [], ) +brpc_proto_library( + name = "cc_ubring_performance_proto", + srcs = ["ubring_performance/test.proto"], + include = "ubring_performance", + proto_deps = [], +) + cc_binary( name = "echo_c++_server", srcs = [ @@ -113,6 +123,36 @@ cc_binary( ], ) +cc_binary( + name = "ubring_performance_server", + srcs = [ + "ubring_performance/server.cpp", + ], + copts = COPTS, + includes = [ + "ubring_performance", + ], + deps = [ + ":cc_ubring_performance_proto", + "//:brpc", + ], +) + +cc_binary( + name = "ubring_performance_client", + srcs = [ + "ubring_performance/client.cpp", + ], + copts = COPTS, + includes = [ + "ubring_performance", + ], + deps = [ + ":cc_ubring_performance_proto", + "//:brpc", + ], +) + cc_binary( name = "redis_c++_server", srcs = [ diff --git a/example/build_with_bazel/BUILD.bazel b/example/build_with_bazel/BUILD.bazel index 9ac3da0c2d..021127f239 100644 --- a/example/build_with_bazel/BUILD.bazel +++ b/example/build_with_bazel/BUILD.bazel @@ -12,9 +12,6 @@ # 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. -# -# Thie empty BUILD.bazel file is required to make Bazel treat -# this directory as a package. cc_binary( @@ -22,8 +19,5 @@ cc_binary( srcs = ["test.cc"], deps = [ "@apache_brpc//:brpc", - "@apache_brpc//:bthread", - "@apache_brpc//:bvar", - "@apache_brpc//:butil", ], ) diff --git a/example/build_with_bazel_module/.bazelrc b/example/build_with_bazel_module/.bazelrc new file mode 100644 index 0000000000..dd2ba48d5a --- /dev/null +++ b/example/build_with_bazel_module/.bazelrc @@ -0,0 +1,61 @@ +# 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. + +# Bazel doesn't need more than 200MB of memory for local build based on memory profiling: +# https://docs.bazel.build/versions/master/skylark/performance.html#memory-profiling +# The default JVM max heapsize is 1/4 of physical memory up to 32GB which could be large +# enough to consume all memory constrained by cgroup in large host. +# Limiting JVM heapsize here to let it do GC more when approaching the limit to +# leave room for compiler/linker. +# The number 3G is chosen heuristically to both support large VM and small VM with RBE. +# Startup options cannot be selected via config. +startup --host_jvm_args=-Xmx3g +startup --host_jvm_args="-DBAZEL_TRACK_SOURCE_DIRECTORIES=1" + +# Default build options. These are applied first and unconditionally. +common --registry=https://bcr.bazel.build +common --registry=https://baidu.github.io/babylon/registry +common --registry=https://raw.githubusercontent.com/apache/brpc/master/registry + +build --verbose_failures +# Keep SHT_SYMTAB in built binaries so google::Symbolize can resolve +# in-binary functions (e.g. TestBody() in test binaries) by name +# instead of falling back to "". Bazel's default +# `--strip=sometimes` strips debug/symbol sections in fastbuild mode, +# which is what `bazel test` uses unless `-c dbg` is given. +build --strip=never +build --cxxopt="-std=c++17" +build --copt="-fno-omit-frame-pointer" +# Use gnu17 for asm keyword. +build --conlyopt="-std=gnu17" + +# Enable position independent code (this is the default on macOS and Windows) +# (Workaround for https://github.com/bazelbuild/rules_foreign_cc/issues/421) +build --copt=-fPIC +build --fission=dbg,opt +build --features=per_object_debug_info + +# We already have absl in the build, define absl=1 to tell googletest to use absl for backtrace. +build --define absl=1 + +test --config=test +test --test_output=streamed + +# Pass PATH, CC, CXX and LLVM_CONFIG variables from the environment. +build --action_env=CC +build --action_env=CXX +build --action_env=LLVM_CONFIG +build --action_env=PATH + diff --git a/example/build_with_bazel_module/.bazelversion b/example/build_with_bazel_module/.bazelversion new file mode 100644 index 0000000000..b26a34e470 --- /dev/null +++ b/example/build_with_bazel_module/.bazelversion @@ -0,0 +1 @@ +7.2.1 diff --git a/example/build_with_bazel_module/BUILD.bazel b/example/build_with_bazel_module/BUILD.bazel new file mode 100644 index 0000000000..8dbc38012c --- /dev/null +++ b/example/build_with_bazel_module/BUILD.bazel @@ -0,0 +1,32 @@ +# 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. + +load("@apache_brpc//bazel/tools:brpc_proto_library.bzl", "brpc_proto_library") + +brpc_proto_library( + name = "cc_echo_c++_proto", + srcs = ["echo.proto"], +) + +cc_binary( + name = "echo_c++_server", + srcs = [ + "server.cpp", + ], + deps = [ + ":cc_echo_c++_proto", + "@apache_brpc//:brpc", + ], +) diff --git a/example/build_with_bazel_module/MODULE.bazel b/example/build_with_bazel_module/MODULE.bazel new file mode 100644 index 0000000000..e5d66a8e10 --- /dev/null +++ b/example/build_with_bazel_module/MODULE.bazel @@ -0,0 +1,30 @@ +# 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. + +module( + name = 'brpc-example', + version = '1.17.0', + compatibility_level = 1, +) + +bazel_dep(name = 'protobuf', version = '27.3', repo_name = 'com_google_protobuf') +bazel_dep(name = 'brpc', version = '1.17.0', repo_name = 'apache_brpc') + +local_path_override( + module_name = "brpc", + path = "../..", +) \ No newline at end of file diff --git a/example/build_with_bazel_module/echo.proto b/example/build_with_bazel_module/echo.proto new file mode 100644 index 0000000000..e963faf577 --- /dev/null +++ b/example/build_with_bazel_module/echo.proto @@ -0,0 +1,33 @@ +// 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. + +syntax="proto2"; +option cc_generic_services = true; + +package example; + +message EchoRequest { + required string message = 1; +}; + +message EchoResponse { + required string message = 1; +}; + +service EchoService { + rpc Echo(EchoRequest) returns (EchoResponse); +}; diff --git a/example/build_with_bazel_module/server.cpp b/example/build_with_bazel_module/server.cpp new file mode 100644 index 0000000000..54ca096016 --- /dev/null +++ b/example/build_with_bazel_module/server.cpp @@ -0,0 +1,99 @@ +// 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. + +// A server to receive EchoRequest and send back EchoResponse. + +#include +#include +#include +#include "echo.pb.h" + +DEFINE_bool(echo_attachment, true, "Echo attachment as well"); +DEFINE_int32(port, 8002, "TCP Port of this server"); +DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no " + "read/write operations during the last `idle_timeout_s'"); +DEFINE_int32(max_concurrency, 0, "Limit of request processing in parallel"); +DEFINE_int32(internal_port, -1, "Only allow builtin services at this port"); + +namespace example { +// Your implementation of EchoService +class EchoServiceImpl : public EchoService { +public: + EchoServiceImpl() {} + ~EchoServiceImpl() {} + void Echo(google::protobuf::RpcController* cntl_base, + const EchoRequest* request, + EchoResponse* response, + google::protobuf::Closure* done) { + brpc::ClosureGuard done_guard(done); + brpc::Controller* cntl = + static_cast(cntl_base); + + // Echo request and its attachment + response->set_message(request->message()); + if (FLAGS_echo_attachment) { + cntl->response_attachment().append(cntl->request_attachment()); + } + } +}; +} // namespace example + +DEFINE_bool(h, false, "print help information"); + +int main(int argc, char* argv[]) { + std::string help_str = "dummy help infomation"; + GFLAGS_NAMESPACE::SetUsageMessage(help_str); + + // Parse gflags. We recommend you to use gflags as well. + GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true); + + if (FLAGS_h) { + fprintf(stderr, "%s\n%s\n%s", help_str.c_str(), help_str.c_str(), help_str.c_str()); + return 0; + } + + // Generally you only need one Server. + brpc::Server server; + + // Instance of your service. + example::EchoServiceImpl echo_service_impl; + + // Add the service into server. Notice the second parameter, because the + // service is put on stack, we don't want server to delete it, otherwise + // use brpc::SERVER_OWNS_SERVICE. + if (server.AddService(&echo_service_impl, + brpc::SERVER_DOESNT_OWN_SERVICE) != 0) { + LOG(ERROR) << "Fail to add service"; + return -1; + } + + // Start the server. + brpc::ServerOptions options; + options.mutable_ssl_options()->default_cert.certificate = "cert.pem"; + options.mutable_ssl_options()->default_cert.private_key = "key.pem"; + options.idle_timeout_sec = FLAGS_idle_timeout_s; + options.max_concurrency = FLAGS_max_concurrency; + options.internal_port = FLAGS_internal_port; + if (server.Start(FLAGS_port, &options) != 0) { + LOG(ERROR) << "Fail to start EchoServer"; + return -1; + } + + // Wait until Ctrl-C is pressed, then Stop() and Join() the server. + server.RunUntilAskedToQuit(); + return 0; +} diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index 9eec3c0f86..e57cda196a 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -39,12 +39,59 @@ macro(brpc_example_find_common_deps out_libs) find_package(Threads REQUIRED) find_package(Protobuf REQUIRED) + set(BRPC_EXAMPLE_CXX_STANDARD 14) + set(_protobuf_absl_targets) + if(Protobuf_VERSION VERSION_GREATER 4.21) + # Protobuf 5+ exposes Abseil types from generated code and requires + # C++17. Keep this list in sync with the top-level CMake build. + set(BRPC_EXAMPLE_CXX_STANDARD 17) + find_package(absl REQUIRED CONFIG) + set(_protobuf_absl_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_globals + absl::log_severity + absl::memory + absl::node_hash_map + absl::node_hash_set + absl::random_distributions + absl::random_random + absl::span + absl::status + absl::statusor + absl::strings + absl::synchronization + absl::time + absl::type_traits + absl::utility + absl::variant + ) + endif() + - # Search for libthrift* by best effort. If it is not found and brpc is - # compiled with thrift protocol enabled, a link error would be reported. - find_library(THRIFT_LIB NAMES thrift) - if(NOT THRIFT_LIB) - set(THRIFT_LIB "") + # brpc built with -DWITH_URMA=ON carries undefined urma_* symbols. Link + # liburma when the header is present, which indicates a URMA-capable build. + set(_brpc_example_urma_lib "") + if(EXISTS "/usr/lib64/liburma.so" OR EXISTS "/usr/lib/liburma.so") + set(_brpc_example_urma_lib "urma") endif() find_path(BRPC_INCLUDE_PATH NAMES brpc/server.h) @@ -77,14 +124,21 @@ macro(brpc_example_find_common_deps out_libs) find_package(OpenSSL REQUIRED) + find_library(URMA_LIB NAMES urma) + if(NOT URMA_LIB) + set(URMA_LIB "") + endif() + set(_common_libs Threads::Threads ${GFLAGS_LIBRARY} ${PROTOBUF_LIBRARIES} + ${_protobuf_absl_targets} ${LEVELDB_LIB} ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${THRIFT_LIB} + ${_brpc_example_urma_lib} dl ) @@ -118,13 +172,19 @@ function(brpc_example_configure_target target_name) ${OPENSSL_INCLUDE_DIR} ${GPERFTOOLS_INCLUDE_DIR} ${RDMA_INCLUDE_PATH} + ${URMA_INCLUDE_PATH} ) if(_include_dirs) target_include_directories(${target_name} PRIVATE ${_include_dirs}) endif() - target_compile_features(${target_name} PRIVATE cxx_std_14) + if(NOT BRPC_EXAMPLE_CXX_STANDARD) + set(BRPC_EXAMPLE_CXX_STANDARD 14) + endif() + target_compile_features(${target_name} PRIVATE + cxx_std_${BRPC_EXAMPLE_CXX_STANDARD} + ) target_compile_definitions(${target_name} PRIVATE NDEBUG __const__=__unused__ @@ -147,6 +207,10 @@ function(brpc_example_configure_target target_name) target_compile_definitions(${target_name} PRIVATE BRPC_WITH_RDMA=1) endif() + if(BRPC_EXAMPLE_WITH_URMA) + target_compile_definitions(${target_name} PRIVATE BRPC_WITH_URMA=1) + endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") include(CheckFunctionExists) check_function_exists(clock_gettime BRPC_EXAMPLE_HAVE_CLOCK_GETTIME) diff --git a/example/ubring_performance/client.cpp b/example/ubring_performance/client.cpp index c14268a430..9c26ea85b3 100644 --- a/example/ubring_performance/client.cpp +++ b/example/ubring_performance/client.cpp @@ -165,16 +165,19 @@ class PerformanceTest { std::unique_ptr cntl_guard(closure->cntl); std::unique_ptr response_guard(closure->resp); if (closure->cntl->Failed()) { - LOG(DEBUG) << "RPC call failed: " << closure->cntl->ErrorText(); - // Don't stop the test immediately, just log the error and continue - } else { - g_latency_recorder << closure->cntl->latency_us(); - if (closure->resp->cpu_usage().size() > 0) { - g_server_cpu_recorder << atof(closure->resp->cpu_usage().c_str()) * 100; - } - g_total_bytes.fetch_add(closure->cntl->request_attachment().size(), butil::memory_order_relaxed); - g_total_cnt.fetch_add(1, butil::memory_order_relaxed); + LOG(ERROR) << "RPC call failed: " << closure->cntl->ErrorText(); + // RPCs in this example are expected to succeed. Silently ignoring + // failures would hide problems and invalidate the performance result. + closure->test->_stop = true; + return; + } + + g_latency_recorder << closure->cntl->latency_us(); + if (closure->resp->cpu_usage().size() > 0) { + g_server_cpu_recorder << atof(closure->resp->cpu_usage().c_str()) * 100; } + g_total_bytes.fetch_add(closure->cntl->request_attachment().size(), butil::memory_order_relaxed); + g_total_cnt.fetch_add(1, butil::memory_order_relaxed); cntl_guard.reset(NULL); response_guard.reset(NULL); diff --git a/example/urma_performance/CMakeLists.txt b/example/urma_performance/CMakeLists.txt new file mode 100644 index 0000000000..eae472fe90 --- /dev/null +++ b/example/urma_performance/CMakeLists.txt @@ -0,0 +1,37 @@ +# 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. + +cmake_minimum_required(VERSION 3.16...3.28) +project(urma_performance C CXX) + +include(${CMAKE_CURRENT_LIST_DIR}/../cmake/BrpcExample.cmake) + +option(LINK_SO "Whether examples are linked dynamically" OFF) + +brpc_example_find_common_deps(DYNAMIC_LIB) + +protobuf_generate_cpp(PROTO_SRC PROTO_HEADER test.proto) +set(BRPC_EXAMPLE_WITH_URMA ON) + + +add_executable(urma_performance_client client.cpp ${PROTO_SRC} ${PROTO_HEADER}) +brpc_example_configure_target(urma_performance_client) +add_executable(urma_performance_server server.cpp ${PROTO_SRC} ${PROTO_HEADER}) +brpc_example_configure_target(urma_performance_server) + +target_link_libraries(urma_performance_client PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB}) +target_link_libraries(urma_performance_server PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB}) diff --git a/example/urma_performance/client.cpp b/example/urma_performance/client.cpp new file mode 100644 index 0000000000..9449dbe960 --- /dev/null +++ b/example/urma_performance/client.cpp @@ -0,0 +1,156 @@ +// 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. + +#include +#include + +#include +#include + +#include + +#include "butil/atomicops.h" +#include "butil/fast_rand.h" +#include "butil/logging.h" +#include "brpc/channel.h" +#include "brpc/controller.h" +#include "bthread/bthread.h" +#include "bvar/latency_recorder.h" +#include "bvar/variable.h" +#include "test.pb.h" + +#if BRPC_WITH_URMA + +DEFINE_string(server, "127.0.0.1:8003", "IP Port of urma performance server"); +DEFINE_int32(thread_num, 0, "How many threads are used"); +DEFINE_int32(queue_depth, 1, "How many requests can be pending in the queue"); +DEFINE_int32(expected_qps, 0, "The expected QPS"); +DEFINE_int32(max_thread_num, 16, "The max number of threads are used"); +DEFINE_int32(attachment_size, -1, "Attachment size is used (in Bytes)"); +DEFINE_int32(rpc_timeout_ms, 5000, "Timeout for each RPC in milliseconds"); +DEFINE_bool(echo_attachment, false, "Select whether attachment should be echo"); +DEFINE_bool(use_urma, true, "Use URMA transport (true) or TCP (false)"); + +bvar::LatencyRecorder g_latency("client"); +bvar::Adder g_error_count("client_error_count"); + +static void* worker(void* arg) { + test::PerfTestService_Stub* stub = + static_cast(arg); + int qps = FLAGS_expected_qps; + while (!brpc::IsAskedToQuit()) { + butil::FastRandSeed seed; + butil::init_fast_rand_seed(&seed); + std::vector cntls(FLAGS_queue_depth); + std::vector reqs(FLAGS_queue_depth); + std::vector resps(FLAGS_queue_depth); + std::vector ids(FLAGS_queue_depth); + for (int i = 0; i < FLAGS_queue_depth; ++i) { + cntls[i].set_log_id(butil::fast_rand(&seed) & 0x7fffffff); + reqs[i].set_echo_attachment(FLAGS_echo_attachment); + if (FLAGS_attachment_size >= 0) { + cntls[i].request_attachment().resize(FLAGS_attachment_size, 'a'); + } + ids[i] = cntls[i].call_id(); + stub->Test(&cntls[i], &reqs[i], &resps[i], brpc::DoNothing()); + } + for (int i = 0; i < FLAGS_queue_depth; ++i) { + brpc::Join(ids[i]); + if (cntls[i].Failed()) { + g_error_count << 1; + LOG_EVERY_SECOND(WARNING) + << "RPC failed: " << cntls[i].ErrorText(); + } else { + g_latency << cntls[i].latency_us(); + } + } + if (qps > 0) { + usleep(FLAGS_queue_depth * 1000000 / qps); + } + } + return nullptr; +} + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + brpc::ChannelOptions options; + options.socket_mode = FLAGS_use_urma ? brpc::SOCKET_MODE_URMA + : brpc::SOCKET_MODE_TCP; + options.connect_timeout_ms = FLAGS_rpc_timeout_ms; + options.timeout_ms = FLAGS_rpc_timeout_ms; + options.max_retry = 0; + brpc::Channel channel; + if (channel.Init(FLAGS_server.c_str(), &options) != 0) { + LOG(ERROR) << "Fail to init channel to " << FLAGS_server; + return -1; + } + test::PerfTestService_Stub stub(&channel); + + // Complete one RPC before starting all workers. This makes handshake and + // data-path failures visible instead of looking like a hung benchmark. + brpc::Controller warmup_cntl; + warmup_cntl.set_timeout_ms(FLAGS_rpc_timeout_ms); + test::PerfTestRequest warmup_req; + test::PerfTestResponse warmup_resp; + warmup_req.set_echo_attachment(false); + stub.Test(&warmup_cntl, &warmup_req, &warmup_resp, nullptr); + if (warmup_cntl.Failed()) { + LOG(ERROR) << "Warm-up RPC failed after timeout_ms=" + << FLAGS_rpc_timeout_ms << ": " + << warmup_cntl.ErrorText(); + return -1; + } + LOG(INFO) << "Warm-up RPC to " << FLAGS_server + << " succeeded, latency=" << warmup_cntl.latency_us() << "us"; + + int thread_num = FLAGS_thread_num; + if (thread_num == 0) { + thread_num = FLAGS_max_thread_num; + } + if (thread_num <= 0 || FLAGS_queue_depth <= 0) { + LOG(ERROR) << "thread_num and queue_depth must be positive"; + return -1; + } + std::vector tids(thread_num); + for (int i = 0; i < thread_num; ++i) { + bthread_start_background(&tids[i], nullptr, worker, &stub); + } + LOG(INFO) << "URMA performance client started (server=" << FLAGS_server + << ", use_urma=" << FLAGS_use_urma + << ", threads=" << thread_num + << ", rpc_timeout_ms=" << FLAGS_rpc_timeout_ms << ")"; + while (!brpc::IsAskedToQuit()) { + sleep(1); + LOG(INFO) << "qps=" << g_latency.qps(1) + << " latency=" << g_latency.latency(1) << "us" + << " errors=" << g_error_count.get_value(); + } + for (int i = 0; i < thread_num; ++i) { + bthread_join(tids[i], nullptr); + } + return 0; +} + +#else + +#include +int main() { + printf("This example requires brpc built with -DWITH_URMA=ON.\n"); + return 0; +} + +#endif // BRPC_WITH_URMA diff --git a/example/urma_performance/server.cpp b/example/urma_performance/server.cpp new file mode 100644 index 0000000000..baaff323b6 --- /dev/null +++ b/example/urma_performance/server.cpp @@ -0,0 +1,96 @@ +// 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. + +#include + +#include "butil/atomicops.h" +#include "butil/logging.h" +#include "butil/time.h" +#include "brpc/closure_guard.h" +#include "brpc/controller.h" +#include "brpc/server.h" +#include "bvar/variable.h" +#include "test.pb.h" + +#if BRPC_WITH_URMA + +DEFINE_int32(port, 8003, "TCP Port of this server"); +DEFINE_bool(use_urma, true, "Use URMA transport (true) or TCP (false)"); + +butil::atomic g_last_time(0); + +namespace test { +class PerfTestServiceImpl : public PerfTestService { +public: + void Test(google::protobuf::RpcController* cntl_base, + const PerfTestRequest* request, + PerfTestResponse* response, + google::protobuf::Closure* done) { + brpc::ClosureGuard done_guard(done); + const uint64_t last = + g_last_time.load(butil::memory_order_relaxed); + const uint64_t now = butil::monotonic_time_us(); + if (now > last && now - last > 100000) { + if (g_last_time.exchange(now, butil::memory_order_relaxed) == last) { + response->set_cpu_usage( + bvar::Variable::describe_exposed("process_cpu_usage")); + } else { + response->set_cpu_usage(""); + } + } else { + response->set_cpu_usage(""); + } + if (request->echo_attachment()) { + brpc::Controller* cntl = static_cast(cntl_base); + cntl->response_attachment().append(cntl->request_attachment()); + } + } +}; +} // namespace test + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + brpc::Server server; + test::PerfTestServiceImpl service; + + if (server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) { + LOG(ERROR) << "Fail to add PerfTestService"; + return -1; + } + + brpc::ServerOptions options; + options.socket_mode = FLAGS_use_urma ? brpc::SOCKET_MODE_URMA + : brpc::SOCKET_MODE_TCP; + if (server.Start(FLAGS_port, &options) != 0) { + LOG(ERROR) << "Fail to start server"; + return -1; + } + LOG(INFO) << "URMA performance server started on port " << FLAGS_port + << " (use_urma=" << FLAGS_use_urma << ")"; + server.RunUntilAskedToQuit(); + return 0; +} + +#else + +#include +int main() { + printf("This example requires brpc built with -DWITH_URMA=ON.\n"); + return 0; +} + +#endif // BRPC_WITH_URMA diff --git a/example/urma_performance/test.proto b/example/urma_performance/test.proto new file mode 100644 index 0000000000..10b41c8fe5 --- /dev/null +++ b/example/urma_performance/test.proto @@ -0,0 +1,34 @@ +// 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. + +syntax = "proto2"; + +option cc_generic_services = true; + +package test; + +message PerfTestRequest { + required bool echo_attachment = 1; +} + +message PerfTestResponse { + required string cpu_usage = 1; +} + +service PerfTestService { + rpc Test(PerfTestRequest) returns (PerfTestResponse); +} diff --git a/src/brpc/builtin/bad_method_service.cpp b/src/brpc/builtin/bad_method_service.cpp index 346b68d613..5d5ed3260a 100644 --- a/src/brpc/builtin/bad_method_service.cpp +++ b/src/brpc/builtin/bad_method_service.cpp @@ -47,7 +47,7 @@ void BadMethodService::no_method(::google::protobuf::RpcController* cntl_base, os << "Missing method name for service=" << request->service_name() << '.'; const Server::ServiceProperty* sp = ServerPrivateAccessor(server) .FindServicePropertyAdaptively(request->service_name()); - if (sp != NULL && sp->service != NULL) { + if (sp != nullptr && sp->service != nullptr) { const google::protobuf::ServiceDescriptor* sd = sp->service->GetDescriptor(); os << " Available methods are: " << newline << newline; @@ -58,7 +58,7 @@ void BadMethodService::no_method(::google::protobuf::RpcController* cntl_base, << ");" << newline; } } - if (sp != NULL && sp->restful_map != NULL) { + if (sp != nullptr && sp->restful_map != nullptr) { os << " This path is associated with a RestfulMap!"; } cntl->SetFailed(ENOMETHOD, "%s", os.str().c_str()); diff --git a/src/brpc/builtin/bthreads_service.cpp b/src/brpc/builtin/bthreads_service.cpp index fca86bc6bb..7a2c0835d5 100644 --- a/src/brpc/builtin/bthreads_service.cpp +++ b/src/brpc/builtin/bthreads_service.cpp @@ -52,11 +52,11 @@ void BthreadsService::default_method(::google::protobuf::RpcController* cntl_bas bool enable_trace = false; #ifdef BRPC_BTHREAD_TRACER const std::string* st = cntl->http_request().uri().GetQuery("st"); - if (NULL != st && *st == "1") { + if (nullptr != st && *st == "1") { enable_trace = true; } #endif // BRPC_BTHREAD_TRACER - char* endptr = NULL; + char* endptr = nullptr; bthread_t tid = strtoull(constraint.c_str(), &endptr, 10); if (*endptr == '\0' || *endptr == '/' || *endptr == '?') { ::bthread::print_task(os, tid, enable_trace); diff --git a/src/brpc/builtin/common.cpp b/src/brpc/builtin/common.cpp index 8663682d75..d9d90202f3 100644 --- a/src/brpc/builtin/common.cpp +++ b/src/brpc/builtin/common.cpp @@ -35,13 +35,13 @@ DEFINE_string(rpc_profiling_dir, "./rpc_data/profiling", bool UseHTML(const HttpHeader& header) { const std::string* console = header.uri().GetQuery(CONSOLE_STR); - if (console != NULL) { + if (console != nullptr) { return atoi(console->c_str()) == 0; } // [curl header] // User-Agent: curl/7.12.1 (x86_64-redhat-linux-gnu) libcurl/7.12.1 ... const std::string* agent = header.GetHeader(USER_AGENT_STR); - if (agent == NULL) { // use text when user-agent is absent + if (agent == nullptr) { // use text when user-agent is absent return false; } return agent->find("curl/") == std::string::npos; @@ -50,8 +50,8 @@ bool UseHTML(const HttpHeader& header) { // Written by Jack Handy // jakkhandy@hotmail.com inline bool url_wildcmp(const char* wild, const char* str) { - const char* cp = NULL; - const char* mp = NULL; + const char* cp = nullptr; + const char* mp = nullptr; while (*str && *wild != '*') { if (*wild != *str && *wild != '$') { @@ -384,7 +384,7 @@ const char* GetProgramChecksum() { bool SupportGzip(Controller* cntl) { const std::string* encodings = cntl->http_request().GetHeader("Accept-Encoding"); - if (encodings == NULL) { + if (encodings == nullptr) { return false; } return encodings->find("gzip") != std::string::npos; diff --git a/src/brpc/builtin/common.h b/src/brpc/builtin/common.h index 0c1af8418b..d2e7787647 100644 --- a/src/brpc/builtin/common.h +++ b/src/brpc/builtin/common.h @@ -73,7 +73,7 @@ std::ostream& operator<<(std::ostream& os, const PrintedAsDateTime&); struct Path { static const butil::EndPoint *LOCAL; Path(const char* uri2, const butil::EndPoint* html_addr2) - : uri(uri2), html_addr(html_addr2), text(NULL) {} + : uri(uri2), html_addr(html_addr2), text(nullptr) {} Path(const char* uri2, const butil::EndPoint* html_addr2, const char* text2) : uri(uri2), html_addr(html_addr2), text(text2) {} diff --git a/src/brpc/builtin/connections_service.cpp b/src/brpc/builtin/connections_service.cpp index 02adc56b38..22786352cb 100644 --- a/src/brpc/builtin/connections_service.cpp +++ b/src/brpc/builtin/connections_service.cpp @@ -223,7 +223,7 @@ void ConnectionsService::PrintConnections( // Special treatment for nshead services. Notice that // pref_index is comparable to ProtocolType after r31951 if (pref_index == (int)PROTOCOL_NSHEAD && - server->options().nshead_service != NULL) { + server->options().nshead_service != nullptr) { if (nshead_service_name.empty()) { nshead_service_name = BriefName(butil::class_name_str( *server->options().nshead_service)); @@ -244,7 +244,7 @@ void ConnectionsService::PrintConnections( ptr->GetStat(&stat); PrintRealDateTime(os, ptr->_reset_fd_real_us); int rttfd = ptr->fd(); - if (rttfd < 0 && first_sub != NULL) { + if (rttfd < 0 && first_sub != nullptr) { rttfd = first_sub->fd(); } diff --git a/src/brpc/builtin/dir_service.cpp b/src/brpc/builtin/dir_service.cpp index 98973b9641..c292a262d8 100644 --- a/src/brpc/builtin/dir_service.cpp +++ b/src/brpc/builtin/dir_service.cpp @@ -48,7 +48,7 @@ void DirService::default_method(::google::protobuf::RpcController* cntl_base, open_path = "/"; } DIR* dir = opendir(open_path.c_str()); - if (NULL == dir) { + if (nullptr == dir) { butil::fd_guard fd(open(open_path.c_str(), O_RDONLY)); if (fd < 0) { cntl->SetFailed(errno, "Cannot open `%s'", open_path.c_str()); @@ -81,7 +81,7 @@ void DirService::default_method(::google::protobuf::RpcController* cntl_base, cntl->http_response().set_content_type("text/plain"); } else { const bool use_html = UseHTML(cntl->http_request()); - const butil::EndPoint* const html_addr = (use_html ? Path::LOCAL : NULL); + const butil::EndPoint* const html_addr = (use_html ? Path::LOCAL : nullptr); cntl->http_response().set_content_type( use_html ? "text/html" : "text/plain"); @@ -90,10 +90,10 @@ void DirService::default_method(::google::protobuf::RpcController* cntl_base, // readdir_r is marked as deprecated since glibc 2.24. #if defined(__GLIBC__) && \ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24)) - for (struct dirent* p = NULL; (p = readdir(dir)) != NULL; ) { + for (struct dirent* p = nullptr; (p = readdir(dir)) != nullptr; ) { #else struct dirent entbuf; - for (struct dirent* p = NULL; readdir_r(dir, &entbuf, &p) == 0 && p; ) { + for (struct dirent* p = nullptr; readdir_r(dir, &entbuf, &p) == 0 && p; ) { #endif files.push_back(p->d_name); } diff --git a/src/brpc/builtin/flags_service.cpp b/src/brpc/builtin/flags_service.cpp index 1c9075c54e..18152baa86 100644 --- a/src/brpc/builtin/flags_service.cpp +++ b/src/brpc/builtin/flags_service.cpp @@ -146,7 +146,7 @@ void FlagsService::default_method(::google::protobuf::RpcController* cntl_base, cntl->http_response().set_content_type( use_html ? "text/html" : "text/plain"); - if (value_str != NULL) { + if (value_str != nullptr) { // reload value if ?setvalue=VALUE is present. if (constraint.empty()) { cntl->SetFailed(ENOMETHOD, "Require gflag name"); @@ -189,7 +189,7 @@ void FlagsService::default_method(::google::protobuf::RpcController* cntl_base, std::vector wildcards; std::set exact; if (!constraint.empty()) { - for (butil::StringMultiSplitter sp(constraint.c_str(), ",;"); sp != NULL; ++sp) { + for (butil::StringMultiSplitter sp(constraint.c_str(), ",;"); sp != nullptr; ++sp) { std::string name(sp.field(), sp.length()); if (name.find_first_of("$*") != std::string::npos) { wildcards.push_back(name); diff --git a/src/brpc/builtin/flot_min_js.cpp b/src/brpc/builtin/flot_min_js.cpp index a123b4bc9b..d2680576dd 100644 --- a/src/brpc/builtin/flot_min_js.cpp +++ b/src/brpc/builtin/flot_min_js.cpp @@ -25,13 +25,13 @@ namespace brpc { static pthread_once_t s_flot_min_buf_once = PTHREAD_ONCE_INIT; -static butil::IOBuf* s_flot_min_buf = NULL; -static butil::IOBuf* s_flot_min_buf_gzip = NULL; +static butil::IOBuf* s_flot_min_buf = nullptr; +static butil::IOBuf* s_flot_min_buf_gzip = nullptr; static void InitFlotMinBuf() { s_flot_min_buf = new butil::IOBuf; s_flot_min_buf->append(flot_min_js()); s_flot_min_buf_gzip = new butil::IOBuf; - CHECK(policy::GzipCompress(*s_flot_min_buf, s_flot_min_buf_gzip, NULL)); + CHECK(policy::GzipCompress(*s_flot_min_buf, s_flot_min_buf_gzip, nullptr)); } const butil::IOBuf& flot_min_js_iobuf() { pthread_once(&s_flot_min_buf_once, InitFlotMinBuf); diff --git a/src/brpc/builtin/get_favicon_service.cpp b/src/brpc/builtin/get_favicon_service.cpp index 64b0d708ed..81ce8e18d9 100644 --- a/src/brpc/builtin/get_favicon_service.cpp +++ b/src/brpc/builtin/get_favicon_service.cpp @@ -51,7 +51,7 @@ static unsigned char s_favicon_array[] = { }; static pthread_once_t s_favicon_buf_once = PTHREAD_ONCE_INIT; -static butil::IOBuf* s_favicon_buf = NULL; +static butil::IOBuf* s_favicon_buf = nullptr; static void InitFavIcon() { s_favicon_buf = new butil::IOBuf; s_favicon_buf->append((const void *)s_favicon_array, diff --git a/src/brpc/builtin/get_js_service.cpp b/src/brpc/builtin/get_js_service.cpp index 4b3477de9c..ee053edf75 100644 --- a/src/brpc/builtin/get_js_service.cpp +++ b/src/brpc/builtin/get_js_service.cpp @@ -63,7 +63,7 @@ void GetJsService::jquery_min( const std::string* ims = cntl->http_request().GetHeader("If-Modified-Since"); - if (ims != NULL && *ims == g_last_modified) { + if (ims != nullptr && *ims == g_last_modified) { cntl->http_response().set_status_code(HTTP_STATUS_NOT_MODIFIED); return; } @@ -89,7 +89,7 @@ void GetJsService::flot_min( const std::string* ims = cntl->http_request().GetHeader("If-Modified-Since"); - if (ims != NULL && *ims == g_last_modified) { + if (ims != nullptr && *ims == g_last_modified) { cntl->http_response().set_status_code(HTTP_STATUS_NOT_MODIFIED); return; } @@ -115,7 +115,7 @@ void GetJsService::viz_min( const std::string* ims = cntl->http_request().GetHeader("If-Modified-Since"); - if (ims != NULL && *ims == g_last_modified) { + if (ims != nullptr && *ims == g_last_modified) { cntl->http_response().set_status_code(HTTP_STATUS_NOT_MODIFIED); return; } diff --git a/src/brpc/builtin/hotspots_service.cpp b/src/brpc/builtin/hotspots_service.cpp index 8d4d97bc77..2433a1e540 100644 --- a/src/brpc/builtin/hotspots_service.cpp +++ b/src/brpc/builtin/hotspots_service.cpp @@ -155,11 +155,11 @@ struct ProfilingEnvironment { // Different ProfilingType have different env. static ProfilingEnvironment g_env[5] = { - { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, - { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, - { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, - { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, - { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL } + { PTHREAD_MUTEX_INITIALIZER, 0, nullptr, nullptr, nullptr }, + { PTHREAD_MUTEX_INITIALIZER, 0, nullptr, nullptr, nullptr }, + { PTHREAD_MUTEX_INITIALIZER, 0, nullptr, nullptr, nullptr }, + { PTHREAD_MUTEX_INITIALIZER, 0, nullptr, nullptr, nullptr }, + { PTHREAD_MUTEX_INITIALIZER, 0, nullptr, nullptr, nullptr } }; // The `content' should be small so that it can be written into file in one @@ -175,7 +175,7 @@ static bool WriteSmallFile(const char* filepath_in, return false; } FILE* fp = fopen(path.value().c_str(), "w"); - if (NULL == fp) { + if (nullptr == fp) { LOG(ERROR) << "Fail to open `" << path.value() << '\''; return false; } @@ -199,12 +199,12 @@ static bool WriteSmallFile(const char* filepath_in, return false; } FILE* fp = fopen(path.value().c_str(), "w"); - if (NULL == fp) { + if (nullptr == fp) { LOG(ERROR) << "Fail to open `" << path.value() << '\''; return false; } butil::IOBufAsZeroCopyInputStream iter(content); - const void* data = NULL; + const void* data = nullptr; int size = 0; while (iter.Next(&data, &size)) { if (fwrite(data, size, 1UL, fp) != 1UL) { @@ -221,8 +221,8 @@ static int ReadSeconds(const Controller* cntl) { int seconds = DEFAULT_PROFILING_SECONDS; const std::string* param = cntl->http_request().uri().GetQuery("seconds"); - if (param != NULL) { - char* endptr = NULL; + if (param != nullptr) { + char* endptr = nullptr; const long sec = strtol(param->c_str(), &endptr, 10); if (endptr == param->c_str() + param->length()) { seconds = sec; @@ -235,8 +235,8 @@ static int ReadSeconds(const Controller* cntl) { } static const char* GetBaseName(const std::string* full_base_name) { - if (full_base_name == NULL) { - return NULL; + if (full_base_name == nullptr) { + return nullptr; } size_t offset = full_base_name->find_last_of('/'); if (offset == std::string::npos) { @@ -338,10 +338,10 @@ static void ConsumeWaiters(ProfilingType type, const Controller* cur_cntl, ProfilingEnvironment& env = g_env[type]; if (env.client) { BAIDU_SCOPED_LOCK(env.mutex); - if (env.client == NULL) { + if (env.client == nullptr) { return; } - if (env.cached_result == NULL) { + if (env.cached_result == nullptr) { env.cached_result = new ProfilingResult; } env.cached_result->id = env.client->id; @@ -350,7 +350,7 @@ static void ConsumeWaiters(ProfilingType type, const Controller* cur_cntl, env.cached_result->result = cur_cntl->response_attachment(); delete env.client; - env.client = NULL; + env.client = nullptr; if (env.waiters) { env.waiters->swap(*waiters); } @@ -360,7 +360,7 @@ static void ConsumeWaiters(ProfilingType type, const Controller* cur_cntl, // This function is always called with g_env[type].mutex UNLOCKED. static void NotifyWaiters(ProfilingType type, const Controller* cur_cntl, const std::string* view) { - if (view != NULL) { + if (view != nullptr) { return; } std::vector saved_waiters; @@ -380,7 +380,7 @@ static void NotifyWaiters(ProfilingType type, const Controller* cur_cntl, static const char* s_pprof_binary_path = nullptr; static bool check_GOOGLE_PPROF_BINARY_PATH() { char* str = getenv("GOOGLE_PPROF_BINARY_PATH"); - if (str == NULL) { + if (str == nullptr) { return false; } butil::fd_guard fd(open(str, O_RDONLY)); @@ -431,7 +431,7 @@ static void DisplayResult(Controller* cntl, } #endif } - if (base_name != NULL) { + if (base_name != nullptr) { if (!ValidProfilePath(*base_name)) { return cntl->SetFailed(EINVAL, "Invalid query `base'"); } @@ -448,7 +448,7 @@ static void DisplayResult(Controller* cntl, display_type, show_ccount); // Try to read cache first. FILE* fp = fopen(expected_result_name, "r"); - if (fp != NULL) { + if (fp != nullptr) { bool succ = false; char buffer[1024]; while (1) { @@ -561,7 +561,7 @@ static void DisplayResult(Controller* cntl, // current profile is. butil::IOBuf before_label; butil::IOBuf tmp; - if (cntl->http_request().uri().GetQuery("view") == NULL) { + if (cntl->http_request().uri().GetQuery("view") == nullptr) { tmp.append(prof_name); tmp.append("[addToProfEnd]"); } @@ -670,8 +670,8 @@ static void DoProfiling(ProfilingType type, int64_t prof_id = 0; const std::string* prof_id_str = cntl->http_request().uri().GetQuery("profiling_id"); - if (prof_id_str != NULL) { - char* endptr = NULL; + if (prof_id_str != nullptr) { + char* endptr = nullptr; prof_id = strtoll(prof_id_str->c_str(), &endptr, 10); LOG_IF(ERROR, *endptr != '\0') << "Invalid profiling_id=" << prof_id; } @@ -679,7 +679,7 @@ static void DoProfiling(ProfilingType type, { BAIDU_SCOPED_LOCK(g_env[type].mutex); if (g_env[type].client) { - if (NULL == g_env[type].waiters) { + if (nullptr == g_env[type].waiters) { g_env[type].waiters = new std::vector; } ProfilingWaiter waiter = { cntl, done_guard.release() }; @@ -687,7 +687,7 @@ static void DoProfiling(ProfilingType type, RPC_VLOG << "Queue request from " << cntl->remote_side(); return; } - if (g_env[type].cached_result != NULL && + if (g_env[type].cached_result != nullptr && g_env[type].cached_result->id == prof_id) { cntl->http_response().set_status_code( g_env[type].cached_result->status_code); @@ -696,7 +696,7 @@ static void DoProfiling(ProfilingType type, RPC_VLOG << "Hit cached result, id=" << prof_id; return; } - CHECK(NULL == g_env[type].client); + CHECK(nullptr == g_env[type].client); g_env[type].client = new ProfilingClient; g_env[type].client->end_us = butil::cpuwide_time_us() + seconds * 1000000L; g_env[type].client->seconds = seconds; @@ -736,7 +736,7 @@ static void DoProfiling(ProfilingType type, } #endif if (type == PROFILING_CPU) { - if ((void*)ProfilerStart == NULL || (void*)ProfilerStop == NULL) { + if ((void*)ProfilerStart == nullptr || (void*)ProfilerStop == nullptr) { os << "CPU profiler is not enabled" << (use_html ? "" : "\n"); os.move_to(resp); @@ -787,9 +787,9 @@ static void DoProfiling(ProfilingType type, butil::IOBufProfilerFlush(prof_name); } else if (type == PROFILING_HEAP) { MallocExtension* malloc_ext = MallocExtension::instance(); - if (malloc_ext == NULL || !has_TCMALLOC_SAMPLE_PARAMETER()) { + if (malloc_ext == nullptr || !has_TCMALLOC_SAMPLE_PARAMETER()) { os << "Heap profiler is not enabled"; - if (malloc_ext != NULL) { + if (malloc_ext != nullptr) { os << " (no TCMALLOC_SAMPLE_PARAMETER in env)"; } os << '.' << (use_html ? "" : "\n"); @@ -809,7 +809,7 @@ static void DoProfiling(ProfilingType type, } } else if (type == PROFILING_GROWTH) { MallocExtension* malloc_ext = MallocExtension::instance(); - if (malloc_ext == NULL) { + if (malloc_ext == nullptr) { os << "Growth profiler is not enabled." << (use_html ? "" : "\n"); os.move_to(resp); @@ -921,7 +921,7 @@ static void StartProfiling(ProfilingType type, ProfilingClient profiling_client; size_t nwaiters = 0; ProfilingEnvironment & env = g_env[type]; - if (view == NULL) { + if (view == nullptr) { BAIDU_SCOPED_LOCK(env.mutex); if (env.client) { profiling_client = *env.client; @@ -965,7 +965,7 @@ static void StartProfiling(ProfilingType type, "}\n" "$(function() {\n" " function onDataReceived(data) {\n"; - if (view == NULL) { + if (view == nullptr) { os << " var selEnd = data.indexOf('[addToProfEnd]');\n" " if (selEnd != -1) {\n" @@ -1090,7 +1090,7 @@ static void StartProfiling(ProfilingType type, os << ""; for (size_t i = 0; i < past_profs.size(); ++i) { os << ""; for (size_t i = 0; i' << GetBaseName(&past_profs[i]); @@ -1123,7 +1123,7 @@ static void StartProfiling(ProfilingType type, os << ""; } - if (!enabled && view == NULL) { + if (!enabled && view == nullptr) { os << "

Error: " << type_str << " profiler is not enabled." << extra_desc << "

" "

To enable all profilers, link tcmalloc and define macros BRPC_ENABLE_CPU_PROFILER" @@ -1135,7 +1135,7 @@ static void StartProfiling(ProfilingType type, return; } - if ((type == PROFILING_CPU || type == PROFILING_CONTENTION) && view == NULL) { + if ((type == PROFILING_CPU || type == PROFILING_CONTENTION) && view == nullptr) { if (seconds < 0) { os << "Invalid seconds"; os.move_to(cntl->response_attachment()); @@ -1163,7 +1163,7 @@ static void StartProfiling(ProfilingType type, os << ", showing in about " << wait_seconds << " seconds ..."; } } else { - if ((type == PROFILING_CPU || type == PROFILING_CONTENTION) && view == NULL) { + if ((type == PROFILING_CPU || type == PROFILING_CONTENTION) && view == nullptr) { os << "Profiling " << ProfilingType2String(type) << " for " << seconds << " seconds ..."; } else { diff --git a/src/brpc/builtin/ids_service.cpp b/src/brpc/builtin/ids_service.cpp index ba6a25fb9c..a57941524c 100644 --- a/src/brpc/builtin/ids_service.cpp +++ b/src/brpc/builtin/ids_service.cpp @@ -44,7 +44,7 @@ void IdsService::default_method(::google::protobuf::RpcController* cntl_base, os << "# Use /ids/\n"; bthread::id_pool_status(os); } else { - char* endptr = NULL; + char* endptr = nullptr; bthread_id_t id = { strtoull(constraint.c_str(), &endptr, 10) }; if (*endptr == '\0' || *endptr == '/') { bthread::id_status(id, os); diff --git a/src/brpc/builtin/index_service.cpp b/src/brpc/builtin/index_service.cpp index 3b1aa3bcb5..b7cf160d53 100644 --- a/src/brpc/builtin/index_service.cpp +++ b/src/brpc/builtin/index_service.cpp @@ -54,15 +54,15 @@ void IndexService::default_method(::google::protobuf::RpcController* controller, google::protobuf::Service* svc = server->FindServiceByFullName( StatusService::descriptor()->full_name()); StatusService* st_svc = dynamic_cast(svc); - if (st_svc == NULL) { + if (st_svc == nullptr) { cntl->SetFailed("Fail to find StatusService"); return; } - return st_svc->default_method(cntl, NULL, NULL, done_guard.release()); + return st_svc->default_method(cntl, nullptr, nullptr, done_guard.release()); } cntl->http_response().set_content_type( use_html ? "text/html" : "text/plain"); - const butil::EndPoint* const html_addr = (use_html ? Path::LOCAL : NULL); + const butil::EndPoint* const html_addr = (use_html ? Path::LOCAL : nullptr); const char* const NL = (use_html ? "
\n" : "\n"); const char* const SP = (use_html ? " " : " "); diff --git a/src/brpc/builtin/jquery_min_js.cpp b/src/brpc/builtin/jquery_min_js.cpp index 818e399dc9..27a3015b9f 100644 --- a/src/brpc/builtin/jquery_min_js.cpp +++ b/src/brpc/builtin/jquery_min_js.cpp @@ -25,13 +25,13 @@ namespace brpc { static pthread_once_t s_jquery_min_buf_once = PTHREAD_ONCE_INIT; -static butil::IOBuf* s_jquery_min_buf = NULL; -static butil::IOBuf* s_jquery_min_buf_gzip = NULL; +static butil::IOBuf* s_jquery_min_buf = nullptr; +static butil::IOBuf* s_jquery_min_buf_gzip = nullptr; static void InitJQueryMinBuf() { s_jquery_min_buf = new butil::IOBuf; s_jquery_min_buf->append(jquery_min_js()); s_jquery_min_buf_gzip = new butil::IOBuf; - CHECK(policy::GzipCompress(*s_jquery_min_buf, s_jquery_min_buf_gzip, NULL)); + CHECK(policy::GzipCompress(*s_jquery_min_buf, s_jquery_min_buf_gzip, nullptr)); } const butil::IOBuf& jquery_min_js_iobuf() { pthread_once(&s_jquery_min_buf_once, InitJQueryMinBuf); diff --git a/src/brpc/builtin/pprof_service.cpp b/src/brpc/builtin/pprof_service.cpp index e22144f2ad..3e445a9ce2 100644 --- a/src/brpc/builtin/pprof_service.cpp +++ b/src/brpc/builtin/pprof_service.cpp @@ -58,8 +58,8 @@ static int ReadSeconds(Controller* cntl) { int seconds = 0; const std::string* param = cntl->http_request().uri().GetQuery("seconds"); - if (param != NULL) { - char* endptr = NULL; + if (param != nullptr) { + char* endptr = nullptr; const long sec = strtol(param->c_str(), &endptr, 10); if (endptr == param->c_str() + param->length()) { seconds = sec; @@ -101,7 +101,7 @@ void PProfService::profile( ClosureGuard done_guard(done); Controller* cntl = static_cast(controller_base); cntl->http_response().set_content_type("text/plain"); - if ((void*)ProfilerStart == NULL || (void*)ProfilerStop == NULL) { + if ((void*)ProfilerStart == nullptr || (void*)ProfilerStop == nullptr) { cntl->SetFailed(ENOMETHOD, "%s, to enable cpu profiler, check out " "docs/cn/cpu_profiler.md", berror(ENOMETHOD)); @@ -221,9 +221,9 @@ void PProfService::heap( } MallocExtension* malloc_ext = MallocExtension::instance(); - if (malloc_ext == NULL || !has_TCMALLOC_SAMPLE_PARAMETER()) { + if (malloc_ext == nullptr || !has_TCMALLOC_SAMPLE_PARAMETER()) { const char* extra_desc = ""; - if (malloc_ext != NULL) { + if (malloc_ext != nullptr) { extra_desc = " (no TCMALLOC_SAMPLE_PARAMETER in env)"; } cntl->SetFailed(ENOMETHOD, "Heap profiler is not enabled%s," @@ -255,7 +255,7 @@ void PProfService::growth( ClosureGuard done_guard(done); Controller* cntl = static_cast(controller_base); MallocExtension* malloc_ext = MallocExtension::instance(); - if (malloc_ext == NULL) { + if (malloc_ext == nullptr) { cntl->SetFailed(ENOMETHOD, "%s, to enable growth profiler, check out " "docs/cn/heap_profiler.md", berror(ENOMETHOD)); @@ -312,10 +312,10 @@ static int ExtractSymbolsFromBinary( std::string line; while (std::getline(ss, line)) { butil::StringSplitter sp(line.c_str(), ' '); - if (sp == NULL) { + if (sp == nullptr) { continue; } - char* endptr = NULL; + char* endptr = nullptr; uintptr_t addr = strtoull(sp.field(), &endptr, 16); if (*endptr != ' ') { continue; @@ -327,7 +327,7 @@ static int ExtractSymbolsFromBinary( continue; } ++sp; - if (sp == NULL) { + if (sp == nullptr) { continue; } if (sp.length() != 1UL) { @@ -336,7 +336,7 @@ static int ExtractSymbolsFromBinary( //const char c = *sp.field(); ++sp; - if (sp == NULL) { + if (sp == nullptr) { continue; } const char* name_begin = sp.field(); @@ -403,15 +403,15 @@ static void LoadSymbols() { butil::Timer tm; tm.start(); butil::ScopedFILE fp(fopen("/proc/self/maps", "r")); - if (fp == NULL) { + if (fp == nullptr) { return; } - char* line = NULL; + char* line = nullptr; size_t line_len = 0; ssize_t nr = 0; while ((nr = getline(&line, &line_len, fp.get())) != -1) { butil::StringSplitter sp(line, line + nr, ' '); - if (sp == NULL) { + if (sp == nullptr) { continue; } char* endptr; @@ -426,11 +426,11 @@ static void LoadSymbols() { } ++sp; // ..x. must be executable - if (sp == NULL || sp.length() != 4 || sp.field()[2] != 'x') { + if (sp == nullptr || sp.length() != 4 || sp.field()[2] != 'x') { continue; } ++sp; - if (sp == NULL) { + if (sp == nullptr) { continue; } size_t offset = strtoull(sp.field(), &endptr, 16); @@ -441,7 +441,7 @@ static void LoadSymbols() { for (int i = 0; i < 3; ++i) { ++sp; } - if (sp == NULL) { + if (sp == nullptr) { continue; } size_t n = sp.length(); @@ -551,7 +551,7 @@ void PProfService::symbol( std::vector addr_list; addr_list.reserve(32); butil::StringSplitter sp(addr_cstr, '+'); - for ( ; sp != NULL; ++sp) { + for ( ; sp != nullptr; ++sp) { char* endptr; uintptr_t addr = strtoull(sp.field(), &endptr, 16); addr_list.push_back(addr); diff --git a/src/brpc/builtin/prometheus_metrics_service.cpp b/src/brpc/builtin/prometheus_metrics_service.cpp index 4efc24b9c5..c02e78ddf4 100644 --- a/src/brpc/builtin/prometheus_metrics_service.cpp +++ b/src/brpc/builtin/prometheus_metrics_service.cpp @@ -156,16 +156,16 @@ PrometheusMetricsDumper::ProcessLatencyRecorderSuffix(const butil::StringPiece& if (metric_name.ends_with("_latency")) { metric_name.remove_suffix(8); SummaryItems* si = &_m[metric_name.as_string()]; - si->latency_avg = strtoll(desc_str.data(), NULL, 10); + si->latency_avg = strtoll(desc_str.data(), nullptr, 10); return si; } if (metric_name.ends_with("_count")) { metric_name.remove_suffix(6); SummaryItems* si = &_m[metric_name.as_string()]; - si->count = strtoll(desc_str.data(), NULL, 10); + si->count = strtoll(desc_str.data(), nullptr, 10); return si; } - return NULL; + return nullptr; } bool PrometheusMetricsDumper::DumpLatencyRecorderSuffix( @@ -224,7 +224,7 @@ void PrometheusMetricsService::default_method(::google::protobuf::RpcController* int DumpPrometheusMetricsToIOBuf(butil::IOBuf* output) { butil::IOBufBuilder os; PrometheusMetricsDumper dumper(&os, g_server_info_prefix); - const int ndump = bvar::Variable::dump_exposed(&dumper, NULL); + const int ndump = bvar::Variable::dump_exposed(&dumper, nullptr); if (ndump < 0) { return -1; } @@ -232,7 +232,7 @@ int DumpPrometheusMetricsToIOBuf(butil::IOBuf* output) { if (bvar::FLAGS_bvar_max_dump_multi_dimension_metric_number > 0) { PrometheusMetricsDumper dumper_md(&os, g_server_info_prefix); - const int ndump_md = bvar::MVariableBase::dump_exposed(&dumper_md, NULL); + const int ndump_md = bvar::MVariableBase::dump_exposed(&dumper_md, nullptr); if (ndump_md < 0) { return -1; } diff --git a/src/brpc/builtin/rpcz_service.cpp b/src/brpc/builtin/rpcz_service.cpp index 9afb651ee6..fac905a4c5 100644 --- a/src/brpc/builtin/rpcz_service.cpp +++ b/src/brpc/builtin/rpcz_service.cpp @@ -319,7 +319,7 @@ static void PrintClientSpan( static void PrintClientSpan(std::ostream& os,const RpczSpan& span, bool use_html) { int64_t last_time = span.start_send_real_us(); - PrintClientSpan(os, span, &last_time, NULL, use_html); + PrintClientSpan(os, span, &last_time, nullptr, use_html); } static void PrintBthreadSpan(std::ostream& os, const RpczSpan& span, int64_t* last_time, @@ -465,14 +465,14 @@ static int64_t ParseDateTime(const std::string& time_str) { struct tm timeinfo; int64_t microseconds = 999999; char* endptr = strptime(time_str.c_str(), "%Y/%m/%d-%H:%M:%S", &timeinfo); - if (endptr == NULL) { + if (endptr == nullptr) { time_t now; time(&now); - if (localtime_r(&now, &timeinfo) == NULL) { + if (localtime_r(&now, &timeinfo) == nullptr) { return -1; } endptr = strptime(time_str.c_str(), "%H:%M:%S", &timeinfo); - if (endptr == NULL) { + if (endptr == nullptr) { return -1; } } @@ -487,11 +487,11 @@ static int64_t ParseDateTime(const std::string& time_str) { } static bool ParseUint64(const std::string* str, uint64_t* val) { - if (NULL == str) { + if (nullptr == str) { return false; } const char* p = str->c_str(); - char* endptr = NULL; + char* endptr = nullptr; if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { *val = strtoull(p + 2, &endptr, 16); return (*endptr == '\0'); @@ -601,7 +601,7 @@ void RpczService::default_method(::google::protobuf::RpcController* cntl_base, const std::string* time_str = cntl->http_request().uri().GetQuery(TIME_STR); int64_t start_tm; - if (time_str == NULL) { + if (time_str == nullptr) { start_tm = butil::gettimeofday_us(); } else { start_tm = ParseDateTime(*time_str); diff --git a/src/brpc/builtin/sockets_service.cpp b/src/brpc/builtin/sockets_service.cpp index deedf65d12..c17e86cf6e 100644 --- a/src/brpc/builtin/sockets_service.cpp +++ b/src/brpc/builtin/sockets_service.cpp @@ -40,7 +40,7 @@ void SocketsService::default_method(::google::protobuf::RpcController* cntl_base os << "# Use /sockets/\n" << butil::describe_resources() << '\n'; } else { - char* endptr = NULL; + char* endptr = nullptr; SocketId sid = strtoull(constraint.c_str(), &endptr, 10); if (*endptr == '\0' || *endptr == '/') { Socket::DebugSocket(os, sid); diff --git a/src/brpc/builtin/sorttable_js.cpp b/src/brpc/builtin/sorttable_js.cpp index a37bac749f..8ef8250c25 100644 --- a/src/brpc/builtin/sorttable_js.cpp +++ b/src/brpc/builtin/sorttable_js.cpp @@ -23,7 +23,7 @@ namespace brpc { static pthread_once_t s_sorttable_buf_once = PTHREAD_ONCE_INIT; -static butil::IOBuf* s_sorttable_buf = NULL; +static butil::IOBuf* s_sorttable_buf = nullptr; static void InitSortTableBuf() { s_sorttable_buf = new butil::IOBuf; s_sorttable_buf->append(sorttable_js()); diff --git a/src/brpc/builtin/vars_service.cpp b/src/brpc/builtin/vars_service.cpp index 00235e213e..007b040499 100644 --- a/src/brpc/builtin/vars_service.cpp +++ b/src/brpc/builtin/vars_service.cpp @@ -311,7 +311,7 @@ void VarsService::default_method(::google::protobuf::RpcController* cntl_base, ::google::protobuf::Closure* done) { ClosureGuard done_guard(done); Controller *cntl = static_cast(cntl_base); - if (cntl->http_request().uri().GetQuery("series") != NULL) { + if (cntl->http_request().uri().GetQuery("series") != nullptr) { butil::IOBufBuilder os; bvar::SeriesOptions series_options; const int rc = bvar::Variable::describe_series_exposed( @@ -330,7 +330,7 @@ void VarsService::default_method(::google::protobuf::RpcController* cntl_base, } const bool use_html = UseHTML(cntl->http_request()); bool with_tabs = false; - if (use_html && cntl->http_request().uri().GetQuery("dataonly") == NULL) { + if (use_html && cntl->http_request().uri().GetQuery("dataonly") == nullptr) { with_tabs = true; } cntl->http_response().set_content_type( diff --git a/src/brpc/builtin/viz_min_js.cpp b/src/brpc/builtin/viz_min_js.cpp index 36970ef424..f2400df9fc 100644 --- a/src/brpc/builtin/viz_min_js.cpp +++ b/src/brpc/builtin/viz_min_js.cpp @@ -25,7 +25,7 @@ namespace brpc { static pthread_once_t s_viz_min_buf_once = PTHREAD_ONCE_INIT; -static butil::IOBuf* s_viz_min_buf = NULL; +static butil::IOBuf* s_viz_min_buf = nullptr; static void InitVizMinBuf() { s_viz_min_buf = new butil::IOBuf; s_viz_min_buf->append(viz_min_js()); @@ -38,12 +38,12 @@ const butil::IOBuf& viz_min_js_iobuf() { // viz.js is huge. We separate the creation of gzip version from uncompress // version so that at most time we only keep gzip version in memory. static pthread_once_t s_viz_min_buf_gzip_once = PTHREAD_ONCE_INIT; -static butil::IOBuf* s_viz_min_buf_gzip = NULL; +static butil::IOBuf* s_viz_min_buf_gzip = nullptr; static void InitVizMinBufGzip() { butil::IOBuf viz_min; viz_min.append(viz_min_js()); s_viz_min_buf_gzip = new butil::IOBuf; - CHECK(policy::GzipCompress(viz_min, s_viz_min_buf_gzip, NULL)); + CHECK(policy::GzipCompress(viz_min, s_viz_min_buf_gzip, nullptr)); } const butil::IOBuf& viz_min_js_iobuf_gzip() { pthread_once(&s_viz_min_buf_gzip_once, InitVizMinBufGzip); diff --git a/src/brpc/channel.cpp b/src/brpc/channel.cpp index 83fc37b077..d578c2a3ac 100644 --- a/src/brpc/channel.cpp +++ b/src/brpc/channel.cpp @@ -139,6 +139,8 @@ static ChannelSignature ComputeChannelSignature(const ChannelOptions& opt) { } if (opt.socket_mode == SOCKET_MODE_RDMA) { buf.append("|rdma"); + } else if (opt.socket_mode == SOCKET_MODE_URMA) { + buf.append("|urma"); } butil::MurmurHash3_x64_128_Update(&mm_ctx, buf.data(), buf.size()); buf.clear(); diff --git a/src/brpc/channel.h b/src/brpc/channel.h index 28a17ac8ea..62bc6bfb49 100644 --- a/src/brpc/channel.h +++ b/src/brpc/channel.h @@ -106,7 +106,8 @@ struct ChannelOptions { const ChannelSSLOptions& ssl_options() const { return *_ssl_options; } ChannelSSLOptions* mutable_ssl_options(); - // Let this channel Choose to use a certain socket: 0 SOCKET_MODE_TCP, 1 SOCKET_MODE_RDMA. + // Let this channel choose a transport. + // See SocketMode for supported values. // Default: SOCKET_MODE_TCP SocketMode socket_mode; diff --git a/src/brpc/controller.cpp b/src/brpc/controller.cpp index 244d5d237f..8a8410beb9 100644 --- a/src/brpc/controller.cpp +++ b/src/brpc/controller.cpp @@ -183,8 +183,8 @@ static void CreateIgnoreAllRead() { s_ignore_all_read = new IgnoreAllRead; } // you don't have to set the fields to initial state after deletion since // they'll be set uniformly after this method is called. void Controller::ResetNonPods() { - if (auto span = _span.lock()) { - Span::Submit(span, butil::cpuwide_time_us()); + if (_span) { + Span::Submit(_span, butil::cpuwide_time_us()); } _span.reset(); _error_text.clear(); @@ -463,9 +463,9 @@ void Controller::SetFailed(const std::string& reason) { AppendServerIdentiy(); } _error_text.append(reason); - if (auto span = _span.lock()) { - span->set_error_code(_error_code); - span->Annotate(reason); + if (_span) { + _span->set_error_code(_error_code); + _span->Annotate(reason); } UpdateResponseHeader(this); } @@ -492,9 +492,9 @@ void Controller::SetFailed(int error_code, const char* reason_fmt, ...) { va_start(ap, reason_fmt); butil::string_vappendf(&_error_text, reason_fmt, ap); va_end(ap); - if (auto span = _span.lock()) { - span->set_error_code(_error_code); - span->AnnotateCStr(_error_text.c_str() + old_size, 0); + if (_span) { + _span->set_error_code(_error_code); + _span->AnnotateCStr(_error_text.c_str() + old_size, 0); } UpdateResponseHeader(this); } @@ -520,9 +520,9 @@ void Controller::CloseConnection(const char* reason_fmt, ...) { va_start(ap, reason_fmt); butil::string_vappendf(&_error_text, reason_fmt, ap); va_end(ap); - if (auto span = _span.lock()) { - span->set_error_code(_error_code); - span->AnnotateCStr(_error_text.c_str() + old_size, 0); + if (_span) { + _span->set_error_code(_error_code); + _span->AnnotateCStr(_error_text.c_str() + old_size, 0); } UpdateResponseHeader(this); } @@ -982,9 +982,9 @@ void Controller::EndRPC(const CompletionInfo& info) { } // RPC finished, now it's safe to release `LoadBalancerWithNaming' _lb.reset(); - if (auto span = _span.lock()) { - span->set_ending_cid(info.id); - span->set_async(_done); + if (_span) { + _span->set_ending_cid(info.id); + _span->set_async(_done); // Submit the span if we're in async RPC. For sync RPC, the span // is submitted after Join() to get a more accurate resuming timestamp. if (_done) { @@ -1058,14 +1058,14 @@ void Controller::DoneInBackupThread() { void Controller::SubmitSpan() { const int64_t now = butil::cpuwide_time_us(); - if (auto span = _span.lock()) { - span->set_start_callback_us(now); - if (auto parent_span = span->local_parent().lock()) { + if (_span) { + _span->set_start_callback_us(now); + if (auto parent_span = _span->local_parent().lock()) { if (parent_span->is_active()) { parent_span->AsParent(); } } - Span::Submit(span, now); + Span::Submit(_span, now); _span.reset(); } } @@ -1176,12 +1176,12 @@ void Controller::IssueRPC(int64_t start_realtime_us) { CHECK_EQ(_remote_side, tmp_sock->remote_side()); } - if (auto span = _span.lock()) { + if (_span) { if (_current_call.nretry == 0) { - span->set_remote_side(_remote_side); + _span->set_remote_side(_remote_side); } else { - span->Annotate("Retrying %s", - endpoint2str(_remote_side).c_str()); + _span->Annotate("Retrying %s", + endpoint2str(_remote_side).c_str()); } } // Handle connection type @@ -1292,7 +1292,7 @@ void Controller::IssueRPC(int64_t start_realtime_us) { int rc; size_t packet_size = 0; if (user_packet_guard) { - if (auto span = _span.lock()) { + if (_span) { packet_size = user_packet_guard->EstimatedByteSize(); } rc = _current_call.sending_sock->Write(user_packet_guard, &wopt); @@ -1300,13 +1300,13 @@ void Controller::IssueRPC(int64_t start_realtime_us) { packet_size = packet.size(); rc = _current_call.sending_sock->Write(&packet, &wopt); } - if (auto span = _span.lock()) { + if (_span) { if (_current_call.nretry == 0) { - span->set_sent_us(butil::cpuwide_time_us()); - span->set_request_size(packet_size); + _span->set_sent_us(butil::cpuwide_time_us()); + _span->set_request_size(packet_size); } else { - span->Annotate("Requested(%lld) [%d]", - (long long)packet_size, _current_call.nretry + 1); + _span->Annotate("Requested(%lld) [%d]", + (long long)packet_size, _current_call.nretry + 1); } } if (using_auth) { @@ -1447,15 +1447,15 @@ const Controller* Controller::sub(int index) const { } uint64_t Controller::trace_id() const { - if (auto span = _span.lock()) { - return span->trace_id(); + if (_span) { + return _span->trace_id(); } return 0; } uint64_t Controller::span_id() const { - if (auto span = _span.lock()) { - return span->span_id(); + if (_span) { + return _span->span_id(); } return 0; } @@ -1480,7 +1480,7 @@ void Controller::HandleStreamConnection(Socket *host_socket) { return; } size_t stream_num = _request_streams.size(); - std::vector ptrs(stream_num); + std::vector ptrs(stream_num); if (!FailedInline()) { if (_remote_stream_settings == NULL) { if (!FailedInline()) { @@ -1488,7 +1488,7 @@ void Controller::HandleStreamConnection(Socket *host_socket) { } } else { for (size_t i = 0; i < stream_num; ++i) { - if (Socket::Address(_request_streams[i], &ptrs[i]) != 0) { + if (Stream::Address(_request_streams[i], &ptrs[i]) != 0) { if (!FailedInline()) { SetFailed(EREQUEST, "Request stream=%" PRIu64 " was closed before responded", _request_streams[i]); @@ -1511,14 +1511,14 @@ void Controller::HandleStreamConnection(Socket *host_socket) { } return; } - Stream* s = (Stream*)ptrs[0]->conn(); + Stream* s = ptrs[0].get(); s->SetConnected(_remote_stream_settings); if (stream_num > 1) { auto extra_stream_ids = std::move(*_remote_stream_settings->mutable_extra_stream_ids()); _remote_stream_settings->clear_extra_stream_ids(); for (size_t i = 1; i < stream_num; ++i) { if(!ptrs[i]) continue; - Stream* extra_stream = (Stream *) ptrs[i]->conn(); + Stream* extra_stream = ptrs[i].get(); _remote_stream_settings->set_stream_id(extra_stream_ids[i - 1]); extra_stream->SetHostSocket(host_socket); extra_stream->SetConnected(_remote_stream_settings); @@ -1802,7 +1802,7 @@ ControllerPrivateAccessor& ControllerPrivateAccessor::set_span(Span* span) { } std::shared_ptr ControllerPrivateAccessor::span() const { - return _cntl->_span.lock(); + return _cntl->_span; } } // namespace brpc diff --git a/src/brpc/controller.h b/src/brpc/controller.h index 5d38de0b0f..564c0875e1 100644 --- a/src/brpc/controller.h +++ b/src/brpc/controller.h @@ -877,7 +877,7 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); private: // NOTE: align and group fields to make Controller as compact as possible. - std::weak_ptr _span; + std::shared_ptr _span; uint32_t _flags; // all boolean fields inside Controller int32_t _error_code; std::string _error_text; diff --git a/src/brpc/details/controller_private_accessor.h b/src/brpc/details/controller_private_accessor.h index 07a071bdc8..ea0d30e116 100644 --- a/src/brpc/details/controller_private_accessor.h +++ b/src/brpc/details/controller_private_accessor.h @@ -63,7 +63,7 @@ class ControllerPrivateAccessor { } void move_in_server_receiving_sock(SocketUniquePtr& ptr) { - CHECK(_cntl->_current_call.sending_sock == NULL); + CHECK(_cntl->_current_call.sending_sock == nullptr); _cntl->_current_call.sending_sock.reset(ptr.release()); } diff --git a/src/brpc/details/has_epollrdhup.cpp b/src/brpc/details/has_epollrdhup.cpp index dd085ad8fc..9a49f56bd5 100644 --- a/src/brpc/details/has_epollrdhup.cpp +++ b/src/brpc/details/has_epollrdhup.cpp @@ -41,8 +41,7 @@ static unsigned int check_epollrdhup() { if (socketpair(AF_UNIX, SOCK_STREAM, 0, (int*)fds) < 0) { return 0; } - epoll_event evt = { static_cast(EPOLLIN | EPOLLRDHUP | EPOLLET), - { NULL }}; + epoll_event evt = { static_cast(EPOLLIN | EPOLLRDHUP | EPOLLET), { nullptr }}; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &evt) < 0) { return 0; } diff --git a/src/brpc/details/health_check.cpp b/src/brpc/details/health_check.cpp index 7cf4e32bcf..5bb3b02397 100644 --- a/src/brpc/details/health_check.cpp +++ b/src/brpc/details/health_check.cpp @@ -100,8 +100,8 @@ void* HealthCheckManager::AppCheck(void* arg) { done->cntl.http_request().uri() = done->hc_option.health_check_path; ControllerPrivateAccessor(&done->cntl).set_health_check_call(); done->last_check_time_ms = butil::cpuwide_time_ms(); - done->channel.CallMethod(NULL, &done->cntl, NULL, NULL, done); - return NULL; + done->channel.CallMethod(nullptr, &done->cntl, nullptr, nullptr, done); + return nullptr; } void OnAppHealthCheckDone::Run() { @@ -187,10 +187,10 @@ bool HealthCheckTask::OnTriggeringTask(timespec* next_abstime) { } } - // g_vars must not be NULL because it is newed at the creation of + // g_vars must not be nullptr because it is newed at the creation of // first Socket. When g_vars is used, the socket is at health-checking // state, which means the socket must be created and then g_vars can - // not be NULL. + // not be nullptr. g_vars->nhealthcheck << 1; int hc = 0; if (ptr->_user) { diff --git a/src/brpc/details/hpack.cpp b/src/brpc/details/hpack.cpp index e627e81d25..c9c707c9b9 100644 --- a/src/brpc/details/hpack.cpp +++ b/src/brpc/details/hpack.cpp @@ -38,7 +38,7 @@ struct IndexTableOptions { IndexTableOptions() : max_size(0) , start_index(0) - , static_table(NULL) + , static_table(nullptr) , static_table_size(0) , need_indexes(false) {} @@ -83,7 +83,7 @@ DISALLOW_COPY_AND_ASSIGN(IndexTable); const Header* HeaderAt(int index) const { if (BAIDU_UNLIKELY(index < _start_index)) { - return NULL; + return nullptr; } return _header_queue.bottom(index - _start_index); }; @@ -319,10 +319,10 @@ DISALLOW_COPY_AND_ASSIGN(HuffmanTree); const HuffmanNode* node(NodeId id) const { if (id == 0u) { - return NULL; + return nullptr; } if (id > _node_memory.size()) { - return NULL; + return nullptr; } return &_node_memory[id - 1]; } @@ -386,7 +386,7 @@ DISALLOW_COPY_AND_ASSIGN(HuffmanEncoder); _out->push_back(_partial_byte); _partial_byte = 0; _remain_bit = 0; - _out = NULL; + _out = nullptr; ++_out_bytes; } @@ -496,8 +496,8 @@ inline void EncodeInteger(butil::IOBufAppender* out, uint8_t msb, } // Static variables -static HuffmanTree* s_huffman_tree = NULL; -static IndexTable* s_static_table = NULL; +static HuffmanTree* s_huffman_tree = nullptr; +static IndexTable* s_static_table = nullptr; static pthread_once_t s_create_once = PTHREAD_ONCE_INIT; static void CreateStaticTableOrDie() { @@ -530,7 +530,7 @@ static const size_t MAX_HPACK_INTEGER = 10 * 1024 * 1024ul; inline ssize_t DecodeInteger(butil::IOBufBytesIterator& iter, uint8_t prefix_size, uint32_t* value) { - if (iter == NULL) { + if (iter == nullptr) { return 0; // No enough data } uint8_t first_byte = *iter; @@ -615,7 +615,7 @@ inline void EncodeString(butil::IOBufAppender* out, const std::string& s, } inline ssize_t DecodeString(butil::IOBufBytesIterator& iter, std::string* out) { - if (iter == NULL) { + if (iter == nullptr) { return 0; } const bool huffman = *iter & 0x80; @@ -634,7 +634,7 @@ inline ssize_t DecodeString(butil::IOBufBytesIterator& iter, std::string* out) { return in_bytes; } HuffmanDecoder d(out, s_huffman_tree); - for (; iter != NULL && length; ++iter, --length) { + for (; iter != nullptr && length; ++iter, --length) { if (d.Decode(*iter) != 0) { return -1; } @@ -646,19 +646,19 @@ inline ssize_t DecodeString(butil::IOBufBytesIterator& iter, std::string* out) { } HPacker::HPacker() - : _encode_table(NULL) - , _decode_table(NULL) { + : _encode_table(nullptr) + , _decode_table(nullptr) { CreateStaticTableOnceOrDie(); } HPacker::~HPacker() { if (_encode_table) { delete _encode_table; - _encode_table = NULL; + _encode_table = nullptr; } if (_decode_table) { delete _decode_table; - _decode_table = NULL; + _decode_table = nullptr; } } @@ -752,7 +752,7 @@ inline ssize_t HPacker::DecodeWithKnownPrefix( } if (index != 0) { const Header* indexed_header = HeaderAt(index); - if (indexed_header == NULL) { + if (indexed_header == nullptr) { LOG(ERROR) << "No header at index=" << index; return -1; } @@ -776,7 +776,7 @@ inline ssize_t HPacker::DecodeWithKnownPrefix( ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter, Header* h) { ssize_t skipped_bytes = 0; decode_next: - if (iter == NULL) { + if (iter == nullptr) { return 0; } const uint8_t first_byte = *iter; @@ -799,7 +799,7 @@ ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter, Header* h) { return index_bytes; } const Header* indexed_header = HeaderAt(index); - if (indexed_header == NULL) { + if (indexed_header == nullptr) { LOG(ERROR) << "No header at index=" << index; return -1; } diff --git a/src/brpc/details/http_message.cpp b/src/brpc/details/http_message.cpp index 003bafa074..13beb67a01 100644 --- a/src/brpc/details/http_message.cpp +++ b/src/brpc/details/http_message.cpp @@ -117,7 +117,7 @@ int HttpMessage::on_header_value(http_parser *parser, } if (FLAGS_http_verbose) { butil::IOBufBuilder* vs = http_message->_vmsgbuilder.get(); - if (vs == NULL) { + if (vs == nullptr) { vs = new butil::IOBufBuilder; http_message->_vmsgbuilder.reset(vs); if (parser->type == HTTP_REQUEST) { @@ -177,7 +177,7 @@ int HttpMessage::on_headers_complete(http_parser *parser) { URI& uri = headers.uri(); if (uri._host.empty()) { const std::string* host_header = headers.GetHeader("host"); - if (host_header != NULL) { + if (host_header != nullptr) { uri.SetHostAndPort(*host_header); } } @@ -236,7 +236,7 @@ int HttpMessage::UnlockAndFlushToBodyReader(std::unique_lock& mu) butil::Status st = r->OnReadOnePart(blk.data(), blk.size()); if (!st.ok()) { mu.lock(); - _body_reader = NULL; + _body_reader = nullptr; mu.unlock(); r->OnEndOfMessage(st); return -1; @@ -274,7 +274,7 @@ int HttpMessage::OnBody(const char *at, const size_t length) { // the body is probably streaming data which is too long to print. header().status_code() == HTTP_STATUS_OK) { LOG(INFO) << '\n' << _vmsgbuilder->buf(); - _vmsgbuilder.reset(NULL); + _vmsgbuilder.reset(nullptr); } else { if (_vbodylen < (size_t)FLAGS_http_verbose_max_body_length) { int plen = std::min(length, (size_t)FLAGS_http_verbose_max_body_length @@ -291,7 +291,7 @@ int HttpMessage::OnBody(const char *at, const size_t length) { } if (!_read_body_progressively) { // Normal read. - if (NULL != _current_source_iobuf) { + if (nullptr != _current_source_iobuf) { _current_source_iobuf->append_to( &_body, length, _parsed_block_size + (at - _current_block_base)); } else { @@ -302,7 +302,7 @@ int HttpMessage::OnBody(const char *at, const size_t length) { // Progressive read. std::unique_lock mu(_body_mutex); ProgressiveReader* r = _body_reader; - while (r == NULL) { + while (r == nullptr) { // When _body is full, the sleep-waiting may block parse handler // of the protocol. A more efficient solution is to remove the // socket from epoll and add it back when the _body is not full, @@ -328,7 +328,7 @@ int HttpMessage::OnBody(const char *at, const size_t length) { return 0; } mu.lock(); - _body_reader = NULL; + _body_reader = nullptr; mu.unlock(); r->OnEndOfMessage(st); return -1; @@ -341,10 +341,10 @@ int HttpMessage::OnMessageComplete() { - (size_t)FLAGS_http_verbose_max_body_length << " bytes>"; } LOG(INFO) << '\n' << _vmsgbuilder->buf(); - _vmsgbuilder.reset(NULL); + _vmsgbuilder.reset(nullptr); } _cur_header.clear(); - _cur_value = NULL; + _cur_value = nullptr; if (!_read_body_progressively) { // Normal read. _stage = HTTP_ON_MESSAGE_COMPLETE; @@ -353,7 +353,7 @@ int HttpMessage::OnMessageComplete() { // Progressive read. std::unique_lock mu(_body_mutex); _stage = HTTP_ON_MESSAGE_COMPLETE; - if (_body_reader != NULL) { + if (_body_reader != nullptr) { // Solve the case: SetBodyReader quit at ntry=MAX_TRY with non-empty // _body and the remaining _body is just the last part. // Make sure _body is emptied. @@ -362,7 +362,7 @@ int HttpMessage::OnMessageComplete() { } mu.lock(); ProgressiveReader* r = _body_reader; - _body_reader = NULL; + _body_reader = nullptr; mu.unlock(); r->OnEndOfMessage(butil::Status()); } @@ -379,7 +379,7 @@ class FailAllRead : public ProgressiveReader { void OnEndOfMessage(const butil::Status&) {} }; -static FailAllRead* s_fail_all_read = NULL; +static FailAllRead* s_fail_all_read = nullptr; static pthread_once_t s_fail_all_read_once = PTHREAD_ONCE_INIT; static void CreateFailAllRead() { s_fail_all_read = new FailAllRead; } @@ -393,7 +393,7 @@ void HttpMessage::SetBodyReader(ProgressiveReader* r) { int ntry = 0; do { std::unique_lock mu(_body_mutex); - if (_body_reader != NULL) { + if (_body_reader != nullptr) { mu.unlock(); return r->OnEndOfMessage( butil::Status(EPERM, "SetBodyReader is called more than once")); @@ -456,7 +456,7 @@ HttpMessage::HttpMessage(bool read_body_progressively, HttpMessage::~HttpMessage() { if (_body_reader) { ProgressiveReader* saved_body_reader = _body_reader; - _body_reader = NULL; + _body_reader = nullptr; // Successfully ended message is ended in OnMessageComplete() or // SetBodyReader() and _body_reader should be null-ed. Non-null // _body_reader here just means the socket is broken before completion @@ -499,7 +499,7 @@ ssize_t HttpMessage::ParseFromIOBuf(const butil::IOBuf &buf) { _parsed_block_size = 0; _current_source_iobuf = &buf; BRPC_SCOPE_EXIT { - _current_source_iobuf = NULL; + _current_source_iobuf = nullptr; }; size_t nprocessed = 0; for (size_t i = 0; i < buf.backing_block_num(); ++i) { @@ -632,7 +632,7 @@ void MakeRawHttpRequest(butil::IOBuf* request, //the request-target consists of only the host name and port number of //the tunnel destination, separated by a colon. For example, //Host: server.example.com:80 - if (h->GetHeader("host") == NULL) { + if (h->GetHeader("host") == nullptr) { os << "Host: "; if (!uri.host().empty()) { os << uri.host(); @@ -652,15 +652,15 @@ void MakeRawHttpRequest(butil::IOBuf* request, it != h->HeaderEnd(); ++it) { os << it->first << ": " << it->second << BRPC_CRLF; } - if (h->GetHeader("Accept") == NULL) { + if (h->GetHeader("Accept") == nullptr) { os << "Accept: */*" BRPC_CRLF; } // The fake "curl" user-agent may let servers return plain-text results. - if (h->GetHeader("User-Agent") == NULL) { + if (h->GetHeader("User-Agent") == nullptr) { os << "User-Agent: brpc/1.0 curl/7.0" BRPC_CRLF; } const std::string& user_info = h->uri().user_info(); - if (!user_info.empty() && h->GetHeader("Authorization") == NULL) { + if (!user_info.empty() && h->GetHeader("Authorization") == nullptr) { // NOTE: just assume user_info is well formatted, namely // ":". Users are very unlikely to add extra // characters in this part and even if users did, most of them are diff --git a/src/brpc/details/http_message.h b/src/brpc/details/http_message.h index ae4a016dc9..14f8fbb70f 100644 --- a/src/brpc/details/http_message.h +++ b/src/brpc/details/http_message.h @@ -114,21 +114,21 @@ class HttpMessage { // For mutual exclusion between on_body and SetBodyReader. butil::Mutex _body_mutex; // Read body progressively - ProgressiveReader* _body_reader{NULL}; + ProgressiveReader* _body_reader{nullptr}; butil::IOBuf _body; size_t _body_size{0}; bool _body_too_large{false}; // Store the IOBuf information in `ParseFromIOBuf' // for later zero-copy usage in `OnBody'. - const butil::IOBuf* _current_source_iobuf{NULL}; - const char* _current_block_base{NULL}; + const butil::IOBuf* _current_source_iobuf{nullptr}; + const char* _current_block_base{nullptr}; size_t _parsed_block_size{0}; // Parser related members struct http_parser _parser; std::string _cur_header; - std::string *_cur_value{NULL}; + std::string *_cur_value{nullptr}; protected: // Only valid when -http_verbose is on @@ -141,7 +141,7 @@ std::ostream& operator<<(std::ostream& os, const http_parser& parser); // Serialize a http request. // header: may be modified in some cases // remote_side: used when "Host" is absent -// content: could be NULL. +// content: could be nullptr. void MakeRawHttpRequest(butil::IOBuf* request, HttpHeader* header, const butil::EndPoint& remote_side, @@ -149,7 +149,7 @@ void MakeRawHttpRequest(butil::IOBuf* request, // Serialize a http response. // header: may be modified in some cases -// content: cleared after usage. could be NULL. +// content: cleared after usage. could be nullptr. void MakeRawHttpResponse(butil::IOBuf* response, HttpHeader* header, butil::IOBuf* content); diff --git a/src/brpc/details/http_parser.cpp b/src/brpc/details/http_parser.cpp index a4aa4d1276..2c68cffca3 100644 --- a/src/brpc/details/http_parser.cpp +++ b/src/brpc/details/http_parser.cpp @@ -96,7 +96,7 @@ do { \ return (ER); \ } \ } \ - FOR##_mark = NULL; \ + FOR##_mark = nullptr; \ } \ } while (0) @@ -2424,7 +2424,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, if (u->field_set & (1 << UF_PORT)) { /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); + unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, nullptr, 10); /* Ports have a max value of 2^16 */ if (v > 0xffff) { diff --git a/src/brpc/details/jemalloc_profiler.cpp b/src/brpc/details/jemalloc_profiler.cpp index fdd06fb4ef..2091eda7d4 100644 --- a/src/brpc/details/jemalloc_profiler.cpp +++ b/src/brpc/details/jemalloc_profiler.cpp @@ -137,7 +137,7 @@ static std::string JeProfileDump() { } const char* p_prof_name = prof_name; - int ret = mallctl("prof.dump", NULL, NULL, (void*)&p_prof_name, sizeof(p_prof_name)); + int ret = mallctl("prof.dump", nullptr, nullptr, (void*)&p_prof_name, sizeof(p_prof_name)); if (ret != 0) { LOG(WARNING) << "mallctl set prof.dump:" << p_prof_name << " err, ret:" << ret; return ""; diff --git a/src/brpc/details/mesalink_ssl_helper.cpp b/src/brpc/details/mesalink_ssl_helper.cpp index aa83fa6c35..171f045b4a 100644 --- a/src/brpc/details/mesalink_ssl_helper.cpp +++ b/src/brpc/details/mesalink_ssl_helper.cpp @@ -138,7 +138,7 @@ void ExtractHostnames(X509* x, std::vector* hostnames) { struct FreeSSL { inline void operator()(SSL* ssl) const { - if (ssl != NULL) { + if (ssl != nullptr) { SSL_free(ssl); } } @@ -146,7 +146,7 @@ struct FreeSSL { struct FreeBIO { inline void operator()(BIO* io) const { - if (io != NULL) { + if (io != nullptr) { BIO_free(io); } } @@ -154,7 +154,7 @@ struct FreeBIO { struct FreeX509 { inline void operator()(X509* x) const { - if (x != NULL) { + if (x != nullptr) { X509_free(x); } } @@ -162,7 +162,7 @@ struct FreeX509 { struct FreeEVPKEY { inline void operator()(EVP_PKEY* k) const { - if (k != NULL) { + if (k != nullptr) { EVP_PKEY_free(k); } } @@ -177,7 +177,7 @@ static int LoadCertificate(SSL_CTX* ctx, std::unique_ptr kbio( BIO_new_mem_buf((void*)private_key.c_str(), -1)); std::unique_ptr key( - PEM_read_bio_PrivateKey(kbio.get(), NULL, 0, NULL)); + PEM_read_bio_PrivateKey(kbio.get(), nullptr, 0, nullptr)); if (SSL_CTX_use_PrivateKey(ctx, key.get()) != 1) { LOG(ERROR) << "Fail to load " << private_key << ": " << SSLError(ERR_get_error()); @@ -205,7 +205,7 @@ static int LoadCertificate(SSL_CTX* ctx, } } std::unique_ptr x( - PEM_read_bio_X509(cbio.get(), NULL, 0, NULL)); + PEM_read_bio_X509(cbio.get(), nullptr, 0, nullptr)); if (!x) { LOG(ERROR) << "Fail to parse " << certificate << ": " << SSLError(ERR_get_error()); @@ -221,8 +221,8 @@ static int LoadCertificate(SSL_CTX* ctx, // Load the certificate chain //SSL_CTX_clear_chain_certs(ctx); - X509* ca = NULL; - while ((ca = PEM_read_bio_X509(cbio.get(), NULL, 0, NULL))) { + X509* ca = nullptr; + while ((ca = PEM_read_bio_X509(cbio.get(), nullptr, 0, nullptr))) { if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { LOG(ERROR) << "Fail to load chain certificate in " << certificate << ": " << SSLError(ERR_get_error()); @@ -251,16 +251,16 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, if (verify.verify_depth > 0) { std::string cafile = verify.ca_file_path; if (!cafile.empty()) { - if (SSL_CTX_load_verify_locations(ctx, cafile.c_str(), NULL) == 0) { + if (SSL_CTX_load_verify_locations(ctx, cafile.c_str(), nullptr) == 0) { LOG(ERROR) << "Fail to load CA file " << cafile << ": " << SSLError(ERR_get_error()); return -1; } } SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER - | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); + | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), nullptr); } else { - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr); } return 0; @@ -271,21 +271,21 @@ SSL_CTX* CreateClientSSLContext(const ChannelSSLOptions& options) { SSL_CTX_new(TLSv1_2_client_method())); if (!ssl_ctx) { LOG(ERROR) << "Fail to new SSL_CTX: " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } if (!options.client_cert.certificate.empty() && LoadCertificate(ssl_ctx.get(), options.client_cert.certificate, - options.client_cert.private_key, NULL) != 0) { - return NULL; + options.client_cert.private_key, nullptr) != 0) { + return nullptr; } int protocols = ParseSSLProtocols(options.protocols); if (protocols < 0 || SetSSLOptions(ssl_ctx.get(), options.ciphers, protocols, options.verify) != 0) { - return NULL; + return nullptr; } SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_CLIENT); @@ -300,12 +300,12 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, SSL_CTX_new(TLSv1_2_server_method())); if (!ssl_ctx) { LOG(ERROR) << "Fail to new SSL_CTX: " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } if (LoadCertificate(ssl_ctx.get(), certificate, private_key, hostnames) != 0) { - return NULL; + return nullptr; } int protocols = TLSv1 | TLSv1_1 | TLSv1_2; @@ -314,7 +314,7 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, } if (SetSSLOptions(ssl_ctx.get(), options.ciphers, protocols, options.verify) != 0) { - return NULL; + return nullptr; } /* SSL_CTX_set_timeout(ssl_ctx.get(), options.session_lifetime_s); */ @@ -324,19 +324,19 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, } SSL* CreateSSLSession(SSL_CTX* ctx, SocketId id, int fd, bool server_mode) { - if (ctx == NULL) { + if (ctx == nullptr) { LOG(WARNING) << "Lack SSL_ctx to create an SSL session"; - return NULL; + return nullptr; } SSL* ssl = SSL_new(ctx); - if (ssl == NULL) { + if (ssl == nullptr) { LOG(ERROR) << "Fail to SSL_new: " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } if (SSL_set_fd(ssl, fd) != 1) { LOG(ERROR) << "Fail to SSL_set_fd: " << SSLError(ERR_get_error()); SSL_free(ssl); - return NULL; + return nullptr; } if (server_mode) { diff --git a/src/brpc/details/method_status.cpp b/src/brpc/details/method_status.cpp index 3bed6bf209..d23283fbd7 100644 --- a/src/brpc/details/method_status.cpp +++ b/src/brpc/details/method_status.cpp @@ -159,7 +159,7 @@ int HandleResponseWritten(bthread_id_t id, void* data, int /*error_code*/) { ConcurrencyRemover::~ConcurrencyRemover() { if (_status) { _status->OnResponded(_c->ErrorCode(), butil::cpuwide_time_us() - _received_us); - _status = NULL; + _status = nullptr; } ServerPrivateAccessor(_c->server()).RemoveConcurrency(_c); } diff --git a/src/brpc/details/method_status.h b/src/brpc/details/method_status.h index 9b7f070991..fab56e90fc 100644 --- a/src/brpc/details/method_status.h +++ b/src/brpc/details/method_status.h @@ -37,8 +37,8 @@ class MethodStatus : public Describable { // Call this function when the method is about to be called. // Returns false when the method is overloaded. If rejected_cc is not - // NULL, it's set with the rejected concurrency. - bool OnRequested(int* rejected_cc = NULL, Controller* cntl = NULL); + // nullptr, it's set with the rejected concurrency. + bool OnRequested(int* rejected_cc = nullptr, Controller* cntl = nullptr); // Call this when the method just finished. // `error_code' : The error code obtained from the controller. Equal to @@ -96,7 +96,7 @@ class ConcurrencyRemover { inline bool MethodStatus::OnRequested(int* rejected_cc, Controller* cntl) { const int cc = _nconcurrency.fetch_add(1, butil::memory_order_relaxed) + 1; - if (NULL == _cl || _cl->OnRequested(cc, cntl)) { + if (nullptr == _cl || _cl->OnRequested(cc, cntl)) { return true; } if (rejected_cc) { @@ -112,7 +112,7 @@ inline void MethodStatus::OnResponded(int error_code, int64_t latency) { } else { _nerror_bvar << 1; } - if (NULL != _cl) { + if (nullptr != _cl) { _cl->OnResponded(error_code, latency); } } diff --git a/src/brpc/details/naming_service_thread.cpp b/src/brpc/details/naming_service_thread.cpp index 7eb005e8f0..2303af1f26 100644 --- a/src/brpc/details/naming_service_thread.cpp +++ b/src/brpc/details/naming_service_thread.cpp @@ -56,7 +56,7 @@ inline bool operator==(const NSKey& k1, const NSKey& k2) { typedef butil::FlatMap NamingServiceMap; // Construct on demand to make the code work before main() -static NamingServiceMap* g_nsthread_map = NULL; +static NamingServiceMap* g_nsthread_map = nullptr; static pthread_mutex_t g_nsthread_map_mutex = PTHREAD_MUTEX_INITIALIZER; NamingServiceThread::Actions::Actions(NamingServiceThread* owner) @@ -64,7 +64,7 @@ NamingServiceThread::Actions::Actions(NamingServiceThread* owner) , _wait_id(INVALID_BTHREAD_ID) , _has_wait_error(false) , _wait_error(0) { - CHECK_EQ(0, bthread_id_create(&_wait_id, NULL, NULL)); + CHECK_EQ(0, bthread_id_create(&_wait_id, nullptr, nullptr)); } NamingServiceThread::Actions::~Actions() { @@ -161,7 +161,7 @@ void NamingServiceThread::Actions::ResetServers( _sockets.end()); } std::vector removed_ids; - ServerNodeWithId2ServerId(_removed_sockets, &removed_ids, NULL); + ServerNodeWithId2ServerId(_removed_sockets, &removed_ids, nullptr); { BAIDU_SCOPED_LOCK(_owner->_mutex); @@ -207,7 +207,7 @@ void NamingServiceThread::Actions::ResetServers( } void NamingServiceThread::Actions::EndWait(int error_code) { - if (bthread_id_trylock(_wait_id, NULL) == 0) { + if (bthread_id_trylock(_wait_id, nullptr) == 0) { _wait_error = error_code; _has_wait_error.store(true, butil::memory_order_release); bthread_id_unlock_and_destroy(_wait_id); @@ -225,7 +225,7 @@ int NamingServiceThread::Actions::WaitForFirstBatchOfServers() { NamingServiceThread::NamingServiceThread() : _tid(0) - , _ns(NULL) + , _ns(nullptr) , _actions(this) { } @@ -235,22 +235,22 @@ NamingServiceThread::~NamingServiceThread() { if (!_protocol.empty()) { const NSKey key(_protocol, _service_name, _options.channel_signature); std::unique_lock mu(g_nsthread_map_mutex); - if (g_nsthread_map != NULL) { + if (g_nsthread_map != nullptr) { NamingServiceThread** ptr = g_nsthread_map->seek(key); - if (ptr != NULL && *ptr == this) { + if (ptr != nullptr && *ptr == this) { g_nsthread_map->erase(key); } } } if (_tid) { bthread_stop(_tid); - bthread_join(_tid, NULL); + bthread_join(_tid, nullptr); _tid = 0; } { BAIDU_SCOPED_LOCK(_mutex); std::vector to_be_removed; - ServerNodeWithId2ServerId(_last_sockets, &to_be_removed, NULL); + ServerNodeWithId2ServerId(_last_sockets, &to_be_removed, nullptr); if (!_last_sockets.empty()) { for (std::map::iterator @@ -263,20 +263,20 @@ NamingServiceThread::~NamingServiceThread() { if (_ns) { _ns->Destroy(); - _ns = NULL; + _ns = nullptr; } } void* NamingServiceThread::RunThis(void* arg) { static_cast(arg)->Run(); - return NULL; + return nullptr; } int NamingServiceThread::Start(NamingService* naming_service, const std::string& protocol, const std::string& service_name, const GetNamingServiceThreadOptions* opt_in) { - if (naming_service == NULL) { + if (naming_service == nullptr) { LOG(ERROR) << "Param[naming_service] is NULL"; return -1; } @@ -290,7 +290,7 @@ int NamingServiceThread::Start(NamingService* naming_service, if (_ns->RunNamingServiceReturnsQuickly()) { RunThis(this); } else { - int rc = bthread_start_urgent(&_tid, NULL, RunThis, this); + int rc = bthread_start_urgent(&_tid, nullptr, RunThis, this); if (rc) { LOG(ERROR) << "Fail to create bthread: " << berror(rc); return rc; @@ -337,7 +337,7 @@ void NamingServiceThread::ServerNodeWithId2ServerId( int NamingServiceThread::AddWatcher(NamingServiceWatcher* watcher, const NamingServiceFilter* filter) { - if (watcher == NULL) { + if (watcher == nullptr) { LOG(ERROR) << "Param[watcher] is NULL"; return -1; } @@ -354,7 +354,7 @@ int NamingServiceThread::AddWatcher(NamingServiceWatcher* watcher, } int NamingServiceThread::RemoveWatcher(NamingServiceWatcher* watcher) { - if (watcher == NULL) { + if (watcher == nullptr) { LOG(ERROR) << "Param[watcher] is NULL"; return -1; } @@ -391,14 +391,14 @@ static const char* ParseNamingServiceUrl(const char* url, char* protocol) { // Accepting "[^:]{1,MAX_PROTOCOL_LEN}://*.*" // ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ // protocol service_name - if (__builtin_expect(url != NULL, 1)) { + if (__builtin_expect(url != nullptr, 1)) { const char* p1 = url; while (*p1 != ':') { if (p1 < url + MAX_PROTOCOL_LEN && *p1) { protocol[p1 - url] = *p1; ++p1; } else { - return NULL; + return nullptr; } } if (p1 <= url + MAX_PROTOCOL_LEN) { @@ -409,7 +409,7 @@ static const char* ParseNamingServiceUrl(const char* url, char* protocol) { } } } - return NULL; + return nullptr; } int GetNamingServiceThread( @@ -418,12 +418,12 @@ int GetNamingServiceThread( const GetNamingServiceThreadOptions* options) { char protocol[MAX_PROTOCOL_LEN + 1]; const char* const service_name = ParseNamingServiceUrl(url, protocol); - if (service_name == NULL) { + if (service_name == nullptr) { LOG(ERROR) << "Invalid naming service url=" << url; return -1; } const NamingService* source_ns = NamingServiceExtension()->Find(protocol); - if (source_ns == NULL) { + if (source_ns == nullptr) { LOG(ERROR) << "Unknown protocol=" << protocol; return -1; } @@ -433,19 +433,14 @@ int GetNamingServiceThread( butil::intrusive_ptr nsthread; { std::unique_lock mu(g_nsthread_map_mutex); - if (g_nsthread_map == NULL) { - g_nsthread_map = new (std::nothrow) NamingServiceMap; - if (NULL == g_nsthread_map) { - mu.unlock(); - LOG(ERROR) << "Fail to new g_nsthread_map"; - return -1; - } + if (g_nsthread_map == nullptr) { + g_nsthread_map = new NamingServiceMap; if (g_nsthread_map->init(64) != 0) { LOG(WARNING) << "Fail to init g_nsthread_map"; } } NamingServiceThread*& ptr = (*g_nsthread_map)[key]; - if (ptr != NULL) { + if (ptr != nullptr) { if (ptr->AddRefManually() == 0) { // The ns thread's last intrusive_ptr was just destructed and // the removal-from-global-map-code in ptr->~NamingServiceThread() @@ -453,18 +448,13 @@ int GetNamingServiceThread( // thread. // Notice that we don't need to remove the reference because // the object is already destructing. - ptr = NULL; + ptr = nullptr; } else { nsthread.reset(ptr, false); } } - if (ptr == NULL) { - NamingServiceThread* thr = new (std::nothrow) NamingServiceThread; - if (thr == NULL) { - mu.unlock(); - LOG(ERROR) << "Fail to new NamingServiceThread"; - return -1; - } + if (ptr == nullptr) { + NamingServiceThread* thr = new NamingServiceThread; ptr = thr; nsthread.reset(ptr); new_thread = true; @@ -491,7 +481,7 @@ int GetNamingServiceThread( void NamingServiceThread::Describe(std::ostream& os, const DescribeOptions& options) const { - if (_ns == NULL) { + if (_ns == nullptr) { os << "null"; } else { _ns->Describe(os, options); diff --git a/src/brpc/details/naming_service_thread.h b/src/brpc/details/naming_service_thread.h index f01fbea6a4..befb475c80 100644 --- a/src/brpc/details/naming_service_thread.h +++ b/src/brpc/details/naming_service_thread.h @@ -101,7 +101,7 @@ class NamingServiceThread : public SharedObject, public Describable { void EndWait(int error_code); int AddWatcher(NamingServiceWatcher* w, const NamingServiceFilter* f); - int AddWatcher(NamingServiceWatcher* w) { return AddWatcher(w, NULL); } + int AddWatcher(NamingServiceWatcher* w) { return AddWatcher(w, nullptr); } int RemoveWatcher(NamingServiceWatcher* w); void Describe(std::ostream& os, const DescribeOptions&) const override; diff --git a/src/brpc/details/server_private_accessor.h b/src/brpc/details/server_private_accessor.h index aacf283564..d553b4dcfa 100644 --- a/src/brpc/details/server_private_accessor.h +++ b/src/brpc/details/server_private_accessor.h @@ -111,12 +111,12 @@ class ScopedNonServiceError { ~ScopedNonServiceError() { if (_server) { ServerPrivateAccessor(_server).AddError(); - _server = NULL; + _server = nullptr; } } const Server* release() { const Server* tmp = _server; - _server = NULL; + _server = nullptr; return tmp; } private: diff --git a/src/brpc/details/sparse_minute_counter.h b/src/brpc/details/sparse_minute_counter.h index 3834afab9e..d498cec6ba 100644 --- a/src/brpc/details/sparse_minute_counter.h +++ b/src/brpc/details/sparse_minute_counter.h @@ -41,7 +41,7 @@ template class SparseMinuteCounter { Item(int64_t ts, const T& v) : timestamp_ms(ts), value(v) {} }; public: - SparseMinuteCounter() : _q(NULL) {} + SparseMinuteCounter() : _q(nullptr) {} ~SparseMinuteCounter() { DestroyQueue(_q); } // Add `value' into this counter at timestamp `now_ms' @@ -145,7 +145,7 @@ template bool SparseMinuteCounter::TryPop(int64_t now_ms, T* popped) { if (_q) { const Item* const oldest = _q->top(); - if (oldest == NULL || now_ms < oldest->timestamp_ms + 60000) { + if (oldest == nullptr || now_ms < oldest->timestamp_ms + 60000) { return false; } *popped = oldest->value; diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp index 52246980aa..1673db1d87 100644 --- a/src/brpc/details/ssl_helper.cpp +++ b/src/brpc/details/ssl_helper.cpp @@ -49,10 +49,10 @@ bool SupportsPeerNameVerification() { } #ifndef OPENSSL_NO_DH -static DH* g_dh_1024 = NULL; -static DH* g_dh_2048 = NULL; -static DH* g_dh_4096 = NULL; -static DH* g_dh_8192 = NULL; +static DH* g_dh_1024 = nullptr; +static DH* g_dh_2048 = nullptr; +static DH* g_dh_4096 = nullptr; +static DH* g_dh_8192 = nullptr; #endif // OPENSSL_NO_DH static const char* const PEM_START = "-----BEGIN"; @@ -202,18 +202,18 @@ static void SSLMessageCallback(int write_p, int version, int content_type, #if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10101000L) static pthread_once_t g_ssl_keylog_once = PTHREAD_ONCE_INIT; -static FILE* g_ssl_keylog_file = NULL; +static FILE* g_ssl_keylog_file = nullptr; static void InitSSLKeyLogFile() { const char* path = getenv("SSLKEYLOGFILE"); - if (path == NULL || path[0] == '\0') { + if (path == nullptr || path[0] == '\0') { return; } g_ssl_keylog_file = fopen(path, "ae"); - if (g_ssl_keylog_file == NULL) { + if (g_ssl_keylog_file == nullptr) { PLOG(WARNING) << "Fail to open SSLKEYLOGFILE=" << path; } else { - setvbuf(g_ssl_keylog_file, NULL, _IOLBF, 0); + setvbuf(g_ssl_keylog_file, nullptr, _IOLBF, 0); LOG(WARNING) << "SSLKEYLOGFILE is enabled (path: " << path << "). " << "Sensitive TLS session keys will be written to this file. " << "This feature is intended for debugging only and should NOT be used in production environments."; @@ -222,7 +222,7 @@ static void InitSSLKeyLogFile() { static void SSLKeyLogCallback(const SSL* ssl, const char* line) { (void)ssl; - if (line == NULL || g_ssl_keylog_file == NULL) { + if (line == nullptr || g_ssl_keylog_file == nullptr) { return; } // Write the full key log line with newline in one call to keep output atomic. @@ -231,7 +231,7 @@ static void SSLKeyLogCallback(const SSL* ssl, const char* line) { static void MaybeSetKeyLogCallback(SSL_CTX* ctx) { pthread_once(&g_ssl_keylog_once, InitSSLKeyLogFile); - if (ctx != NULL && g_ssl_keylog_file != NULL) { + if (ctx != nullptr && g_ssl_keylog_file != nullptr) { SSL_CTX_set_keylog_callback(ctx, SSLKeyLogCallback); } } @@ -268,10 +268,10 @@ static DH* SSLGetDHCallback(SSL* ssl, int exp, int keylen) { void ExtractHostnames(X509* x, std::vector* hostnames) { #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME STACK_OF(GENERAL_NAME)* names = (STACK_OF(GENERAL_NAME)*) - X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + X509_get_ext_d2i(x, NID_subject_alt_name, nullptr, nullptr); if (names) { for (size_t i = 0; i < static_cast(sk_GENERAL_NAME_num(names)); i++) { - char* str = NULL; + char* str = nullptr; GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i); if (name->type == GEN_DNS) { if (ASN1_STRING_to_UTF8((unsigned char**)&str, @@ -289,7 +289,7 @@ void ExtractHostnames(X509* x, std::vector* hostnames) { int i = -1; X509_NAME* xname = X509_get_subject_name(x); while ((i = X509_NAME_get_index_by_NID(xname, NID_commonName, i)) != -1) { - char* str = NULL; + char* str = nullptr; X509_NAME_ENTRY* entry = X509_NAME_get_entry(xname, i); const int len = ASN1_STRING_to_UTF8((unsigned char**)&str, X509_NAME_ENTRY_get_data(entry)); @@ -303,7 +303,7 @@ void ExtractHostnames(X509* x, std::vector* hostnames) { struct FreeSSL { inline void operator()(SSL* ssl) const { - if (ssl != NULL) { + if (ssl != nullptr) { SSL_free(ssl); } } @@ -311,7 +311,7 @@ struct FreeSSL { struct FreeBIO { inline void operator()(BIO* io) const { - if (io != NULL) { + if (io != nullptr) { BIO_free(io); } } @@ -319,7 +319,7 @@ struct FreeBIO { struct FreeX509 { inline void operator()(X509* x) const { - if (x != NULL) { + if (x != nullptr) { X509_free(x); } } @@ -327,7 +327,7 @@ struct FreeX509 { struct FreeEVPKEY { inline void operator()(EVP_PKEY* k) const { - if (k != NULL) { + if (k != nullptr) { EVP_PKEY_free(k); } } @@ -342,7 +342,7 @@ static int LoadCertificate(SSL_CTX* ctx, std::unique_ptr kbio( BIO_new_mem_buf((void*)private_key.c_str(), -1)); std::unique_ptr key( - PEM_read_bio_PrivateKey(kbio.get(), NULL, 0, NULL)); + PEM_read_bio_PrivateKey(kbio.get(), nullptr, 0, nullptr)); if (SSL_CTX_use_PrivateKey(ctx, key.get()) != 1) { LOG(ERROR) << "Fail to load " << private_key << ": " << SSLError(ERR_get_error()); @@ -371,7 +371,7 @@ static int LoadCertificate(SSL_CTX* ctx, } } std::unique_ptr x( - PEM_read_bio_X509_AUX(cbio.get(), NULL, 0, NULL)); + PEM_read_bio_X509_AUX(cbio.get(), nullptr, 0, nullptr)); if (!x) { LOG(ERROR) << "Fail to parse " << certificate << ": " << SSLError(ERR_get_error()); @@ -389,13 +389,13 @@ static int LoadCertificate(SSL_CTX* ctx, #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) SSL_CTX_clear_chain_certs(ctx); #else - if (ctx->extra_certs != NULL) { + if (ctx->extra_certs != nullptr) { sk_X509_pop_free(ctx->extra_certs, X509_free); - ctx->extra_certs = NULL; + ctx->extra_certs = nullptr; } #endif - X509* ca = NULL; - while ((ca = PEM_read_bio_X509(cbio.get(), NULL, 0, NULL))) { + X509* ca = nullptr; + while ((ca = PEM_read_bio_X509(cbio.get(), nullptr, 0, nullptr))) { if (SSL_CTX_add_extra_chain_cert(ctx, ca) != 1) { LOG(ERROR) << "Fail to load chain certificate in " << certificate << ": " << SSLError(ERR_get_error()); @@ -420,7 +420,7 @@ static int LoadCertificate(SSL_CTX* ctx, return -1; } - if (hostnames != NULL) { + if (hostnames != nullptr) { ExtractHostnames(x.get(), hostnames); } return 0; @@ -481,22 +481,22 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, } if (verify.verify_mode == VerifyMode::VERIFY_FAIL_IF_NO_PEER_CERT) { SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER - | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); + | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), nullptr); } else if (verify.verify_mode == VerifyMode::VERIFY_PEER) { - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr); } else if (verify.verify_mode == VerifyMode::VERIFY_NONE) { - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr); } else { // for forward compatibility SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER - | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); + | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), nullptr); } SSL_CTX_set_verify_depth(ctx, verify.verify_depth); std::string cafile = verify.ca_file_path; if (cafile.empty()) { cafile = X509_get_default_cert_area() + std::string("/cert.pem"); } - if (SSL_CTX_load_verify_locations(ctx, cafile.c_str(), NULL) == 0) { + if (SSL_CTX_load_verify_locations(ctx, cafile.c_str(), nullptr) == 0) { if (verify.ca_file_path.empty()) { LOG(WARNING) << "Fail to load default CA file " << cafile << ": " << SSLError(ERR_get_error()); @@ -536,7 +536,7 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, LOG(ERROR) << "Expected peer name requires peer verification"; return -1; } - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr); } SSL_CTX_set_info_callback(ctx, SSLInfoCallback); @@ -587,28 +587,28 @@ SSL_CTX* CreateClientSSLContext(const ChannelSSLOptions& options) { SSL_CTX_new(SSLv23_client_method())); if (!ssl_ctx) { LOG(ERROR) << "Fail to new SSL_CTX: " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } MaybeSetKeyLogCallback(ssl_ctx.get()); if (!options.client_cert.certificate.empty() && LoadCertificate(ssl_ctx.get(), options.client_cert.certificate, - options.client_cert.private_key, NULL) != 0) { - return NULL; + options.client_cert.private_key, nullptr) != 0) { + return nullptr; } int protocols = ParseSSLProtocols(options.protocols); if (protocols < 0 || SetSSLOptions(ssl_ctx.get(), options.ciphers, protocols, options.verify) != 0) { - return NULL; + return nullptr; } if (!options.alpn_protocols.empty()) { std::vector alpn_list; if (!BuildALPNProtocolList(options.alpn_protocols, alpn_list)) { - return NULL; + return nullptr; } SSL_CTX_set_alpn_protos(ssl_ctx.get(), alpn_list.data(), alpn_list.size()); } @@ -626,13 +626,13 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, SSL_CTX_new(SSLv23_server_method())); if (!ssl_ctx) { LOG(ERROR) << "Fail to new SSL_CTX: " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } MaybeSetKeyLogCallback(ssl_ctx.get()); if (LoadCertificate(ssl_ctx.get(), certificate, private_key, hostnames) != 0) { - return NULL; + return nullptr; } int protocols = TLSv1 | TLSv1_1 | TLSv1_2 | TLSv1_3; @@ -641,7 +641,7 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, } if (SetSSLOptions(ssl_ctx.get(), options.ciphers, protocols, options.verify) != 0) { - return NULL; + return nullptr; } #ifdef SSL_MODE_RELEASE_BUFFERS @@ -659,13 +659,13 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, SSL_CTX_set_tmp_dh_callback(ssl_ctx.get(), SSLGetDHCallback); #if !defined(OPENSSL_NO_ECDH) && defined(SSL_CTX_set_tmp_ecdh) - EC_KEY* ecdh = NULL; + EC_KEY* ecdh = nullptr; int i = OBJ_sn2nid(options.ecdhe_curve_name.c_str()); - if (!i || ((ecdh = EC_KEY_new_by_curve_name(i)) == NULL)) { + if (!i || ((ecdh = EC_KEY_new_by_curve_name(i)) == nullptr)) { LOG(ERROR) << "Fail to find ECDHE named curve=" << options.ecdhe_curve_name << ": " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } SSL_CTX_set_tmp_ecdh(ssl_ctx.get(), ecdh); EC_KEY_free(ecdh); @@ -676,26 +676,26 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, // Set ALPN callback to choose application protocol when alpns is not empty. if (alpns != nullptr && !alpns->empty()) { if (SetServerALPNCallback(ssl_ctx.get(), alpns) != 0) { - return NULL; + return nullptr; } } return ssl_ctx.release(); } SSL* CreateSSLSession(SSL_CTX* ctx, SocketId id, int fd, bool server_mode) { - if (ctx == NULL) { + if (ctx == nullptr) { LOG(WARNING) << "Lack SSL_ctx to create an SSL session"; - return NULL; + return nullptr; } SSL* ssl = SSL_new(ctx); - if (ssl == NULL) { + if (ssl == nullptr) { LOG(ERROR) << "Fail to SSL_new: " << SSLError(ERR_get_error()); - return NULL; + return nullptr; } if (SSL_set_fd(ssl, fd) != 1) { LOG(ERROR) << "Fail to SSL_set_fd: " << SSLError(ERR_get_error()); SSL_free(ssl); - return NULL; + return nullptr; } if (server_mode) { @@ -785,7 +785,7 @@ static unsigned long SSLGetThreadId() { // may crash probably due to some TLS data used inside OpenSSL // Also according to performance test, there is little difference // between pthread mutex and bthread mutex -static butil::Mutex* g_ssl_mutexs = NULL; +static butil::Mutex* g_ssl_mutexs = nullptr; static void SSLLockCallback(int mode, int n, const char* file, int line) { (void)file; @@ -818,94 +818,94 @@ int SSLThreadInit() { #ifndef OPENSSL_NO_DH static DH* SSLGetDH1024() { - BIGNUM* p = get_rfc2409_prime_1024(NULL); + BIGNUM* p = get_rfc2409_prime_1024(nullptr); if (!p) { - return NULL; + return nullptr; } // See RFC 2409, Section 6 "Oakley Groups" // for the reason why 2 is used as generator. - BIGNUM* g = NULL; + BIGNUM* g = nullptr; BN_dec2bn(&g, "2"); if (!g) { BN_free(p); - return NULL; + return nullptr; } DH *dh = DH_new(); if (!dh) { BN_free(p); BN_free(g); - return NULL; + return nullptr; } - DH_set0_pqg(dh, p, NULL, g); + DH_set0_pqg(dh, p, nullptr, g); return dh; } static DH* SSLGetDH2048() { - BIGNUM* p = get_rfc3526_prime_2048(NULL); + BIGNUM* p = get_rfc3526_prime_2048(nullptr); if (!p) { - return NULL; + return nullptr; } // See RFC 3526, Section 3 "2048-bit MODP Group" // for the reason why 2 is used as generator. - BIGNUM* g = NULL; + BIGNUM* g = nullptr; BN_dec2bn(&g, "2"); if (!g) { BN_free(p); - return NULL; + return nullptr; } DH* dh = DH_new(); if (!dh) { BN_free(p); BN_free(g); - return NULL; + return nullptr; } - DH_set0_pqg(dh, p, NULL, g); + DH_set0_pqg(dh, p, nullptr, g); return dh; } static DH* SSLGetDH4096() { - BIGNUM* p = get_rfc3526_prime_4096(NULL); + BIGNUM* p = get_rfc3526_prime_4096(nullptr); if (!p) { - return NULL; + return nullptr; } // See RFC 3526, Section 5 "4096-bit MODP Group" // for the reason why 2 is used as generator. - BIGNUM* g = NULL; + BIGNUM* g = nullptr; BN_dec2bn(&g, "2"); if (!g) { BN_free(p); - return NULL; + return nullptr; } DH *dh = DH_new(); if (!dh) { BN_free(p); BN_free(g); - return NULL; + return nullptr; } - DH_set0_pqg(dh, p, NULL, g); + DH_set0_pqg(dh, p, nullptr, g); return dh; } static DH* SSLGetDH8192() { - BIGNUM* p = get_rfc3526_prime_8192(NULL); + BIGNUM* p = get_rfc3526_prime_8192(nullptr); if (!p) { - return NULL; + return nullptr; } // See RFC 3526, Section 7 "8192-bit MODP Group" // for the reason why 2 is used as generator. - BIGNUM* g = NULL; + BIGNUM* g = nullptr; BN_dec2bn(&g, "2"); if (!g) { BN_free(g); - return NULL; + return nullptr; } DH *dh = DH_new(); if (!dh) { BN_free(p); BN_free(g); - return NULL; + return nullptr; } - DH_set0_pqg(dh, p, NULL, g); + DH_set0_pqg(dh, p, nullptr, g); return dh; } @@ -913,19 +913,19 @@ static DH* SSLGetDH8192() { int SSLDHInit() { #ifndef OPENSSL_NO_DH - if ((g_dh_1024 = SSLGetDH1024()) == NULL) { + if ((g_dh_1024 = SSLGetDH1024()) == nullptr) { LOG(ERROR) << "Fail to initialize DH-1024"; return -1; } - if ((g_dh_2048 = SSLGetDH2048()) == NULL) { + if ((g_dh_2048 = SSLGetDH2048()) == nullptr) { LOG(ERROR) << "Fail to initialize DH-2048"; return -1; } - if ((g_dh_4096 = SSLGetDH4096()) == NULL) { + if ((g_dh_4096 = SSLGetDH4096()) == nullptr) { LOG(ERROR) << "Fail to initialize DH-4096"; return -1; } - if ((g_dh_8192 = SSLGetDH8192()) == NULL) { + if ((g_dh_8192 = SSLGetDH8192()) == nullptr) { LOG(ERROR) << "Fail to initialize DH-8192"; return -1; } @@ -970,7 +970,7 @@ void Print(std::ostream& os, SSL* ssl, const char* sep) { void Print(std::ostream& os, X509* cert, const char* sep) { BIO* buf = BIO_new(BIO_s_mem()); - if (buf == NULL) { + if (buf == nullptr) { return; } BIO_printf(buf, "subject="); @@ -990,7 +990,7 @@ void Print(std::ostream& os, X509* cert, const char* sep) { BIO_printf(buf, "%sissuer=", sep); X509_NAME_print(buf, X509_get_issuer_name(cert), 0); - char* bufp = NULL; + char* bufp = nullptr; int len = BIO_get_mem_data(buf, &bufp); os << butil::StringPiece(bufp, len); } diff --git a/src/brpc/details/ssl_helper.h b/src/brpc/details/ssl_helper.h index 815285c23d..97fa7328a9 100644 --- a/src/brpc/details/ssl_helper.h +++ b/src/brpc/details/ssl_helper.h @@ -60,7 +60,7 @@ bool SupportsPeerNameVerification(); struct FreeSSLCTX { inline void operator()(SSL_CTX* ctx) const { - if (ctx != NULL) { + if (ctx != nullptr) { SSL_CTX_free(ctx); } } diff --git a/src/brpc/details/tcmalloc_extension.cpp b/src/brpc/details/tcmalloc_extension.cpp index 6f0c9e45e3..a8704270f3 100644 --- a/src/brpc/details/tcmalloc_extension.cpp +++ b/src/brpc/details/tcmalloc_extension.cpp @@ -24,7 +24,7 @@ namespace { typedef MallocExtension* (*GetInstanceFn)(); static pthread_once_t g_get_instance_fn_once = PTHREAD_ONCE_INIT; -static GetInstanceFn g_get_instance_fn = NULL; +static GetInstanceFn g_get_instance_fn = nullptr; static void InitGetInstanceFn() { g_get_instance_fn = (GetInstanceFn)dlsym( RTLD_NEXT, "_ZN15MallocExtension8instanceEv"); @@ -43,11 +43,11 @@ MallocExtension* BAIDU_WEAK MallocExtension::instance() { if (g_get_instance_fn) { return g_get_instance_fn(); } - return NULL; + return nullptr; } bool IsHeapProfilerEnabled() { - return MallocExtension::instance() != NULL; + return MallocExtension::instance() != nullptr; } bool IsTCMallocEnabled() { @@ -56,7 +56,7 @@ bool IsTCMallocEnabled() { static bool check_TCMALLOC_SAMPLE_PARAMETER() { char* str = getenv("TCMALLOC_SAMPLE_PARAMETER"); - if (str == NULL) { + if (str == nullptr) { return false; } char* endptr; diff --git a/src/brpc/details/tcmalloc_extension.h b/src/brpc/details/tcmalloc_extension.h index 037393ec90..ee23b725fa 100644 --- a/src/brpc/details/tcmalloc_extension.h +++ b/src/brpc/details/tcmalloc_extension.h @@ -168,14 +168,14 @@ class PERFTOOLS_DLL_DECL MallocExtension { // Get the named "property"'s value. Returns true if the property // is known. Returns false if the property is not a valid property // name for the current malloc implementation. - // REQUIRES: property != NULL; value != NULL + // REQUIRES: property != nullptr; value != nullptr virtual bool GetNumericProperty(const char* property, size_t* value); // Set the named "property"'s value. Returns true if the property // is known and writable. Returns false if the property is not a // valid property name for the current malloc implementation, or // is not writable. - // REQUIRES: property != NULL + // REQUIRES: property != nullptr virtual bool SetNumericProperty(const char* property, size_t value); // Mark the current thread as "idle". This routine may optionally @@ -232,14 +232,14 @@ class PERFTOOLS_DLL_DECL MallocExtension { // p must have been allocated by this malloc implementation, // must not be an interior pointer -- that is, must be exactly // the pointer returned to by malloc() et al., not some offset - // from that -- and should not have been freed yet. p may be NULL. + // from that -- and should not have been freed yet. p may be nullptr. // (Currently only implemented in tcmalloc; other implementations // will return 0.) // This is equivalent to malloc_size() in OS X, malloc_usable_size() // in glibc, and _msize() for windows. virtual size_t GetAllocatedSize(void* p); - // The current malloc implementation. Always non-NULL. + // The current malloc implementation. Always non-nullptr. static MallocExtension* instance(); // Change the malloc implementation. Typically called by the @@ -301,7 +301,7 @@ class PERFTOOLS_DLL_DECL MallocExtension { // // It is the responsibility of the caller to "delete[]" the returned array. // - // May return NULL to indicate no results. + // May return nullptr to indicate no results. // // This is an internal extension. Callers should use the more // convenient "GetHeapSample(string*)" method defined above. diff --git a/src/brpc/details/usercode_backup_pool.cpp b/src/brpc/details/usercode_backup_pool.cpp index 338038ae39..fba05e84eb 100644 --- a/src/brpc/details/usercode_backup_pool.cpp +++ b/src/brpc/details/usercode_backup_pool.cpp @@ -67,7 +67,7 @@ static pthread_cond_t s_usercode_cond = PTHREAD_COND_INITIALIZER; static pthread_once_t s_usercode_init = PTHREAD_ONCE_INIT; butil::static_atomic g_usercode_inplace = BUTIL_STATIC_ATOMIC_INIT(0); bool g_too_many_usercode = false; -static UserCodeBackupPool* s_usercode_pool = NULL; +static UserCodeBackupPool* s_usercode_pool = nullptr; static int GetUserCodeInPlace(void*) { return g_usercode_inplace.load(butil::memory_order_relaxed); @@ -75,7 +75,7 @@ static int GetUserCodeInPlace(void*) { static size_t GetUserCodeQueueSize(void*) { BAIDU_SCOPED_LOCK(s_usercode_mutex); - return (s_usercode_pool != NULL ? s_usercode_pool->queue.size() : 0); + return (s_usercode_pool != nullptr ? s_usercode_pool->queue.size() : 0); } static double GetInPoolElapseInSecond(void* arg) { @@ -83,8 +83,8 @@ static double GetInPoolElapseInSecond(void* arg) { } UserCodeBackupPool::UserCodeBackupPool() - : inplace_var("rpc_usercode_inplace", GetUserCodeInPlace, NULL) - , queue_size_var("rpc_usercode_queue_size", GetUserCodeQueueSize, NULL) + : inplace_var("rpc_usercode_inplace", GetUserCodeInPlace, nullptr) + , queue_size_var("rpc_usercode_queue_size", GetUserCodeQueueSize, nullptr) , inpool_count("rpc_usercode_backup_count") , inpool_per_second("rpc_usercode_backup_second", &inpool_count) , inpool_elapse_s(GetInPoolElapseInSecond, &inpool_elapse_us) @@ -94,7 +94,7 @@ UserCodeBackupPool::UserCodeBackupPool() static void* UserCodeRunner(void* args) { butil::PlatformThread::SetNameSimple("brpc_user_code_runner"); static_cast(args)->UserCodeRunningLoop(); - return NULL; + return nullptr; } int UserCodeBackupPool::Init() { @@ -102,7 +102,7 @@ int UserCodeBackupPool::Init() { // during termination of program). for (int i = 0; i < FLAGS_usercode_backup_threads; ++i) { pthread_t th; - if (pthread_create(&th, NULL, UserCodeRunner, this) != 0) { + if (pthread_create(&th, nullptr, UserCodeRunner, this) != 0) { LOG(ERROR) << "Fail to create UserCodeRunner"; return -1; } @@ -120,7 +120,7 @@ void UserCodeBackupPool::UserCodeRunningLoop() { int64_t last_time = butil::cpuwide_time_us(); while (true) { bool blocked = false; - UserCode usercode = { NULL, NULL }; + UserCode usercode = { nullptr, nullptr }; { BAIDU_SCOPED_LOCK(s_usercode_mutex); while (queue.empty()) { diff --git a/src/brpc/input_messenger.cpp b/src/brpc/input_messenger.cpp index 1e42f92351..8ed0246e90 100644 --- a/src/brpc/input_messenger.cpp +++ b/src/brpc/input_messenger.cpp @@ -297,11 +297,11 @@ int InputMessenger::ProcessNewMessage( num_bthread_created = 0; } } - // In RDMA polling mode, all messages must be executed in a new bthread and - // not in the bthread where the polling bthread is located, because the - // method for processing messages may call synchronization primitives, - // causing the polling bthread to be scheduled out. - if (m->_socket_mode == SOCKET_MODE_RDMA || m->_socket_mode == SOCKET_MODE_UBRING) { + // These transports may deliver messages from completion pollers. Process + // the messages in another bthread so user code cannot block the poller. + if (m->_socket_mode == SOCKET_MODE_RDMA || + m->_socket_mode == SOCKET_MODE_UBRING || + m->_socket_mode == SOCKET_MODE_URMA) { m->_transport->QueueMessage(last_msg, &num_bthread_created, true); } if (num_bthread_created) { diff --git a/src/brpc/input_messenger.h b/src/brpc/input_messenger.h index e82ecd4a66..a0163d0698 100644 --- a/src/brpc/input_messenger.h +++ b/src/brpc/input_messenger.h @@ -29,6 +29,11 @@ namespace brpc { namespace rdma { class RdmaEndpoint; } + +namespace urma { +class UrmaEndpoint; +} + namespace ubring { class UBShmEndpoint; } @@ -98,6 +103,7 @@ friend class Socket; friend class TcpTransport; friend class RdmaTransport; friend class rdma::RdmaEndpoint; +friend class urma::UrmaEndpoint; friend class ubring::UBShmEndpoint; public: explicit InputMessenger(size_t capacity = 128); diff --git a/src/brpc/nonreflectable_message.h b/src/brpc/nonreflectable_message.h index 089b23957d..fab6301249 100644 --- a/src/brpc/nonreflectable_message.h +++ b/src/brpc/nonreflectable_message.h @@ -288,8 +288,13 @@ class NonreflectableMessage : public ::google::protobuf::Message { # endif ) { // Only can be used to determine whether the Types are the same. - descriptor = default_instance().GetMetadata().descriptor; - reflection = default_instance().GetMetadata().reflection; +# if GOOGLE_PROTOBUF_VERSION >= 7035000 + set_descriptor(NonreflectableMessage::default_instance().GetMetadata().descriptor); + set_reflection(NonreflectableMessage::default_instance().GetMetadata().reflection); +# else + descriptor = NonreflectableMessage::default_instance().GetMetadata().descriptor; + reflection = NonreflectableMessage::default_instance().GetMetadata().reflection; +# endif } }; diff --git a/src/brpc/policy/auto_concurrency_limiter.cpp b/src/brpc/policy/auto_concurrency_limiter.cpp index e9cce0fa43..0f70d9b043 100644 --- a/src/brpc/policy/auto_concurrency_limiter.cpp +++ b/src/brpc/policy/auto_concurrency_limiter.cpp @@ -97,7 +97,7 @@ AutoConcurrencyLimiter::AutoConcurrencyLimiter() } AutoConcurrencyLimiter* AutoConcurrencyLimiter::New(const AdaptiveMaxConcurrency&) const { - return new (std::nothrow) AutoConcurrencyLimiter; + return new AutoConcurrencyLimiter; } bool AutoConcurrencyLimiter::OnRequested(int current_concurrency, Controller*) { diff --git a/src/brpc/policy/baidu_rpc_protocol.cpp b/src/brpc/policy/baidu_rpc_protocol.cpp index 49863b2c06..b74fb1805a 100644 --- a/src/brpc/policy/baidu_rpc_protocol.cpp +++ b/src/brpc/policy/baidu_rpc_protocol.cpp @@ -157,7 +157,7 @@ bool SerializeRpcMessage(const google::protobuf::Message& message, ok = serializer.SerializeTo(&stream); } else { const CompressHandler* handler = FindCompressHandler(compress_type); - if (NULL == handler) { + if (nullptr == handler) { return false; } ok = handler->Compress(serializer, buf); @@ -232,7 +232,7 @@ static bool SerializeResponse(const google::protobuf::Message& res, ContentType content_type = cntl.response_content_type(); CompressType compress_type = cntl.response_compress_type(); ChecksumType checksum_type = cntl.response_checksum_type(); - const butil::IOBuf* checksum_attachment = NULL; + const butil::IOBuf* checksum_attachment = nullptr; if (cntl.response_checksum_attachment()) { // See the same check in SerializeRpcRequest() for the rationale; // baidu_std never sets this flag itself but we defend anyway. @@ -289,8 +289,8 @@ void SendRpcResponse(int64_t correlation_id, Controller* cntl, } Socket* sock = accessor.get_sending_socket(); - const google::protobuf::Message* req = NULL == messages ? NULL : messages->Request(); - const google::protobuf::Message* res = NULL == messages ? NULL : messages->Response(); + const google::protobuf::Message* req = nullptr == messages ? nullptr : messages->Request(); + const google::protobuf::Message* res = nullptr == messages ? nullptr : messages->Response(); // Recycle resources at the end of this function. BRPC_SCOPE_EXIT { @@ -301,12 +301,12 @@ void SendRpcResponse(int64_t correlation_id, Controller* cntl, std::unique_ptr recycle_cntl(cntl); - if (NULL == messages) { + if (nullptr == messages) { return; } cntl->CallAfterRpcResp(req, res); - if (NULL == server->options().baidu_master_service) { + if (nullptr == server->options().baidu_master_service) { server->options().rpc_pb_message_factory->Return(messages); } else { BaiduProxyPBMessages::Return(static_cast(messages)); @@ -324,10 +324,10 @@ void SendRpcResponse(int64_t correlation_id, Controller* cntl, } bool append_body = false; butil::IOBuf res_body; - // `res' can be NULL here, in which case we don't serialize it + // `res' can be nullptr here, in which case we don't serialize it // If user calls `SetFailed' on Controller, we don't serialize // response either - if (res != NULL && !cntl->Failed()) { + if (res != nullptr && !cntl->Failed()) { append_body = SerializeResponse(*res, *cntl, res_body); } @@ -365,11 +365,11 @@ void SendRpcResponse(int64_t correlation_id, Controller* cntl, meta.set_attachment_size(attached_size); } StreamId response_stream_id = INVALID_STREAM_ID; - SocketUniquePtr stream_ptr; + StreamUniquePtr stream_ptr; if (!response_stream_ids.empty()) { response_stream_id = response_stream_ids[0]; - if (Socket::Address(response_stream_id, &stream_ptr) == 0) { - Stream* s = (Stream *) stream_ptr->conn(); + if (Stream::Address(response_stream_id, &stream_ptr) == 0) { + Stream* s = stream_ptr.get(); StreamSettings *stream_settings = meta.mutable_stream_settings(); s->FillSettings(stream_settings); s->SetHostSocket(sock); @@ -431,13 +431,13 @@ void SendRpcResponse(int64_t correlation_id, Controller* cntl, // written user data would follower the RPC response. // Reuse stream_ptr to avoid address first stream id again if (stream_ptr) { - ((Stream*)stream_ptr->conn())->SetConnected(); + stream_ptr->SetConnected(); } for (size_t i = 1; i < response_stream_ids.size(); ++i) { StreamId extra_stream_id = response_stream_ids[i]; - SocketUniquePtr extra_stream_ptr; - if (Socket::Address(extra_stream_id, &extra_stream_ptr) == 0) { - Stream* extra_stream = (Stream *) extra_stream_ptr->conn(); + StreamUniquePtr extra_stream_ptr; + if (Stream::Address(extra_stream_id, &extra_stream_ptr) == 0) { + Stream* extra_stream = extra_stream_ptr.get(); extra_stream->SetHostSocket(sock); extra_stream->SetConnected(); } else { @@ -523,7 +523,7 @@ bool DeserializeRpcMessage(const butil::IOBuf& data, Controller& cntl, ok = deserializer.DeserializeFrom(&stream); } else { const CompressHandler* handler = FindCompressHandler(compress_type); - if (NULL == handler) { + if (nullptr == handler) { return false; } ok = handler->Decompress(data, &deserializer); @@ -607,13 +607,9 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { sample->submit(start_parse_us); } - std::unique_ptr cntl(new (std::nothrow) Controller); - if (NULL == cntl.get()) { - LOG(WARNING) << "Fail to new Controller"; - return; - } + std::unique_ptr cntl(new Controller); - RpcPBMessages* messages = NULL; + RpcPBMessages* messages = nullptr; ServerPrivateAccessor server_accessor(server); ControllerPrivateAccessor accessor(cntl.get()); @@ -673,7 +669,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { span->set_request_size(msg->payload.size() + msg->meta.size() + 12); } - MethodStatus* method_status = NULL; + MethodStatus* method_status = nullptr; do { if (!server->IsRunning()) { cntl->SetFailed(ELOGOFF, "Server is stopping"); @@ -703,9 +699,9 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { } } - google::protobuf::Service* svc = NULL; - google::protobuf::MethodDescriptor* method = NULL; - if (NULL != server->options().baidu_master_service) { + google::protobuf::Service* svc = nullptr; + google::protobuf::MethodDescriptor* method = nullptr; + if (nullptr != server->options().baidu_master_service) { if (socket->is_overcrowded() && !server->options().ignore_eovercrowded && !server->options().baidu_master_service->ignore_eovercrowded()) { @@ -714,11 +710,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { break; } svc = server->options().baidu_master_service; - auto sampled_request = new (std::nothrow) SampledRequest; - if (NULL == sampled_request) { - cntl->SetFailed(ENOMEM, "Fail to get sampled_request"); - break; - } + auto sampled_request = new SampledRequest; sampled_request->meta.set_service_name(request_meta.service_name()); sampled_request->meta.set_method_name(request_meta.method_name()); cntl->reset_sampled_request(sampled_request); @@ -753,7 +745,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { if (svc_name.find('.') == butil::StringPiece::npos) { const Server::ServiceProperty* sp = server_accessor.FindServicePropertyByName(svc_name); - if (NULL == sp) { + if (nullptr == sp) { cntl->SetFailed(ENOSERVICE, "Fail to find service=%s", request_meta.service_name().c_str()); break; @@ -763,7 +755,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { const Server::MethodProperty* mp = server_accessor.FindMethodPropertyByFullName( svc_name, request_meta.method_name()); - if (NULL == mp) { + if (nullptr == mp) { cntl->SetFailed(ENOMETHOD, "Fail to find method=%s/%s", request_meta.service_name().c_str(), request_meta.method_name().c_str()); @@ -772,7 +764,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { BadMethodRequest breq; BadMethodResponse bres; breq.set_service_name(request_meta.service_name()); - mp->service->CallMethod(mp->method, cntl.get(), &breq, &bres, NULL); + mp->service->CallMethod(mp->method, cntl.get(), &breq, &bres, nullptr); break; } if (socket->is_overcrowded() && @@ -827,7 +819,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) { // it into the checksum now when the client asked us to. const butil::IOBuf* checksum_attachment = cntl->request_checksum_attachment() ? - &cntl->request_attachment() : NULL; + &cntl->request_attachment() : nullptr; if (!DeserializeRpcMessage(req_buf, *cntl, content_type, compress_type, checksum_type, messages->Request(), @@ -898,7 +890,7 @@ bool VerifyRpcRequest(const InputMessageBase* msg_base) { return false; } const Authenticator* auth = server->options().auth; - if (NULL == auth) { + if (nullptr == auth) { // Fast pass (no authentication) return true; } @@ -939,7 +931,7 @@ void ProcessRpcResponse(InputMessageBase* msg_base) { } const bthread_id_t cid = { static_cast(meta.correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; StreamId remote_stream_id = meta.has_stream_settings() ? meta.stream_settings().stream_id(): INVALID_STREAM_ID; @@ -1016,7 +1008,7 @@ void ProcessRpcResponse(InputMessageBase* msg_base) { // it into the checksum now when the server told us to. const butil::IOBuf* checksum_attachment = cntl->response_checksum_attachment() ? - &cntl->response_attachment() : NULL; + &cntl->response_attachment() : nullptr; if (cntl->response()->GetDescriptor() == SerializedResponse::descriptor()) { ((SerializedResponse*)cntl->response())-> serialized_data().append(*res_buf_ptr); @@ -1044,7 +1036,7 @@ void ProcessRpcResponse(InputMessageBase* msg_base) { void SerializeRpcRequest(butil::IOBuf* request_buf, Controller* cntl, const google::protobuf::Message* request) { // Check sanity of request. - if (NULL == request) { + if (nullptr == request) { return cntl->SetFailed(EREQUEST, "`request' is NULL"); } if (request->GetDescriptor() == SerializedRequest::descriptor()) { @@ -1059,7 +1051,7 @@ void SerializeRpcRequest(butil::IOBuf* request_buf, Controller* cntl, ContentType content_type = cntl->request_content_type(); CompressType compress_type = cntl->request_compress_type(); ChecksumType checksum_type = cntl->request_checksum_type(); - const butil::IOBuf* checksum_attachment = NULL; + const butil::IOBuf* checksum_attachment = nullptr; if (cntl->request_checksum_attachment()) { // Progressive reading (HTTP-only feature) hands the attachment to // the user piece by piece as it arrives, so there's no single, @@ -1108,7 +1100,7 @@ void PackRpcRequest(butil::IOBuf* req_buf, if (cntl->request_checksum_attachment()) { meta.set_checksum_with_attachment(true); } - } else if (NULL != cntl->sampled_request()) { + } else if (nullptr != cntl->sampled_request()) { // Replaying. Keep service-name as the one seen by server. request_meta->set_service_name(cntl->sampled_request()->meta.service_name()); request_meta->set_method_name(cntl->sampled_request()->meta.method_name()); @@ -1129,12 +1121,12 @@ void PackRpcRequest(butil::IOBuf* req_buf, if (!request_stream_ids.empty()) { StreamSettings* stream_settings = meta.mutable_stream_settings(); StreamId request_stream_id = request_stream_ids[0]; - SocketUniquePtr ptr; - if (Socket::Address(request_stream_id, &ptr) != 0) { + StreamUniquePtr ptr; + if (Stream::Address(request_stream_id, &ptr) != 0) { return cntl->SetFailed(EREQUEST, "Stream=%" PRIu64 " was closed", request_stream_id); } - Stream* s = (Stream*) ptr->conn(); + Stream* s = ptr.get(); s->FillSettings(stream_settings); for (size_t i = 1; i < request_stream_ids.size(); ++i) { stream_settings->mutable_extra_stream_ids()->Add(request_stream_ids[i]); diff --git a/src/brpc/policy/consistent_hashing_load_balancer.cpp b/src/brpc/policy/consistent_hashing_load_balancer.cpp index d29ad55e3c..5ff1558f8b 100644 --- a/src/brpc/policy/consistent_hashing_load_balancer.cpp +++ b/src/brpc/policy/consistent_hashing_load_balancer.cpp @@ -193,7 +193,7 @@ size_t ConsistentHashingLoadBalancer::RemoveBatch( bool use_set = true; if (id_set.init(servers.size() * 2) == 0) { for (size_t i = 0; i < servers.size(); ++i) { - if (id_set.insert(servers[i]) == NULL) { + if (id_set.insert(servers[i]) == nullptr) { use_set = false; break; } @@ -205,7 +205,7 @@ size_t ConsistentHashingLoadBalancer::RemoveBatch( bg.clear(); for (size_t i = 0; i < fg.size(); ++i) { const bool removed = - use_set ? (id_set.seek(fg[i].server_sock) != NULL) + use_set ? (id_set.seek(fg[i].server_sock) != nullptr) : (std::find(servers.begin(), servers.end(), fg[i].server_sock) != servers.end()); if (!removed) { @@ -285,9 +285,8 @@ size_t ConsistentHashingLoadBalancer::RemoveServersInBatch( } LoadBalancer *ConsistentHashingLoadBalancer::New(const butil::StringPiece& params) const { - ConsistentHashingLoadBalancer* lb = - new (std::nothrow) ConsistentHashingLoadBalancer(_type); - if (lb && !lb->SetParameters(params)) { + ConsistentHashingLoadBalancer* lb = new ConsistentHashingLoadBalancer(_type); + if (!lb->SetParameters(params)) { delete lb; lb = nullptr; } diff --git a/src/brpc/policy/consul_naming_service.cpp b/src/brpc/policy/consul_naming_service.cpp index 70e0a46506..5bee4093aa 100644 --- a/src/brpc/policy/consul_naming_service.cpp +++ b/src/brpc/policy/consul_naming_service.cpp @@ -103,7 +103,7 @@ int ConsulNamingService::GetServers(const char* service_name, Controller cntl; cntl.http_request().uri() = consul_url; - _channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + _channel.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(ERROR) << "Fail to access " << consul_url << ": " << cntl.ErrorText(); diff --git a/src/brpc/policy/couchbase_protocol.cpp b/src/brpc/policy/couchbase_protocol.cpp index 0ab79bfb90..8e59c4f6e2 100644 --- a/src/brpc/policy/couchbase_protocol.cpp +++ b/src/brpc/policy/couchbase_protocol.cpp @@ -84,7 +84,7 @@ ParseResult ParseCouchbaseMessage(butil::IOBuf* source, Socket* socket, bool /*read_eof*/, const void* /*arg*/) { while (1) { const uint8_t* p_cbmagic = (const uint8_t*)source->fetch1(); - if (NULL == p_cbmagic) { + if (nullptr == p_cbmagic) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } if (*p_cbmagic != (uint8_t)CB_MAGIC_RESPONSE) { @@ -92,7 +92,7 @@ ParseResult ParseCouchbaseMessage(butil::IOBuf* source, Socket* socket, } char buf[24]; const uint8_t* p = (const uint8_t*)source->fetch(buf, sizeof(buf)); - if (NULL == p) { + if (nullptr == p) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } const CouchbaseResponseHeader* header = (const CouchbaseResponseHeader*)p; @@ -118,7 +118,7 @@ ParseResult ParseCouchbaseMessage(butil::IOBuf* source, Socket* socket, } MostCommonMessage* msg = static_cast(socket->parsing_context()); - if (msg == NULL) { + if (msg == nullptr) { msg = MostCommonMessage::Get(); socket->reset_parsing_context(msg); } @@ -155,7 +155,7 @@ void ProcessCouchbaseResponse(InputMessageBase* msg_base) { static_cast(msg_base)); const bthread_id_t cid = msg->pi.id_wait; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -171,7 +171,7 @@ void ProcessCouchbaseResponse(InputMessageBase* msg_base) { span->set_start_parse_us(start_parse_us); } const int saved_error = cntl->ErrorCode(); - if (cntl->response() == NULL) { + if (cntl->response() == nullptr) { cntl->SetFailed(ERESPONSE, "response is NULL!"); } else if (cntl->response()->GetDescriptor() != CouchbaseOperations::CouchbaseResponse::descriptor()) { @@ -195,7 +195,7 @@ void ProcessCouchbaseResponse(InputMessageBase* msg_base) { void SerializeCouchbaseRequest(butil::IOBuf* buf, Controller* cntl, const google::protobuf::Message* request) { - if (request == NULL) { + if (request == nullptr) { return cntl->SetFailed(EREQUEST, "request is NULL"); } if (request->GetDescriptor() != diff --git a/src/brpc/policy/crc32c_checksum.cpp b/src/brpc/policy/crc32c_checksum.cpp index 7a3b8ef9d7..8af7fbe2ff 100644 --- a/src/brpc/policy/crc32c_checksum.cpp +++ b/src/brpc/policy/crc32c_checksum.cpp @@ -41,10 +41,10 @@ uint32_t ExtendCrc32c(uint32_t crc, const butil::IOBuf& buf) { } // Computes the crc32c over `in.buf', and over `in.attachment' as well when -// the caller opted in (ChecksumIn::attachment != NULL). +// the caller opted in (ChecksumIn::attachment != nullptr). uint32_t ComputeCrc32c(const ChecksumIn& in) { uint32_t crc = ExtendCrc32c(0, *in.buf); - if (in.attachment != NULL) { + if (in.attachment != nullptr) { crc = ExtendCrc32c(crc, *in.attachment); } return crc; diff --git a/src/brpc/policy/dh.cpp b/src/brpc/policy/dh.cpp index e56cf19eb7..cb66c9c2cb 100644 --- a/src/brpc/policy/dh.cpp +++ b/src/brpc/policy/dh.cpp @@ -25,9 +25,9 @@ namespace brpc { namespace policy { void DHWrapper::clear() { - if (_pdh != NULL) { + if (_pdh != nullptr) { DH_free(_pdh); - _pdh = NULL; + _pdh = nullptr; } } @@ -37,8 +37,8 @@ int DHWrapper::initialize(bool ensure_128bytes_public_key) { return -1; } if (ensure_128bytes_public_key) { - const BIGNUM* pub_key = NULL; - DH_get0_key(_pdh, &pub_key, NULL); + const BIGNUM* pub_key = nullptr; + DH_get0_key(_pdh, &pub_key, nullptr); int key_size = BN_num_bytes(pub_key); if (key_size != 128) { RPC_VLOG << "regenerate 128B key, current=" << key_size; @@ -52,8 +52,8 @@ int DHWrapper::initialize(bool ensure_128bytes_public_key) { } int DHWrapper::copy_public_key(char* pkey, int* pkey_size) const { - const BIGNUM* pub_key = NULL; - DH_get0_key(_pdh, &pub_key, NULL); + const BIGNUM* pub_key = nullptr; + DH_get0_key(_pdh, &pub_key, nullptr); // copy public key to bytes. // sometimes, the key_size is 127, seems ok. int key_size = BN_num_bytes(pub_key); @@ -75,7 +75,7 @@ int DHWrapper::copy_public_key(char* pkey, int* pkey_size) const { int DHWrapper::copy_shared_key(const void* ppkey, int ppkey_size, void* skey, int* skey_size) const { BIGNUM* ppk = BN_bin2bn((const unsigned char*)ppkey, ppkey_size, 0); - if (ppk == NULL) { + if (ppk == nullptr) { LOG(ERROR) << "Fail to BN_bin2bn"; return -1; } @@ -91,13 +91,13 @@ int DHWrapper::copy_shared_key(const void* ppkey, int ppkey_size, } int DHWrapper::do_initialize() { - BIGNUM* p = get_rfc2409_prime_1024(NULL); + BIGNUM* p = get_rfc2409_prime_1024(nullptr); if (!p) { return -1; } // See RFC 2409, Section 6 "Oakley Groups" // for the reason why 2 is used as generator. - BIGNUM* g = NULL; + BIGNUM* g = nullptr; BN_dec2bn(&g, "2"); if (!g) { BN_free(p); @@ -109,7 +109,7 @@ int DHWrapper::do_initialize() { BN_free(g); return -1; } - DH_set0_pqg(_pdh, p, NULL, g); + DH_set0_pqg(_pdh, p, nullptr, g); // Generate private and public key if (!DH_generate_key(_pdh)) { diff --git a/src/brpc/policy/dh.h b/src/brpc/policy/dh.h index 8b888ba304..bac804871a 100644 --- a/src/brpc/policy/dh.h +++ b/src/brpc/policy/dh.h @@ -28,7 +28,7 @@ namespace policy { // Diffie-Hellman key exchange class DHWrapper { public: - DHWrapper() : _pdh(NULL) {} + DHWrapper() : _pdh(nullptr) {} ~DHWrapper() { clear(); } // initialize dh, generate the public and private key. diff --git a/src/brpc/policy/discovery_naming_service.cpp b/src/brpc/policy/discovery_naming_service.cpp index b935bcfc49..2dca269eb4 100644 --- a/src/brpc/policy/discovery_naming_service.cpp +++ b/src/brpc/policy/discovery_naming_service.cpp @@ -47,7 +47,7 @@ DEFINE_int32(discovery_reregister_threshold, 3, "The renew error threshold beyon " which Register would be called again"); static pthread_once_t s_init_discovery_channel_once = PTHREAD_ONCE_INIT; -static Channel* s_discovery_channel = NULL; +static Channel* s_discovery_channel = nullptr; static int ListDiscoveryNodes(const char* discovery_api_addr, std::string* servers) { Channel api_channel; @@ -61,7 +61,7 @@ static int ListDiscoveryNodes(const char* discovery_api_addr, std::string* serve } Controller cntl; cntl.http_request().uri() = discovery_api_addr; - api_channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + api_channel.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(FATAL) << "Fail to access " << cntl.http_request().uri() << ": " << cntl.ErrorText(); @@ -143,7 +143,7 @@ DiscoveryClient::DiscoveryClient() DiscoveryClient::~DiscoveryClient() { if (_registered.load(butil::memory_order_acquire)) { bthread_stop(_th); - bthread_join(_th, NULL); + bthread_join(_th, nullptr); DoCancel(); } } @@ -193,7 +193,7 @@ int DiscoveryClient::DoRenew() const { << "®ion=" << _params.region << "&zone=" << _params.zone; os.move_to(cntl.request_attachment()); - chan.CallMethod(NULL, &cntl, NULL, NULL, NULL); + chan.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(ERROR) << "Fail to post /discovery/renew: " << cntl.ErrorText(); return -1; @@ -214,7 +214,7 @@ void* DiscoveryClient::PeriodicRenew(void* arg) { butil::fast_rand_less_than(FLAGS_discovery_renew_interval_s / 2); if (bthread_usleep(init_sleep_s * 1000000) != 0) { if (errno == ESTOP) { - return NULL; + return nullptr; } } @@ -237,7 +237,7 @@ void* DiscoveryClient::PeriodicRenew(void* arg) { consecutive_renew_error = 0; bthread_usleep(FLAGS_discovery_renew_interval_s * 1000000); } - return NULL; + return nullptr; } int DiscoveryClient::Register(const DiscoveryRegisterParam& params) { @@ -253,7 +253,7 @@ int DiscoveryClient::Register(const DiscoveryRegisterParam& params) { if (DoRegister() != 0) { return -1; } - if (bthread_start_background(&_th, NULL, PeriodicRenew, this) != 0) { + if (bthread_start_background(&_th, nullptr, PeriodicRenew, this) != 0) { LOG(ERROR) << "Fail to start background PeriodicRenew"; return -1; } @@ -262,7 +262,7 @@ int DiscoveryClient::Register(const DiscoveryRegisterParam& params) { int DiscoveryClient::DoRegister() { Channel* chan = GetOrNewDiscoveryChannel(); - if (NULL == chan) { + if (nullptr == chan) { LOG(ERROR) << "Fail to create discovery channel"; return -1; } @@ -289,7 +289,7 @@ int DiscoveryClient::DoRegister() { << "&version=" << _params.version << "&metadata=" << _params.metadata; os.move_to(cntl.request_attachment()); - chan->CallMethod(NULL, &cntl, NULL, NULL, NULL); + chan->CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(ERROR) << "Fail to register " << _params.appid << ": " << cntl.ErrorText(); return -1; @@ -327,7 +327,7 @@ int DiscoveryClient::DoCancel() const { << "®ion=" << _params.region << "&zone=" << _params.zone; os.move_to(cntl.request_attachment()); - chan.CallMethod(NULL, &cntl, NULL, NULL, NULL); + chan.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(ERROR) << "Fail to post /discovery/cancel: " << cntl.ErrorText(); return -1; @@ -345,14 +345,14 @@ int DiscoveryClient::DoCancel() const { int DiscoveryNamingService::GetServers(const char* service_name, std::vector* servers) { - if (service_name == NULL || *service_name == '\0' || + if (service_name == nullptr || *service_name == '\0' || FLAGS_discovery_env.empty() || FLAGS_discovery_status.empty()) { LOG_ONCE(ERROR) << "Invalid parameters"; return -1; } Channel* chan = GetOrNewDiscoveryChannel(); - if (NULL == chan) { + if (nullptr == chan) { LOG(ERROR) << "Fail to create discovery channel"; return -1; } @@ -366,7 +366,7 @@ int DiscoveryNamingService::GetServers(const char* service_name, uri_str.append(FLAGS_discovery_zone); } cntl.http_request().uri() = uri_str; - chan->CallMethod(NULL, &cntl, NULL, NULL, NULL); + chan->CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(ERROR) << "Fail to get /discovery/fetchs: " << cntl.ErrorText(); return -1; diff --git a/src/brpc/policy/domain_naming_service.cpp b/src/brpc/policy/domain_naming_service.cpp index d93d799051..8c2632cd6e 100644 --- a/src/brpc/policy/domain_naming_service.cpp +++ b/src/brpc/policy/domain_naming_service.cpp @@ -57,7 +57,7 @@ int DomainNamingService::GetServers(const char* dns_name, int port = _default_port; if (dns_name[i] == ':') { ++i; - char* end = NULL; + char* end = nullptr; port = strtol(dns_name + i, &end, 10); if (end == dns_name + i) { LOG(ERROR) << "No port after colon in `" << dns_name << '\''; @@ -89,7 +89,7 @@ int DomainNamingService::GetServers(const char* dns_name, snprintf(portBuf, arraysize(portBuf), "%d", port); auto ret = getaddrinfo(buf, portBuf, &hints, &addrResult); if (!ret) { - for(auto rp = addrResult; rp != NULL; rp = rp->ai_next) { + for(auto rp = addrResult; rp != nullptr; rp = rp->ai_next) { butil::EndPoint point; auto ret = butil::sockaddr2endpoint((struct sockaddr_storage*)rp->ai_addr, rp->ai_addrlen, &point); if(!ret) { @@ -112,21 +112,21 @@ int DomainNamingService::GetServers(const char* dns_name, // returned hostent is TLS. Check following link for the ref: // https://lists.apple.com/archives/darwin-dev/2006/May/msg00008.html struct hostent* result = gethostbyname(buf); - if (result == NULL) { + if (result == nullptr) { LOG(WARNING) << "result of gethostbyname is NULL"; return -1; } #else - if (_aux_buf == NULL) { + if (_aux_buf == nullptr) { _aux_buf_len = 1024; _aux_buf.reset(new char[_aux_buf_len]); } int ret = 0; int error = 0; struct hostent ent; - struct hostent* result = NULL; + struct hostent* result = nullptr; do { - result = NULL; + result = nullptr; error = 0; ret = gethostbyname_r(buf, &ent, _aux_buf.get(), _aux_buf_len, &result, &error); @@ -144,7 +144,7 @@ int DomainNamingService::GetServers(const char* dns_name, << "' herror=`" << hstrerror(error) << '\''; return -1; } - if (result == NULL) { + if (result == nullptr) { LOG(WARNING) << "result of gethostbyname_r is NULL"; return -1; } @@ -153,7 +153,7 @@ int DomainNamingService::GetServers(const char* dns_name, //TODO add protocols other than IPv4 supports butil::EndPoint point; point.port = port; - for (int i = 0; result->h_addr_list[i] != NULL; ++i) { + for (int i = 0; result->h_addr_list[i] != nullptr; ++i) { if (result->h_addrtype == AF_INET) { // Only fetch IPv4 addresses bcopy(result->h_addr_list[i], &point.ip, result->h_length); diff --git a/src/brpc/policy/dynpart_load_balancer.cpp b/src/brpc/policy/dynpart_load_balancer.cpp index ad3cbbcbff..24a2570423 100644 --- a/src/brpc/policy/dynpart_load_balancer.cpp +++ b/src/brpc/policy/dynpart_load_balancer.cpp @@ -155,7 +155,7 @@ int DynPartLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { } DynPartLoadBalancer* DynPartLoadBalancer::New(const butil::StringPiece&) const { - return new (std::nothrow) DynPartLoadBalancer; + return new DynPartLoadBalancer; } void DynPartLoadBalancer::Destroy() { diff --git a/src/brpc/policy/esp_protocol.cpp b/src/brpc/policy/esp_protocol.cpp index ee8464b85e..1341a998f8 100644 --- a/src/brpc/policy/esp_protocol.cpp +++ b/src/brpc/policy/esp_protocol.cpp @@ -67,14 +67,14 @@ void SerializeEspRequest( Controller* cntl, const google::protobuf::Message* req_base) { - if (req_base == NULL) { + if (req_base == nullptr) { return cntl->SetFailed(EREQUEST, "request is NULL"); } ControllerPrivateAccessor accessor(cntl); if (req_base->GetDescriptor() != EspMessage::descriptor()) { return cntl->SetFailed(EINVAL, "Type of request must be EspMessage"); } - if (cntl->response() != NULL && + if (cntl->response() != nullptr && cntl->response()->GetDescriptor() != EspMessage::descriptor()) { return cntl->SetFailed(EINVAL, "Type of response must be EspMessage"); } @@ -105,7 +105,7 @@ void PackEspRequest(butil::IOBuf* packet_buf, span->set_request_size(request.length()); } - if (auth != NULL) { + if (auth != nullptr) { std::string auth_str; auth->GenerateCredential(&auth_str); //means first request in this connect, need to special head @@ -121,7 +121,7 @@ void ProcessEspResponse(InputMessageBase* msg_base) { // Fetch correlation id that we saved before in `PackEspRequest' const CallId cid = { static_cast(msg->socket()->correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -140,7 +140,7 @@ void ProcessEspResponse(InputMessageBase* msg_base) { EspMessage* response = (EspMessage*)cntl->response(); const int saved_error = cntl->ErrorCode(); - if (response != NULL) { + if (response != nullptr) { msg->meta.copy_to(&response->head, sizeof(EspHead)); msg->payload.swap(response->body); if (response->head.msg != 0) { diff --git a/src/brpc/policy/file_naming_service.cpp b/src/brpc/policy/file_naming_service.cpp index df49673f0f..4ecdd89632 100644 --- a/src/brpc/policy/file_naming_service.cpp +++ b/src/brpc/policy/file_naming_service.cpp @@ -38,7 +38,7 @@ bool SplitIntoServerAndTag(const butil::StringPiece& line, return false; } const char* const addr_start = line.data() + i; - const char* tag_start = NULL; + const char* tag_start = nullptr; ssize_t tag_size = 0; for (; i < line.size() && !isspace(line[i]); ++i) {} if (server_addr) { @@ -69,7 +69,7 @@ bool SplitIntoServerAndTag(const butil::StringPiece& line, int FileNamingService::GetServers(const char *service_name, std::vector* servers) { servers->clear(); - char* line = NULL; + char* line = nullptr; size_t line_len = 0; ssize_t nr = 0; // Sort/unique the inserted vector is faster, but may have a different order diff --git a/src/brpc/policy/giano_authenticator.cpp b/src/brpc/policy/giano_authenticator.cpp index d74f1063c9..7961f0fa76 100644 --- a/src/brpc/policy/giano_authenticator.cpp +++ b/src/brpc/policy/giano_authenticator.cpp @@ -27,29 +27,27 @@ namespace policy { GianoAuthenticator::GianoAuthenticator(const baas::CredentialGenerator* gen, const baas::CredentialVerifier* ver) { if (gen) { - _generator = new(std::nothrow) baas::CredentialGenerator(*gen); - CHECK(_generator); + _generator = new baas::CredentialGenerator(*gen); } else { - _generator = NULL; + _generator = nullptr; } if (ver) { - _verifier = new(std::nothrow) baas::CredentialVerifier(*ver); - CHECK(_verifier); + _verifier = new baas::CredentialVerifier(*ver); } else { - _verifier = NULL; + _verifier = nullptr; } } GianoAuthenticator::~GianoAuthenticator() { delete _generator; - _generator = NULL; + _generator = nullptr; delete _verifier; - _verifier = NULL; + _verifier = nullptr; } int GianoAuthenticator::GenerateCredential(std::string* auth_str) const { - if (NULL == _generator) { + if (nullptr == _generator) { LOG(FATAL) << "CredentialGenerator is NULL"; return -1; } @@ -62,7 +60,7 @@ int GianoAuthenticator::VerifyCredential( const std::string& auth_str, const butil::EndPoint& client_addr, AuthContext* out_ctx) const { - if (NULL == _verifier) { + if (nullptr == _verifier) { LOG(FATAL) << "CredentialVerifier is NULL"; return -1; } @@ -75,7 +73,7 @@ int GianoAuthenticator::VerifyCredential( << baas::sdk::GetReturnCodeMessage(rc); return -1; } - if (out_ctx != NULL) { + if (out_ctx != nullptr) { out_ctx->set_user(ctx.user()); out_ctx->set_group(ctx.group()); out_ctx->set_roles(ctx.roles()); diff --git a/src/brpc/policy/giano_authenticator.h b/src/brpc/policy/giano_authenticator.h index d2b9acbd2f..362497789d 100644 --- a/src/brpc/policy/giano_authenticator.h +++ b/src/brpc/policy/giano_authenticator.h @@ -29,7 +29,7 @@ namespace policy { class GianoAuthenticator: public Authenticator { public: - // Either `gen' or `ver' can be NULL (but not at the same time), + // Either `gen' or `ver' can be nullptr (but not at the same time), // in which case it can only verify/generate credential data explicit GianoAuthenticator(const baas::CredentialGenerator* gen, const baas::CredentialVerifier* ver); diff --git a/src/brpc/policy/gzip_compress.cpp b/src/brpc/policy/gzip_compress.cpp index e8c77a5563..73a6f02f42 100644 --- a/src/brpc/policy/gzip_compress.cpp +++ b/src/brpc/policy/gzip_compress.cpp @@ -64,7 +64,7 @@ static bool Compress(const google::protobuf::Message& msg, butil::IOBuf* buf, LOG(WARNING) << "Fail to serialize input message=" << msg.GetDescriptor()->full_name() << ", format=" << Format2CStr(format) << " : " - << (NULL == gzip.ZlibErrorMessage() ? "" : gzip.ZlibErrorMessage()); + << (nullptr == gzip.ZlibErrorMessage() ? "" : gzip.ZlibErrorMessage()); } return ok && gzip.Close(); } @@ -83,7 +83,7 @@ static bool Decompress(const butil::IOBuf& data, google::protobuf::Message* msg, LOG(WARNING) << "Fail to deserialize input message=" << msg->GetDescriptor()->full_name() << ", format=" << Format2CStr(format) << " : " - << (NULL == gzip.ZlibErrorMessage() ? "" : gzip.ZlibErrorMessage()); + << (nullptr == gzip.ZlibErrorMessage() ? "" : gzip.ZlibErrorMessage()); } return ok; } @@ -105,9 +105,9 @@ bool GzipCompress(const butil::IOBuf& msg, butil::IOBuf* buf, } google::protobuf::io::GzipOutputStream out(&wrapper, gzip_opt); butil::IOBufAsZeroCopyInputStream in(msg); - const void* data_in = NULL; + const void* data_in = nullptr; int size_in = 0; - void* data_out = NULL; + void* data_out = nullptr; int size_out = 0; while (1) { if (size_out == 0 && !out.Next(&data_out, &size_out)) { @@ -141,9 +141,9 @@ inline bool GzipDecompressBase( butil::IOBufAsZeroCopyInputStream wrapper(data); google::protobuf::io::GzipInputStream in(&wrapper, format); butil::IOBufAsZeroCopyOutputStream out(msg); - const void* data_in = NULL; + const void* data_in = nullptr; int size_in = 0; - void* data_out = NULL; + void* data_out = nullptr; int size_out = 0; while (1) { if (size_out == 0 && !out.Next(&data_out, &size_out)) { diff --git a/src/brpc/policy/http2_rpc_protocol.cpp b/src/brpc/policy/http2_rpc_protocol.cpp index d527a055c2..af9ed0b151 100644 --- a/src/brpc/policy/http2_rpc_protocol.cpp +++ b/src/brpc/policy/http2_rpc_protocol.cpp @@ -28,6 +28,7 @@ DECLARE_bool(http_verbose); DECLARE_int32(http_verbose_max_body_length); DECLARE_int32(health_check_interval); DECLARE_bool(usercode_in_pthread); +DECLARE_int64(socket_max_unwritten_bytes); namespace policy { @@ -147,6 +148,12 @@ static int WriteAck(Socket* s, const void* data, size_t n) { return s->Write(&sendbuf, &wopt); } +static int WriteAck(Socket* s, butil::IOBuf* data) { + Socket::WriteOptions wopt; + wopt.ignore_eovercrowded = true; + return s->Write(data, &wopt); +} + // [ https://tools.ietf.org/html/rfc7540#section-6.5.1 ] enum H2SettingsIdentifier { @@ -269,18 +276,13 @@ inline bool AddWindowSize(butil::atomic* window_size, int64_t diff) { // If a sender receives a WINDOW_UPDATE that causes a flow-control window // to exceed this maximum, it MUST terminate either the stream or the connection, // as appropriate. - int64_t before_add = window_size->fetch_add(diff, butil::memory_order_relaxed); - if ((((before_add | diff) >> 31) & 1) == 0) { - // two positive int64_t, check positive overflow - if ((before_add + diff) & (1 << 31)) { - return false; - } - } - if ((((before_add & diff) >> 31) & 1) == 1) { - // two negative int64_t, check negaitive overflow - if (((before_add + diff) & (1 << 31)) == 0) { - return false; - } + const int64_t before_add = + window_size->fetch_add(diff, butil::memory_order_relaxed); + const int64_t after_add = before_add + diff; + if (after_add > std::numeric_limits::max() || + after_add < std::numeric_limits::min()) { + window_size->fetch_sub(diff, butil::memory_order_relaxed); + return false; } // window_size being negative is OK return true; @@ -316,27 +318,26 @@ void InitFrameHandlers() { inline H2Context::FrameHandler FindFrameHandler(H2FrameType type) { pthread_once(&s_frame_handlers_init_once, InitFrameHandlers); if (type < 0 || type > H2_FRAME_TYPE_MAX) { - return NULL; + return nullptr; } return s_frame_handlers[type]; } H2Context::H2Context(Socket* socket, const Server* server) : _socket(socket) - // Maximize the window size to make sending big request possible before - // receving the remote settings. - , _remote_window_left(H2Settings::MAX_WINDOW_SIZE) + , _remote_window_left(H2Settings::DEFAULT_INITIAL_WINDOW_SIZE) , _conn_state(H2_CONNECTION_UNINITIALIZED) , _last_received_stream_id(-1) , _last_sent_stream_id(1) , _goaway_stream_id(-1) , _remote_settings_received(false) + , _pending_data_size(0) , _deferred_window_update(0) { // Stop printing the field which is useless for remote settings. _remote_settings.connection_window_size = 0; - // Maximize the window size to make sending big request possible before - // receving the remote settings. - _remote_settings.stream_window_size = H2Settings::MAX_WINDOW_SIZE; + // SETTINGS_INITIAL_WINDOW_SIZE defaults to 65535 until the peer sends a + // different value. Larger requests are resumed by WINDOW_UPDATE. + _remote_settings.stream_window_size = H2Settings::DEFAULT_INITIAL_WINDOW_SIZE; if (server) { _unack_local_settings = server->options().h2_settings; } else { @@ -370,13 +371,25 @@ int H2Context::Init() { return 0; } +H2Settings H2Context::remote_settings() const { + std::unique_lock mu(_stream_mutex); + return _remote_settings; +} + +size_t H2Context::VolatilePendingStreamSize() const { + std::unique_lock mu(_stream_mutex); + return _pending_streams.size(); +} + H2StreamContext* H2Context::RemoveStreamAndDeferWU(int stream_id) { - H2StreamContext* sctx = NULL; + H2StreamContext* sctx = nullptr; { std::unique_lock mu(_stream_mutex); if (!_pending_streams.erase(stream_id, &sctx)) { - return NULL; + return nullptr; } + CHECK_GE(_pending_data_size, sctx->_pending_data.size()); + _pending_data_size -= sctx->_pending_data.size(); } // The remote stream will not send any more data, sending back the // stream-level WINDOW_UPDATE is pointless, just move the value into @@ -394,6 +407,7 @@ void H2Context::RemoveGoAwayStreams( std::unique_lock mu(_stream_mutex); _goaway_stream_id = goaway_stream_id; _pending_streams.swap(tmp); + _pending_data_size = 0; } for (StreamMap::const_iterator it = tmp.begin(); it != tmp.end(); ++it) { out_streams->push_back(it->second); @@ -408,6 +422,9 @@ void H2Context::RemoveGoAwayStreams( } } for (size_t i = 0; i < out_streams->size(); ++i) { + CHECK_GE(_pending_data_size, + (*out_streams)[i]->_pending_data.size()); + _pending_data_size -= (*out_streams)[i]->_pending_data.size(); _pending_streams.erase((*out_streams)[i]->stream_id()); } } @@ -419,7 +436,7 @@ H2StreamContext* H2Context::FindStream(int stream_id) { if (psctx) { return *psctx; } - return NULL; + return nullptr; } int H2Context::TryToInsertStream(int stream_id, H2StreamContext* ctx) { @@ -428,7 +445,10 @@ int H2Context::TryToInsertStream(int stream_id, H2StreamContext* ctx) { return 1; } H2StreamContext*& sctx = _pending_streams[stream_id]; - if (sctx == NULL) { + if (sctx == nullptr) { + // Synchronize creation with SETTINGS_INITIAL_WINDOW_SIZE updates. + ctx->_remote_window_left.store(_remote_settings.stream_window_size, + butil::memory_order_relaxed); sctx = ctx; return 0; } @@ -461,7 +481,7 @@ ParseResult H2Context::ConsumeFrameHead( return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG); } frame_head->stream_id = static_cast(stream_id); - return MakeMessage(NULL); + return MakeMessage(nullptr); } ParseResult H2Context::Consume( @@ -489,7 +509,7 @@ ParseResult H2Context::Consume( } else { _conn_state = H2_CONNECTION_READY; } - return MakeMessage(NULL); + return MakeMessage(nullptr); } else if (_conn_state == H2_CONNECTION_READY) { H2FrameHead frame_head; ParseResult res = ConsumeFrameHead(it, &frame_head); @@ -497,7 +517,7 @@ ParseResult H2Context::Consume( return res; } H2Context::FrameHandler handler = FindFrameHandler(frame_head.type); - if (handler == NULL) { + if (handler == nullptr) { LOG(ERROR) << "Invalid frame type=" << (int)frame_head.type; return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG); } @@ -518,14 +538,14 @@ ParseResult H2Context::Consume( if (sctx) { if (is_server_side()) { delete sctx; - return MakeMessage(NULL); + return MakeMessage(nullptr); } else { sctx->header().set_status_code( H2ErrorToStatusCode(h2_res.error())); return MakeMessage(sctx); } } - return MakeMessage(NULL); + return MakeMessage(nullptr); } else { // send GOAWAY char goawaybuf[FRAME_HEAD_SIZE + 8]; SerializeFrameHead(goawaybuf, 8, H2_FRAME_GOAWAY, 0, 0); @@ -535,7 +555,7 @@ ParseResult H2Context::Consume( LOG(WARNING) << "Fail to send GOAWAY to " << *_socket; return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG); } - return MakeMessage(NULL); + return MakeMessage(nullptr); } } else { return MakeParseError(PARSE_ERROR_NO_RESOURCE); @@ -574,7 +594,7 @@ H2ParseResult H2Context::OnHeaders( return MakeH2Error(H2_FRAME_SIZE_ERROR); } frag_size -= pad_length; - H2StreamContext* sctx = NULL; + H2StreamContext* sctx = nullptr; if (is_server_side() && frame_head.stream_id > _last_received_stream_id) { // new stream if ((frame_head.stream_id & 1) == 0) { @@ -596,14 +616,14 @@ H2ParseResult H2Context::OnHeaders( } } else { sctx = FindStream(frame_head.stream_id); - if (sctx == NULL) { + if (sctx == nullptr) { if (is_client_side()) { RPC_VLOG << "Fail to find stream_id=" << frame_head.stream_id; // Ignore the message without closing the socket. H2StreamContext tmp_sctx(false); tmp_sctx.Init(this, frame_head.stream_id); tmp_sctx.OnHeaders(it, frame_head, frag_size, pad_length); - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } else { LOG(ERROR) << "Fail to find stream_id=" << frame_head.stream_id; return MakeH2Error(H2_PROTOCOL_ERROR); @@ -642,27 +662,27 @@ H2ParseResult H2StreamContext::OnHeaders( if (frame_head.flags & H2_FLAGS_END_STREAM) { return OnEndStream(); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } else { if (frame_head.flags & H2_FLAGS_END_STREAM) { // Delay calling OnEndStream() in OnContinuation() _stream_ended = true; } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } } H2ParseResult H2Context::OnContinuation( butil::IOBufBytesIterator& it, const H2FrameHead& frame_head) { H2StreamContext* sctx = FindStream(frame_head.stream_id); - if (sctx == NULL) { + if (sctx == nullptr) { if (is_client_side()) { RPC_VLOG << "Fail to find stream_id=" << frame_head.stream_id; // Ignore the message without closing the socket. H2StreamContext tmp_sctx(false); tmp_sctx.Init(this, frame_head.stream_id); tmp_sctx.OnContinuation(it, frame_head); - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } else { LOG(ERROR) << "Fail to find stream_id=" << frame_head.stream_id; return MakeH2Error(H2_PROTOCOL_ERROR); @@ -693,7 +713,7 @@ H2ParseResult H2StreamContext::OnContinuation( return OnEndStream(); } } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } H2ParseResult H2Context::OnData( @@ -714,7 +734,7 @@ H2ParseResult H2Context::OnData( } frag_size -= pad_length; H2StreamContext* sctx = FindStream(frame_head.stream_id); - if (sctx == NULL) { + if (sctx == nullptr) { // If a DATA frame is received whose stream is not in "open" or "half-closed (local)" state, // the recipient MUST respond with a stream error (Section 5.4.2) of type STREAM_CLOSED. // Ignore the message without closing the socket. @@ -782,7 +802,7 @@ H2ParseResult H2StreamContext::OnData( if (frame_head.flags & H2_FLAGS_END_STREAM) { return OnEndStream(); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } H2ParseResult H2Context::OnResetStream( @@ -793,9 +813,9 @@ H2ParseResult H2Context::OnResetStream( } const H2Error h2_error = static_cast(LoadUint32(it)); H2StreamContext* sctx = FindStream(frame_head.stream_id); - if (sctx == NULL) { + if (sctx == nullptr) { RPC_VLOG << "Fail to find stream_id=" << frame_head.stream_id; - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } return sctx->OnResetStream(h2_error, frame_head); } @@ -815,7 +835,7 @@ H2ParseResult H2StreamContext::OnResetStream( } #endif H2StreamContext* sctx = _conn_ctx->RemoveStreamAndDeferWU(stream_id()); - if (sctx == NULL) { + if (sctx == nullptr) { LOG(ERROR) << "Fail to find stream_id=" << stream_id(); return MakeH2Error(H2_PROTOCOL_ERROR); } @@ -825,7 +845,7 @@ H2ParseResult H2StreamContext::OnResetStream( } else { // No need to process the request. delete sctx; - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } } @@ -842,9 +862,9 @@ H2ParseResult H2StreamContext::OnEndStream() { } #endif H2StreamContext* sctx = _conn_ctx->RemoveStreamAndDeferWU(stream_id()); - if (sctx == NULL) { + if (sctx == nullptr) { RPC_VLOG << "Fail to find stream_id=" << stream_id(); - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } CHECK_EQ(sctx, this); @@ -870,45 +890,29 @@ H2ParseResult H2Context::OnSettings( return MakeH2Error(H2_PROTOCOL_ERROR); } _local_settings = _unack_local_settings; - return MakeH2Message(NULL); - } - const int64_t old_stream_window_size = _remote_settings.stream_window_size; - if (!_remote_settings_received) { - // To solve the problem that sender can't send large request before receving - // remote setting, the initial window size of stream/connection is set to - // MAX_WINDOW_SIZE(see constructor of H2Context). - // As a result, in the view of remote side, window size is 65535 by default so - // it may not send its stream size to sender, making stream size still be - // MAX_WINDOW_SIZE. In this case we need to revert this value to default. - H2Settings tmp_settings; - if (!ParseH2Settings(&tmp_settings, it, frame_head.payload_size)) { - LOG(ERROR) << "Fail to parse from SETTINGS"; - return MakeH2Error(H2_PROTOCOL_ERROR); - } - _remote_settings = tmp_settings; - _remote_window_left.fetch_sub( - H2Settings::MAX_WINDOW_SIZE - H2Settings::DEFAULT_INITIAL_WINDOW_SIZE, - butil::memory_order_relaxed); - _remote_settings_received = true; - } else { + return MakeH2Message(nullptr); + } + int64_t window_diff = 0; + { + std::unique_lock mu(_stream_mutex); + const int64_t old_stream_window_size = + _remote_settings.stream_window_size; if (!ParseH2Settings(&_remote_settings, it, frame_head.payload_size)) { LOG(ERROR) << "Fail to parse from SETTINGS"; return MakeH2Error(H2_PROTOCOL_ERROR); } - } - const int64_t window_diff = - static_cast(_remote_settings.stream_window_size) - - old_stream_window_size; - if (window_diff) { - // Do not update the connection flow-control window here, which can only - // be changed using WINDOW_UPDATE frames. - // https://tools.ietf.org/html/rfc7540#section-6.9.2 - // TODO(gejun): Has race conditions with AppendAndDestroySelf - std::unique_lock mu(_stream_mutex); - for (StreamMap::const_iterator it = _pending_streams.begin(); - it != _pending_streams.end(); ++it) { - if (!AddWindowSize(&it->second->_remote_window_left, window_diff)) { - return MakeH2Error(H2_FLOW_CONTROL_ERROR); + _remote_settings_received = true; + window_diff = static_cast(_remote_settings.stream_window_size) + - old_stream_window_size; + if (window_diff) { + // SETTINGS_INITIAL_WINDOW_SIZE changes all existing stream windows, + // but never the connection-level flow-control window. + for (StreamMap::const_iterator it = _pending_streams.begin(); + it != _pending_streams.end(); ++it) { + if (!AddWindowSize(&it->second->_remote_window_left, + window_diff)) { + return MakeH2Error(H2_FLOW_CONTROL_ERROR); + } } } } @@ -919,7 +923,10 @@ H2ParseResult H2Context::OnSettings( LOG(WARNING) << "Fail to respond settings with ack to " << *_socket; return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + if (window_diff > 0 && !FlushPendingData(0)) { + return MakeH2Error(H2_PROTOCOL_ERROR); + } + return MakeH2Message(nullptr); } H2ParseResult H2Context::OnPriority( @@ -945,7 +952,7 @@ H2ParseResult H2Context::OnPing( return MakeH2Error(H2_PROTOCOL_ERROR); } if (frame_head.flags & H2_FLAGS_ACK) { - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } char pongbuf[FRAME_HEAD_SIZE + 8]; @@ -955,12 +962,12 @@ H2ParseResult H2Context::OnPing( LOG(WARNING) << "Fail to send ack of PING to " << *_socket; return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } static void* ProcessHttpResponseWrapper(void* void_arg) { ProcessHttpResponse(static_cast(void_arg)); - return NULL; + return nullptr; } H2ParseResult H2Context::OnGoAway( @@ -992,7 +999,7 @@ H2ParseResult H2Context::OnGoAway( std::vector goaway_streams; RemoveGoAwayStreams(last_stream_id, &goaway_streams); if (goaway_streams.empty()) { - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } for (size_t i = 0; i < goaway_streams.size(); ++i) { H2StreamContext* sctx = goaway_streams[i]; @@ -1010,7 +1017,7 @@ H2ParseResult H2Context::OnGoAway( return MakeH2Message(goaway_streams[0]); } else { // server serves requests on-demand, ignoring GOAWAY is OK. - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } } @@ -1026,27 +1033,51 @@ H2ParseResult H2Context::OnWindowUpdate( return MakeH2Error(H2_PROTOCOL_ERROR); } if (frame_head.stream_id == 0) { - if (!AddWindowSize(&_remote_window_left, inc)) { - LOG(ERROR) << "Invalid connection-level window_size_increment=" << inc; - return MakeH2Error(H2_FLOW_CONTROL_ERROR); + { + std::unique_lock mu(_stream_mutex); + if (!AddWindowSize(&_remote_window_left, inc)) { + LOG(ERROR) << "Invalid connection-level window_size_increment=" << inc; + return MakeH2Error(H2_FLOW_CONTROL_ERROR); + } + } + if (!FlushPendingData(0)) { + return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } else { - H2StreamContext* sctx = FindStream(frame_head.stream_id); - if (sctx == NULL) { - RPC_VLOG << "Fail to find stream_id=" << frame_head.stream_id; - return MakeH2Message(NULL); + { + std::unique_lock mu(_stream_mutex); + H2StreamContext** psctx = _pending_streams.seek(frame_head.stream_id); + if (psctx == nullptr) { + RPC_VLOG << "Fail to find stream_id=" << frame_head.stream_id; + return MakeH2Message(nullptr); + } + if (!AddWindowSize(&(*psctx)->_remote_window_left, inc)) { + LOG(ERROR) << "Invalid stream-level window_size_increment=" << inc + << " to remote_window_left=" + << (*psctx)->_remote_window_left.load(butil::memory_order_relaxed); + return MakeH2Error(H2_FLOW_CONTROL_ERROR); + } } - if (!AddWindowSize(&sctx->_remote_window_left, inc)) { - LOG(ERROR) << "Invalid stream-level window_size_increment=" << inc - << " to remote_window_left=" << sctx->_remote_window_left.load(butil::memory_order_relaxed); - return MakeH2Error(H2_FLOW_CONTROL_ERROR); + if (!FlushPendingData(frame_head.stream_id)) { + return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } } void H2Context::Describe(std::ostream& os, const DescribeOptions& opt) const { + H2Settings remote_settings; + bool remote_settings_received = false; + size_t pending_stream_size = 0; + size_t pending_data_size = 0; + { + std::unique_lock mu(_stream_mutex); + remote_settings = _remote_settings; + remote_settings_received = _remote_settings_received; + pending_stream_size = _pending_streams.size(); + pending_data_size = _pending_data_size; + } if (opt.verbose) { os << '\n'; } @@ -1058,8 +1089,8 @@ void H2Context::Describe(std::ostream& os, const DescribeOptions& opt) const { << _deferred_window_update.load(butil::memory_order_relaxed) << sep << "remote_conn_window_left=" << _remote_window_left.load(butil::memory_order_relaxed) - << sep << "remote_settings=" << _remote_settings - << sep << "remote_settings_received=" << _remote_settings_received + << sep << "remote_settings=" << remote_settings + << sep << "remote_settings_received=" << remote_settings_received << sep << "local_settings=" << _local_settings << sep << "hpacker={"; IndentingOStream os2(os, 2); @@ -1071,7 +1102,8 @@ void H2Context::Describe(std::ostream& os, const DescribeOptions& opt) const { abandoned_size = _abandoned_streams.size(); } os << sep << "abandoned_streams=" << abandoned_size - << sep << "pending_streams=" << VolatilePendingStreamSize(); + << sep << "pending_streams=" << pending_stream_size + << sep << "pending_data_size=" << pending_data_size; if (opt.verbose) { os << '\n'; } @@ -1115,7 +1147,7 @@ ParseResult ParseH2Message(butil::IOBuf *source, Socket *socket, bvar::ScopedTimer > tm(g_parse_time); #endif H2Context* ctx = static_cast(socket->parsing_context()); - if (ctx == NULL) { + if (ctx == nullptr) { if (read_eof || source->empty()) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } @@ -1135,7 +1167,7 @@ ParseResult ParseH2Message(butil::IOBuf *source, Socket *socket, ParseResult res = ctx->Consume(it, socket); if (res.is_ok()) { last_bytes_left = it.bytes_left(); - if (res.message() == NULL) { + if (res.message() == nullptr) { // no message to process, continue parsing. continue; } @@ -1158,7 +1190,7 @@ inline void H2Context::ClearAbandonedStreams() { _abandoned_streams.pop_back(); mu.unlock(); H2StreamContext* sctx = RemoveStreamAndDeferWU(stream_id); - if (sctx != NULL) { + if (sctx != nullptr) { delete sctx; } mu.lock(); @@ -1167,7 +1199,7 @@ inline void H2Context::ClearAbandonedStreams() { H2StreamContext::H2StreamContext(bool read_body_progressively) : HttpContext(read_body_progressively) - , _conn_ctx(NULL) + , _conn_ctx(nullptr) #if defined(BRPC_H2_STREAM_STATE) , _state(H2_STREAM_IDLE) #endif @@ -1205,28 +1237,6 @@ void H2StreamContext::SetState(H2StreamState state) { } #endif -bool H2StreamContext::ConsumeWindowSize(int64_t size) { - // This method is guaranteed to be called in AppendAndDestroySelf() which - // is run sequentially. As a result, _remote_window_left of this stream - // context will not be decremented (may be incremented) because following - // AppendAndDestroySelf() are not run yet. - // This fact is important to make window_size changes to stream and - // connection contexts transactionally. - if (_remote_window_left.load(butil::memory_order_relaxed) < size) { - return false; - } - if (!MinusWindowSize(&_conn_ctx->_remote_window_left, size)) { - return false; - } - int64_t after_sub = _remote_window_left.fetch_sub(size, butil::memory_order_relaxed) - size; - if (after_sub < 0) { - LOG(FATAL) << "Impossible, the http2 impl is buggy"; - _remote_window_left.fetch_add(size, butil::memory_order_relaxed); - return false; - } - return true; -} - int H2StreamContext::ConsumeHeaders(butil::IOBufBytesIterator& it) { HPacker& hpacker = _conn_ctx->hpacker(); HttpHeader& h = header(); @@ -1273,7 +1283,7 @@ int H2StreamContext::ConsumeHeaders(butil::IOBufBytesIterator& it) { h.uri().set_scheme(pair.value); } else if (strcmp(name + 2, /*:s*/"tatus") == 0) { matched = true; - char* endptr = NULL; + char* endptr = nullptr; const int sc = strtol(pair.value.c_str(), &endptr, 10); if (*endptr != '\0') { LOG(ERROR) << "Invalid status=" << pair.value; @@ -1298,7 +1308,7 @@ int H2StreamContext::ConsumeHeaders(butil::IOBufBytesIterator& it) { if (FLAGS_http_verbose) { butil::IOBufBuilder* vs = this->_vmsgbuilder.get(); - if (vs == NULL) { + if (vs == nullptr) { vs = new butil::IOBufBuilder; this->_vmsgbuilder.reset(vs); if (_conn_ctx->is_server_side()) { @@ -1316,43 +1326,53 @@ int H2StreamContext::ConsumeHeaders(butil::IOBufBytesIterator& it) { const CommonStrings* get_common_strings(); -static void PackH2Message(butil::IOBuf* out, +static void PackH2Headers(butil::IOBuf* out, butil::IOBuf& headers, - butil::IOBuf& trailer_headers, - const butil::IOBuf& data, int stream_id, - H2Context* conn_ctx) { - const H2Settings& remote_settings = conn_ctx->remote_settings(); + uint32_t max_frame_size, + bool end_stream) { char headbuf[FRAME_HEAD_SIZE]; H2FrameHead headers_head = { (uint32_t)headers.size(), H2_FRAME_HEADERS, 0, stream_id}; - if (data.empty() && trailer_headers.empty()) { + if (end_stream) { headers_head.flags |= H2_FLAGS_END_STREAM; } - if (headers_head.payload_size <= remote_settings.max_frame_size) { + if (headers_head.payload_size <= max_frame_size) { headers_head.flags |= H2_FLAGS_END_HEADERS; SerializeFrameHead(headbuf, headers_head); out->append(headbuf, sizeof(headbuf)); out->append(butil::IOBuf::Movable(headers)); } else { - headers_head.payload_size = remote_settings.max_frame_size; + headers_head.payload_size = max_frame_size; SerializeFrameHead(headbuf, headers_head); out->append(headbuf, sizeof(headbuf)); headers.cutn(out, headers_head.payload_size); H2FrameHead cont_head = {0, H2_FRAME_CONTINUATION, 0, stream_id}; while (!headers.empty()) { - if (headers.size() <= remote_settings.max_frame_size) { + if (headers.size() <= max_frame_size) { cont_head.flags |= H2_FLAGS_END_HEADERS; cont_head.payload_size = headers.size(); } else { - cont_head.payload_size = remote_settings.max_frame_size; + cont_head.payload_size = max_frame_size; } SerializeFrameHead(headbuf, cont_head); out->append(headbuf, FRAME_HEAD_SIZE); headers.cutn(out, cont_head.payload_size); } } +} + +static void PackH2Message(butil::IOBuf* out, + butil::IOBuf& headers, + butil::IOBuf& trailer_headers, + const butil::IOBuf& data, + int stream_id, + H2Context* conn_ctx) { + const H2Settings& remote_settings = conn_ctx->remote_settings(); + char headbuf[FRAME_HEAD_SIZE]; + PackH2Headers(out, headers, stream_id, remote_settings.max_frame_size, + data.empty() && trailer_headers.empty()); if (!data.empty()) { H2FrameHead data_head = {0, H2_FRAME_DATA, 0, stream_id}; butil::IOBufBytesIterator it(data); @@ -1388,6 +1408,135 @@ static void PackH2Message(butil::IOBuf* out, } } +void H2Context::AppendPendingDataLocked(H2StreamContext* sctx, + butil::IOBuf* out) { + CHECK(sctx != nullptr); + const uint32_t max_frame_size = _remote_settings.max_frame_size; + char headbuf[FRAME_HEAD_SIZE]; + while (!sctx->_pending_data.empty()) { + const int64_t conn_window = + _remote_window_left.load(butil::memory_order_relaxed); + const int64_t stream_window = + sctx->_remote_window_left.load(butil::memory_order_relaxed); + if (conn_window <= 0 || stream_window <= 0) { + break; + } + const size_t payload_size = std::min( + sctx->_pending_data.size(), + std::min(static_cast(max_frame_size), + static_cast(std::min(conn_window, stream_window)))); + CHECK_GT(payload_size, 0u); + _remote_window_left.fetch_sub(payload_size, butil::memory_order_relaxed); + sctx->_remote_window_left.fetch_sub(payload_size, + butil::memory_order_relaxed); + + H2FrameHead data_head = { + static_cast(payload_size), H2_FRAME_DATA, 0, + sctx->stream_id()}; + if (payload_size == sctx->_pending_data.size()) { + data_head.flags |= H2_FLAGS_END_STREAM; + } + SerializeFrameHead(headbuf, data_head); + out->append(headbuf, sizeof(headbuf)); + sctx->_pending_data.cutn(out, payload_size); + CHECK_GE(_pending_data_size, payload_size); + _pending_data_size -= payload_size; + } +} + +butil::Status H2Context::TryToInsertClientStream( + int stream_id, H2StreamContext* sctx, const butil::IOBuf& data, + butil::IOBuf* out) { + std::unique_lock mu(_stream_mutex); + if (_goaway_stream_id >= 0 && stream_id > _goaway_stream_id) { + return butil::Status(ELOGOFF, "the connection just issued GOAWAY"); + } + if (_pending_streams.seek(stream_id) != nullptr) { + return butil::Status(EINTERNAL, + "Fail to insert existing stream_id"); + } + if (_pending_streams.size() >= _remote_settings.max_concurrent_streams) { + return butil::Status( + ELIMIT, "Pending Stream count exceeds max concurrent stream"); + } + + sctx->_remote_window_left.store(_remote_settings.stream_window_size, + butil::memory_order_relaxed); + const int64_t conn_window = + _remote_window_left.load(butil::memory_order_relaxed); + const int64_t stream_window = + sctx->_remote_window_left.load(butil::memory_order_relaxed); + size_t sendable_size = 0; + if (conn_window > 0 && stream_window > 0) { + sendable_size = std::min( + data.size(), + static_cast(std::min(conn_window, stream_window))); + } + const size_t pending_size = data.size() - sendable_size; + if (FLAGS_socket_max_unwritten_bytes > 0) { + const auto limit = + static_cast(FLAGS_socket_max_unwritten_bytes); + // Check and reserve pending bytes under the same lock. Otherwise, + // concurrent requests may all observe available capacity before any + // of them adds its unsent DATA. + if (_pending_data_size > limit || + pending_size > limit - _pending_data_size) { + return butil::Status(EOVERCROWDED, + "Too much pending HTTP/2 request data"); + } + } + + // Mutate stream and window state only after all failure checks above. + _pending_streams[stream_id] = sctx; + if (!data.empty()) { + CHECK(sctx->_pending_data.empty()); + sctx->_pending_data = data; + _pending_data_size += data.size(); + AppendPendingDataLocked(sctx, out); + } + return butil::Status::OK(); +} + +void H2Context::ClearPendingData(int stream_id) { + std::unique_lock mu(_stream_mutex); + H2StreamContext** psctx = _pending_streams.seek(stream_id); + if (psctx == nullptr) { + return; + } + CHECK_GE(_pending_data_size, (*psctx)->_pending_data.size()); + _pending_data_size -= (*psctx)->_pending_data.size(); + (*psctx)->_pending_data.clear(); +} + +bool H2Context::PendingDataOvercrowded() const { + std::unique_lock mu(_stream_mutex); + return FLAGS_socket_max_unwritten_bytes > 0 && + _pending_data_size >= + static_cast(FLAGS_socket_max_unwritten_bytes); +} + +bool H2Context::FlushPendingData(int stream_id) { + butil::IOBuf out; + { + std::unique_lock mu(_stream_mutex); + if (stream_id != 0) { + H2StreamContext** psctx = _pending_streams.seek(stream_id); + if (psctx != nullptr) { + AppendPendingDataLocked(*psctx, &out); + } + } else { + for (StreamMap::const_iterator it = _pending_streams.begin(); + it != _pending_streams.end(); ++it) { + if (_remote_window_left.load(butil::memory_order_relaxed) <= 0) { + break; + } + AppendPendingDataLocked(it->second, &out); + } + } + } + return out.empty() || WriteAck(_socket, &out) == 0; +} + H2UnsentRequest* H2UnsentRequest::New(Controller* c) { const HttpHeader& h = c->http_request(); const CommonStrings* const common = get_common_strings(); @@ -1485,12 +1634,13 @@ void H2UnsentRequest::DestroyStreamUserData(SocketUniquePtr& sending_sock, int error_code, bool /*end_of_rpc*/) { RemoveRefOnQuit deref_self(this); - if (sending_sock != NULL && error_code != 0) { + if (sending_sock != nullptr && error_code != 0) { CHECK_EQ(cntl, _cntl); std::unique_lock mu(_mutex); - _cntl = NULL; + _cntl = nullptr; if (_stream_id != 0) { H2Context* ctx = static_cast(sending_sock->parsing_context()); + ctx->ClearPendingData(_stream_id); ctx->AddAbandonedStream(_stream_id); } } @@ -1508,15 +1658,15 @@ H2UnsentRequest::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) { bvar::ScopedTimer > tm(g_append_request_time); #endif RemoveRefOnQuit deref_self(this); - if (socket == NULL) { + if (socket == nullptr) { return butil::Status::OK(); } H2Context* ctx = static_cast(socket->parsing_context()); // Create a http2 stream and store correlation_id in. - if (ctx == NULL) { + if (ctx == nullptr) { CHECK(socket->CreatedByConnect()); - ctx = new H2Context(socket, NULL); + ctx = new H2Context(socket, nullptr); if (ctx->Init() != 0) { delete ctx; return butil::Status(EINTERNAL, "Fail to init H2Context"); @@ -1534,15 +1684,10 @@ H2UnsentRequest::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) { out->append(settingsbuf, nb); } - // TODO(zhujiashun): also check this in server push - if (ctx->VolatilePendingStreamSize() > ctx->remote_settings().max_concurrent_streams) { - return butil::Status(ELIMIT, "Pending Stream count exceeds max concurrent stream"); - } - // Although the critical section looks huge, it should rarely be contended // since timeout of RPC is much larger than the delay of sending. std::unique_lock mu(_mutex); - if (_cntl == NULL) { + if (_cntl == nullptr) { return butil::Status(ECANCELED, "The RPC was already failed"); } @@ -1557,30 +1702,15 @@ H2UnsentRequest::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) { } _sctx->Init(ctx, id); - // check flow control restriction - if (!_cntl->request_attachment().empty()) { - const int64_t data_size = _cntl->request_attachment().size(); - if (!_sctx->ConsumeWindowSize(data_size)) { - return butil::Status(ELIMIT, "remote_window_left is not enough, data_size=%" PRId64, data_size); - } - } - - const int rc = ctx->TryToInsertStream(id, _sctx.get()); - if (rc < 0) { - return butil::Status(EINTERNAL, "Fail to insert existing stream_id"); - } else if (rc > 0) { - return butil::Status(ELOGOFF, "the connection just issued GOAWAY"); - } - _stream_id = _sctx->stream_id(); - // After calling TryToInsertStream, the ownership of _sctx is transferred to ctx - _sctx.release(); + H2StreamContext* const sctx = _sctx.get(); HPacker& hpacker = ctx->hpacker(); butil::IOBufAppender appender; HPackOptions options; options.encode_name = FLAGS_h2_hpack_encode_name; options.encode_value = FLAGS_h2_hpack_encode_value; - if (ctx->remote_settings().header_table_size == 0) { + const H2Settings remote_settings = ctx->remote_settings(); + if (remote_settings.header_table_size == 0) { options.index_policy = HPACK_NEVER_INDEX_HEADER; } @@ -1597,8 +1727,24 @@ H2UnsentRequest::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) { } butil::IOBuf frag; appender.move_to(frag); - butil::IOBuf dummy_buf; - PackH2Message(out, frag, dummy_buf, _cntl->request_attachment(), _stream_id, ctx); + const butil::IOBuf& request_data = _cntl->request_attachment(); + PackH2Headers(out, frag, id, remote_settings.max_frame_size, + request_data.empty()); + const butil::Status insert_status = + ctx->TryToInsertClientStream(id, sctx, request_data, out); + if (!insert_status.ok()) { + return insert_status; + } + _stream_id = id; + // TryToInsertClientStream transfers ownership of _sctx to ctx on success. + _sctx.release(); + const int64_t conn_wu = ctx->ReleaseDeferredWindowUpdate(); + if (conn_wu > 0) { + char winbuf[FRAME_HEAD_SIZE + 4]; + SerializeFrameHead(winbuf, 4, H2_FRAME_WINDOW_UPDATE, 0, 0); + SaveUint32(winbuf + FRAME_HEAD_SIZE, conn_wu); + out->append(winbuf, sizeof(winbuf)); + } return butil::Status::OK(); } @@ -1608,7 +1754,7 @@ size_t H2UnsentRequest::EstimatedByteSize() { sz += _list[i].name.size() + _list[i].value.size() + 1; } std::unique_lock mu(_mutex); - if (_cntl == NULL) { + if (_cntl == nullptr) { return 0; } if (_cntl->has_http_request()) { @@ -1628,7 +1774,7 @@ void H2UnsentRequest::Print(std::ostream& os) const { os << "> " << _list[i].name << " = " << _list[i].value << '\n'; } std::unique_lock mu(_mutex); - if (_cntl == NULL) { + if (_cntl == nullptr) { return; } if (_cntl->has_http_request()) { @@ -1700,7 +1846,7 @@ H2UnsentResponse::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) { bvar::ScopedTimer > tm(g_append_response_time); #endif DestroyingPtr destroy_self(this); - if (socket == NULL) { + if (socket == nullptr) { return butil::Status::OK(); } H2Context* ctx = static_cast(socket->parsing_context()); @@ -1800,7 +1946,7 @@ void PackH2Request(butil::IOBuf*, ControllerPrivateAccessor accessor(cntl); HttpHeader* header = &cntl->http_request(); - if (auth != NULL && header->GetHeader("Authorization") == NULL) { + if (auth != nullptr && header->GetHeader("Authorization") == nullptr) { std::string auth_data; if (auth->GenerateCredential(&auth_data) != 0) { return cntl->SetFailed(EREQUEST, "Fail to GenerateCredential"); @@ -1821,20 +1967,21 @@ void PackH2Request(butil::IOBuf*, static bool IsH2SocketValid(Socket* s) { H2Context* c = static_cast(s->parsing_context()); - return (c == NULL || !c->RunOutStreams()); + return c == nullptr || + (!c->RunOutStreams() && !c->PendingDataOvercrowded()); } StreamUserData* H2GlobalStreamCreator::OnCreatingStream( SocketUniquePtr* inout, Controller* cntl) { if ((*inout)->GetAgentSocket(inout, IsH2SocketValid) != 0) { cntl->SetFailed(EINTERNAL, "Fail to create agent socket"); - return NULL; + return nullptr; } H2UnsentRequest* h2_req = H2UnsentRequest::New(cntl); if (!h2_req) { cntl->SetFailed(ENOMEM, "Fail to create H2UnsentRequest"); - return NULL; + return nullptr; } return h2_req; } diff --git a/src/brpc/policy/http2_rpc_protocol.h b/src/brpc/policy/http2_rpc_protocol.h index b4422ee057..022f978c85 100644 --- a/src/brpc/policy/http2_rpc_protocol.h +++ b/src/brpc/policy/http2_rpc_protocol.h @@ -38,7 +38,7 @@ class H2StreamContext; class H2ParseResult { public: explicit H2ParseResult(H2Error err, int stream_id) - : _msg(NULL), _err(err), _stream_id(stream_id) {} + : _msg(nullptr), _err(err), _stream_id(stream_id) {} explicit H2ParseResult(H2StreamContext* msg) : _msg(msg), _err(H2_NO_ERROR), _stream_id(0) {} @@ -48,7 +48,7 @@ class H2ParseResult { bool is_ok() const { return error() == H2_NO_ERROR; } int stream_id() const { return _stream_id; } - // definitely NULL when result is failed. + // definitely nullptr when result is failed. H2StreamContext* message() const { return _msg; } private: @@ -258,8 +258,6 @@ class H2StreamContext : public HttpContext { return _deferred_window_update.exchange(0, butil::memory_order_relaxed); } - bool ConsumeWindowSize(int64_t size); - #if defined(BRPC_H2_STREAM_STATE) H2StreamState state() const { return _state; } void SetState(H2StreamState state); @@ -276,6 +274,9 @@ friend class H2Context; butil::atomic _deferred_window_update; uint64_t _correlation_id; butil::IOBuf _remaining_header_fragment; + // Request body which cannot be sent yet due to remote flow control. + // Accessed under H2Context::_stream_mutex. + butil::IOBuf _pending_data; }; StreamCreator* get_h2_global_stream_creator(); @@ -317,9 +318,9 @@ class H2Context : public Destroyable, public Describable { butil::IOBufBytesIterator&, const H2FrameHead&); // main_socket: the socket owns this object as parsing_context - // server: NULL means client-side + // server: nullptr means client-side H2Context(Socket* main_socket, const Server* server); - ~H2Context(); + ~H2Context() override; // Must be called before usage. int Init(); @@ -337,10 +338,13 @@ class H2Context : public Destroyable, public Describable { // Try to map stream_id to ctx if stream_id does not exist before // Returns 0 on success, -1 on exist, 1 on goaway. int TryToInsertStream(int stream_id, H2StreamContext* ctx); - size_t VolatilePendingStreamSize() const { return _pending_streams.size(); } + size_t VolatilePendingStreamSize() const; + bool PendingDataOvercrowded() const; HPacker& hpacker() { return _hpacker; } - const H2Settings& remote_settings() const { return _remote_settings; } + // Return a consistent snapshot because SETTINGS may be processed by the + // socket reader while a request is being packed by a writer. + H2Settings remote_settings() const; const H2Settings& local_settings() const { return _local_settings; } bool is_client_side() const { return _socket->CreatedByConnect(); } @@ -374,6 +378,15 @@ friend void InitFrameHandlers(); void RemoveGoAwayStreams(int goaway_stream_id, std::vector* out_streams); H2StreamContext* FindStream(int stream_id); + // Atomically checks stream and pending-DATA limits, inserts the client + // stream, and appends DATA allowed by the current remote windows. On + // success, ownership of sctx is transferred to this context. On failure, + // no stream, window, or pending-DATA state is changed. + butil::Status TryToInsertClientStream( + int stream_id, H2StreamContext*, const butil::IOBuf&, butil::IOBuf*); + void AppendPendingDataLocked(H2StreamContext*, butil::IOBuf*); + void ClearPendingData(int stream_id); + bool FlushPendingData(int stream_id); // True if the connection is established by client, otherwise it's // accepted by server. @@ -393,6 +406,9 @@ friend void InitFrameHandlers(); typedef butil::FlatMap StreamMap; mutable butil::Mutex _stream_mutex; StreamMap _pending_streams; + // Total bytes retained in H2StreamContext::_pending_data on this + // connection. Accessed under _stream_mutex. + size_t _pending_data_size; butil::atomic _deferred_window_update; }; diff --git a/src/brpc/policy/http_rpc_protocol.cpp b/src/brpc/policy/http_rpc_protocol.cpp index 8cbe06980f..ca1d30d1fa 100644 --- a/src/brpc/policy/http_rpc_protocol.cpp +++ b/src/brpc/policy/http_rpc_protocol.cpp @@ -89,7 +89,7 @@ static bool GetUserAddressFromHeaderImpl(const HttpHeader& headers, butil::EndPoint* user_addr) { const std::string* user_addr_str = headers.GetHeader(FLAGS_http_header_of_user_ip); - if (user_addr_str == NULL) { + if (user_addr_str == nullptr) { return false; } //TODO add protocols other than IPv4 supports. @@ -161,7 +161,7 @@ CommonStrings::CommonStrings() , DEFAULT_PATH("/") {} -static CommonStrings* common = NULL; +static CommonStrings* common = nullptr; static pthread_once_t g_common_strings_once = PTHREAD_ONCE_INIT; static void CreateCommonStrings() { common = new CommonStrings; @@ -363,7 +363,7 @@ void ProcessHttpResponse(InputMessageBase* msg) { return; } const bthread_id_t cid = { cid_value }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -397,7 +397,7 @@ void ProcessHttpResponse(InputMessageBase* msg) { if (!is_http2) { // If header has "Connection: close", close the connection. const std::string* conn_cmd = res_header->GetHeader(common->CONNECTION); - if (conn_cmd != NULL && 0 == strcasecmp(conn_cmd->c_str(), "close")) { + if (conn_cmd != nullptr && 0 == strcasecmp(conn_cmd->c_str(), "close")) { // Server asked to close the connection. if (imsg_guard->read_body_progressively()) { // Close the socket when reading completes. @@ -414,7 +414,7 @@ void ProcessHttpResponse(InputMessageBase* msg) { const std::string* grpc_status = res_header->GetHeader(common->GRPC_STATUS); if (grpc_status) { // TODO: More strict parsing - GrpcStatus status = (GrpcStatus)strtol(grpc_status->data(), NULL, 10); + GrpcStatus status = (GrpcStatus)strtol(grpc_status->data(), nullptr, 10); if (status != GRPC_OK) { const std::string* grpc_message = res_header->GetHeader(common->GRPC_MESSAGE); @@ -451,7 +451,7 @@ void ProcessHttpResponse(InputMessageBase* msg) { static_cast(res_header->status_code()), res_header->reason_phrase(), (int)body_str.size(), body_str.c_str()); - } else if (cntl->response() != NULL && + } else if (cntl->response() != nullptr && cntl->response()->GetDescriptor()->field_count() != 0) { cntl->SetFailed(ERESPONSE, "A protobuf response can't be parsed" " from progressively-read HTTP body"); @@ -481,13 +481,13 @@ void ProcessHttpResponse(InputMessageBase* msg) { // set the returned error code to controller. Otherwise, // set EHTTP to controller uniformly. const std::string* error_code_ptr = res_header->GetHeader(common->ERROR_CODE); - int error_code = error_code_ptr ? strtol(error_code_ptr->data(), NULL, 10) : 0; + int error_code = error_code_ptr ? strtol(error_code_ptr->data(), nullptr, 10) : 0; if (FLAGS_use_http_error_code && error_code != 0) { cntl->SetFailed(error_code, "%s", err.c_str()); } else { cntl->SetFailed(EHTTP, "%s", err.c_str()); } - if (cntl->response() == NULL || + if (cntl->response() == nullptr || cntl->response()->GetDescriptor()->field_count() == 0) { // A http call. Http users may need the body(containing a html, // json etc) even if the http call was failed. This is different @@ -497,18 +497,18 @@ void ProcessHttpResponse(InputMessageBase* msg) { } break; } - if (cntl->response() == NULL || + if (cntl->response() == nullptr || cntl->response()->GetDescriptor()->field_count() == 0) { // a http call, content is the "real response". cntl->response_attachment().swap(res_body); break; } - const std::string* encoding = NULL; + const std::string* encoding = nullptr; if (is_grpc) { if (grpc_compressed) { encoding = res_header->GetHeader(common->GRPC_ENCODING); - if (encoding == NULL) { + if (encoding == nullptr) { cntl->SetFailed(ERESPONSE, "Fail to find header `grpc-encoding' " "in compressed gRPC response"); break; @@ -517,7 +517,7 @@ void ProcessHttpResponse(InputMessageBase* msg) { } else { encoding = res_header->GetHeader(common->CONTENT_ENCODING); } - if (encoding != NULL && *encoding == common->GZIP) { + if (encoding != nullptr && *encoding == common->GZIP) { TRACEPRINTF("Decompressing response=%lu", (unsigned long)res_body.size()); butil::IOBuf uncompressed; @@ -581,8 +581,8 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, hreq.set_content_type(param); } } - if (pbreq != NULL) { - // If request is not NULL, message body will be serialized proto/json, + if (pbreq != nullptr) { + // If request is not nullptr, message body will be serialized proto/json, if (!pbreq->IsInitialized()) { return cntl->SetFailed( EREQUEST, "Missing required fields in request: %s", @@ -657,7 +657,7 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, if (request_size >= (size_t)FLAGS_http_body_compress_threshold) { TRACEPRINTF("Compressing request=%lu", (unsigned long)request_size); butil::IOBuf compressed; - if (GzipCompress(cntl->request_attachment(), &compressed, NULL)) { + if (GzipCompress(cntl->request_attachment(), &compressed, nullptr)) { cntl->request_attachment().swap(compressed); if (is_grpc) { grpc_compressed = true; @@ -684,7 +684,7 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, // HTTP before 1.1 needs to set keep-alive explicitly. if (hreq.before_http_1_1() && cntl->connection_type() != CONNECTION_TYPE_SHORT && - hreq.GetHeader(common->CONNECTION) == NULL) { + hreq.GetHeader(common->CONNECTION) == nullptr) { hreq.SetHeader(common->CONNECTION, common->KEEP_ALIVE); } } else { @@ -706,9 +706,9 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, } // Set url to /ServiceName/MethodName when we're about to call protobuf - // services (indicated by non-NULL method). + // services (indicated by non-nullptr method). const google::protobuf::MethodDescriptor* method = cntl->method(); - if (method != NULL) { + if (method != nullptr) { hreq.set_method(HTTP_METHOD_POST); std::string path; path.reserve(2 + method->service()->full_name().size() @@ -742,7 +742,7 @@ void PackHttpRequest(butil::IOBuf* buf, } ControllerPrivateAccessor accessor(cntl); HttpHeader* header = &cntl->http_request(); - if (auth != NULL && header->GetHeader(common->AUTHORIZATION) == NULL) { + if (auth != nullptr && header->GetHeader(common->AUTHORIZATION) == nullptr) { std::string auth_data; if (auth->GenerateCredential(&auth_data) != 0) { return cntl->SetFailed(EREQUEST, "Fail to GenerateCredential"); @@ -775,11 +775,11 @@ class HttpResponseSender { friend class HttpResponseSenderAsDone; public: HttpResponseSender() - : HttpResponseSender(NULL) {} + : HttpResponseSender(nullptr) {} explicit HttpResponseSender(Controller* cntl/*own*/) : _cntl(cntl) - , _messages(NULL) - , _method_status(NULL) + , _messages(nullptr) + , _method_status(nullptr) , _received_us(0) , _h2_stream_id(-1) {} @@ -789,8 +789,8 @@ friend class HttpResponseSenderAsDone; , _method_status(s._method_status) , _received_us(s._received_us) , _h2_stream_id(s._h2_stream_id) { - s._messages = NULL; - s._method_status = NULL; + s._messages = nullptr; + s._method_status = nullptr; s._received_us = 0; s._h2_stream_id = -1; } @@ -813,7 +813,7 @@ class HttpResponseSenderAsDone : public google::protobuf::Closure { public: explicit HttpResponseSenderAsDone(HttpResponseSender* s) : _sender(std::move(*s)) {} void Run() override { - if (NULL != _sender._messages) { + if (nullptr != _sender._messages) { _sender._cntl->CallAfterRpcResp(_sender._messages->Request(), _sender._messages->Response()); } @@ -827,12 +827,12 @@ class HttpResponseSenderAsDone : public google::protobuf::Closure { HttpResponseSender::~HttpResponseSender() { // Return messages to factory at the end. BRPC_SCOPE_EXIT { - if (NULL != _messages) { + if (nullptr != _messages) { _cntl->server()->options().rpc_pb_message_factory->Return(_messages); } }; Controller* cntl = _cntl.get(); - if (cntl == NULL) { + if (cntl == nullptr) { return; } ControllerPrivateAccessor accessor(cntl); @@ -842,7 +842,7 @@ HttpResponseSender::~HttpResponseSender() { } ConcurrencyRemover concurrency_remover(_method_status, cntl, _received_us); Socket* socket = accessor.get_sending_socket(); - const google::protobuf::Message* res = NULL != _messages ? _messages->Response() : NULL; + const google::protobuf::Message* res = nullptr != _messages ? _messages->Response() : nullptr; if (cntl->IsCloseConnection()) { socket->SetFailed(); @@ -871,7 +871,7 @@ HttpResponseSender::~HttpResponseSender() { // Convert response to json/proto if needed. // Notice: Not check res->IsInitialized() which should be checked in the // conversion function. - if (res != NULL && + if (res != nullptr && cntl->response_attachment().empty() && // ^ user did not fill the body yet. res->GetDescriptor()->field_count() > 0 && @@ -912,16 +912,16 @@ HttpResponseSender::~HttpResponseSender() { // after receiving the response. if (!is_http2) { const std::string* res_conn = res_header->GetHeader(common->CONNECTION); - if (res_conn == NULL || strcasecmp(res_conn->c_str(), "close") != 0) { + if (res_conn == nullptr || strcasecmp(res_conn->c_str(), "close") != 0) { const std::string* req_conn = req_header->GetHeader(common->CONNECTION); if (req_header->before_http_1_1()) { - if (req_conn != NULL && + if (req_conn != nullptr && strcasecmp(req_conn->c_str(), "keep-alive") == 0) { res_header->SetHeader(common->CONNECTION, common->KEEP_ALIVE); } } else { - if (req_conn != NULL && + if (req_conn != nullptr && strcasecmp(req_conn->c_str(), "close") == 0) { res_header->SetHeader(common->CONNECTION, common->CLOSE); } @@ -974,7 +974,7 @@ HttpResponseSender::~HttpResponseSender() { && (is_http2 || SupportGzip(cntl))) { TRACEPRINTF("Compressing response=%lu", (unsigned long)response_size); butil::IOBuf tmpbuf; - if (GzipCompress(cntl->response_attachment(), &tmpbuf, NULL)) { + if (GzipCompress(cntl->response_attachment(), &tmpbuf, nullptr)) { cntl->response_attachment().swap(tmpbuf); if (is_grpc) { grpc_compressed = true; @@ -1012,7 +1012,7 @@ HttpResponseSender::~HttpResponseSender() { } SocketMessagePtr h2_response( H2UnsentResponse::New(cntl, _h2_stream_id, is_grpc)); - if (h2_response == NULL) { + if (h2_response == nullptr) { LOG(ERROR) << "Fail to make http2 response"; errno = EINVAL; rc = -1; @@ -1026,7 +1026,7 @@ HttpResponseSender::~HttpResponseSender() { rc = socket->Write(h2_response, &wopt); } } else { - butil::IOBuf* content = NULL; + butil::IOBuf* content = nullptr; if (cntl->Failed() || !cntl->has_progressive_writer()) { content = &cntl->response_attachment(); } @@ -1063,7 +1063,7 @@ HttpResponseSender::~HttpResponseSender() { static void FillUnresolvedPath(std::string* unresolved_path, const std::string& uri_path, butil::StringSplitter& splitter) { - if (unresolved_path == NULL) { + if (unresolved_path == nullptr) { return; } if (!splitter) { @@ -1077,7 +1077,7 @@ static void FillUnresolvedPath(std::string* unresolved_path, unresolved_path->clear(); for (butil::StringSplitter slash_sp( splitter.field(), splitter.field() + path_len, '/'); - slash_sp != NULL; ++slash_sp) { + slash_sp != nullptr; ++slash_sp) { if (!unresolved_path->empty()) { unresolved_path->push_back('/'); } @@ -1091,7 +1091,7 @@ FindMethodPropertyByURIImpl(const std::string& uri_path, const Server* server, ServerPrivateAccessor wrapper(server); butil::StringSplitter splitter(uri_path.c_str(), '/'); // Show index page for empty URI - if (NULL == splitter) { + if (nullptr == splitter) { return wrapper.FindMethodPropertyByFullName( IndexService::descriptor()->full_name(), common->DEFAULT_METHOD); } @@ -1102,9 +1102,9 @@ FindMethodPropertyByURIImpl(const std::string& uri_path, const Server* server, (full_service_name ? wrapper.FindServicePropertyByFullName(service_name) : wrapper.FindServicePropertyByName(service_name)); - if (NULL == sp) { + if (nullptr == sp) { // normal for urls matching _global_restful_map - return NULL; + return nullptr; } // Find restful methods by uri. if (sp->restful_map) { @@ -1123,9 +1123,9 @@ FindMethodPropertyByURIImpl(const std::string& uri_path, const Server* server, } // Regard URI as [service_name]/[method_name] - const Server::MethodProperty* mp = NULL; + const Server::MethodProperty* mp = nullptr; butil::StringPiece method_name; - if (++splitter != NULL) { + if (++splitter != nullptr) { method_name.set(splitter.field(), splitter.length()); // Copy splitter rather than modifying it directly since it's used // in later branches. @@ -1151,7 +1151,7 @@ FindMethodPropertyByURIImpl(const std::string& uri_path, const Server* server, } // Called an existing service w/o default_method with an unknown method. - return NULL; + return nullptr; } // Used in UT, don't be static @@ -1160,11 +1160,11 @@ FindMethodPropertyByURI(const std::string& uri_path, const Server* server, std::string* unresolved_path) { const Server::MethodProperty* mp = FindMethodPropertyByURIImpl(uri_path, server, unresolved_path); - if (mp != NULL) { - if (mp->http_url != NULL && !mp->params.allow_default_url) { + if (mp != nullptr) { + if (mp->http_url != nullptr && !mp->params.allow_default_url) { // the restful method is accessed from its // default url (SERVICE/METHOD) which should be rejected. - return NULL; + return nullptr; } return mp; } @@ -1176,14 +1176,14 @@ FindMethodPropertyByURI(const std::string& uri_path, const Server* server, return accessor.global_restful_map()->FindMethodProperty( uri_path, unresolved_path); } - return NULL; + return nullptr; } ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, bool read_eof, const void* arg) { HttpContext* http_imsg = static_cast(socket->parsing_context()); - if (http_imsg == NULL) { + if (http_imsg == nullptr) { if (read_eof || source->empty()) { // 1. read_eof: Read EOF after intact HTTP messages, a common case. // Notice that errors except NOT_ENOUGH_DATA can't be returned @@ -1194,13 +1194,8 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, // source is likely to be empty. return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } - http_imsg = new (std::nothrow) HttpContext( - socket->is_read_progressive(), - socket->http_request_method()); - if (http_imsg == NULL) { - LOG(FATAL) << "Fail to new HttpContext"; - return MakeParseError(PARSE_ERROR_NO_RESOURCE); - } + http_imsg = new HttpContext(socket->is_read_progressive(), + socket->http_request_method()); // Parsing http is costly, parsing an incomplete http message from the // beginning repeatedly should be avoided, otherwise the cost may reach // O(n^2) in the worst case. Save incomplete http messages in sockets @@ -1211,7 +1206,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, ssize_t rc = 0; if (read_eof) { // Send EOF to HttpContext, check comments in http_message.h - rc = http_imsg->ParseFromArray(NULL, 0); + rc = http_imsg->ParseFromArray(nullptr, 0); } else { // Empty `source' is sliently ignored and 0 is returned, check // comments in http_message.h @@ -1227,7 +1222,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, HttpHeader header; header.set_status_code(HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE); header.SetHeader("Connection", "close"); - MakeRawHttpResponse(&resp, &header, NULL); + MakeRawHttpResponse(&resp, &header, nullptr); Socket::WriteOptions wopt; wopt.ignore_eovercrowded = true; socket->Write(&resp, &wopt); @@ -1248,7 +1243,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, // be called from ProcessHttpXXX http_imsg->RemoveOneRefForStage2(); socket->OnProgressiveReadCompleted(); - return MakeMessage(NULL); + return MakeMessage(nullptr); } else { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } @@ -1287,7 +1282,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, butil::IOBuf resp; HttpHeader header; header.set_status_code(HTTP_STATUS_CONTINUE); - MakeRawHttpResponse(&resp, &header, NULL); + MakeRawHttpResponse(&resp, &header, nullptr); Socket::WriteOptions wopt; wopt.ignore_eovercrowded = true; socket->Write(&resp, &wopt); @@ -1319,7 +1314,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, // internal fd from epoll thus we can still get EPOLLIN and read // in more data. If the second read happens, parsing_context() // should return the same InputMessage that we see now because we - // don't reset_parsing_context(NULL) in this branch, and following + // don't reset_parsing_context(nullptr) in this branch, and following // ParseFromXXX should return -1 immediately because of the non-zero // parser.http_errno, and ReleaseAdditionalReference() here should // return -1 to prevent us from sending another 400. @@ -1337,7 +1332,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, butil::IOBuf resp; HttpHeader header; header.set_status_code(HTTP_STATUS_BAD_REQUEST); - MakeRawHttpResponse(&resp, &header, NULL); + MakeRawHttpResponse(&resp, &header, nullptr); Socket::WriteOptions wopt; wopt.ignore_eovercrowded = true; socket->Write(&resp, &wopt); @@ -1398,13 +1393,13 @@ bool VerifyHttpRequest(const InputMessageBase* msg) { HttpContext* http_request = (HttpContext*)msg; const Authenticator* auth = server->options().auth; - if (NULL == auth) { + if (nullptr == auth) { // Fast pass return true; } const Server::MethodProperty* mp = FindMethodPropertyByURI( - http_request->header().uri().path(), server, NULL); - if (mp != NULL && mp->is_builtin_service && + http_request->header().uri().path(), server, nullptr); + if (mp != nullptr && mp->is_builtin_service && mp->service->GetDescriptor() != BadMethodService::descriptor()) { // Builtin services on internal_port doesn't need authentication // Builtin services on the public listener must pass authentication @@ -1416,7 +1411,7 @@ bool VerifyHttpRequest(const InputMessageBase* msg) { const std::string *authorization = http_request->header().GetHeader(common->AUTHORIZATION); - if (authorization == NULL) { + if (authorization == nullptr) { SendUnauthorizedResponse(auth->GetUnauthorizedErrorText(), socket, msg); return false; } @@ -1451,11 +1446,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { const Server* server = static_cast(msg->arg()); ScopedNonServiceError non_service_error(server); - Controller* cntl = new (std::nothrow) Controller; - if (NULL == cntl) { - LOG(FATAL) << "Fail to new Controller"; - return; - } + Controller* cntl = new Controller; HttpResponseSender resp_sender(cntl); resp_sender.set_received_us(msg->received_us()); @@ -1490,7 +1481,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { // atoi/atol/atoll don't support 64-bit integer and can't be used. const std::string* log_id_str = req_header.GetHeader(common->LOG_ID); if (log_id_str) { - char* logid_end = NULL; + char* logid_end = nullptr; errno = 0; uint64_t logid = strtoull(log_id_str->c_str(), &logid_end, 10); if (*logid_end || errno) { @@ -1518,18 +1509,18 @@ void ProcessHttpRequest(InputMessageBase *msg) { if (IsTraceable(trace_id_str)) { uint64_t trace_id = 0; if (trace_id_str) { - trace_id = strtoull(trace_id_str->c_str(), NULL, 10); + trace_id = strtoull(trace_id_str->c_str(), nullptr, 10); } uint64_t span_id = 0; const std::string* span_id_str = req_header.GetHeader("x-bd-span-id"); if (span_id_str) { - span_id = strtoull(span_id_str->c_str(), NULL, 10); + span_id = strtoull(span_id_str->c_str(), nullptr, 10); } uint64_t parent_span_id = 0; const std::string* parent_span_id_str = req_header.GetHeader("x-bd-parent-span-id"); if (parent_span_id_str) { - parent_span_id = strtoull(parent_span_id_str->c_str(), NULL, 10); + parent_span_id = strtoull(parent_span_id_str->c_str(), nullptr, 10); } span = Span::CreateServerSpan( path, trace_id, span_id, parent_span_id, msg->base_real_us()); @@ -1552,7 +1543,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { google::protobuf::Service* svc = server->options().http_master_service; const google::protobuf::MethodDescriptor* md = svc->GetDescriptor()->FindMethodByName(common->DEFAULT_METHOD); - if (md == NULL) { + if (md == nullptr) { cntl->SetFailed(ENOMETHOD, "No default_method in http_master_service"); return; } @@ -1565,12 +1556,12 @@ void ProcessHttpRequest(InputMessageBase *msg) { span->AsParent(); } // `cntl', `req' and `res' will be deleted inside `done' - return svc->CallMethod(md, cntl, NULL, NULL, done); + return svc->CallMethod(md, cntl, nullptr, nullptr, done); } const Server::MethodProperty* const mp = FindMethodPropertyByURI(path, server, &req_header._unresolved_path); - if (NULL == mp) { + if (nullptr == mp) { if (security_mode) { std::string escape_path; WebEscape(path, &escape_path); @@ -1584,7 +1575,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { BadMethodResponse bres; butil::StringSplitter split(path.c_str(), '/'); breq.set_service_name(std::string(split.field(), split.length())); - mp->service->CallMethod(mp->method, cntl, &breq, &bres, NULL); + mp->service->CallMethod(mp->method, cntl, &breq, &bres, nullptr); return; } // Switch to service-specific error. @@ -1667,7 +1658,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { bool is_grpc_ct = false; const HttpContentType content_type = ParseContentType(req_header.content_type(), &is_grpc_ct); - const std::string* encoding = NULL; + const std::string* encoding = nullptr; if (is_http2 && is_grpc_ct) { bool grpc_compressed = false; if (!RemoveGrpcPrefix(&req_body, &grpc_compressed)) { @@ -1676,7 +1667,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { } if (grpc_compressed) { encoding = req_header.GetHeader(common->GRPC_ENCODING); - if (encoding == NULL) { + if (encoding == nullptr) { cntl->SetFailed( EREQUEST, "Fail to find header `grpc-encoding'" " in compressed gRPC request"); @@ -1692,7 +1683,7 @@ void ProcessHttpRequest(InputMessageBase *msg) { } else { // http or h2 but not grpc encoding = req_header.GetHeader(common->CONTENT_ENCODING); } - if (encoding != NULL && *encoding == common->GZIP) { + if (encoding != nullptr && *encoding == common->GZIP) { TRACEPRINTF("Decompressing request=%lu", (unsigned long)req_body.size()); butil::IOBuf uncompressed; @@ -1801,14 +1792,14 @@ const std::string& GetHttpMethodName( } void HttpContext::CheckProgressiveRead(const void* arg, Socket *socket) { - if (arg == NULL || !((Server *)arg)->has_progressive_read_method()) { - // arg == NULL indicates not in server-end + if (arg == nullptr || !((Server *)arg)->has_progressive_read_method()) { + // arg == nullptr indicates not in server-end return; } const Server::MethodProperty *const sp = FindMethodPropertyByURI( header().uri().path(), (Server *)arg, const_cast(&header().unresolved_path())); - if (sp != NULL && sp->params.enable_progressive_read) { + if (sp != nullptr && sp->params.enable_progressive_read) { set_read_body_progressively(true); socket->read_will_be_progressive(CONNECTION_TYPE_SHORT); } diff --git a/src/brpc/policy/hulu_pbrpc_protocol.cpp b/src/brpc/policy/hulu_pbrpc_protocol.cpp index f69804851f..cb397a49b2 100644 --- a/src/brpc/policy/hulu_pbrpc_protocol.cpp +++ b/src/brpc/policy/hulu_pbrpc_protocol.cpp @@ -247,11 +247,11 @@ static void SendHuluResponse(int64_t correlation_id, bool append_body = false; butil::IOBuf res_body_buf; - // `res' can be NULL here, in which case we don't serialize it + // `res' can be nullptr here, in which case we don't serialize it // If user calls `SetFailed' on Controller, we don't serialize // response either CompressType type = cntl->response_compress_type(); - if (res != NULL && !cntl->Failed()) { + if (res != nullptr && !cntl->Failed()) { if (!res->IsInitialized()) { cntl->SetFailed( ERESPONSE, "Missing required fields in response: %s", @@ -373,11 +373,7 @@ void ProcessHuluRequest(InputMessageBase* msg_base) { sample->submit(start_parse_us); } - std::unique_ptr cntl(new (std::nothrow) HuluController()); - if (NULL == cntl.get()) { - LOG(WARNING) << "Fail to new Controller"; - return; - } + std::unique_ptr cntl(new HuluController()); std::unique_ptr req; std::unique_ptr res; @@ -428,7 +424,7 @@ void ProcessHuluRequest(InputMessageBase* msg_base) { span->set_request_size(msg->payload.size() + msg->meta.size() + 12); } - MethodStatus* method_status = NULL; + MethodStatus* method_status = nullptr; do { if (!server->IsRunning()) { cntl->SetFailed(ELOGOFF, "Server is stopping"); @@ -449,7 +445,7 @@ void ProcessHuluRequest(InputMessageBase* msg_base) { const Server::MethodProperty *sp = server_accessor.FindMethodPropertyByNameAndIndex( meta.service_name(), meta.method_index()); - if (NULL == sp) { + if (nullptr == sp) { cntl->SetFailed(ENOMETHOD, "Fail to find method=%d of service=%s", meta.method_index(), meta.service_name().c_str()); break; @@ -458,7 +454,7 @@ void ProcessHuluRequest(InputMessageBase* msg_base) { BadMethodRequest breq; BadMethodResponse bres; breq.set_service_name(meta.service_name()); - sp->service->CallMethod(sp->method, cntl.get(), &breq, &bres, NULL); + sp->service->CallMethod(sp->method, cntl.get(), &breq, &bres, nullptr); break; } if (socket->is_overcrowded() && @@ -562,7 +558,7 @@ bool VerifyHuluRequest(const InputMessageBase* msg_base) { return false; } const Authenticator* auth = server->options().auth; - if (NULL == auth) { + if (nullptr == auth) { // Fast pass (no authentication) return true; } @@ -603,7 +599,7 @@ void ProcessHuluResponse(InputMessageBase* msg_base) { } const bthread_id_t cid = { static_cast(meta.correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -670,7 +666,7 @@ void PackHuluRequest(butil::IOBuf* req_buf, const butil::IOBuf& req_body, const Authenticator* auth) { HuluRpcRequestMeta meta; - if (auth != NULL && auth->GenerateCredential( + if (auth != nullptr && auth->GenerateCredential( meta.mutable_credential_data()) != 0) { return cntl->SetFailed(EREQUEST, "Fail to generate credential"); } @@ -691,7 +687,7 @@ void PackHuluRequest(butil::IOBuf* req_buf, } HuluController* hulu_controller = dynamic_cast(cntl); - if (hulu_controller != NULL) { + if (hulu_controller != nullptr) { if (hulu_controller->request_source_addr() != 0) { meta.set_user_defined_source_addr( hulu_controller->request_source_addr()); diff --git a/src/brpc/policy/list_naming_service.cpp b/src/brpc/policy/list_naming_service.cpp index 3a8ba45e0b..d5eb639e32 100644 --- a/src/brpc/policy/list_naming_service.cpp +++ b/src/brpc/policy/list_naming_service.cpp @@ -45,7 +45,7 @@ int ParseServerList(const char* service_name, LOG(FATAL) << "Param[service_name] is NULL"; return -1; } - for (butil::StringSplitter sp(service_name, ','); sp != NULL; ++sp) { + for (butil::StringSplitter sp(service_name, ','); sp != nullptr; ++sp) { line.assign(sp.field(), sp.length()); butil::StringPiece addr; butil::StringPiece tag; diff --git a/src/brpc/policy/locality_aware_load_balancer.cpp b/src/brpc/policy/locality_aware_load_balancer.cpp index beea51690e..81729d781e 100644 --- a/src/brpc/policy/locality_aware_load_balancer.cpp +++ b/src/brpc/policy/locality_aware_load_balancer.cpp @@ -55,12 +55,12 @@ bool LocalityAwareLoadBalancer::Add(Servers& bg, const Servers& fg, if (bg.weight_tree.capacity() < INITIAL_WEIGHT_TREE_SIZE) { bg.weight_tree.reserve(INITIAL_WEIGHT_TREE_SIZE); } - if (bg.server_map.seek(id) != NULL) { + if (bg.server_map.seek(id) != nullptr) { // The id duplicates. return false; } const size_t* pindex = fg.server_map.seek(id); - if (pindex == NULL) { + if (pindex == nullptr) { // Both fg and bg do not have the id. We create and insert a new Weight // structure. Later when we modify the other buffer(current fg), just // copy the pointer. @@ -106,7 +106,7 @@ bool LocalityAwareLoadBalancer::Add(Servers& bg, const Servers& fg, bool LocalityAwareLoadBalancer::Remove( Servers& bg, SocketId id, LocalityAwareLoadBalancer* lb) { size_t* pindex = bg.server_map.seek(id); - if (NULL == pindex) { + if (nullptr == pindex) { // The id does not exist. return false; } @@ -362,7 +362,7 @@ void LocalityAwareLoadBalancer::Feedback(const CallInfo& info) { return; } const size_t* pindex = s->server_map.seek(info.server_id); - if (NULL == pindex) { + if (nullptr == pindex) { return; } const size_t index = *pindex; @@ -470,9 +470,9 @@ int64_t LocalityAwareLoadBalancer::Weight::Update( return ResetWeight(index, end_time_us); } -LocalityAwareLoadBalancer* LocalityAwareLoadBalancer::New( - const butil::StringPiece&) const { - return new (std::nothrow) LocalityAwareLoadBalancer; +LocalityAwareLoadBalancer* +LocalityAwareLoadBalancer::New(const butil::StringPiece&) const { + return new LocalityAwareLoadBalancer; } void LocalityAwareLoadBalancer::Destroy() { diff --git a/src/brpc/policy/memcache_binary_protocol.cpp b/src/brpc/policy/memcache_binary_protocol.cpp index e3174be588..dcb435b059 100644 --- a/src/brpc/policy/memcache_binary_protocol.cpp +++ b/src/brpc/policy/memcache_binary_protocol.cpp @@ -78,7 +78,7 @@ ParseResult ParseMemcacheMessage(butil::IOBuf* source, Socket* socket, bool /*read_eof*/, const void */*arg*/) { while (1) { const uint8_t* p_mcmagic = (const uint8_t*)source->fetch1(); - if (NULL == p_mcmagic) { + if (nullptr == p_mcmagic) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } if (*p_mcmagic != (uint8_t)MC_MAGIC_RESPONSE) { @@ -86,7 +86,7 @@ ParseResult ParseMemcacheMessage(butil::IOBuf* source, } char buf[24]; const uint8_t* p = (const uint8_t*)source->fetch(buf, sizeof(buf)); - if (NULL == p) { + if (nullptr == p) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } const MemcacheResponseHeader* header = (const MemcacheResponseHeader*)p; @@ -112,7 +112,7 @@ ParseResult ParseMemcacheMessage(butil::IOBuf* source, } MostCommonMessage* msg = static_cast(socket->parsing_context()); - if (msg == NULL) { + if (msg == nullptr) { msg = MostCommonMessage::Get(); socket->reset_parsing_context(msg); } @@ -159,7 +159,7 @@ void ProcessMemcacheResponse(InputMessageBase* msg_base) { DestroyingPtr msg(static_cast(msg_base)); const bthread_id_t cid = msg->pi.id_wait; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -175,7 +175,7 @@ void ProcessMemcacheResponse(InputMessageBase* msg_base) { span->set_start_parse_us(start_parse_us); } const int saved_error = cntl->ErrorCode(); - if (cntl->response() == NULL) { + if (cntl->response() == nullptr) { cntl->SetFailed(ERESPONSE, "response is NULL!"); } else if (cntl->response()->GetDescriptor() != MemcacheResponse::descriptor()) { cntl->SetFailed(ERESPONSE, "Must be MemcacheResponse"); @@ -197,7 +197,7 @@ void ProcessMemcacheResponse(InputMessageBase* msg_base) { void SerializeMemcacheRequest(butil::IOBuf* buf, Controller* cntl, const google::protobuf::Message* request) { - if (request == NULL) { + if (request == nullptr) { return cntl->SetFailed(EREQUEST, "request is NULL"); } if (request->GetDescriptor() != MemcacheRequest::descriptor()) { diff --git a/src/brpc/policy/mongo_protocol.cpp b/src/brpc/policy/mongo_protocol.cpp index ee416421d8..cae64b5b06 100644 --- a/src/brpc/policy/mongo_protocol.cpp +++ b/src/brpc/policy/mongo_protocol.cpp @@ -46,7 +46,7 @@ namespace policy { struct SendMongoResponse : public google::protobuf::Closure { SendMongoResponse(const Server *server) : - status(NULL), + status(nullptr), received_us(0L), server(server) {} ~SendMongoResponse(); @@ -113,22 +113,22 @@ void SendMongoResponse::Run() { ParseResult ParseMongoMessage(butil::IOBuf* source, Socket* socket, bool /*read_eof*/, const void *arg) { const Server* server = static_cast(arg); - // arg may be NULL when the parser is invoked outside of a full Server + // arg may be nullptr when the parser is invoked outside of a full Server // context (e.g. during protocol probing or fuzz testing). Without this // guard, server->options() dereferences a null pointer and crashes. - if (NULL == server) { + if (nullptr == server) { LOG(FATAL) << "Failed creating server"; return MakeParseError(PARSE_ERROR_TRY_OTHERS); } const MongoServiceAdaptor* adaptor = server->options().mongo_service_adaptor; - if (NULL == adaptor) { + if (nullptr == adaptor) { // The server does not enable mongo adaptor. return MakeParseError(PARSE_ERROR_TRY_OTHERS); } char buf[sizeof(mongo_head_t)]; const char *p = (const char *)source->fetch(buf, sizeof(buf)); - if (NULL == p) { + if (nullptr == p) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } mongo_head_t header = *(const mongo_head_t*)p; @@ -153,9 +153,9 @@ ParseResult ParseMongoMessage(butil::IOBuf* source, // socket::_input_message, and created at the first time when msg // comes over the socket. Destroyable *socket_context_msg = socket->parsing_context(); - if (NULL == socket_context_msg) { + if (nullptr == socket_context_msg) { MongoContext *context = adaptor->CreateSocketContext(); - if (NULL == context) { + if (nullptr == context) { return MakeParseError(PARSE_ERROR_NO_RESOURCE); } socket_context_msg = new MongoContextMessage(context); @@ -203,7 +203,7 @@ void ProcessMongoRequest(InputMessageBase* msg_base) { MongoContextMessage *context_msg = dynamic_cast(socket->parsing_context()); - if (NULL == context_msg) { + if (nullptr == context_msg) { LOG(WARNING) << "socket context wasn't set correctly"; return; } @@ -245,7 +245,7 @@ void ProcessMongoRequest(InputMessageBase* msg_base) { break; } - if (NULL == mp || + if (nullptr == mp || mp->service->GetDescriptor() == BadMethodService::descriptor()) { mongo_done->cntl.SetFailed(ENOMETHOD, "Fail to find default_method"); break; diff --git a/src/brpc/policy/mysql/mysql.cpp b/src/brpc/policy/mysql/mysql.cpp index 154f7398d3..8d49d06639 100644 --- a/src/brpc/policy/mysql/mysql.cpp +++ b/src/brpc/policy/mysql/mysql.cpp @@ -91,17 +91,17 @@ void MysqlRequest::SharedCtor() { _has_error = false; _cached_size_ = 0; _has_command = false; - _tx = NULL; - _stmt = NULL; + _tx = nullptr; + _stmt = nullptr; _param_index = 0; } MysqlRequest::~MysqlRequest() { SharedDtor(); - if (_stmt != NULL) { + if (_stmt != nullptr) { delete _stmt; } - _stmt = NULL; + _stmt = nullptr; } void MysqlRequest::SharedDtor() { @@ -115,10 +115,10 @@ void MysqlRequest::Clear() { _has_error = false; _buf.clear(); _has_command = false; - _tx = NULL; + _tx = nullptr; if (_stmt) { delete _stmt; - _stmt = NULL; + _stmt = nullptr; } _param_index = 0; } @@ -141,11 +141,11 @@ void MysqlRequest::MergeFrom(const MysqlRequest& from) { // _tx is a non-owning pointer (never deleted by MysqlRequest): shallow copy. _tx = from._tx; // _stmt is owned (deleted in the dtor): deep-copy to avoid double free. - if (_stmt != NULL) { + if (_stmt != nullptr) { delete _stmt; - _stmt = NULL; + _stmt = nullptr; } - if (from._stmt != NULL) { + if (from._stmt != nullptr) { _stmt = new MysqlStatementStub(*from._stmt); } } @@ -196,7 +196,7 @@ bool MysqlRequest::AddParam(int8_t p) { if (_has_error) { return false; } - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(int8_t): no prepared statement bound to request"; _has_error = true; return false; @@ -212,7 +212,7 @@ bool MysqlRequest::AddParam(int8_t p) { } } bool MysqlRequest::AddParam(uint8_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(uint8_t): no prepared statement bound to request"; _has_error = true; return false; @@ -229,7 +229,7 @@ bool MysqlRequest::AddParam(uint8_t p) { } } bool MysqlRequest::AddParam(int16_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(int16_t): no prepared statement bound to request"; _has_error = true; return false; @@ -245,7 +245,7 @@ bool MysqlRequest::AddParam(int16_t p) { } } bool MysqlRequest::AddParam(uint16_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(uint16_t): no prepared statement bound to request"; _has_error = true; return false; @@ -262,7 +262,7 @@ bool MysqlRequest::AddParam(uint16_t p) { } } bool MysqlRequest::AddParam(int32_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(int32_t): no prepared statement bound to request"; _has_error = true; return false; @@ -278,7 +278,7 @@ bool MysqlRequest::AddParam(int32_t p) { } } bool MysqlRequest::AddParam(uint32_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(uint32_t): no prepared statement bound to request"; _has_error = true; return false; @@ -295,7 +295,7 @@ bool MysqlRequest::AddParam(uint32_t p) { } } bool MysqlRequest::AddParam(int64_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(int64_t): no prepared statement bound to request"; _has_error = true; return false; @@ -312,7 +312,7 @@ bool MysqlRequest::AddParam(int64_t p) { } } bool MysqlRequest::AddParam(uint64_t p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(uint64_t): no prepared statement bound to request"; _has_error = true; return false; @@ -329,7 +329,7 @@ bool MysqlRequest::AddParam(uint64_t p) { } } bool MysqlRequest::AddParam(float p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(float): no prepared statement bound to request"; _has_error = true; return false; @@ -345,7 +345,7 @@ bool MysqlRequest::AddParam(float p) { } } bool MysqlRequest::AddParam(double p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(double): no prepared statement bound to request"; _has_error = true; return false; @@ -361,7 +361,7 @@ bool MysqlRequest::AddParam(double p) { } } bool MysqlRequest::AddParam(const butil::StringPiece& p) { - if (_stmt == NULL || _stmt->stmt() == NULL) { + if (_stmt == nullptr || _stmt->stmt() == nullptr) { LOG(WARNING) << "MysqlRequest::AddParam(StringPiece): no prepared statement bound to request"; _has_error = true; return false; @@ -473,7 +473,7 @@ ParseError MysqlResponse::ConsumePartialIOBuf(butil::IOBuf& buf, if (_other_replies.size() < reply_size()) { MysqlReply* replies = (MysqlReply*)_arena.allocate(sizeof(MysqlReply) * (replies_size - 1)); - if (replies == NULL) { + if (replies == nullptr) { LOG(ERROR) << "Fail to allocate MysqlReply[" << replies_size - 1 << "]"; return PARSE_ERROR_ABSOLUTELY_WRONG; } diff --git a/src/brpc/policy/mysql/mysql.h b/src/brpc/policy/mysql/mysql.h index d55086e713..9ff8d72c42 100644 --- a/src/brpc/policy/mysql/mysql.h +++ b/src/brpc/policy/mysql/mysql.h @@ -42,7 +42,7 @@ namespace brpc { // MysqlRequest request; // request.Query("select * from table"); // MysqlResponse response; -// channel.CallMethod(NULL, &controller, &request, &response, NULL/*done*/); +// channel.CallMethod(nullptr, &controller, &request, &response, nullptr/*done*/); // if (!cntl.Failed()) { // LOG(INFO) << response.reply(0); // } diff --git a/src/brpc/policy/mysql/mysql_auth_packet.h b/src/brpc/policy/mysql/mysql_auth_packet.h index dcefa3c772..1c98f4063b 100644 --- a/src/brpc/policy/mysql/mysql_auth_packet.h +++ b/src/brpc/policy/mysql/mysql_auth_packet.h @@ -54,14 +54,14 @@ static const uint32_t kMaxPayloadLen = (1u << 24) - 1; // // 0xFB is the protocol's NULL marker (a NULL column value in a result // row), NOT an ordinary integer: when |buf| begins with 0xFB the value is -// NULL, *out is set to 0, *is_null (when non-NULL) is set to true, and 1 +// NULL, *out is set to 0, *is_null (when non-nullptr) is set to true, and 1 // (the single byte consumed) is returned. For every non-NULL result // *is_null is set to false. // // Returns 0 on failure: an empty buffer, a truncated multi-byte value, or // the reserved 0xFF marker. On failure *out is set to 0 and *is_null -// (when non-NULL) to false, so a caller that forgets to check the return -// value never reads an uninitialized result. |is_null| may be NULL when +// (when non-nullptr) to false, so a caller that forgets to check the return +// value never reads an uninitialized result. |is_null| may be nullptr when // the caller does not need to distinguish NULL from 0. size_t DecodeLengthEncodedInt(const butil::StringPiece& buf, uint64_t* out, bool* is_null = nullptr); @@ -71,10 +71,10 @@ void EncodeLengthEncodedInt(uint64_t value, std::string* out); // Decodes a length-encoded string into |out_value| and returns the // number of bytes consumed. A leading 0xFB encodes the protocol NULL -// value: when present *out_value is cleared, *is_null (when non-NULL) is +// value: when present *out_value is cleared, *is_null (when non-nullptr) is // set to true, and 1 (the marker byte) is returned. For a non-NULL // string *is_null is set to false. Returns 0 if the leading lenenc-int -// is invalid or the declared payload is truncated. |is_null| may be NULL. +// is invalid or the declared payload is truncated. |is_null| may be nullptr. size_t DecodeLengthEncodedString(const butil::StringPiece& buf, std::string* out_value, bool* is_null = nullptr); diff --git a/src/brpc/policy/mysql/mysql_command.cpp b/src/brpc/policy/mysql/mysql_command.cpp index a4ecf9df35..fa48abbbc4 100644 --- a/src/brpc/policy/mysql/mysql_command.cpp +++ b/src/brpc/policy/mysql/mysql_command.cpp @@ -74,7 +74,7 @@ butil::Status MakePacket(butil::IOBuf* outbuf, const H& head, const F& func, con butil::Status MysqlMakeCommand(butil::IOBuf* outbuf, const MysqlCommandType type, const butil::StringPiece& command) { - if (outbuf == NULL || command.size() == 0) { + if (outbuf == nullptr || command.size() == 0) { return butil::Status(EINVAL, "[MysqlMakeCommand] Param[outbuf] or [stmt] is NULL"); } auto func = @@ -200,7 +200,7 @@ butil::Status MysqlMakeExecuteData(MysqlStatementStub* stmt, break; case MYSQL_FIELD_TYPE_STRING: { const butil::StringPiece* p = (butil::StringPiece*)value; - if (p == NULL || p->data() == NULL) { + if (p == nullptr || p->data() == nullptr) { param_types.types[index + index] = MYSQL_FIELD_TYPE_NULL; param_types.types[index + index + 1] = 0x00; null_mask.mask[index / 8] |= 1 << (index & 7); diff --git a/src/brpc/policy/mysql/mysql_protocol.cpp b/src/brpc/policy/mysql/mysql_protocol.cpp index c82f1a2670..7155406286 100644 --- a/src/brpc/policy/mysql/mysql_protocol.cpp +++ b/src/brpc/policy/mysql/mysql_protocol.cpp @@ -108,12 +108,12 @@ bool PackRequest(butil::IOBuf* buf, const butil::IOBuf& request) { if (accessor.pipelined_count() == MYSQL_PREPARED_STATEMENT) { Socket* sock = accessor.get_sending_socket(); - if (sock == NULL) { + if (sock == nullptr) { LOG(ERROR) << "[MYSQL PACK] get sending socket with NULL"; return false; } auto stub = static_cast(accessor.session_data()); - if (stub == NULL) { + if (stub == nullptr) { LOG(ERROR) << "[MYSQL PACK] get prepare statement with NULL"; return false; } @@ -145,7 +145,7 @@ bool PackRequest(butil::IOBuf* buf, ParseError HandleAuthentication(const InputResponse* msg, const Socket* socket, PipelinedInfo* pi) { const bthread_id_t cid = pi->id_wait; - Controller* cntl = NULL; + Controller* cntl = nullptr; if (bthread_id_lock(cid, (void**)&cntl) != 0) { LOG(ERROR) << "[MYSQL PARSE] fail to lock controller"; return PARSE_ERROR_ABSOLUTELY_WRONG; @@ -153,7 +153,7 @@ ParseError HandleAuthentication(const InputResponse* msg, const Socket* socket, ParseError parseCode = PARSE_OK; const AuthContext* ctx = socket->auth_context(); - if (ctx == NULL) { + if (ctx == nullptr) { parseCode = PARSE_ERROR_ABSOLUTELY_WRONG; LOG(ERROR) << "[MYSQL PARSE] auth context is null"; goto END_OF_AUTH; @@ -286,7 +286,7 @@ ParseError HandlePrepareStatement(const InputResponse* msg, } const MysqlReply::PrepareOk& ok = msg->response.reply(0).prepare_ok(); const bthread_id_t cid = pi->id_wait; - Controller* cntl = NULL; + Controller* cntl = nullptr; if (bthread_id_lock(cid, (void**)&cntl) != 0) { LOG(ERROR) << "[MYSQL PARSE] fail to lock controller"; return PARSE_ERROR_ABSOLUTELY_WRONG; @@ -294,16 +294,16 @@ ParseError HandlePrepareStatement(const InputResponse* msg, ParseError parseCode = PARSE_OK; butil::IOBuf buf; butil::Status st; - MysqlStatementStub* stub = NULL; - MysqlStatement* stmt = NULL; + MysqlStatementStub* stub = nullptr; + MysqlStatement* stmt = nullptr; stub = static_cast(ControllerPrivateAccessor(cntl).session_data()); - if (stub == NULL) { + if (stub == nullptr) { LOG(ERROR) << "[MYSQL PACK] get prepare statement with NULL"; parseCode = PARSE_ERROR_ABSOLUTELY_WRONG; goto END_OF_PREPARE; } stmt = stub->stmt(); - if (stmt == NULL || stmt->param_count() != ok.param_count()) { + if (stmt == nullptr || stmt->param_count() != ok.param_count()) { LOG(ERROR) << "[MYSQL PACK] stmt can't be NULL"; parseCode = PARSE_ERROR_ABSOLUTELY_WRONG; goto END_OF_PREPARE; @@ -356,7 +356,7 @@ ParseResult ParseMysqlMessage(butil::IOBuf* source, } InputResponse* msg = static_cast(socket->parsing_context()); - if (msg == NULL) { + if (msg == nullptr) { msg = new InputResponse; socket->reset_parsing_context(msg); } @@ -413,7 +413,7 @@ void ProcessMysqlResponse(InputMessageBase* msg_base) { DestroyingPtr msg(static_cast(msg_base)); const bthread_id_t cid = msg->id_wait; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -431,7 +431,7 @@ void ProcessMysqlResponse(InputMessageBase* msg_base) { span->set_start_parse_us(start_parse_us); } const int saved_error = cntl->ErrorCode(); - if (cntl->response() != NULL) { + if (cntl->response() != nullptr) { if (cntl->response()->GetDescriptor() != MysqlResponse::descriptor()) { LOG(ERROR) << "[MYSQL PROCESS] response message is not a MysqlResponse"; cntl->SetFailed(ERESPONSE, "Must be MysqlResponse"); @@ -450,7 +450,7 @@ void ProcessMysqlResponse(InputMessageBase* msg_base) { void SerializeMysqlRequest(butil::IOBuf* buf, Controller* cntl, const google::protobuf::Message* request) { - if (request == NULL) { + if (request == nullptr) { LOG(ERROR) << "[MYSQL SERIALIZE] request is NULL"; return cntl->SetFailed(EREQUEST, "request is NULL"); } @@ -473,11 +473,11 @@ void SerializeMysqlRequest(butil::IOBuf* buf, accessor.set_mysql_statement_type(MYSQL_NORMAL_STATEMENT); auto tx = rr->tx(); - if (tx != NULL) { + if (tx != nullptr) { accessor.use_bind_sock(tx->GetSocketId()); } auto st = rr->stmt(); - if (st != NULL) { + if (st != nullptr) { accessor.set_session_data(rr->stmt()); accessor.set_mysql_statement_type(MYSQL_PREPARED_STATEMENT); } @@ -496,12 +496,12 @@ void PackMysqlRequest(butil::IOBuf* buf, ControllerPrivateAccessor accessor(cntl); if (auth) { const MysqlAuthenticator* my_auth(dynamic_cast(auth)); - if (my_auth == NULL) { + if (my_auth == nullptr) { LOG(ERROR) << "[MYSQL PACK] there is not MysqlAuthenticator"; return; } Socket* sock = accessor.get_sending_socket(); - if (sock == NULL) { + if (sock == nullptr) { LOG(ERROR) << "[MYSQL PACK] get sending socket with NULL"; return; } diff --git a/src/brpc/policy/mysql/mysql_reply.cpp b/src/brpc/policy/mysql/mysql_reply.cpp index 46778f2e64..2f3a97078c 100644 --- a/src/brpc/policy/mysql/mysql_reply.cpp +++ b/src/brpc/policy/mysql/mysql_reply.cpp @@ -40,9 +40,9 @@ namespace brpc { template inline bool my_alloc_check(butil::Arena* arena, const size_t n, Type*& pointer) { - if (pointer == NULL) { + if (pointer == nullptr) { pointer = (Type*)arena->allocate(sizeof(Type) * n); - if (pointer == NULL) { + if (pointer == nullptr) { LOG(ERROR) << "my_alloc_check: arena failed to allocate " << (sizeof(Type) * n) << " bytes (n=" << n << ")"; return false; @@ -56,9 +56,9 @@ inline bool my_alloc_check(butil::Arena* arena, const size_t n, Type*& pointer) template <> inline bool my_alloc_check(butil::Arena* arena, const size_t n, char*& pointer) { - if (pointer == NULL) { + if (pointer == nullptr) { pointer = (char*)arena->allocate(sizeof(char) * n); - if (pointer == NULL) { + if (pointer == nullptr) { LOG(ERROR) << "my_alloc_check: arena failed to allocate " << n << " char bytes"; return false; } @@ -120,7 +120,7 @@ const char* MysqlRspTypeToString(MysqlRspType type) { inline bool is_full_package(const butil::IOBuf& buf) { uint8_t header[4]; const uint8_t* p = (const uint8_t*)buf.fetch(header, sizeof(header)); - if (p == NULL) { + if (p == nullptr) { return false; } uint32_t payload_size = mysql_uint3korr(p); @@ -133,7 +133,7 @@ inline bool is_full_package(const butil::IOBuf& buf) { inline bool is_an_eof(const butil::IOBuf& buf) { uint8_t tmp[5]; const uint8_t* p = (const uint8_t*)buf.fetch(tmp, sizeof(tmp)); - if (p == NULL) { + if (p == nullptr) { return false; } uint8_t type = p[4]; @@ -222,7 +222,7 @@ ParseError MysqlReply::ConsumePartialIOBuf(butil::IOBuf& buf, // never coalesced. uint8_t status[4 + 2]; const uint8_t* sp = (const uint8_t*)buf.fetch(status, sizeof(status)); - const bool fast_auth_success = (sp != NULL && sp[5] == 0x03); + const bool fast_auth_success = (sp != nullptr && sp[5] == 0x03); if (fast_auth_success) { // Determine, WITHOUT consuming anything, whether the OK packet // that follows the fast-auth marker is also fully buffered. @@ -455,7 +455,7 @@ ParseError MysqlReply::Auth::Parse(butil::IOBuf& buf, butil::Arena* arena) { { butil::IOBuf version; buf.cut_until(&version, delim); - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, version.size(), d)); version.copy_to(d); _version.set(d, version.size()); @@ -468,7 +468,7 @@ ParseError MysqlReply::Auth::Parse(butil::IOBuf& buf, butil::Arena* arena) { { butil::IOBuf salt; buf.cut_until(&salt, delim); - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, salt.size(), d)); salt.copy_to(d); _salt.set(d, salt.size()); @@ -494,7 +494,7 @@ ParseError MysqlReply::Auth::Parse(butil::IOBuf& buf, butil::Arena* arena) { { butil::IOBuf salt2; buf.cut_until(&salt2, delim); - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, salt2.size(), d)); salt2.copy_to(d); _salt2.set(d, salt2.size()); @@ -505,7 +505,7 @@ ParseError MysqlReply::Auth::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, _auth_plugin_length, d)); buf.cutn(d, _auth_plugin_length); _auth_plugin.set(d, _auth_plugin_length); @@ -529,12 +529,12 @@ ParseError MysqlReply::AuthMoreData::Parse(butil::IOBuf& buf, butil::Arena* aren buf.pop_front(1); const int64_t len = (int64_t)header.payload_size - 1; if (len > 0) { - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, d)); buf.cutn(d, len); _data.set(d, len); } else { - _data.set(NULL, 0); + _data.set(nullptr, 0); } set_parsed(); return PARSE_OK; @@ -587,7 +587,7 @@ ParseError MysqlReply::Column::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* catalog = NULL; + char* catalog = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, catalog)); buf.cutn(catalog, len); _catalog.set(catalog, len); @@ -598,7 +598,7 @@ ParseError MysqlReply::Column::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* database = NULL; + char* database = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, database)); buf.cutn(database, len); _database.set(database, len); @@ -609,7 +609,7 @@ ParseError MysqlReply::Column::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* table = NULL; + char* table = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, table)); buf.cutn(table, len); _table.set(table, len); @@ -620,7 +620,7 @@ ParseError MysqlReply::Column::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* origin_table = NULL; + char* origin_table = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, origin_table)); buf.cutn(origin_table, len); _origin_table.set(origin_table, len); @@ -631,7 +631,7 @@ ParseError MysqlReply::Column::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* name = NULL; + char* name = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, name)); buf.cutn(name, len); _name.set(name, len); @@ -642,7 +642,7 @@ ParseError MysqlReply::Column::Parse(butil::IOBuf& buf, butil::Arena* arena) { << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* origin_name = NULL; + char* origin_name = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, origin_name)); buf.cutn(origin_name, len); _origin_name.set(origin_name, len); @@ -698,7 +698,7 @@ ParseError MysqlReply::Ok::Parse(butil::IOBuf& buf, butil::Arena* arena) { new_size = buf.size(); if (old_size - new_size < header.payload_size) { const int64_t len = header.payload_size - (old_size - new_size); - char* msg = NULL; + char* msg = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, msg)); buf.cutn(msg, len); _msg.set(msg, len); @@ -746,7 +746,7 @@ ParseError MysqlReply::Error::Parse(butil::IOBuf& buf, butil::Arena* arena) { } buf.pop_front(1); // '#' // 5 byte server status - char* status = NULL; + char* status = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, 5, status)); buf.cutn(status, 5); _status.set(status, 5); @@ -760,7 +760,7 @@ ParseError MysqlReply::Error::Parse(butil::IOBuf& buf, butil::Arena* arena) { return PARSE_ERROR_ABSOLUTELY_WRONG; } uint64_t len = header.payload_size - 9; - char* msg = NULL; + char* msg = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, msg)); buf.cutn(msg, len); _msg.set(msg, len); @@ -798,7 +798,7 @@ ParseError MysqlReply::Row::Parse(butil::IOBuf& buf, // (length-encoded in the result-set header), so a large value would // otherwise be an unbounded stack allocation / stack overflow. const uint64_t size = ((column_count + 7 + 2) >> 3); - uint8_t* null_mask = NULL; + uint8_t* null_mask = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, (size_t)size, null_mask)); for (uint64_t i = 0; i < size; ++i) { null_mask[i] = 0; @@ -849,39 +849,39 @@ ParseError MysqlReply::Field::Parse(butil::IOBuf& buf, break; case MYSQL_FIELD_TYPE_TINY: if (column->_flag & MYSQL_UNSIGNED_FLAG) { - _data.tiny = strtoul(str.to_string().c_str(), NULL, 10); + _data.tiny = strtoul(str.to_string().c_str(), nullptr, 10); } else { - _data.stiny = strtol(str.to_string().c_str(), NULL, 10); + _data.stiny = strtol(str.to_string().c_str(), nullptr, 10); } break; case MYSQL_FIELD_TYPE_SHORT: case MYSQL_FIELD_TYPE_YEAR: if (column->_flag & MYSQL_UNSIGNED_FLAG) { - _data.small = strtoul(str.to_string().c_str(), NULL, 10); + _data.small = strtoul(str.to_string().c_str(), nullptr, 10); } else { - _data.ssmall = strtol(str.to_string().c_str(), NULL, 10); + _data.ssmall = strtol(str.to_string().c_str(), nullptr, 10); } break; case MYSQL_FIELD_TYPE_INT24: case MYSQL_FIELD_TYPE_LONG: if (column->_flag & MYSQL_UNSIGNED_FLAG) { - _data.integer = strtoul(str.to_string().c_str(), NULL, 10); + _data.integer = strtoul(str.to_string().c_str(), nullptr, 10); } else { - _data.sinteger = strtol(str.to_string().c_str(), NULL, 10); + _data.sinteger = strtol(str.to_string().c_str(), nullptr, 10); } break; case MYSQL_FIELD_TYPE_LONGLONG: if (column->_flag & MYSQL_UNSIGNED_FLAG) { - _data.bigint = strtoul(str.to_string().c_str(), NULL, 10); + _data.bigint = strtoul(str.to_string().c_str(), nullptr, 10); } else { - _data.sbigint = strtol(str.to_string().c_str(), NULL, 10); + _data.sbigint = strtol(str.to_string().c_str(), nullptr, 10); } break; case MYSQL_FIELD_TYPE_FLOAT: - _data.float32 = strtof(str.to_string().c_str(), NULL); + _data.float32 = strtof(str.to_string().c_str(), nullptr); break; case MYSQL_FIELD_TYPE_DOUBLE: - _data.float64 = strtod(str.to_string().c_str(), NULL); + _data.float64 = strtod(str.to_string().c_str(), nullptr); break; case MYSQL_FIELD_TYPE_DECIMAL: case MYSQL_FIELD_TYPE_NEWDECIMAL: @@ -902,7 +902,7 @@ ParseError MysqlReply::Field::Parse(butil::IOBuf& buf, case MYSQL_FIELD_TYPE_NEWDATE: case MYSQL_FIELD_TYPE_TIMESTAMP: case MYSQL_FIELD_TYPE_DATETIME: { - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, d)); str.copy_to(d); _data.str.set(d, len); @@ -1017,7 +1017,7 @@ ParseError MysqlReply::Field::Parse(butil::IOBuf& buf, << " exceeds remaining buffer size " << buf.size(); return PARSE_ERROR_ABSOLUTELY_WRONG; } - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, len, d)); buf.cutn(d, len); _data.str.set(d, len); @@ -1089,7 +1089,7 @@ ParseError MysqlReply::Field::ParseBinaryTime(butil::IOBuf& buf, } size_t i = 0; - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, dstlen + 2, d)); d[dstlen] = '\0'; d[dstlen + 1] = '\0'; @@ -1224,7 +1224,7 @@ ParseError MysqlReply::Field::ParseBinaryDataTime(butil::IOBuf& buf, } size_t i = 0; - char* d = NULL; + char* d = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, dstlen, d)); // Read only the fields present for this `len`; absent fields are 0. // len == 0 -> no bytes (all-zero value). @@ -1392,8 +1392,8 @@ ParseError MysqlReply::ResultSet::Parse(butil::IOBuf& buf, butil::Arena* arena, break; } // allocate memory for row and fields - Row* row = NULL; - Field* fields = NULL; + Row* row = nullptr; + Field* fields = nullptr; MY_ALLOC_CHECK(my_alloc_check(arena, 1, row)); MY_ALLOC_CHECK(my_alloc_check(arena, _header._column_count, fields)); row->_fields = fields; diff --git a/src/brpc/policy/mysql/mysql_reply.h b/src/brpc/policy/mysql/mysql_reply.h index 2cb90528fa..14bf0dbd26 100644 --- a/src/brpc/policy/mysql/mysql_reply.h +++ b/src/brpc/policy/mysql/mysql_reply.h @@ -298,7 +298,7 @@ class MysqlReply { float float32; double float64; butil::StringPiece str; - } _data = {.str = NULL}; + } _data = {.str = nullptr}; MysqlFieldType _type; bool _unsigned; bool _is_nil; @@ -374,7 +374,7 @@ class MysqlReply { }; // Mysql result set struct ResultSet : private CheckParsed { - ResultSet() : _columns(NULL), _row_count(0) { + ResultSet() : _columns(nullptr), _row_count(0) { _cur = _first = _last = &_dummy; } ParseError Parse(butil::IOBuf& buf, butil::Arena* arena, bool binary); @@ -589,7 +589,7 @@ inline uint8_t MysqlReply::AuthMoreData::seq() const { return _seq; } // mysql prepared statement ok -inline MysqlReply::PrepareOk::PrepareOk() : _params(NULL), _columns(NULL) {} +inline MysqlReply::PrepareOk::PrepareOk() : _params(nullptr), _columns(nullptr) {} inline uint32_t MysqlReply::PrepareOk::stmt_id() const { CHECK(_header._stmt_id > 0) << "stmt id is wrong"; return _header._stmt_id; @@ -691,7 +691,7 @@ inline uint8_t MysqlReply::Column::decimal() const { return _decimal; } // mysql reply row -inline MysqlReply::Row::Row() : _fields(NULL), _field_count(0), _next(NULL) {} +inline MysqlReply::Row::Row() : _fields(nullptr), _field_count(0), _next(nullptr) {} inline uint64_t MysqlReply::Row::field_count() const { return _field_count; } diff --git a/src/brpc/policy/mysql/mysql_statement.cpp b/src/brpc/policy/mysql/mysql_statement.cpp index 5f41088ab8..d4018c8ed8 100644 --- a/src/brpc/policy/mysql/mysql_statement.cpp +++ b/src/brpc/policy/mysql/mysql_statement.cpp @@ -46,7 +46,7 @@ uint32_t MysqlStatement::StatementId(SocketId socket_id) const { return 0; } const MysqlStatementId* p = ptr->seek(socket_id); - if (p == NULL) { + if (p == nullptr) { LOG(WARNING) << "MysqlStatement::StatementId: no prepared statement id " "cached for socket_id=" << socket_id << " (statement not found / not prepared on this " diff --git a/src/brpc/policy/mysql/mysql_statement_inl.h b/src/brpc/policy/mysql/mysql_statement_inl.h index 3e1323c87a..9dbf07f52e 100644 --- a/src/brpc/policy/mysql/mysql_statement_inl.h +++ b/src/brpc/policy/mysql/mysql_statement_inl.h @@ -45,7 +45,7 @@ inline size_t my_init_kv(MysqlStatementKVMap& m) { inline size_t my_update_kv(MysqlStatementKVMap& m, SocketId key, MysqlStatementId value) { MysqlStatementId* p = m.seek(key); - if (p == NULL) { + if (p == nullptr) { m.insert(key, value); } else { *p = value; diff --git a/src/brpc/policy/mysql/mysql_transaction.cpp b/src/brpc/policy/mysql/mysql_transaction.cpp index 58871dd952..267ba00961 100644 --- a/src/brpc/policy/mysql/mysql_transaction.cpp +++ b/src/brpc/policy/mysql/mysql_transaction.cpp @@ -36,14 +36,14 @@ SocketId MysqlTransaction::GetSocketId() const { bool MysqlTransaction::DoneTransaction(const char* command) { bool rc = false; MysqlRequest request(this); - if (_socket == NULL) { // must already commit or rollback, return true. + if (_socket == nullptr) { // must already commit or rollback, return true. return true; } else if (!request.Query(command)) { LOG(ERROR) << "Fail to query command" << command; } else { MysqlResponse response; Controller cntl; - _channel.CallMethod(NULL, &cntl, &request, &response, NULL); + _channel.CallMethod(nullptr, &cntl, &request, &response, nullptr); if (!cntl.Failed()) { if (response.reply(0).is_ok()) { rc = true; @@ -67,7 +67,7 @@ MysqlTransactionUniquePtr NewMysqlTransaction(Channel& channel, if (channel.options().connection_type == CONNECTION_TYPE_SINGLE) { LOG(ERROR) << "mysql transaction can't use connection type 'single'"; - return NULL; + return nullptr; } std::stringstream ss; // repeatable read is mysql default isolation level, so ignore it. @@ -85,21 +85,21 @@ MysqlTransactionUniquePtr NewMysqlTransaction(Channel& channel, MysqlRequest request; if (!request.Query(ss.str())) { LOG(ERROR) << "Fail to query command" << ss.str(); - return NULL; + return nullptr; } MysqlTransactionUniquePtr tx; MysqlResponse response; Controller cntl; ControllerPrivateAccessor(&cntl).set_bind_sock_action(BIND_SOCK_RESERVE); - channel.CallMethod(NULL, &cntl, &request, &response, NULL); + channel.CallMethod(nullptr, &cntl, &request, &response, nullptr); if (!cntl.Failed()) { // repeatable read isolation send one reply, other isolation has two reply if ((opts.isolation_level == MysqlIsoRepeatableRead && response.reply(0).is_ok()) || (response.reply(0).is_ok() && response.reply(1).is_ok())) { SocketUniquePtr socket; ControllerPrivateAccessor(&cntl).get_bind_sock(&socket); - if (socket == NULL) { + if (socket == nullptr) { LOG(ERROR) << "Fail create mysql transaction, get bind socket failed"; } else { tx.reset(new MysqlTransaction(channel, socket, cntl.connection_type())); @@ -111,7 +111,7 @@ MysqlTransactionUniquePtr NewMysqlTransaction(Channel& channel, // ref (which would leak the pooled connection). SocketUniquePtr socket; ControllerPrivateAccessor(&cntl).get_bind_sock(&socket); - if (socket != NULL && cntl.connection_type() == CONNECTION_TYPE_POOLED) { + if (socket != nullptr && cntl.connection_type() == CONNECTION_TYPE_POOLED) { socket->ReturnToPool(); } LOG(ERROR) << "Fail create mysql transaction, " << response; diff --git a/src/brpc/policy/nacos_naming_service.cpp b/src/brpc/policy/nacos_naming_service.cpp index c4cc46b225..95c3e4d537 100644 --- a/src/brpc/policy/nacos_naming_service.cpp +++ b/src/brpc/policy/nacos_naming_service.cpp @@ -97,7 +97,7 @@ int NacosNamingService::RefreshAccessToken(const char *service_name) { auto iter_ttl = doc.FindMember("tokenTtl"); if (iter_ttl != doc.MemberEnd() && iter_ttl->value.IsInt()) { - _token_expire_time = time(NULL) + iter_ttl->value.GetInt() - 10; + _token_expire_time = time(nullptr) + iter_ttl->value.GetInt() - 10; } else { _token_expire_time = 0; } @@ -257,7 +257,7 @@ int NacosNamingService::GetServers(const char *service_name, !FLAGS_nacos_username.empty() && !FLAGS_nacos_password.empty(); const bool has_invalid_access_token = _access_token.empty() || - (0 < _token_expire_time && _token_expire_time <= time(NULL)); + (0 < _token_expire_time && _token_expire_time <= time(nullptr)); bool token_changed = false; if (authentiction_enabled && has_invalid_access_token) { diff --git a/src/brpc/policy/nova_pbrpc_protocol.cpp b/src/brpc/policy/nova_pbrpc_protocol.cpp index a1d88f2562..224da322d1 100644 --- a/src/brpc/policy/nova_pbrpc_protocol.cpp +++ b/src/brpc/policy/nova_pbrpc_protocol.cpp @@ -112,7 +112,7 @@ void ProcessNovaResponse(InputMessageBase* msg_base) { // Fetch correlation id that we saved before in `PackNovaRequest' const bthread_id_t cid = { static_cast(socket->correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -131,7 +131,7 @@ void ProcessNovaResponse(InputMessageBase* msg_base) { // Fetch compress flag from nshead char buf[sizeof(nshead_t)]; const char *p = (const char *)msg->meta.fetch(buf, sizeof(buf)); - if (NULL == p) { + if (nullptr == p) { LOG(WARNING) << "Fail to fetch nshead from client=" << socket->remote_side(); return; diff --git a/src/brpc/policy/nshead_mcpack_protocol.cpp b/src/brpc/policy/nshead_mcpack_protocol.cpp index 8ba49f936e..d242808f65 100644 --- a/src/brpc/policy/nshead_mcpack_protocol.cpp +++ b/src/brpc/policy/nshead_mcpack_protocol.cpp @@ -82,7 +82,7 @@ void NsheadMcpackAdaptor::SerializeResponseToIOBuf( type = COMPRESS_TYPE_NONE; } - if (pb_res == NULL) { + if (pb_res == nullptr) { cntl->CloseConnection("response was not created yet"); return; } @@ -103,7 +103,7 @@ void ProcessNsheadMcpackResponse(InputMessageBase* msg_base) { // Fetch correlation id that we saved before in `PackNsheadMcpackRequest' const bthread_id_t cid = { static_cast(socket->correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -120,7 +120,7 @@ void ProcessNsheadMcpackResponse(InputMessageBase* msg_base) { } const int saved_error = cntl->ErrorCode(); google::protobuf::Message* res = cntl->response(); - if (res == NULL) { + if (res == nullptr) { // silently ignore response. return; } diff --git a/src/brpc/policy/nshead_protocol.cpp b/src/brpc/policy/nshead_protocol.cpp index 82f696e3c2..72fc89947d 100644 --- a/src/brpc/policy/nshead_protocol.cpp +++ b/src/brpc/policy/nshead_protocol.cpp @@ -42,7 +42,7 @@ void bthread_assign_data(void* data); namespace brpc { NsheadClosure::NsheadClosure(void* additional_space) - : _server(NULL) + : _server(nullptr) , _received_us(0) , _do_respond(true) , _additional_space(additional_space) { @@ -231,7 +231,7 @@ void ProcessNsheadRequest(InputMessageBase* msg_base) { const nshead_t *req_head = (const nshead_t *)p; NsheadService* service = server->options().nshead_service; - if (service == NULL) { + if (service == nullptr) { LOG_EVERY_SECOND(WARNING) << "Received nshead request however the server does not set" " ServerOptions.nshead_service, close the connection."; @@ -261,7 +261,7 @@ void ProcessNsheadRequest(InputMessageBase* msg_base) { CHECK(method_status->OnRequested()); } - void* sub_space = NULL; + void* sub_space = nullptr; if (service->_additional_space) { sub_space = (char*)space + sizeof(NsheadClosure); } @@ -359,7 +359,7 @@ void ProcessNsheadResponse(InputMessageBase* msg_base) { // Fetch correlation id that we saved before in `PackNsheadRequest' const CallId cid = { static_cast(msg->socket()->correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -377,7 +377,7 @@ void ProcessNsheadResponse(InputMessageBase* msg_base) { // MUST be NsheadMessage (checked in SerializeNsheadRequest) NsheadMessage* response = (NsheadMessage*)cntl->response(); const int saved_error = cntl->ErrorCode(); - if (response != NULL) { + if (response != nullptr) { msg->meta.copy_to(&response->head, sizeof(nshead_t)); msg->payload.swap(response->body); } // else just ignore the response. @@ -399,13 +399,13 @@ bool VerifyNsheadRequest(const InputMessageBase* msg_base) { void SerializeNsheadRequest(butil::IOBuf* request_buf, Controller* cntl, const google::protobuf::Message* req_base) { - if (req_base == NULL) { + if (req_base == nullptr) { return cntl->SetFailed(EREQUEST, "request is NULL"); } if (req_base->GetDescriptor() != NsheadMessage::descriptor()) { return cntl->SetFailed(EINVAL, "Type of request must be NsheadMessage"); } - if (cntl->response() != NULL && + if (cntl->response() != nullptr && cntl->response()->GetDescriptor() != NsheadMessage::descriptor()) { return cntl->SetFailed(EINVAL, "Type of response must be NsheadMessage"); } diff --git a/src/brpc/policy/p2c_ewma_load_balancer.cpp b/src/brpc/policy/p2c_ewma_load_balancer.cpp index 2b3f5bb594..bd71d34fdf 100644 --- a/src/brpc/policy/p2c_ewma_load_balancer.cpp +++ b/src/brpc/policy/p2c_ewma_load_balancer.cpp @@ -72,12 +72,12 @@ bool P2CEwmaLoadBalancer::Add(Servers& bg, const Servers& fg, if (bg.server_list.capacity() < 128) { bg.server_list.reserve(128); } - if (bg.server_map.seek(id.id) != NULL) { + if (bg.server_map.seek(id.id) != nullptr) { return false; } - ServerInfo info = { id.id, WeightOfTag(id.tag), NULL }; + ServerInfo info = { id.id, WeightOfTag(id.tag), nullptr }; const size_t* pindex = fg.server_map.seek(id.id); - if (pindex == NULL) { + if (pindex == nullptr) { // Both buffers do not have the server. Create the stat structure // which will be shared by both buffers. info.stat = std::make_shared(); @@ -92,7 +92,7 @@ bool P2CEwmaLoadBalancer::Add(Servers& bg, const Servers& fg, bool P2CEwmaLoadBalancer::Remove(Servers& bg, const ServerId& id) { size_t* pindex = bg.server_map.seek(id.id); - if (pindex == NULL) { + if (pindex == nullptr) { return false; } const size_t index = *pindex; @@ -181,7 +181,7 @@ int P2CEwmaLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { const int64_t now_us = in.begin_time_us > 0 ? in.begin_time_us : butil::gettimeofday_us(); - const ServerInfo* best = NULL; + const ServerInfo* best = nullptr; double best_score = 0; SocketUniquePtr best_ptr; // Score the server at `index' and keep it if it beats the current best. @@ -196,7 +196,7 @@ int P2CEwmaLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { return; } const double score = Score(info, now_us); - if (best == NULL || score < best_score) { + if (best == nullptr || score < best_score) { best = &info; best_score = score; best_ptr.swap(ptr); @@ -233,7 +233,7 @@ int P2CEwmaLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { chosen[nchosen++] = index; consider(index); } - if (best == NULL) { + if (best == nullptr) { // All sampled servers were excluded or unavailable, fall back // to scoring the whole list before violating exclusion below. for (size_t i = 0; i < n; ++i) { @@ -242,7 +242,7 @@ int P2CEwmaLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { } } - if (best == NULL) { + if (best == nullptr) { // Always take last chance: all servers are excluded, send to any // available one as rr/random do. for (size_t i = 0; i < n; ++i) { @@ -251,7 +251,7 @@ int P2CEwmaLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { break; } } - if (best == NULL) { + if (best == nullptr) { return EHOSTDOWN; } } @@ -269,7 +269,7 @@ void P2CEwmaLoadBalancer::Feedback(const CallInfo& info) { return; } const size_t* pindex = s->server_map.seek(info.server_id); - if (pindex == NULL) { + if (pindex == nullptr) { // The server was removed after selection, its stat is gone with it. return; } @@ -317,10 +317,10 @@ void P2CEwmaLoadBalancer::Feedback(const CallInfo& info) { P2CEwmaLoadBalancer* P2CEwmaLoadBalancer::New( const butil::StringPiece& params) const { - P2CEwmaLoadBalancer* lb = new (std::nothrow) P2CEwmaLoadBalancer; - if (lb != NULL && !lb->SetParameters(params)) { + P2CEwmaLoadBalancer* lb = new P2CEwmaLoadBalancer; + if (!lb->SetParameters(params)) { delete lb; - lb = NULL; + lb = nullptr; } return lb; } diff --git a/src/brpc/policy/public_pbrpc_protocol.cpp b/src/brpc/policy/public_pbrpc_protocol.cpp index a4298a15da..111a863e91 100644 --- a/src/brpc/policy/public_pbrpc_protocol.cpp +++ b/src/brpc/policy/public_pbrpc_protocol.cpp @@ -74,7 +74,7 @@ void PublicPbrpcServiceAdaptor::ParseNsheadMeta( const RequestBody& body = pbreq.requestbody(0); const Server::MethodProperty *sp = ServerPrivateAccessor(&svr) .FindMethodPropertyByNameAndIndex(body.service(), body.method_id()); - if (NULL == sp) { + if (nullptr == sp) { cntl->SetFailed(ENOMETHOD, "Fail to find method by service=%s method_id=%u", body.service().c_str(), body.method_id()); return; @@ -165,7 +165,7 @@ void ProcessPublicPbrpcResponse(InputMessageBase* msg_base) { const ResponseHead& head = pbres.responsehead(); const ResponseBody& body = pbres.responsebody(0); const bthread_id_t cid = { static_cast(body.id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -241,7 +241,7 @@ void PackPublicPbrpcRequest(butil::IOBuf* buf, head->set_connection(!short_connection); head->set_charset(CHARSET); char time_buf[128]; - time_t now = time(NULL); + time_t now = time(nullptr); strftime(time_buf, sizeof(time_buf), TIME_FORMAT, localtime(&now)); head->set_create_time(time_buf); if (controller->has_log_id()) { diff --git a/src/brpc/policy/randomized_load_balancer.cpp b/src/brpc/policy/randomized_load_balancer.cpp index 4ff43d753f..a76eaa91b6 100644 --- a/src/brpc/policy/randomized_load_balancer.cpp +++ b/src/brpc/policy/randomized_load_balancer.cpp @@ -134,10 +134,10 @@ int RandomizedLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { RandomizedLoadBalancer* RandomizedLoadBalancer::New( const butil::StringPiece& params) const { - RandomizedLoadBalancer* lb = new (std::nothrow) RandomizedLoadBalancer; - if (lb && !lb->SetParameters(params)) { + RandomizedLoadBalancer* lb = new RandomizedLoadBalancer; + if (!lb->SetParameters(params)) { delete lb; - lb = NULL; + lb = nullptr; } return lb; } diff --git a/src/brpc/policy/redis_protocol.cpp b/src/brpc/policy/redis_protocol.cpp index 7dc5b5b8f3..3009d7b7aa 100644 --- a/src/brpc/policy/redis_protocol.cpp +++ b/src/brpc/policy/redis_protocol.cpp @@ -64,7 +64,7 @@ int ConsumeCommand(RedisConnContext* ctx, if (ctx->transaction_handler) { result = ctx->transaction_handler->Run(ctx, args, &output, flush_batched); if (result == REDIS_CMD_HANDLED) { - ctx->transaction_handler.reset(NULL); + ctx->transaction_handler.reset(nullptr); } else if (result == REDIS_CMD_BATCHED) { LOG(ERROR) << "BATCHED should not be returned by a transaction handler."; return -1; @@ -126,7 +126,7 @@ ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket, return MakeParseError(PARSE_ERROR_TRY_OTHERS); } RedisConnContext* ctx = static_cast(socket->parsing_context()); - if (ctx == NULL) { + if (ctx == nullptr) { ctx = new RedisConnContext(rs); socket->reset_parsing_context(ctx); } @@ -182,7 +182,7 @@ ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket, do { InputResponse* msg = static_cast(socket->parsing_context()); - if (msg == NULL) { + if (msg == nullptr) { msg = new InputResponse; socket->reset_parsing_context(msg); } @@ -228,7 +228,7 @@ void ProcessRedisResponse(InputMessageBase* msg_base) { DestroyingPtr msg(static_cast(msg_base)); const bthread_id_t cid = msg->id_wait; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -244,7 +244,7 @@ void ProcessRedisResponse(InputMessageBase* msg_base) { span->set_start_parse_us(start_parse_us); } const int saved_error = cntl->ErrorCode(); - if (cntl->response() != NULL) { + if (cntl->response() != nullptr) { if (cntl->response()->GetDescriptor() != RedisResponse::descriptor()) { cntl->SetFailed(ERESPONSE, "Must be RedisResponse"); } else { @@ -273,7 +273,7 @@ void ProcessRedisRequest(InputMessageBase* msg_base) { } void SerializeRedisRequest(butil::IOBuf* buf, Controller* cntl, const google::protobuf::Message* request) { - if (request == NULL) { + if (request == nullptr) { return cntl->SetFailed(EREQUEST, "request is NULL"); } if (request->GetDescriptor() != RedisRequest::descriptor()) { @@ -310,7 +310,7 @@ void PackRedisRequest(butil::IOBuf* buf, buf->append(auth_str); const RedisAuthenticator* redis_auth = dynamic_cast(auth); - if (redis_auth == NULL) { + if (redis_auth == nullptr) { return cntl->SetFailed(EREQUEST, "Fail to generate credential"); } ControllerPrivateAccessor(cntl).set_auth_flags( diff --git a/src/brpc/policy/remote_file_naming_service.cpp b/src/brpc/policy/remote_file_naming_service.cpp index c5aeac9e75..b2e929544b 100644 --- a/src/brpc/policy/remote_file_naming_service.cpp +++ b/src/brpc/policy/remote_file_naming_service.cpp @@ -61,7 +61,7 @@ int RemoteFileNamingService::GetServers(const char *service_name_cstr, std::vector* servers) { servers->clear(); - if (_channel == NULL) { + if (_channel == nullptr) { butil::StringPiece tmpname(service_name_cstr); size_t pos = tmpname.find("://"); butil::StringPiece proto; @@ -105,7 +105,7 @@ int RemoteFileNamingService::GetServers(const char *service_name_cstr, Controller cntl; cntl.http_request().uri() = _path; - _channel->CallMethod(NULL, &cntl, NULL, NULL, NULL); + _channel->CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr); if (cntl.Failed()) { LOG(WARNING) << "Fail to access " << _server_addr << _path << ": " << cntl.ErrorText(); diff --git a/src/brpc/policy/round_robin_load_balancer.cpp b/src/brpc/policy/round_robin_load_balancer.cpp index cf67624085..c219808b6a 100644 --- a/src/brpc/policy/round_robin_load_balancer.cpp +++ b/src/brpc/policy/round_robin_load_balancer.cpp @@ -134,10 +134,10 @@ int RoundRobinLoadBalancer::SelectServer(const SelectIn& in, SelectOut* out) { RoundRobinLoadBalancer* RoundRobinLoadBalancer::New( const butil::StringPiece& params) const { - RoundRobinLoadBalancer* lb = new (std::nothrow) RoundRobinLoadBalancer; - if (lb && !lb->SetParameters(params)) { + RoundRobinLoadBalancer* lb = new RoundRobinLoadBalancer; + if (!lb->SetParameters(params)) { delete lb; - lb = NULL; + lb = nullptr; } return lb; } diff --git a/src/brpc/policy/rtmp_protocol.cpp b/src/brpc/policy/rtmp_protocol.cpp index 62322018d1..2b50c6a3f0 100644 --- a/src/brpc/policy/rtmp_protocol.cpp +++ b/src/brpc/policy/rtmp_protocol.cpp @@ -106,7 +106,7 @@ static const size_t MAGIC_NUMBER_SIZE = 4; /* magic number */ // ========== The handshaking described in RTMP spec ========== // The random data for handshaking -static butil::IOBuf* s_rtmp_handshake_server_random = NULL; +static butil::IOBuf* s_rtmp_handshake_server_random = nullptr; static pthread_once_t s_sr_once = PTHREAD_ONCE_INIT; static void InitRtmpHandshakeServerRandom() { char buf[1528]; @@ -121,7 +121,7 @@ static const butil::IOBuf& GetRtmpHandshakeServerRandom() { return *s_rtmp_handshake_server_random; } -static butil::IOBuf* s_rtmp_handshake_client_random = NULL; +static butil::IOBuf* s_rtmp_handshake_client_random = nullptr; static pthread_once_t s_cr_once = PTHREAD_ONCE_INIT; static void InitRtmpHandshakeClientRandom() { char buf[1528]; @@ -147,16 +147,16 @@ namespace adobe_hs { // Modified from code in SRS2 (src/protocol/srs_rtmp_handshake.cpp:94) int openssl_HMACsha256(const void* key, int key_size, const void* data, int data_size, void* digest) { - if (NULL == EVP_sha256) { + if (nullptr == EVP_sha256) { LOG_ONCE(ERROR) << "Fail to find EVP_sha256, fall back to simple handshaking"; return -1; } unsigned int digest_size = 0; unsigned char* temp_digest = (unsigned char*)digest; - if (key == NULL) { + if (key == nullptr) { // NOTE: first parameter of EVP_Digest in older openssl is void*. if (EVP_Digest(const_cast(data), data_size, temp_digest, - &digest_size, EVP_sha256(), NULL) < 0) { + &digest_size, EVP_sha256(), nullptr) < 0) { LOG(ERROR) << "Fail to EVP_Digest"; return -1; } @@ -165,7 +165,7 @@ int openssl_HMACsha256(const void* key, int key_size, // inconsistent in different version of openssl. if (HMAC(EVP_sha256(), key, key_size, (const unsigned char*) data, data_size, - temp_digest, &digest_size) == NULL) { + temp_digest, &digest_size) == nullptr) { LOG(ERROR) << "Fail to HMAC"; return -1; } @@ -431,7 +431,7 @@ bool C1S1Base::ComputeDigestBase(const void* key, int key_size, bool C1::Generate(C1S1Schema schema) { _schema = schema; - time = ::time(NULL); + time = ::time(nullptr); version = FP_VERSION; key_blk.Generate(); digest_blk.Generate(); @@ -473,7 +473,7 @@ bool C1::Load(const void* buf) { bool S1::Generate(const C1& c1) { _schema = c1.schema(); - time = ::time(NULL); + time = ::time(nullptr); version = FMS_VERSION; key_blk.Generate(); digest_blk.Generate(); @@ -710,7 +710,7 @@ RtmpUnsentMessage* MakeUnsentControlMessage( RtmpContext::RtmpContext(const RtmpClientOptions* copt, const Server* server) : _state(RtmpContext::STATE_UNINITIALIZED) - , _s1_digest(NULL) + , _s1_digest(nullptr) , _chunk_size_out(RTMP_INITIAL_CHUNK_SIZE) , _chunk_size_in(RTMP_INITIAL_CHUNK_SIZE) , _window_ack_size(RTMP_DEFAULT_WINDOW_ACK_SIZE) @@ -719,12 +719,12 @@ RtmpContext::RtmpContext(const RtmpClientOptions* copt, const Server* server) , _cs_id_allocator(RTMP_CONTROL_CHUNK_STREAM_ID + 1) , _ms_id_allocator(RTMP_CONTROL_MESSAGE_STREAM_ID + 1) , _client_options(copt) - , _on_connect(NULL) - , _on_connect_arg(NULL) + , _on_connect(nullptr) + , _on_connect_arg(nullptr) , _only_check_simple_s0s1(false) , _create_stream_with_play_or_publish(false) , _server(server) - , _service(NULL) + , _service(nullptr) , _trans_id_allocator(2) , _simplified_rtmp(false) { if (server) { @@ -771,13 +771,13 @@ RtmpContext::~RtmpContext() { for (size_t i = 0; i < RTMP_CHUNK_ARRAY_1ST_SIZE; ++i) { SubChunkArray* p = _cstream_ctx[i].load(butil::memory_order_relaxed); if (p) { - _cstream_ctx[i].store(NULL, butil::memory_order_relaxed); + _cstream_ctx[i].store(nullptr, butil::memory_order_relaxed); delete p; } } free(_s1_digest); - _s1_digest = NULL; + _s1_digest = nullptr; } void RtmpContext::Destroy() { @@ -787,13 +787,13 @@ void RtmpContext::Destroy() { butil::Status RtmpUnsentMessage::AppendAndDestroySelf(butil::IOBuf* out, Socket* s) { std::unique_ptr destroy_self(this); - if (s == NULL) { // abandoned + if (s == nullptr) { // abandoned RPC_VLOG << "Socket=NULL"; return butil::Status::OK(); } RtmpContext* ctx = static_cast(s->parsing_context()); RtmpChunkStream* cstream = ctx->GetChunkStream(chunk_stream_id); - if (cstream == NULL) { + if (cstream == nullptr) { s->SetFailed(EINVAL, "Invalid chunk_stream_id=%u", chunk_stream_id); return butil::Status(EINVAL, "Invalid chunk_stream_id=%u", chunk_stream_id); } @@ -820,7 +820,7 @@ RtmpContext::SubChunkArray::~SubChunkArray() { for (size_t i = 0; i < RTMP_CHUNK_ARRAY_2ND_SIZE; ++i) { RtmpChunkStream* stream = ptrs[i].load(butil::memory_order_relaxed); if (stream) { - ptrs[i].store(NULL, butil::memory_order_relaxed); + ptrs[i].store(nullptr, butil::memory_order_relaxed); delete stream; } } @@ -829,15 +829,15 @@ RtmpContext::SubChunkArray::~SubChunkArray() { RtmpChunkStream* RtmpContext::GetChunkStream(uint32_t cs_id) { if (cs_id > RTMP_MAX_CHUNK_STREAM_ID) { LOG(ERROR) << "Invalid chunk_stream_id=" << cs_id; - return NULL; + return nullptr; } const uint32_t index1 = cs_id / RTMP_CHUNK_ARRAY_2ND_SIZE; SubChunkArray* sub_array = _cstream_ctx[index1].load(butil::memory_order_consume); - if (sub_array == NULL) { + if (sub_array == nullptr) { // Optimistic creation. sub_array = new SubChunkArray; - SubChunkArray* expected = NULL; + SubChunkArray* expected = nullptr; if (!_cstream_ctx[index1].compare_exchange_strong( expected, sub_array, butil::memory_order_acq_rel)) { delete sub_array; @@ -847,10 +847,10 @@ RtmpChunkStream* RtmpContext::GetChunkStream(uint32_t cs_id) { const uint32_t index2 = cs_id - index1 * RTMP_CHUNK_ARRAY_2ND_SIZE; RtmpChunkStream* cstream = sub_array->ptrs[index2].load(butil::memory_order_consume); - if (cstream == NULL) { + if (cstream == nullptr) { // Optimistic creation. cstream = new RtmpChunkStream(this, cs_id); - RtmpChunkStream* expected = NULL; + RtmpChunkStream* expected = nullptr; if (!sub_array->ptrs[index2].compare_exchange_strong( expected, cstream, butil::memory_order_acq_rel)) { delete cstream; @@ -868,19 +868,19 @@ void RtmpContext::ClearChunkStream(uint32_t cs_id) { const uint32_t index1 = cs_id / RTMP_CHUNK_ARRAY_2ND_SIZE; SubChunkArray* sub_array = _cstream_ctx[index1].load(butil::memory_order_consume); - if (sub_array == NULL) { + if (sub_array == nullptr) { LOG(ERROR) << "chunk_stream_id=" << cs_id << " does not exist"; return; } const uint32_t index2 = cs_id - index1 * RTMP_CHUNK_ARRAY_2ND_SIZE; RtmpChunkStream* cstream = sub_array->ptrs[index2].load(butil::memory_order_consume); - if (cstream == NULL) { + if (cstream == nullptr) { LOG(ERROR) << "chunk_stream_id=" << cs_id << " does not exist"; return; } delete sub_array->ptrs[index2].exchange( - NULL, butil::memory_order_acquire); + nullptr, butil::memory_order_acquire); } void RtmpContext::AllocateChunkStreamId(uint32_t* chunk_stream_id) { @@ -921,7 +921,7 @@ bool RtmpContext::FindMessageStream( uint32_t stream_id, butil::intrusive_ptr* stream) { BAIDU_SCOPED_LOCK(_stream_mutex); MessageStreamInfo* info = _mstream_map.seek(stream_id); - if (info == NULL || info->stream == NULL) { + if (info == nullptr || info->stream == nullptr) { return false; } *stream = info->stream; @@ -939,7 +939,7 @@ bool RtmpContext::AddClientStream(RtmpStreamBase* stream) { { std::unique_lock mu(_stream_mutex); MessageStreamInfo& info = _mstream_map[stream_id]; - if (info.stream != NULL) { + if (info.stream != nullptr) { mu.unlock(); LOG(ERROR) << "stream_id=" << stream_id << " is already used"; return false; @@ -959,7 +959,7 @@ bool RtmpContext::AddServerStream(RtmpStreamBase* stream) { return false; } MessageStreamInfo& info = _mstream_map[stream_id]; - if (info.stream != NULL) { + if (info.stream != nullptr) { mu.unlock(); LOG(ERROR) << "stream_id=" << stream_id << " is already used"; return false; @@ -972,7 +972,7 @@ bool RtmpContext::AddServerStream(RtmpStreamBase* stream) { } bool RtmpContext::RemoveMessageStream(RtmpStreamBase* stream) { - if (stream == NULL) { + if (stream == nullptr) { LOG(FATAL) << "Param[stream] is NULL"; return false; } @@ -987,7 +987,7 @@ bool RtmpContext::RemoveMessageStream(RtmpStreamBase* stream) { { std::unique_lock mu(_stream_mutex); MessageStreamInfo* info = _mstream_map.seek(stream_id); - if (info == NULL) { + if (info == nullptr) { mu.unlock(); return false; } @@ -1026,7 +1026,7 @@ bool RtmpContext::AddTransaction(uint32_t* out_transaction_id, continue; } step *= 2; // 1,2,4,8,16,32,64,128,256,512,1024 - if (_trans_map.seek(transaction_id) == NULL) { + if (_trans_map.seek(transaction_id) == nullptr) { _trans_map[transaction_id] = handler; *out_transaction_id = transaction_id; return true; @@ -1037,11 +1037,11 @@ bool RtmpContext::AddTransaction(uint32_t* out_transaction_id, RtmpTransactionHandler* RtmpContext::RemoveTransaction(uint32_t transaction_id) { - RtmpTransactionHandler* handler = NULL; + RtmpTransactionHandler* handler = nullptr; { BAIDU_SCOPED_LOCK(_trans_mutex); RtmpTransactionHandler** phandler = _trans_map.seek(transaction_id); - if (phandler != NULL) { + if (phandler != nullptr) { handler = *phandler; _trans_map.erase(transaction_id); } @@ -1209,7 +1209,7 @@ ParseResult RtmpContext::WaitForC0C1orSimpleRtmp(butil::IOBuf* source, Socket* s s1.Save(buf); tmp.append(buf, RTMP_HANDSHAKE_SIZE1); _s1_digest = malloc(adobe_hs::DigestBlock::DIGEST_SIZE); - if (_s1_digest == NULL) { + if (_s1_digest == nullptr) { LOG(ERROR) << "Fail to malloc"; return MakeParseError(PARSE_ERROR_NO_RESOURCE); } @@ -1329,7 +1329,7 @@ ParseResult RtmpContext::WaitForS2(butil::IOBuf* source, Socket* socket) { ParseResult RtmpContext::OnChunks(butil::IOBuf* source, Socket* socket) { // Parse basic header. const char* p = (const char*)source->fetch1(); - if (NULL == p) { + if (nullptr == p) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } const uint8_t first_byte = *p; @@ -1357,7 +1357,7 @@ ParseResult RtmpContext::OnChunks(butil::IOBuf* source, Socket* socket) { } // else 1-byte basic header, keep cs_id as it is. RtmpBasicHeader bh = { cs_id, fmt, basic_header_len }; RtmpChunkStream* cstream = GetChunkStream(cs_id); - if (cstream == NULL) { + if (cstream == nullptr) { LOG(ERROR) << "Invalid chunk_stream_id=" << cs_id; return MakeParseError(PARSE_ERROR_NO_RESOURCE); } @@ -1400,14 +1400,14 @@ RtmpChunkStream::WriteParams::WriteParams() , last_timestamp_delta(0) { } -MethodStatus* g_client_msg_status = NULL; +MethodStatus* g_client_msg_status = nullptr; static pthread_once_t g_client_msg_status_once = PTHREAD_ONCE_INIT; static void InitClientMessageStatus() { g_client_msg_status = new MethodStatus; g_client_msg_status->Expose("rtmp_client_in"); } -MethodStatus* g_server_msg_status = NULL; +MethodStatus* g_server_msg_status = nullptr; static pthread_once_t g_server_msg_status_once = PTHREAD_ONCE_INIT; static void InitServerMessageStatus() { g_server_msg_status = new MethodStatus; @@ -1619,8 +1619,8 @@ ParseResult RtmpChunkStream::Feed(const RtmpBasicHeader& bh, AddChunk(); if (_r.left_message_length == 0) { - MethodStatus* st = NULL; - if (ctx->service() != NULL) { + MethodStatus* st = nullptr; + if (ctx->service() != nullptr) { pthread_once(&g_server_msg_status_once, InitServerMessageStatus); st = g_server_msg_status; } else { @@ -1643,7 +1643,7 @@ ParseResult RtmpChunkStream::Feed(const RtmpBasicHeader& bh, } else { _r.first_chunk_of_message = false; } - return MakeMessage(NULL); + return MakeMessage(nullptr); } int RtmpChunkStream::SerializeMessage(butil::IOBuf* buf, @@ -1746,26 +1746,26 @@ static const RtmpChunkStream::MessageHandler s_msg_handlers[] = { &RtmpChunkStream::OnUserControlMessage, // 4 &RtmpChunkStream::OnWindowAckSize,// 5 &RtmpChunkStream::OnSetPeerBandwidth, // 6 - NULL, //7 + nullptr, //7 &RtmpChunkStream::OnAudioMessage, // 8 &RtmpChunkStream::OnVideoMessage, // 9 - NULL, // 10 - NULL, // 11 - NULL, // 12 - NULL, // 13 - NULL, // 14 + nullptr, // 10 + nullptr, // 11 + nullptr, // 12 + nullptr, // 13 + nullptr, // 14 &RtmpChunkStream::OnDataMessageAMF3, // 15 &RtmpChunkStream::OnSharedObjectMessageAMF3, // 16 &RtmpChunkStream::OnCommandMessageAMF3, // 17 &RtmpChunkStream::OnDataMessageAMF0, // 18 &RtmpChunkStream::OnSharedObjectMessageAMF0, // 19 &RtmpChunkStream::OnCommandMessageAMF0, // 20 - NULL, // 21 + nullptr, // 21 &RtmpChunkStream::OnAggregateMessage, // 22 }; typedef butil::FlatMap CommandHandlerMap; -static CommandHandlerMap* s_cmd_handlers = NULL; +static CommandHandlerMap* s_cmd_handlers = nullptr; static pthread_once_t s_cmd_handlers_init_once = PTHREAD_ONCE_INIT; static void InitCommandHandlers() { // Dispatch commands based on "Command Name". @@ -1817,7 +1817,7 @@ bool RtmpChunkStream::OnMessage(const RtmpBasicHeader& bh, return false; } MessageHandler handler = s_msg_handlers[index]; - if (handler == NULL) { + if (handler == nullptr) { RTMP_ERROR(socket, mh) << "Unknown message_type=" << (int)mh.message_type; return false; } @@ -1869,7 +1869,12 @@ bool RtmpChunkStream::OnAbortMessage( RTMP_ERROR(socket, mh) << "Invalid chunk_stream_id=" << cs_id; return false; } - connection_context()->ClearChunkStream(cs_id); + // Do not delete the chunk stream that is currently being parsed (i.e. + // the one running this Feed). Clearing it here would free `this' while + // Feed() still holds and later touches it, causing a use-after-free. + if (cs_id != _cs_id) { + connection_context()->ClearChunkStream(cs_id); + } return true; } @@ -1962,7 +1967,7 @@ bool RtmpChunkStream::OnStreamBegin(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service != NULL) { + if (service != nullptr) { RTMP_ERROR(socket, mh) << "Server should not receive `StreamBegin'"; return false; } @@ -1979,7 +1984,7 @@ bool RtmpChunkStream::OnStreamEOF(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service != NULL) { + if (service != nullptr) { RTMP_ERROR(socket, mh) << "Server should not receive `StreamEOF'"; return false; } @@ -1996,7 +2001,7 @@ bool RtmpChunkStream::OnStreamDry(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service != NULL) { + if (service != nullptr) { RTMP_ERROR(socket, mh) << "Server should not receive `StreamDry'"; return false; } @@ -2013,7 +2018,7 @@ bool RtmpChunkStream::OnStreamIsRecorded(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service != NULL) { + if (service != nullptr) { RTMP_ERROR(socket, mh) << "Server should not receive `StreamIsRecorded'"; return false; } @@ -2030,7 +2035,7 @@ bool RtmpChunkStream::OnSetBufferLength(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service == NULL) { + if (service == nullptr) { RTMP_ERROR(socket, mh) << "Client should not receive `SetBufferLength'"; return false; } @@ -2061,7 +2066,7 @@ bool RtmpChunkStream::OnPingRequest(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service != NULL) { + if (service != nullptr) { RTMP_ERROR(socket, mh) << "Server should not receive `PingRequest'"; return false; } @@ -2088,7 +2093,7 @@ bool RtmpChunkStream::OnPingResponse(const RtmpMessageHeader& mh, const butil::StringPiece& event_data, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service == NULL) { + if (service == nullptr) { RTMP_ERROR(socket, mh) << "Client should not receive `PingResponse'"; return false; } @@ -2282,7 +2287,7 @@ bool RtmpChunkStream::OnCommandMessageAMF0( pthread_once(&s_cmd_handlers_init_once, InitCommandHandlers); RtmpChunkStream::CommandHandler* phandler = s_cmd_handlers->seek(command_name); - if (phandler == NULL) { + if (phandler == nullptr) { RTMP_ERROR(socket, mh) << "Unknown command_name=" << command_name; return false; } @@ -2351,7 +2356,7 @@ bool RtmpChunkStream::OnConnect(const RtmpMessageHeader& mh, << "] connect{" << req->ShortDebugString() << '}'; TemporaryArrayBuilder, 5> msgs; - char* p = NULL; + char* p = nullptr; // WindowAckSize // TODO(gejun): seems not effective to ffplay. char wasbuf[4]; @@ -2460,10 +2465,10 @@ bool RtmpChunkStream::OnBWDone(const RtmpMessageHeader& mh, } void RtmpContext::OnConnected(int error_code) { - if (_on_connect != NULL) { + if (_on_connect != nullptr) { void (*saved_on_connect)(int, void*) = _on_connect; void* saved_arg = _on_connect_arg; - _on_connect = NULL; + _on_connect = nullptr; saved_on_connect(error_code, saved_arg); } } @@ -2502,7 +2507,7 @@ bool RtmpChunkStream::OnResult(const RtmpMessageHeader& mh, } RtmpContext* ctx = static_cast(socket->parsing_context()); RtmpTransactionHandler* handler = ctx->RemoveTransaction(transaction_id); - if (handler == NULL) { + if (handler == nullptr) { RTMP_WARNING(socket, mh) << "Unknown _result.TransactionId=" << transaction_id; return false; @@ -2532,7 +2537,7 @@ bool RtmpChunkStream::OnError(const RtmpMessageHeader& mh, } RtmpContext* ctx = static_cast(socket->parsing_context()); RtmpTransactionHandler* handler = ctx->RemoveTransaction(transaction_id); - if (handler == NULL) { + if (handler == nullptr) { RTMP_WARNING(socket, mh) << "Unknown _error.TransactionId=" << transaction_id; return false; @@ -2577,7 +2582,7 @@ bool RtmpChunkStream::OnCreateStream(const RtmpMessageHeader& mh, AMFInputStream* istream, Socket* socket) { RtmpService* service = connection_context()->service(); - if (service == NULL) { + if (service == nullptr) { RTMP_ERROR(socket, mh) << "Client should not receive `createStream'"; return false; } @@ -2595,16 +2600,16 @@ bool RtmpChunkStream::OnCreateStream(const RtmpMessageHeader& mh, return false; } const AMFField* cmd_name_field = cmd_obj.Find("CommandName"); - if (cmd_name_field != NULL && cmd_name_field->IsString()) { + if (cmd_name_field != nullptr && cmd_name_field->IsString()) { is_publish = (cmd_name_field->AsString() == "publish"); } const AMFField* stream_name_field = cmd_obj.Find("StreamName"); - if (stream_name_field != NULL && stream_name_field->IsString()) { + if (stream_name_field != nullptr && stream_name_field->IsString()) { stream_name_field->AsString().CopyToString(&stream_name); } if (is_publish) { const AMFField* publish_type_field = cmd_obj.Find("PublishType"); - if (publish_type_field != NULL && publish_type_field->IsString()) { + if (publish_type_field != nullptr && publish_type_field->IsString()) { Str2RtmpPublishType(publish_type_field->AsString(), &publish_type); } } @@ -2614,10 +2619,10 @@ bool RtmpChunkStream::OnCreateStream(const RtmpMessageHeader& mh, butil::intrusive_ptr stream( service->NewStream(connection_context()->_connect_req)); if (connection_context()->_connect_req.stream_multiplexing() && - stream != NULL) { + stream != nullptr) { stream->_client_supports_stream_multiplexing = true; } - if (NULL == stream) { + if (nullptr == stream) { error_text = "Fail to create stream"; LOG(ERROR) << error_text; } else { @@ -3414,26 +3419,26 @@ bool RtmpChunkStream::OnPause(const RtmpMessageHeader& mh, inline ParseResult IsPossiblyRtmp(const butil::IOBuf* source) { const char* p = (const char*)source->fetch1(); - if (p == NULL) { + if (p == nullptr) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } if (*p != RTMP_DEFAULT_VERSION) { return MakeParseError(PARSE_ERROR_TRY_OTHERS); } - return MakeMessage(NULL); + return MakeMessage(nullptr); } ParseResult ParseRtmpMessage(butil::IOBuf* source, Socket *socket, bool read_eof, const void* arg) { RtmpContext* rtmp_ctx = static_cast(socket->parsing_context()); - if (rtmp_ctx == NULL) { - if (arg == NULL) { + if (rtmp_ctx == nullptr) { + if (arg == nullptr) { // We are probably parsing another client-side protocol. return MakeParseError(PARSE_ERROR_TRY_OTHERS); } const Server* server = static_cast(arg); RtmpService* service = server->options().rtmp_service; - if (service == NULL) { + if (service == nullptr) { // Validating RTMP protocol only checks the first byte, which // is very easy to be confused with other protocols. Currently // if rtmp_service is not set, the protocol is skipped w/o any @@ -3449,11 +3454,7 @@ ParseResult ParseRtmpMessage(butil::IOBuf* source, Socket *socket, bool read_eof if (!r.is_ok()) { return r; } - rtmp_ctx = new (std::nothrow) RtmpContext(NULL, server); - if (rtmp_ctx == NULL) { - LOG(FATAL) << "Fail to new RtmpContext"; - return MakeParseError(PARSE_ERROR_NO_RESOURCE); - } + rtmp_ctx = new RtmpContext(nullptr, server); socket->reset_parsing_context(rtmp_ctx); // We don't need to customize app_connect at server-side. } @@ -3486,7 +3487,7 @@ void OnServerStreamCreated::Run(bool error, std::unique_ptr delete_self(this); // End the createStream call. RtmpContext* ctx = static_cast(socket->parsing_context()); - if (ctx == NULL) { + if (ctx == nullptr) { LOG(FATAL) << "RtmpContext must be created"; return; } @@ -3495,7 +3496,7 @@ void OnServerStreamCreated::Run(bool error, const int64_t received_us = start_parse_us; const int64_t base_realtime = butil::gettimeofday_us() - received_us; const bthread_id_t cid = _call_id; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -3512,7 +3513,7 @@ void OnServerStreamCreated::Run(bool error, break; } const AMFField* field = cmd_obj.Find("PlayOrPublishAccepted"); - if (field != NULL && field->IsBool() && field->AsBool()) { + if (field != nullptr && field->IsBool() && field->AsBool()) { _stream->_created_stream_with_play_or_publish = true; } if (error) { @@ -3560,12 +3561,12 @@ void OnServerStreamCreated::Cancel() { butil::Status RtmpCreateStreamMessage::AppendAndDestroySelf(butil::IOBuf* out, Socket* s) { std::unique_ptr destroy_self(this); - if (s == NULL) { // abandoned + if (s == nullptr) { // abandoned return butil::Status::OK(); } // Serialize createStream command RtmpContext* ctx = static_cast(socket->parsing_context()); - if (ctx == NULL) { + if (ctx == nullptr) { return butil::Status(EINVAL, "RtmpContext of %s is not created", socket->description().c_str()); } @@ -3606,7 +3607,7 @@ RtmpCreateStreamMessage::AppendAndDestroySelf(butil::IOBuf* out, Socket* s) { CHECK(ostream.good()); } RtmpChunkStream* cstream = ctx->GetChunkStream(RTMP_CONTROL_CHUNK_STREAM_ID); - if (cstream == NULL) { + if (cstream == nullptr) { socket->SetFailed(EINVAL, "Invalid chunk_stream_id=%u", RTMP_CONTROL_CHUNK_STREAM_ID); return butil::Status(EINVAL, "Invalid chunk_stream_id=%u", @@ -3626,7 +3627,7 @@ RtmpCreateStreamMessage::AppendAndDestroySelf(butil::IOBuf* out, Socket* s) { void PackRtmpRequest(butil::IOBuf* /*buf*/, SocketMessage** user_message, uint64_t /*correlation_id*/, - const google::protobuf::MethodDescriptor* /*NULL*/, + const google::protobuf::MethodDescriptor* /*nullptr*/, Controller* cntl, const butil::IOBuf& /*request*/, const Authenticator*) { @@ -3634,7 +3635,7 @@ void PackRtmpRequest(butil::IOBuf* /*buf*/, ControllerPrivateAccessor accessor(cntl); Socket* s = accessor.get_sending_socket(); RtmpContext* ctx = static_cast(s->parsing_context()); - if (ctx == NULL) { + if (ctx == nullptr) { cntl->SetFailed(EINVAL, "RtmpContext of %s is not created", s->description().c_str()); return; @@ -3670,7 +3671,7 @@ void PackRtmpRequest(butil::IOBuf* /*buf*/, void SerializeRtmpRequest(butil::IOBuf* /*buf*/, Controller* /*cntl*/, - const google::protobuf::Message* /*NULL*/) { + const google::protobuf::Message* /*nullptr*/) { } } // namespace policy diff --git a/src/brpc/policy/rtmp_protocol.h b/src/brpc/policy/rtmp_protocol.h index b5572c2f18..2ed9fd3c2e 100644 --- a/src/brpc/policy/rtmp_protocol.h +++ b/src/brpc/policy/rtmp_protocol.h @@ -169,12 +169,12 @@ class RtmpUnsentMessage : public SocketMessage { // if this field is non-zero. uint32_t new_chunk_size; butil::IOBuf body; - // If next is not NULL, next->AppendAndDestroySelf() will be called + // If next is not nullptr, next->AppendAndDestroySelf() will be called // recursively. For implementing batched messages. SocketMessagePtr next; public: RtmpUnsentMessage() - : chunk_stream_id(0) , new_chunk_size(0), next(NULL) {} + : chunk_stream_id(0) , new_chunk_size(0), next(nullptr) {} // @SocketMessage butil::Status AppendAndDestroySelf(butil::IOBuf* out, Socket*); }; @@ -255,7 +255,7 @@ friend class RtmpUnsentMessage; // Get literal form of the state. static const char* state2str(State); - // One of copt/service must be NULL, indicating this context belongs + // One of copt/service must be nullptr, indicating this context belongs // to a server-side or client-side socket. RtmpContext(const RtmpClientOptions* copt, const Server* server); ~RtmpContext(); @@ -272,8 +272,8 @@ friend class RtmpUnsentMessage; const Server* server() const { return _server; } RtmpService* service() const { return _service; } - bool is_server_side() const { return service() != NULL; } - bool is_client_side() const { return service() == NULL; } + bool is_server_side() const { return service() != nullptr; } + bool is_client_side() const { return service() == nullptr; } // XXXMessageStream may be called from multiple threads(currently not), // so they're protected by _stream_mutex @@ -325,7 +325,7 @@ friend class RtmpUnsentMessage; } // Called when the RTMP connection is established. void OnConnected(int error_code); - bool unconnected() const { return _on_connect != NULL; } + bool unconnected() const { return _on_connect != nullptr; } void only_check_simple_s0s1() { _only_check_simple_s0s1 = true; } bool can_stream_be_created_with_play_or_publish() const diff --git a/src/brpc/policy/sofa_pbrpc_protocol.cpp b/src/brpc/policy/sofa_pbrpc_protocol.cpp index 01b21851d5..6b663c19f9 100644 --- a/src/brpc/policy/sofa_pbrpc_protocol.cpp +++ b/src/brpc/policy/sofa_pbrpc_protocol.cpp @@ -189,11 +189,12 @@ ParseResult ParseSofaMessage(butil::IOBuf* source, Socket* socket, << " + body_size=" << body_size; return MakeParseError(PARSE_ERROR_TRY_OTHERS); } - if (body_size > FLAGS_max_body_size) { - // We need this log to report the body_size to give users some clues + if (body_size > FLAGS_max_body_size || + meta_size > FLAGS_max_body_size) { + // We need this log to report the size to give users some clues // which is not printed in InputMessenger. - LOG(ERROR) << "body_size=" << body_size << " from " - << socket->remote_side() << " is too large"; + LOG(ERROR) << "body_size=" << body_size << " meta_size=" << meta_size + << " from " << socket->remote_side() << " is too large"; return MakeParseError(PARSE_ERROR_TOO_BIG_DATA); } else if (source->length() < sizeof(header_buf) + msg_size) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); @@ -236,11 +237,11 @@ static void SendSofaResponse(int64_t correlation_id, bool append_body = false; butil::IOBuf res_body; - // `res' can be NULL here, in which case we don't serialize it + // `res' can be nullptr here, in which case we don't serialize it // If user calls `SetFailed' on Controller, we don't serialize // response either CompressType type = cntl->response_compress_type(); - if (res != NULL && !cntl->Failed()) { + if (res != nullptr && !cntl->Failed()) { if (!res->IsInitialized()) { cntl->SetFailed( ERESPONSE, "Missing required fields in response: %s", @@ -344,11 +345,7 @@ void ProcessSofaRequest(InputMessageBase* msg_base) { sample->submit(start_parse_us); } - std::unique_ptr cntl(new (std::nothrow) Controller); - if (NULL == cntl.get()) { - LOG(WARNING) << "Fail to new Controller"; - return; - } + std::unique_ptr cntl(new Controller); std::unique_ptr req; std::unique_ptr res; @@ -387,7 +384,7 @@ void ProcessSofaRequest(InputMessageBase* msg_base) { span->set_request_size(msg->meta.size() + msg->payload.size() + 24); } - MethodStatus* method_status = NULL; + MethodStatus* method_status = nullptr; do { if (!server->IsRunning()) { cntl->SetFailed(ELOGOFF, "Server is stopping"); @@ -408,7 +405,7 @@ void ProcessSofaRequest(InputMessageBase* msg_base) { const Server::MethodProperty *sp = server_accessor.FindMethodPropertyByFullName(meta.method()); - if (NULL == sp) { + if (nullptr == sp) { cntl->SetFailed(ENOMETHOD, "Fail to find method=%s", meta.method().c_str()); break; @@ -508,7 +505,7 @@ void ProcessSofaResponse(InputMessageBase* msg_base) { } const bthread_id_t cid = { static_cast(meta.sequence_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) diff --git a/src/brpc/policy/streaming_rpc_protocol.cpp b/src/brpc/policy/streaming_rpc_protocol.cpp index b741acff5c..bdad1f2385 100644 --- a/src/brpc/policy/streaming_rpc_protocol.cpp +++ b/src/brpc/policy/streaming_rpc_protocol.cpp @@ -53,7 +53,7 @@ void PackStreamMessage(butil::IOBuf* out, out->append(head, ARRAY_SIZE(head)); butil::IOBufAsZeroCopyOutputStream wrapper(out); CHECK(fm.SerializeToZeroCopyStream(&wrapper)); - if (data != NULL) { + if (data != nullptr) { out->append(*data); } } @@ -102,11 +102,11 @@ ParseResult ParseStreamingMessage(butil::IOBuf* source, LOG(WARNING) << "Fail to Parse StreamFrameMeta from " << *socket; break; } - SocketUniquePtr ptr; - if (Socket::Address((SocketId)fm.stream_id(), &ptr) != 0) { - RPC_VLOG_IF(fm.frame_type() != FRAME_TYPE_RST - && fm.frame_type() != FRAME_TYPE_CLOSE - && fm.frame_type() != FRAME_TYPE_FEEDBACK) + StreamUniquePtr sptr; + if (Stream::Address((StreamId)fm.stream_id(), &sptr) != 0) { + RPC_VLOG_IF(fm.frame_type() != FRAME_TYPE_RST && + fm.frame_type() != FRAME_TYPE_CLOSE && + fm.frame_type() != FRAME_TYPE_FEEDBACK) << "Fail to find stream=" << fm.stream_id(); // It's normal that the stream is closed before receiving feedback frames from peer. // In this case, RST frame should not be sent to peer, otherwise on-fly data can be lost. @@ -116,47 +116,38 @@ ParseResult ParseStreamingMessage(butil::IOBuf* source, break; } meta_buf.clear(); // to reduce memory resident - // ptr->conn() returns the connection-level context attached to the - // socket. It may be NULL when the socket was found by ID but has no - // Stream object associated (e.g. during protocol probing or fuzz - // testing). Calling OnReceived on a null pointer would crash. - Stream* stream_conn = (Stream*)ptr->conn(); - if (stream_conn == NULL) { - LOG(FATAL) << "No stream object found"; - break; - } - stream_conn->OnReceived(fm, &payload, socket); + sptr->OnReceived(fm, &payload, socket); } while (0); // Hack input messenger - return MakeMessage(NULL); + return MakeMessage(nullptr); } void ProcessStreamingMessage(InputMessageBase* /*msg*/) { CHECK(false) << "Should never be called"; } -void SendStreamRst(Socket *sock, int64_t remote_stream_id) { - CHECK(sock != NULL); +void SendStreamRst(Socket* sock, int64_t remote_stream_id) { + CHECK(sock != nullptr); StreamFrameMeta fm; fm.set_stream_id(remote_stream_id); fm.set_frame_type(FRAME_TYPE_RST); butil::IOBuf out; - PackStreamMessage(&out, fm, NULL); + PackStreamMessage(&out, fm, nullptr); Socket::WriteOptions wopt; wopt.ignore_eovercrowded = true; sock->Write(&out, &wopt); } -void SendStreamClose(Socket *sock, int64_t remote_stream_id, +void SendStreamClose(Socket* sock, int64_t remote_stream_id, int64_t source_stream_id) { - CHECK(sock != NULL); + CHECK(sock != nullptr); StreamFrameMeta fm; fm.set_stream_id(remote_stream_id); fm.set_source_stream_id(source_stream_id); fm.set_frame_type(FRAME_TYPE_CLOSE); butil::IOBuf out; - PackStreamMessage(&out, fm, NULL); + PackStreamMessage(&out, fm, nullptr); Socket::WriteOptions wopt; wopt.ignore_eovercrowded = true; sock->Write(&out, &wopt); @@ -165,7 +156,7 @@ void SendStreamClose(Socket *sock, int64_t remote_stream_id, int SendStreamData(Socket* sock, const butil::IOBuf* data, int64_t remote_stream_id, int64_t source_stream_id, bthread_id_t response_id) { - CHECK(sock != NULL); + CHECK(sock != nullptr); StreamFrameMeta fm; fm.set_stream_id(remote_stream_id); fm.set_source_stream_id(source_stream_id); diff --git a/src/brpc/policy/thrift_protocol.cpp b/src/brpc/policy/thrift_protocol.cpp index 2b5739ea3e..dce6bc3899 100755 --- a/src/brpc/policy/thrift_protocol.cpp +++ b/src/brpc/policy/thrift_protocol.cpp @@ -249,7 +249,7 @@ void ThriftClosure::DoRun() { } Socket* sock = accessor.get_sending_socket(); MethodStatus* method_status = (server->options().thrift_service ? - server->options().thrift_service->_status : NULL); + server->options().thrift_service->_status : nullptr); ConcurrencyRemover concurrency_remover(method_status, &_controller, _received_us); if (!method_status) { // Judge errors belongings. @@ -492,7 +492,7 @@ void ProcessThriftRequest(InputMessageBase* msg_base) { cntl->set_log_id(seq_id); // Pass seq_id by log_id ThriftService* service = server->options().thrift_service; - if (service == NULL) { + if (service == nullptr) { LOG_EVERY_SECOND(ERROR) << "Received thrift request however the server does not set" " ServerOptions.thrift_service, close the connection."; @@ -575,7 +575,7 @@ void ProcessThriftResponse(InputMessageBase* msg_base) { // Fetch correlation id that we saved before in `PacThriftRequest' const CallId cid = { static_cast(msg->socket()->correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -656,13 +656,13 @@ bool VerifyThriftRequest(const InputMessageBase* msg_base) { void SerializeThriftRequest(butil::IOBuf* request_buf, Controller* cntl, const google::protobuf::Message* req_base) { - if (req_base == NULL) { + if (req_base == nullptr) { return cntl->SetFailed(EREQUEST, "request is NULL"); } if (req_base->GetDescriptor() != ThriftFramedMessage::descriptor()) { return cntl->SetFailed(EINVAL, "Type of request must be ThriftFramedMessage"); } - if (cntl->response() != NULL && + if (cntl->response() != nullptr && cntl->response()->GetDescriptor() != ThriftFramedMessage::descriptor()) { return cntl->SetFailed(EINVAL, "Type of response must be ThriftFramedMessage"); } diff --git a/src/brpc/policy/timeout_concurrency_limiter.cpp b/src/brpc/policy/timeout_concurrency_limiter.cpp index 21aad33fc1..5ef37fdb5f 100644 --- a/src/brpc/policy/timeout_concurrency_limiter.cpp +++ b/src/brpc/policy/timeout_concurrency_limiter.cpp @@ -67,8 +67,8 @@ TimeoutConcurrencyLimiter::TimeoutConcurrencyLimiter( TimeoutConcurrencyLimiter *TimeoutConcurrencyLimiter::New( const AdaptiveMaxConcurrency &amc) const { - return new (std::nothrow) - TimeoutConcurrencyLimiter(static_cast(amc)); + return new TimeoutConcurrencyLimiter( + static_cast(amc)); } bool TimeoutConcurrencyLimiter::OnRequested(int current_concurrency, diff --git a/src/brpc/policy/ubrpc2pb_protocol.cpp b/src/brpc/policy/ubrpc2pb_protocol.cpp index 2f5194c880..c3c598f0cc 100644 --- a/src/brpc/policy/ubrpc2pb_protocol.cpp +++ b/src/brpc/policy/ubrpc2pb_protocol.cpp @@ -55,7 +55,7 @@ void UbrpcAdaptor::ParseNsheadMeta( } mcpack2pb::ObjectIterator it1(&stream, request.body.size() - stream.popped_bytes()); bool found_content = false; - for (; it1 != NULL; ++it1) { + for (; it1 != nullptr; ++it1) { if (it1->name == "content") { found_content = true; break; @@ -72,7 +72,7 @@ void UbrpcAdaptor::ParseNsheadMeta( } mcpack2pb::ArrayIterator it2(it1->value); - if (it2 == NULL) { + if (it2 == nullptr) { cntl->SetFailed(EREQUEST, "Fail to parse request.content as array"); return; } @@ -81,7 +81,7 @@ void UbrpcAdaptor::ParseNsheadMeta( bool has_params = false; size_t user_req_offset = 0; size_t user_req_size = 0; - for (mcpack2pb::ObjectIterator it3(*it2); it3 != NULL; ++it3) { + for (mcpack2pb::ObjectIterator it3(*it2); it3 != nullptr; ++it3) { if (it3->name == "service_name") { if (it3->value.type() != mcpack2pb::FIELD_STRING) { cntl->SetFailed(EREQUEST, "Expect request.content[0].service_name" @@ -120,7 +120,7 @@ void UbrpcAdaptor::ParseNsheadMeta( user_req_size = it3->value.size(); const size_t stream_end = stream.popped_bytes() + it3->value.size(); mcpack2pb::ObjectIterator it4(it3->value); - if (it4 == NULL || it4.field_count() == 0) { + if (it4 == nullptr || it4.field_count() == 0) { cntl->SetFailed(EREQUEST, "Nothing in request.content[0].params"); return; } @@ -173,7 +173,7 @@ void UbrpcAdaptor::ParseRequestFromIOBuf( Controller* cntl, google::protobuf::Message* pb_req) const { const std::string msg_name = butil::EnsureString(pb_req->GetDescriptor()->full_name()); mcpack2pb::MessageHandler handler = mcpack2pb::find_message_handler(msg_name); - if (handler.parse_body == NULL) { + if (handler.parse_body == nullptr) { return cntl->SetFailed(EREQUEST, "Fail to find parser of %s", msg_name.c_str()); } @@ -216,7 +216,7 @@ void UbrpcAdaptor::SerializeResponseToIOBuf( type = COMPRESS_TYPE_NONE; } - if (pb_res == NULL || cntl->Failed()) { + if (pb_res == nullptr || cntl->Failed()) { if (!cntl->Failed()) { cntl->SetFailed(ERESPONSE, "response was not created yet"); } @@ -231,7 +231,7 @@ void UbrpcAdaptor::SerializeResponseToIOBuf( const std::string msg_name = butil::EnsureString(pb_res->GetDescriptor()->full_name()); mcpack2pb::MessageHandler handler = mcpack2pb::find_message_handler(msg_name); - if (handler.serialize_body == NULL) { + if (handler.serialize_body == nullptr) { cntl->SetFailed(ERESPONSE, "Fail to find serializer of %s", msg_name.c_str()); return AppendError(meta, cntl, raw_res->body); @@ -254,7 +254,7 @@ void UbrpcAdaptor::SerializeResponseToIOBuf( } sr.begin_object("result_params"); const char* const response_name = cntl->idl_names().response_name; - if (response_name != NULL && *response_name) { + if (response_name != nullptr && *response_name) { sr.begin_object(response_name); handler.serialize_body(*pb_res, sr, _format); sr.end_object(); @@ -277,13 +277,13 @@ void UbrpcAdaptor::SerializeResponseToIOBuf( static void ParseResponse(Controller* cntl, butil::IOBuf& buf, google::protobuf::Message* res) { - if (res == NULL) { + if (res == nullptr) { // silently ignore response. return; } const std::string msg_name = butil::EnsureString(res->GetDescriptor()->full_name()); mcpack2pb::MessageHandler handler = mcpack2pb::find_message_handler(msg_name); - if (handler.parse_body == NULL) { + if (handler.parse_body == nullptr) { return cntl->SetFailed(ERESPONSE, "Fail to find parser of %s", msg_name.c_str()); } @@ -295,7 +295,7 @@ static void ParseResponse(Controller* cntl, butil::IOBuf& buf, } mcpack2pb::ObjectIterator it1(&stream, buf.size() - stream.popped_bytes()); bool found_content = false; - for (; it1 != NULL; ++it1) { + for (; it1 != nullptr; ++it1) { if (it1->name == "content") { found_content = true; break; @@ -311,7 +311,7 @@ static void ParseResponse(Controller* cntl, butil::IOBuf& buf, return; } mcpack2pb::ArrayIterator it2(it1->value); - if (it2 == NULL) { + if (it2 == nullptr) { cntl->SetFailed("Fail to parse response.content as array"); return; } @@ -319,7 +319,7 @@ static void ParseResponse(Controller* cntl, butil::IOBuf& buf, size_t user_res_offset = 0; size_t user_res_size = 0; const char* response_name = "result_params"; - for (mcpack2pb::ObjectIterator it3(*it2); it3 != NULL; ++it3) { + for (mcpack2pb::ObjectIterator it3(*it2); it3 != nullptr; ++it3) { if (it3->name == "error") { if (it3->value.type() != mcpack2pb::FIELD_OBJECT) { cntl->SetFailed(ERESPONSE, "Expect response.content[0].error" @@ -329,7 +329,7 @@ static void ParseResponse(Controller* cntl, butil::IOBuf& buf, } int32_t code = 0; std::string msg; - for (mcpack2pb::ObjectIterator it4(it3->value); it4 != NULL; ++it4) { + for (mcpack2pb::ObjectIterator it4(it3->value); it4 != nullptr; ++it4) { if (it4->name == "code") { if (!mcpack2pb::is_primitive(it4->value.type()) || !mcpack2pb::is_integral( @@ -390,10 +390,10 @@ static void ParseResponse(Controller* cntl, butil::IOBuf& buf, user_res_size = it3->value.size(); const size_t stream_end = stream.popped_bytes() + it3->value.size(); const char* const expname = cntl->idl_names().response_name; - if (expname != NULL && *expname) { + if (expname != nullptr && *expname) { mcpack2pb::ObjectIterator it4(it3->value); bool found_response_name = false; - for (; it4 != NULL; ++it4) { + for (; it4 != nullptr; ++it4) { if (it4->name == expname) { found_response_name = true; break; @@ -446,7 +446,7 @@ void ProcessUbrpcResponse(InputMessageBase* msg_base) { // Fetch correlation id that we saved before in `PackUbrpcRequest' const bthread_id_t cid = { static_cast(socket->correlation_id()) }; - Controller* cntl = NULL; + Controller* cntl = nullptr; const int rc = bthread_id_lock(cid, (void**)&cntl); if (rc != 0) { LOG_IF(ERROR, rc != EINVAL && rc != EPERM) @@ -478,12 +478,12 @@ static void SerializeUbrpcRequest(butil::IOBuf* buf, Controller* cntl, return cntl->SetFailed( EREQUEST, "ubrpc protocol doesn't support compression"); } - if (cntl->method() == NULL) { + if (cntl->method() == nullptr) { return cntl->SetFailed(ENOMETHOD, "method is NULL"); } const std::string msg_name = butil::EnsureString(request->GetDescriptor()->full_name()); mcpack2pb::MessageHandler handler = mcpack2pb::find_message_handler(msg_name); - if (handler.serialize_body == NULL) { + if (handler.serialize_body == nullptr) { return cntl->SetFailed(EREQUEST, "Fail to find serializer of %s", msg_name.c_str()); } @@ -506,7 +506,7 @@ static void SerializeUbrpcRequest(butil::IOBuf* buf, Controller* cntl, sr.add_string("method", butil::EnsureString(cntl->method()->name())); sr.begin_object("params"); const char* const request_name = cntl->idl_names().request_name; - if (request_name != NULL && *request_name) { + if (request_name != nullptr && *request_name) { sr.begin_object(request_name); handler.serialize_body(*request, sr, format); sr.end_object(); diff --git a/src/brpc/policy/weighted_randomized_load_balancer.cpp b/src/brpc/policy/weighted_randomized_load_balancer.cpp index 46923acb86..0f9a339a05 100644 --- a/src/brpc/policy/weighted_randomized_load_balancer.cpp +++ b/src/brpc/policy/weighted_randomized_load_balancer.cpp @@ -131,9 +131,11 @@ int WeightedRandomizedLoadBalancer::SelectServer(const SelectIn& in, SelectOut* uint64_t weight_sum = s->weight_sum; for (size_t i = 0; i < n; ++i) { uint64_t random_weight = butil::fast_rand_less_than(weight_sum); + // current_weight_sum is an inclusive prefix sum, so random_weight belongs + // to the first server whose prefix sum is strictly greater than it. const Server random_server(0, 0, random_weight); const auto& server = - std::lower_bound(s->server_list.begin(), s->server_list.end(), + std::upper_bound(s->server_list.begin(), s->server_list.end(), random_server, server_compare); const SocketId id = server->id; if (ExcludedServers::IsExcluded(in.excluded, id)) { @@ -153,7 +155,7 @@ int WeightedRandomizedLoadBalancer::SelectServer(const SelectIn& in, SelectOut* for (size_t i = 0; i < n; ++i) { offset = (offset + stride) % n; SocketId id = s->server_list[offset].id; - if (NULL != random_traversed.seek(id)) { + if (nullptr != random_traversed.seek(id)) { continue; } if (IsServerAvailable(id, out->ptr)) { @@ -168,12 +170,12 @@ int WeightedRandomizedLoadBalancer::SelectServer(const SelectIn& in, SelectOut* // Returns EHOSTDOWN, if no available server is found // after traversing the whole server list. // Otherwise, returns 0 with a available excluded server. - return NULL == out->ptr ? EHOSTDOWN : 0; + return nullptr == out->ptr ? EHOSTDOWN : 0; } LoadBalancer* WeightedRandomizedLoadBalancer::New( const butil::StringPiece&) const { - return new (std::nothrow) WeightedRandomizedLoadBalancer; + return new WeightedRandomizedLoadBalancer; } void WeightedRandomizedLoadBalancer::Destroy() { diff --git a/src/brpc/policy/weighted_round_robin_load_balancer.cpp b/src/brpc/policy/weighted_round_robin_load_balancer.cpp index 44d8a957b3..f52bf2990b 100644 --- a/src/brpc/policy/weighted_round_robin_load_balancer.cpp +++ b/src/brpc/policy/weighted_round_robin_load_balancer.cpp @@ -246,7 +246,7 @@ SocketId WeightedRoundRobinLoadBalancer::GetServerInNextStride( LoadBalancer* WeightedRoundRobinLoadBalancer::New( const butil::StringPiece&) const { - return new (std::nothrow) WeightedRoundRobinLoadBalancer; + return new WeightedRoundRobinLoadBalancer; } void WeightedRoundRobinLoadBalancer::Destroy() { diff --git a/src/brpc/rdma/block_pool.cpp b/src/brpc/rdma/block_pool.cpp index d8dbb8abda..3a332a918e 100644 --- a/src/brpc/rdma/block_pool.cpp +++ b/src/brpc/rdma/block_pool.cpp @@ -44,7 +44,7 @@ DEFINE_bool(rdma_memory_pool_user_specified_memory, false, DEFINE_string(rdma_recv_block_type, "default", "Default size type for recv WR: " "default(8KB - 32B)/large(64KB - 32B)/huge(2MB - 32B)"); -static RegisterCallback g_cb = NULL; +static RegisterCallback g_cb = nullptr; // Number of bytes in 1MB static const size_t BYTES_IN_MB = 1048576; @@ -82,13 +82,13 @@ static const int32_t RDMA_MEMORY_POOL_MAX_BUCKETS = 16; static size_t g_buckets = 1; static bool g_dump_enable = false; -static butil::Mutex* g_dump_mutex = NULL; +static butil::Mutex* g_dump_mutex = nullptr; // Only for default block size -static __thread IdleNode* tls_idle_list = NULL; +static __thread IdleNode* tls_idle_list = nullptr; static __thread size_t tls_idle_num = 0; static __thread bool tls_inited = false; -static butil::Mutex* g_tls_info_mutex = NULL; +static butil::Mutex* g_tls_info_mutex = nullptr; static size_t g_tls_info_cnt = 0; static size_t* g_tls_info[1024]; @@ -102,14 +102,14 @@ struct GlobalInfo { std::vector expansion_list[BLOCK_SIZE_COUNT]; std::vector expansion_size[BLOCK_SIZE_COUNT]; }; -static GlobalInfo* g_info = NULL; +static GlobalInfo* g_info = nullptr; static inline Region* GetRegion(const void* buf) { if (!buf) { errno = EINVAL; - return NULL; + return nullptr; } - Region* r = NULL; + Region* r = nullptr; uintptr_t addr = (uintptr_t)buf; for (int i = 0; i < FLAGS_rdma_memory_pool_max_regions; ++i) { if (g_regions[i].start == 0) { @@ -140,13 +140,13 @@ static void* ExtendBlockPoolImpl(void* region_base, size_t region_size, int bloc if (g_region_num == FLAGS_rdma_memory_pool_max_regions) { LOG_EVERY_SECOND(ERROR) << "Memory pool reaches max regions"; errno = ENOMEM; - return NULL; + return nullptr; } uint32_t id = g_cb(region_base, region_size); if (id == 0) { errno = EINVAL; - return NULL; + return nullptr; } IdleNode* node[g_buckets]; @@ -158,7 +158,7 @@ static void* ExtendBlockPoolImpl(void* region_base, size_t region_size, int bloc butil::return_object(node[j]); } errno = ENOMEM; - return NULL; + return nullptr; } } @@ -187,14 +187,14 @@ static void* ExtendBlockPoolImpl(void* region_base, size_t region_size, int bloc static void* ExtendBlockPool(size_t region_size, int block_type) { if (region_size < 1 || block_type < 0) { errno = EINVAL; - return NULL; + return nullptr; } if (FLAGS_rdma_memory_pool_user_specified_memory) { LOG_EVERY_SECOND(ERROR) << "Fail to extend new region, " "rdma_memory_pool_user_specified_memory is " "true, ExtendBlockPool is disabled"; - return NULL; + return nullptr; } // Regularize region size @@ -203,10 +203,10 @@ static void* ExtendBlockPool(size_t region_size, int block_type) { LOG(INFO) << "Start extend rdma memory " << region_size / BYTES_IN_MB << "MB"; - void* region_base = NULL; + void* region_base = nullptr; if (posix_memalign(®ion_base, 4096, region_size) != 0) { PLOG_EVERY_SECOND(ERROR) << "Memory not enough"; - return NULL; + return nullptr; } return ExtendBlockPoolImpl(region_base, region_size, block_type); @@ -219,12 +219,12 @@ void* ExtendBlockPoolByUser(void* region_base, size_t region_size, int block_typ if (!FLAGS_rdma_memory_pool_user_specified_memory) { LOG_EVERY_SECOND(ERROR) << "User extend memory is disabled"; - return NULL; + return nullptr; } if (reinterpret_cast(region_base) % 4096 != 0) { LOG_EVERY_SECOND(ERROR) << "region_base must be 4096 aligned"; errno = EINVAL; - return NULL; + return nullptr; } region_size = @@ -284,17 +284,14 @@ bool InitBlockPool(RegisterCallback cb) { return false; } g_buckets = FLAGS_rdma_memory_pool_buckets; - g_info = new (std::nothrow) GlobalInfo; - if (!g_info) { - return false; - } + g_info = new GlobalInfo; for (int i = 0; i < BLOCK_SIZE_COUNT; ++i) { - g_info->idle_list[i].resize(g_buckets, NULL); + g_info->idle_list[i].resize(g_buckets, nullptr); if (g_info->idle_list[i].size() != g_buckets) { return false; } - g_info->lock[i].resize(g_buckets, NULL); + g_info->lock[i].resize(g_buckets, nullptr); if (g_info->lock[i].size() != g_buckets) { return false; } @@ -304,12 +301,9 @@ bool InitBlockPool(RegisterCallback cb) { } g_info->region_num[i] = 0; for (size_t j = 0; j < g_buckets; ++j) { - g_info->lock[i][j] = new (std::nothrow) butil::Mutex; - if (!g_info->lock[i][j]) { - return false; - } + g_info->lock[i][j] = new butil::Mutex; } - g_info->expansion_list[i].resize(g_buckets, NULL); + g_info->expansion_list[i].resize(g_buckets, nullptr); if (g_info->expansion_list[i].size() != g_buckets) { return false; } @@ -327,18 +321,18 @@ bool InitBlockPool(RegisterCallback cb) { } if (ExtendBlockPool(FLAGS_rdma_memory_pool_initial_size_mb, - GetRdmaBlockType()) != NULL) { + GetRdmaBlockType()) != nullptr) { return true; } return false; } static void MoveExpansionList2EmptyIdleList(int block_type, size_t index) { - CHECK(NULL == g_info->idle_list[block_type][index]); + CHECK(nullptr == g_info->idle_list[block_type][index]); g_info->idle_list[block_type][index] = g_info->expansion_list[block_type][index]; g_info->idle_size[block_type][index] += g_info->expansion_size[block_type][index]; - g_info->expansion_list[block_type][index] = NULL; + g_info->expansion_list[block_type][index] = nullptr; g_info->expansion_size[block_type][index] = 0; } @@ -354,8 +348,8 @@ static void* AllocBlockFrom(int block_type) { } }; - void* ptr = NULL; - if (0 == block_type && NULL != tls_idle_list) { + void* ptr = nullptr; + if (0 == block_type && nullptr != tls_idle_list) { CHECK(tls_idle_num > 0); IdleNode* n = tls_idle_list; tls_idle_list = n->next; @@ -368,14 +362,14 @@ static void* AllocBlockFrom(int block_type) { size_t index = butil::fast_rand() % g_buckets; BAIDU_SCOPED_LOCK(*g_info->lock[block_type][index]); IdleNode* node = g_info->idle_list[block_type][index]; - if (NULL == node) { + if (nullptr == node) { BAIDU_SCOPED_LOCK(g_info->extend_lock); node = g_info->idle_list[block_type][index]; - if (NULL == node && NULL != g_info->expansion_list[block_type][index]) { + if (nullptr == node && nullptr != g_info->expansion_list[block_type][index]) { MoveExpansionList2EmptyIdleList(block_type, index); node = g_info->idle_list[block_type][index]; } - if (NULL == node) { + if (nullptr == node) { // There is no block left, extend a new region. if (!ExtendBlockPool(FLAGS_rdma_memory_pool_increase_size_mb, block_type)) { LOG_EVERY_SECOND(ERROR) << "Fail to extend new region. " @@ -384,13 +378,13 @@ static void* AllocBlockFrom(int block_type) { << "rdma_memory_pool_initial_size_mb, " << "rdma_memory_pool_increase_size_mb, " << "rdma_memory_pool_max_regions."; - return NULL; + return nullptr; } MoveExpansionList2EmptyIdleList(block_type, index); node = g_info->idle_list[block_type][index]; } } - CHECK(NULL != node); + CHECK(nullptr != node); ptr = node->start; if (node->len > g_block_size[block_type]) { @@ -406,7 +400,7 @@ static void* AllocBlockFrom(int block_type) { if (block_type == 0) { node = g_info->idle_list[0][index]; tls_idle_list = node; - IdleNode* last_node = NULL; + IdleNode* last_node = nullptr; while (node) { if (tls_idle_num > (uint32_t)FLAGS_rdma_memory_pool_tls_cache_num / 2 || node->len > g_block_size[0]) { @@ -417,12 +411,12 @@ static void* AllocBlockFrom(int block_type) { node = node->next; } if (tls_idle_num == 0) { - tls_idle_list = NULL; + tls_idle_list = nullptr; } else { g_info->idle_list[0][index] = node; } if (last_node) { - last_node->next = NULL; + last_node->next = nullptr; } } @@ -432,14 +426,14 @@ static void* AllocBlockFrom(int block_type) { void* AllocBlock(size_t size) { if (size == 0 || size > g_block_size[BLOCK_SIZE_COUNT - 1]) { errno = EINVAL; - return NULL; + return nullptr; } for (int i = 0; i < BLOCK_SIZE_COUNT; ++i) { if (size <= g_block_size[i]) { return AllocBlockFrom(i);; } } - return NULL; + return nullptr; } void RecycleAll() { @@ -515,7 +509,7 @@ int DeallocBlock(void* buf) { // Recycle half the cached blocks in tls for default block size int num = FLAGS_rdma_memory_pool_tls_cache_num / 2; IdleNode* new_head = tls_idle_list; - IdleNode* recycle_tail = NULL; + IdleNode* recycle_tail = nullptr; for (int i = 0; i < num; ++i) { recycle_tail = new_head; len += recycle_tail->len; @@ -614,18 +608,18 @@ void DestroyBlockPool() { butil::return_object(node); node = tmp; } - g_info->idle_list[i][j] = NULL; + g_info->idle_list[i][j] = nullptr; // Release the per-bucket mutexes allocated in InitBlockPool. delete g_info->lock[i][j]; - g_info->lock[i][j] = NULL; + g_info->lock[i][j] = nullptr; } } delete g_info; - g_info = NULL; + g_info = nullptr; delete g_dump_mutex; - g_dump_mutex = NULL; + g_dump_mutex = nullptr; delete g_tls_info_mutex; - g_tls_info_mutex = NULL; + g_tls_info_mutex = nullptr; for (int i = 0; i < g_region_num; ++i) { if (g_regions[i].start == 0) { break; @@ -634,7 +628,7 @@ void DestroyBlockPool() { g_regions[i].start = 0; } g_region_num = 0; - g_cb = NULL; + g_cb = nullptr; } // Just for UT diff --git a/src/brpc/rdma/block_pool.h b/src/brpc/rdma/block_pool.h index c9589fb035..b0b8ffc1e4 100644 --- a/src/brpc/rdma/block_pool.h +++ b/src/brpc/rdma/block_pool.h @@ -72,7 +72,7 @@ typedef uint32_t (*RegisterCallback)(void*, size_t); // The argument is a callback called when the pool is enlarged with a new // region. It should be the memory registration in brpc. However, // in block_pool, we just abstract it into a function to get region id. -// Return the first region's address, NULL if failed and errno is set. +// Return the first region's address, nullptr if failed and errno is set. bool InitBlockPool(RegisterCallback cb); // In scenarios where users need to manually specify memory regions (e.g., using @@ -83,10 +83,10 @@ bool InitBlockPool(RegisterCallback cb); void* ExtendBlockPoolByUser(void* region_base, size_t region_size, int block_type); // Allocate a buf with length at least @a size (require: size>0) -// Return the address allocated, NULL if failed and errno is set. +// Return the address allocated, nullptr if failed and errno is set. void* AllocBlock(size_t size); -// Deallocate the buf (require: buf!=NULL) +// Deallocate the buf (require: buf!=nullptr) // Return 0 if success, -1 if failed and errno is set. // If the given buf is not in any region, the errno is ERANGE. int DeallocBlock(void* buf); diff --git a/src/brpc/rdma/rdma_endpoint.cpp b/src/brpc/rdma/rdma_endpoint.cpp index 6c20ea3994..fd70fb5c2b 100644 --- a/src/brpc/rdma/rdma_endpoint.cpp +++ b/src/brpc/rdma/rdma_endpoint.cpp @@ -53,6 +53,10 @@ extern int (*IbvQueryEce)(ibv_qp*, ibv_ece*); extern int (*IbvSetEce)(ibv_qp*, ibv_ece*); extern bool g_skip_rdma_init; +// Only for UT: force AllocateResources() to fail, so that the "fallback to TCP" path +// of the handshake can be tested without a real RDMA device. +bool g_fail_resource_alloc_for_test = false; + DEFINE_int32(rdma_sq_size, 128, "SQ size for RDMA"); DEFINE_int32(rdma_rq_size, 128, "RQ size for RDMA"); DEFINE_bool(rdma_recv_zerocopy, true, "Enable zerocopy for receive side"); @@ -84,23 +88,23 @@ extern const uint16_t MIN_QP_SIZE = 16; static const uint16_t MAX_QP_SIZE = 4096; extern const uint16_t MIN_BLOCK_SIZE = 1024; -static butil::Mutex* g_rdma_resource_mutex = NULL; -static RdmaResource* g_rdma_resource_list = NULL; +static butil::Mutex* g_rdma_resource_mutex = nullptr; +static RdmaResource* g_rdma_resource_list = nullptr; RdmaResource::~RdmaResource() { - if (NULL != qp) { + if (nullptr != qp) { IbvDestroyQp(qp); } - if (NULL != polling_cq) { + if (nullptr != polling_cq) { IbvDestroyCq(polling_cq); } - if (NULL != send_cq) { + if (nullptr != send_cq) { IbvDestroyCq(send_cq); } - if (NULL != recv_cq) { + if (nullptr != recv_cq) { IbvDestroyCq(recv_cq); } - if (NULL != comp_channel) { + if (nullptr != comp_channel) { IbvDestroyCompChannel(comp_channel); } } @@ -109,7 +113,7 @@ RdmaEndpoint::RdmaEndpoint(Socket* s) : _socket(s) , _state(UNINIT) , _handshake_version(0) - , _resource(NULL) + , _resource(nullptr) , _send_cq_events(0) , _recv_cq_events(0) , _cq_sid(INVALID_SOCKET_ID) @@ -156,7 +160,7 @@ void RdmaEndpoint::Reset() { _state.store(UNINIT, butil::memory_order_relaxed); _handshake_version = 0; _outgoing_ece.reset(); - _resource = NULL; + _resource = nullptr; _send_cq_events = 0; _recv_cq_events = 0; _cq_sid = INVALID_SOCKET_ID; @@ -183,7 +187,7 @@ void RdmaConnect::StartConnect(const Socket* socket, void (*done)(int err, void* data), void* data) { auto* rdma_transport = static_cast(socket->_transport.get()); - CHECK(rdma_transport->_rdma_ep != NULL); + CHECK(rdma_transport->_rdma_ep != nullptr); SocketUniquePtr s; if (Socket::Address(socket->id(), &s) != 0) { return; @@ -219,7 +223,7 @@ void RdmaConnect::Run() { void RdmaEndpoint::OnNewDataFromTcp(Socket* m) { auto* rdma_transport = static_cast(m->_transport.get()); RdmaEndpoint* ep = rdma_transport->GetRdmaEp(); - CHECK(ep != NULL); + CHECK(ep != nullptr); int progress = Socket::PROGRESS_INIT; while (true) { @@ -309,7 +313,7 @@ static int ReadFromFdLoop(butil::atomic* read_butex, } int RdmaEndpoint::ReadFromFd(void* data, size_t len) { - CHECK(data != NULL); + CHECK(data != nullptr); const int fd = _socket->fd(); return ReadFromFdLoop(_read_butex, len, [data, fd](size_t offset, size_t remaining) { @@ -318,7 +322,7 @@ int RdmaEndpoint::ReadFromFd(void* data, size_t len) { } int RdmaEndpoint::ReadFromFd(butil::IOPortal* data, size_t len) { - CHECK(data != NULL); + CHECK(data != nullptr); const int fd = _socket->fd(); return ReadFromFdLoop(_read_butex, len, [data, fd](size_t /*offset*/, size_t remaining) { @@ -362,7 +366,7 @@ static int WriteToFdLoop(size_t len, WriteOnce&& write_once, WaitWritable&& wait } int RdmaEndpoint::WriteToFd(void* data, size_t len) { - CHECK(data != NULL); + CHECK(data != nullptr); Socket* s = _socket; const int fd = s->fd(); return WriteToFdLoop(len, @@ -375,7 +379,7 @@ int RdmaEndpoint::WriteToFd(void* data, size_t len) { } int RdmaEndpoint::WriteToFd(butil::IOBuf* data) { - CHECK(data != NULL); + CHECK(data != nullptr); Socket* s = _socket; const int fd = s->fd(); return WriteToFdLoop(data->size(), @@ -424,16 +428,18 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { << "Start handshake on " << s->description(); std::unique_ptr handshake = CreateClientHandshake(ep); - CHECK(handshake != NULL); + CHECK(handshake != nullptr); ep->_handshake_version = handshake->ProtocolVersion(); // First initialize CQ and QP resources. ep->_state.store(C_ALLOC_QPCQ, butil::memory_order_relaxed); if (ep->AllocateResources() < 0) { - LOG(WARNING) << "Fallback to tcp:" << s->description(); + PLOG(WARNING) << "Fail to allocate rdma resources, fallback to tcp:" + << s->description(); + errno = 0; rdma_transport->_rdma_state = RdmaTransport::RDMA_OFF; ep->_state.store(FALLBACK_TCP, butil::memory_order_release); - return NULL; + return nullptr; } // Send hello message to server @@ -445,7 +451,7 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete rdma handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state.store(FAILED, butil::memory_order_relaxed); - return NULL; + return nullptr; } // Receive and parse remote hello. @@ -459,7 +465,7 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete rdma handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state.store(FAILED, butil::memory_order_relaxed); - return NULL; + return nullptr; } if (r != RemoteHelloResult::NEGOTIATED) { @@ -490,7 +496,7 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete rdma handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state.store(FAILED, butil::memory_order_relaxed); - return NULL; + return nullptr; } if (rdma_transport->_rdma_state == RdmaTransport::RDMA_ON) { @@ -506,7 +512,7 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { errno = 0; - return NULL; + return nullptr; } // Server-side handshake entry: the state machine. @@ -527,9 +533,9 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s) { RdmaTransport* rdma_transport = static_cast(s->_transport.get()); RdmaEndpoint* ep = rdma_transport->_rdma_ep; - CHECK(ep != NULL); + CHECK(ep != nullptr); - if (s->parsing_context() == NULL) { + if (s->parsing_context() == nullptr) { // Phase 1: read the client hello, negotiate, reply server hello. if (source->size() < HELLO_MAGIC_LEN) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); @@ -541,7 +547,7 @@ ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s // magic is NOT consumed; ReceiveAndParseRemoteHello() reads it again // from `source`). std::unique_ptr hs = CreateServerHandshakeByMagic(ep, source, magic); - if (hs == NULL) { + if (hs == nullptr) { return MakeParseError(PARSE_ERROR_TRY_OTHERS); } ep->_handshake_version = hs->ProtocolVersion(); @@ -563,8 +569,8 @@ ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s ep->ApplyRemoteHello(remote); ep->_state.store(S_ALLOC_QPCQ, butil::memory_order_relaxed); if (ep->AllocateResources() < 0) { - LOG(WARNING) << "Fail to allocate rdma resources, fallback to tcp:" - << s->description(); + PLOG(WARNING) << "Fail to allocate rdma resources, fallback to tcp:" + << s->description(); negotiated = false; } else { ep->_state.store(S_BRINGUP_QP, butil::memory_order_relaxed); @@ -605,7 +611,7 @@ ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s LOG(WARNING) << "Too many bytes in handshake ACK, drop connection: " << s->description(); ep->_state.store(FAILED, butil::memory_order_relaxed); - s->reset_parsing_context(NULL); + s->reset_parsing_context(nullptr); return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG); } @@ -618,7 +624,7 @@ ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s << "Server handshake ends (use tcp) on " << s->description(); rdma_transport->_rdma_state = RdmaTransport::RDMA_OFF; ep->_state.store(FALLBACK_TCP, butil::memory_order_release); - s->reset_parsing_context(NULL); + s->reset_parsing_context(nullptr); return MakeParseError(PARSE_ERROR_TRY_OTHERS); } @@ -626,7 +632,7 @@ ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s LOG(WARNING) << "Client wants RDMA in ACK but server fell back: " << s->description(); ep->_state.store(FAILED, butil::memory_order_relaxed); - s->reset_parsing_context(NULL); + s->reset_parsing_context(nullptr); return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG); } @@ -635,7 +641,7 @@ ParseResult RdmaEndpoint::ExecuteServerHandshake(butil::IOBuf* source, Socket* s << ") on " << s->description(); rdma_transport->_rdma_state = RdmaTransport::RDMA_ON; ep->_state.store(ESTABLISHED, butil::memory_order_relaxed); - s->reset_parsing_context(NULL); + s->reset_parsing_context(nullptr); return MakeParseError(PARSE_ERROR_TRY_OTHERS); } @@ -712,7 +718,7 @@ ssize_t RdmaEndpoint::CutFromIOBufList(butil::IOBuf** from, size_t ndata) { return -1; } - CHECK(from != NULL); + CHECK(from != nullptr); CHECK(ndata > 0); size_t total_len = 0; @@ -811,7 +817,7 @@ ssize_t RdmaEndpoint::CutFromIOBufList(butil::IOBuf** from, size_t ndata) { _sq_unsignaled = 0; } - ibv_send_wr* bad = NULL; + ibv_send_wr* bad = nullptr; int err = ibv_post_send(_resource->qp, &wr, &bad); if (err != 0) { // We use other way to guarantee the Send Queue is not full. @@ -861,7 +867,7 @@ int RdmaEndpoint::SendImm(uint32_t imm) { wr.send_flags |= IBV_SEND_SOLICITED | IBV_SEND_SIGNALED; wr.wr_id = 0; - ibv_send_wr* bad = NULL; + ibv_send_wr* bad = nullptr; int err = ibv_post_send(_resource->qp, &wr, &bad); if (err != 0) { std::ostringstream oss; @@ -964,7 +970,7 @@ int RdmaEndpoint::DoPostRecv(void* block, size_t block_size) { wr.num_sge = 1; wr.sg_list = &sge; - ibv_recv_wr* bad = NULL; + ibv_recv_wr* bad = nullptr; int err = ibv_post_recv(_resource->qp, &wr, &bad); if (err != 0) { LOG(WARNING) << "Fail to ibv_post_recv: " << berror(err); @@ -1019,52 +1025,52 @@ static RdmaResource* AllocateQpCq(uint16_t sq_size, uint16_t rq_size) { std::unique_ptr resource(new RdmaResource); if (!FLAGS_rdma_use_polling) { resource->comp_channel = IbvCreateCompChannel(GetRdmaContext()); - if (NULL == resource->comp_channel) { + if (nullptr == resource->comp_channel) { PLOG(WARNING) << "Fail to create comp channel for CQ"; - return NULL; + return nullptr; } if (butil::make_close_on_exec(resource->comp_channel->fd) < 0) { PLOG(WARNING) << "Fail to set comp channel close-on-exec"; - return NULL; + return nullptr; } if (butil::make_non_blocking(resource->comp_channel->fd) < 0) { PLOG(WARNING) << "Fail to set comp channel nonblocking"; - return NULL; + return nullptr; } resource->send_cq = IbvCreateCq(GetRdmaContext(), FLAGS_rdma_prepared_qp_size, - NULL, resource->comp_channel, GetRdmaCompVector()); - if (NULL == resource->send_cq) { + nullptr, resource->comp_channel, GetRdmaCompVector()); + if (nullptr == resource->send_cq) { PLOG(WARNING) << "Fail to create send CQ"; - return NULL; + return nullptr; } resource->recv_cq = IbvCreateCq(GetRdmaContext(), FLAGS_rdma_prepared_qp_size, - NULL, resource->comp_channel, GetRdmaCompVector()); - if (NULL == resource->recv_cq) { + nullptr, resource->comp_channel, GetRdmaCompVector()); + if (nullptr == resource->recv_cq) { PLOG(WARNING) << "Fail to create recv CQ"; - return NULL; + return nullptr; } resource->qp = AllocateQp(resource->send_cq, resource->recv_cq, sq_size, rq_size); - if (NULL == resource->qp) { + if (nullptr == resource->qp) { PLOG(WARNING) << "Fail to create QP"; - return NULL; + return nullptr; } } else { resource->polling_cq = - IbvCreateCq(GetRdmaContext(), 2 * FLAGS_rdma_prepared_qp_size, NULL, NULL, 0); - if (NULL == resource->polling_cq) { + IbvCreateCq(GetRdmaContext(), 2 * FLAGS_rdma_prepared_qp_size, nullptr, nullptr, 0); + if (nullptr == resource->polling_cq) { PLOG(WARNING) << "Fail to create polling CQ"; - return NULL; + return nullptr; } resource->qp = AllocateQp(resource->polling_cq, resource->polling_cq, sq_size, rq_size); - if (NULL == resource->qp) { + if (nullptr == resource->qp) { PLOG(WARNING) << "Fail to create QP"; - return NULL; + return nullptr; } } @@ -1072,12 +1078,30 @@ static RdmaResource* AllocateQpCq(uint16_t sq_size, uint16_t rq_size) { } int RdmaEndpoint::AllocateResources() { + if (DoAllocateResources() == 0) { + return 0; + } + + const int saved_errno = errno; + DeallocateResources(); + _sbuf.clear(); + _rbuf.clear(); + _rbuf_data.clear(); + errno = saved_errno; + return -1; +} + +int RdmaEndpoint::DoAllocateResources() { if (BAIDU_UNLIKELY(g_skip_rdma_init)) { // For UT + if (BAIDU_UNLIKELY(g_fail_resource_alloc_for_test)) { + errno = EINVAL; + return -1; + } return 0; } - CHECK(_resource == NULL); + CHECK(_resource == nullptr); if (_sq_size <= FLAGS_rdma_prepared_qp_size && _rq_size <= FLAGS_rdma_prepared_qp_size) { @@ -1090,17 +1114,17 @@ int RdmaEndpoint::AllocateResources() { if (!_resource) { _resource = AllocateQpCq(_sq_size, _rq_size); } else { - _resource->next = NULL; + _resource->next = nullptr; } if (!_resource) { return -1; } if (!FLAGS_rdma_use_polling) { - if (0 != ReqNotifyCq(true)) { + if (0 != ReqNotifyCq(true, false)) { return -1; } - if (0 != ReqNotifyCq(false)) { + if (0 != ReqNotifyCq(false, false)) { return -1; } @@ -1132,7 +1156,7 @@ int RdmaEndpoint::AllocateResources() { if (_rbuf.size() != _rq_size) { return -1; } - _rbuf_data.resize(_rq_size, NULL); + _rbuf_data.resize(_rq_size, nullptr); if (_rbuf_data.size() != _rq_size) { return -1; } @@ -1172,7 +1196,7 @@ int RdmaEndpoint::BringUpQp(const ParsedHello& remote, bool is_server) { // Client: `remote->ece' is the server's reduced ECE; // just set it here. bool use_ece = true; - if (IbvSetEce != NULL && remote.ece.has_value()) { + if (IbvSetEce != nullptr && remote.ece.has_value()) { ibv_ece ece = *remote.ece; int err = IbvSetEce(_resource->qp, &ece); if (err != 0) { @@ -1238,7 +1262,7 @@ int RdmaEndpoint::BringUpQp(const ParsedHello& remote, bool is_server) { // On the server side, now that the QP reached RTS, query the reduced/negotiated // ECE (the subset of enhancements supported by both peers) so it can be returned // to the client in the server hello. - if (is_server && use_ece && IbvQueryEce != NULL && remote.ece.has_value()) { + if (is_server && use_ece && IbvQueryEce != nullptr && remote.ece.has_value()) { ibv_ece ece; int qerr = IbvQueryEce(_resource->qp, &ece); if (qerr == 0) { @@ -1253,7 +1277,7 @@ int RdmaEndpoint::BringUpQp(const ParsedHello& remote, bool is_server) { } static void DeallocateCq(ibv_cq* cq) { - if (NULL == cq) { + if (nullptr == cq) { return; } @@ -1262,7 +1286,7 @@ static void DeallocateCq(ibv_cq* cq) { } static int DrainCq(ibv_cq* cq) { - if (NULL == cq) { + if (nullptr == cq) { return 0; } @@ -1294,27 +1318,27 @@ void RdmaEndpoint::DeallocateResources() { } } - if (NULL != _resource->send_cq) { + if (nullptr != _resource->send_cq) { IbvAckCqEvents(_resource->send_cq, _send_cq_events); } - if (NULL != _resource->recv_cq) { + if (nullptr != _resource->recv_cq) { IbvAckCqEvents(_resource->recv_cq, _recv_cq_events); } bool remove_consumer = true; _reclaim: if (!move_to_rdma_resource_list) { - if (NULL != _resource->qp) { + if (nullptr != _resource->qp) { int err = IbvDestroyQp(_resource->qp); LOG_IF(WARNING, 0 != err) << "Fail to destroy QP: " << berror(err); - _resource->qp = NULL; + _resource->qp = nullptr; } DeallocateCq(_resource->polling_cq); DeallocateCq(_resource->send_cq); DeallocateCq(_resource->recv_cq); - if (NULL != _resource->comp_channel) { + if (nullptr != _resource->comp_channel) { // Destroy send_comp_channel will destroy this fd, // so that we should remove it from epoll fd first int fd = _resource->comp_channel->fd; @@ -1325,12 +1349,12 @@ void RdmaEndpoint::DeallocateResources() { } - _resource->polling_cq = NULL; - _resource->send_cq = NULL; - _resource->recv_cq = NULL; - _resource->comp_channel = NULL; + _resource->polling_cq = nullptr; + _resource->send_cq = nullptr; + _resource->recv_cq = nullptr; + _resource->comp_channel = nullptr; delete _resource; - _resource = NULL; + _resource = nullptr; } if (INVALID_SOCKET_ID != _cq_sid) { @@ -1339,7 +1363,7 @@ void RdmaEndpoint::DeallocateResources() { if (remove_consumer) { s->_io_event.RemoveConsumer(s->_fd); } - s->_user = NULL; // Do not release user (this RdmaEndpoint). + s->_user = nullptr; // Do not release user (this RdmaEndpoint). s->_fd = -1; // Already remove fd from epoll fd. s->SetFailed(); } @@ -1364,17 +1388,27 @@ void RdmaEndpoint::DeallocateResources() { goto _reclaim; } - BAIDU_SCOPED_LOCK(*g_rdma_resource_mutex); - _resource->next = g_rdma_resource_list; - g_rdma_resource_list = _resource; + { + BAIDU_SCOPED_LOCK(*g_rdma_resource_mutex); + _resource->next = g_rdma_resource_list; + g_rdma_resource_list = _resource; + } + _resource = nullptr; } + + // Detach everything from this endpoint so that the function is + // idempotent: it is called both when the endpoint is reset/destroyed + // and when AllocateResources() fails halfway. + _cq_sid = INVALID_SOCKET_ID; + _send_cq_events = 0; + _recv_cq_events = 0; } static const int MAX_CQ_EVENTS = 128; int RdmaEndpoint::GetAndAckEvents(SocketUniquePtr& s) { - void* context = NULL; - ibv_cq* cq = NULL; + void* context = nullptr; + ibv_cq* cq = nullptr; while (true) { if (IbvGetCqEvent(_resource->comp_channel, &cq, &context) != 0) { if (errno != EAGAIN) { @@ -1411,17 +1445,21 @@ int RdmaEndpoint::GetAndAckEvents(SocketUniquePtr& s) { return 0; } -int RdmaEndpoint::ReqNotifyCq(bool send_cq) { - errno = ibv_req_notify_cq( +int RdmaEndpoint::ReqNotifyCq(bool send_cq, bool fatal_on_error) { + const int err = ibv_req_notify_cq( send_cq ? _resource->send_cq : _resource->recv_cq, send_cq ? 0 : 1); - if (0 != errno) { - const int saved_errno = errno; + if (0 != err) { + errno = err; PLOG(WARNING) << "Fail to arm " << (send_cq ? "send" : "recv") << " CQ comp channel from " << _socket->description(); - _socket->SetFailed(saved_errno, "Fail to arm %s CQ channel from %s: %s", - send_cq ? "send" : "recv", _socket->description().c_str(), - berror(saved_errno)); + if (fatal_on_error) { + _socket->SetFailed(err, "Fail to arm %s CQ channel from %s: %s", + send_cq ? "send" : "recv", _socket->description().c_str(), + berror(err)); + } + // The logging and SetFailed() above may clobber errno. + errno = err; return -1; } @@ -1485,13 +1523,27 @@ void RdmaEndpoint::PollCq(Socket* m) { // that the event arrives after the poll but before the notify, // we should re-poll the CQ once after the notify to check if // there is an available CQE. - if (0 != ep->ReqNotifyCq(true)) { + // The connection is already working in RDMA mode here, a + // failed re-arm means no more CQ event will be reported, + // which is fatal for this connection. + if (0 != ep->ReqNotifyCq(true, true)) { return; } - if (0 != ep->ReqNotifyCq(false)) { + if (0 != ep->ReqNotifyCq(false, true)) { return; } notified = true; + // Both CQs have just been re-armed, thus both of them must be + // re-polled. Note that `cq' is `send_cq' here, so we have to + // switch back to `recv_cq' explicitly. Otherwise only + // `send_cq' would be re-polled, and a recv CQE arriving in + // the window between the poll and the notify of `recv_cq' + // would be left in the CQ without any following event + // (one shot notification is not triggered by the CQE which + // is already in the CQ before the arming), which stalls the + // connection until the next CQE happens to come. + send = false; + cq = ep->_resource->recv_cq; continue; } if (!m->MoreReadEvents(&progress)) { @@ -1721,7 +1773,7 @@ void RdmaEndpoint::PollingModeRelease(bthread_tag_t tag) { auto& running = group.running; running.store(false, std::memory_order_relaxed); for (int i = 0; i < FLAGS_rdma_poller_num; ++i) { - bthread_join(pollers[i].tid, NULL); + bthread_join(pollers[i].tid, nullptr); } } diff --git a/src/brpc/rdma/rdma_endpoint.h b/src/brpc/rdma/rdma_endpoint.h index 36e22ad28d..388e31d78e 100644 --- a/src/brpc/rdma/rdma_endpoint.h +++ b/src/brpc/rdma/rdma_endpoint.h @@ -74,19 +74,19 @@ class RdmaConnect : public AppConnect { private: void Run(); - void (*_done)(int, void*){NULL}; - void* _data{NULL}; + void (*_done)(int, void*){nullptr}; + void* _data{nullptr}; }; struct RdmaResource { - RdmaResource* next{NULL}; - ibv_qp* qp{NULL}; + RdmaResource* next{nullptr}; + ibv_qp* qp{nullptr}; // For polling mode. - ibv_cq* polling_cq{NULL}; + ibv_cq* polling_cq{nullptr}; // For event mode. - ibv_cq* send_cq{NULL}; - ibv_cq* recv_cq{NULL}; - ibv_comp_channel* comp_channel{NULL}; + ibv_cq* send_cq{nullptr}; + ibv_cq* recv_cq{nullptr}; + ibv_comp_channel* comp_channel{nullptr}; RdmaResource() = default; ~RdmaResource(); DISALLOW_COPY_AND_ASSIGN(RdmaResource); @@ -164,10 +164,16 @@ friend int v3_wire::WriteV3Hello(RdmaEndpoint*, const RdmaHello&); // Process handshake at the client static void* ProcessHandshakeAtClient(void* arg); - // Allocate resources + // Allocate resources. On failure the endpoint is left with no RDMA + // resource attached, so that the handshake can safely fall back to TCP. // Return 0 if success, -1 if failed and errno set int AllocateResources(); + // The real implementation of AllocateResources(), which may return + // in the middle with resources partially allocated. + // Return 0 if success, -1 if failed and errno set + int DoAllocateResources(); + // Release resources void DeallocateResources(); @@ -244,7 +250,7 @@ friend int v3_wire::WriteV3Hello(RdmaEndpoint*, const RdmaHello&); int GetAndAckEvents(SocketUniquePtr& s); // Request completion notification on a send/recv CQ. - int ReqNotifyCq(bool send_cq); + int ReqNotifyCq(bool send_cq, bool fatal_on_error); // Poll CQ and get the work completion static void PollCq(Socket* m); diff --git a/src/brpc/rdma/rdma_handshake.cpp b/src/brpc/rdma/rdma_handshake.cpp index 180c2b3f0b..17c6715562 100644 --- a/src/brpc/rdma/rdma_handshake.cpp +++ b/src/brpc/rdma/rdma_handshake.cpp @@ -388,7 +388,7 @@ int RdmaHandshakeClientV3::SendLocalHello() { // Query local ECE capabilities so they can be advertised in the client // hello. v3-only. Best-effort: any failure or missing API just means we // won't advertise ECE (the peer then degrades to no-ECE establishment). - if (FLAGS_rdma_ece && IbvQueryEce != NULL && + if (FLAGS_rdma_ece && IbvQueryEce != nullptr && _ep->_resource && _ep->_resource->qp) { ibv_ece ece; if (IbvQueryEce(_ep->_resource->qp, &ece) == 0) { @@ -505,7 +505,7 @@ std::unique_ptr CreateServerHandshakeByMagic( return std::unique_ptr( new RdmaHandshakeServerV3(ep, source)); } - return NULL; + return nullptr; } } // namespace rdma diff --git a/src/brpc/rdma/rdma_handshake.h b/src/brpc/rdma/rdma_handshake.h index 6238d424f0..2d10220ab9 100644 --- a/src/brpc/rdma/rdma_handshake.h +++ b/src/brpc/rdma/rdma_handshake.h @@ -171,7 +171,7 @@ class RdmaHandshakeServerV3 : public ServerRdmaHandshake { std::unique_ptr CreateClientHandshake(RdmaEndpoint* ep); // Pick the server-side handshake based on the 4B magic already read. -// Returns NULL if `magic` is not a recognized RDMA magic +// Returns nullptr if `magic` is not a recognized RDMA magic // (the caller should then fallback to TCP). // "RDMA" -> RdmaHandshakeServerV2 // "RDM3" -> RdmaHandshakeServerV3 diff --git a/src/brpc/rdma/rdma_handshake_server.cpp b/src/brpc/rdma/rdma_handshake_server.cpp index 4072a11c90..6dfb0c91f5 100644 --- a/src/brpc/rdma/rdma_handshake_server.cpp +++ b/src/brpc/rdma/rdma_handshake_server.cpp @@ -154,7 +154,7 @@ static int SendUnnegotiableHello(Socket* socket, int version) { // Fallback handshake for connections that are NOT in RDMA mode. static ParseResult FallbackServerHandshake(butil::IOBuf* source, Socket* socket) { - if (socket->parsing_context() == NULL) { + if (socket->parsing_context() == nullptr) { if (source->size() < HELLO_MAGIC_LEN) { return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); } @@ -194,7 +194,7 @@ static ParseResult FallbackServerHandshake(butil::IOBuf* source, Socket* socket) CHECK_EQ(source->pop_front(HELLO_ACK_LEN), HELLO_ACK_LEN); // Handshake done (downgraded to TCP); drop the context and let // InputMessenger parse the following real RPC. - socket->reset_parsing_context(NULL); + socket->reset_parsing_context(nullptr); return MakeParseError(PARSE_ERROR_TRY_OTHERS); } diff --git a/src/brpc/rdma/rdma_helper.cpp b/src/brpc/rdma/rdma_helper.cpp index b0e13ad72c..38bd58cac4 100644 --- a/src/brpc/rdma/rdma_helper.cpp +++ b/src/brpc/rdma/rdma_helper.cpp @@ -43,37 +43,37 @@ extern void (*blockmem_deallocate)(void*); namespace brpc { namespace rdma { -void* g_handle_ibverbs = NULL; +void* g_handle_ibverbs = nullptr; bool g_skip_rdma_init = false; -ibv_device** (*IbvGetDeviceList)(int*) = NULL; -void (*IbvFreeDeviceList)(ibv_device**) = NULL; -ibv_context* (*IbvOpenDevice)(ibv_device*) = NULL; -int (*IbvCloseDevice)(ibv_context*) = NULL; -const char* (*IbvGetDeviceName)(ibv_device*) = NULL; -int (*IbvForkInit)(void) = NULL; -int (*IbvQueryDevice)(ibv_context*, ibv_device_attr*) = NULL; -int (*IbvQueryPort)(ibv_context*, uint8_t, ibv_port_attr*) = NULL; -int (*IbvQueryGid)(ibv_context*, uint8_t, int, ibv_gid*) = NULL; -ibv_pd* (*IbvAllocPd)(ibv_context*) = NULL; -int (*IbvDeallocPd)(ibv_pd*) = NULL; -ibv_cq* (*IbvCreateCq)(ibv_context*, int, void*, ibv_comp_channel*, int) = NULL; -int (*IbvDestroyCq)(ibv_cq*) = NULL; -ibv_qp* (*IbvCreateQp)(ibv_pd*, ibv_qp_init_attr*) = NULL; -int (*IbvModifyQp)(ibv_qp*, ibv_qp_attr*, ibv_qp_attr_mask) = NULL; -int (*IbvQueryQp)(ibv_qp*, ibv_qp_attr*, ibv_qp_attr_mask, ibv_qp_init_attr*) = NULL; -int (*IbvDestroyQp)(ibv_qp*) = NULL; -ibv_comp_channel* (*IbvCreateCompChannel)(ibv_context*) = NULL; -int (*IbvDestroyCompChannel)(ibv_comp_channel*) = NULL; -ibv_mr* (*IbvRegMr)(ibv_pd*, void*, size_t, int) = NULL; -int (*IbvDeregMr)(ibv_mr*) = NULL; -int (*IbvGetCqEvent)(ibv_comp_channel*, ibv_cq**, void**) = NULL; -void (*IbvAckCqEvents)(ibv_cq*, unsigned int) = NULL; -int (*IbvGetAsyncEvent)(ibv_context*, ibv_async_event*) = NULL; -void (*IbvAckAsyncEvent)(ibv_async_event*) = NULL; -const char* (*IbvEventTypeStr)(ibv_event_type) = NULL; -int (*IbvQueryEce)(ibv_qp*, ibv_ece*) = NULL; -int (*IbvSetEce)(ibv_qp*, ibv_ece*) = NULL; +ibv_device** (*IbvGetDeviceList)(int*) = nullptr; +void (*IbvFreeDeviceList)(ibv_device**) = nullptr; +ibv_context* (*IbvOpenDevice)(ibv_device*) = nullptr; +int (*IbvCloseDevice)(ibv_context*) = nullptr; +const char* (*IbvGetDeviceName)(ibv_device*) = nullptr; +int (*IbvForkInit)(void) = nullptr; +int (*IbvQueryDevice)(ibv_context*, ibv_device_attr*) = nullptr; +int (*IbvQueryPort)(ibv_context*, uint8_t, ibv_port_attr*) = nullptr; +int (*IbvQueryGid)(ibv_context*, uint8_t, int, ibv_gid*) = nullptr; +ibv_pd* (*IbvAllocPd)(ibv_context*) = nullptr; +int (*IbvDeallocPd)(ibv_pd*) = nullptr; +ibv_cq* (*IbvCreateCq)(ibv_context*, int, void*, ibv_comp_channel*, int) = nullptr; +int (*IbvDestroyCq)(ibv_cq*) = nullptr; +ibv_qp* (*IbvCreateQp)(ibv_pd*, ibv_qp_init_attr*) = nullptr; +int (*IbvModifyQp)(ibv_qp*, ibv_qp_attr*, ibv_qp_attr_mask) = nullptr; +int (*IbvQueryQp)(ibv_qp*, ibv_qp_attr*, ibv_qp_attr_mask, ibv_qp_init_attr*) = nullptr; +int (*IbvDestroyQp)(ibv_qp*) = nullptr; +ibv_comp_channel* (*IbvCreateCompChannel)(ibv_context*) = nullptr; +int (*IbvDestroyCompChannel)(ibv_comp_channel*) = nullptr; +ibv_mr* (*IbvRegMr)(ibv_pd*, void*, size_t, int) = nullptr; +int (*IbvDeregMr)(ibv_mr*) = nullptr; +int (*IbvGetCqEvent)(ibv_comp_channel*, ibv_cq**, void**) = nullptr; +void (*IbvAckCqEvents)(ibv_cq*, unsigned int) = nullptr; +int (*IbvGetAsyncEvent)(ibv_context*, ibv_async_event*) = nullptr; +void (*IbvAckAsyncEvent)(ibv_async_event*) = nullptr; +const char* (*IbvEventTypeStr)(ibv_event_type) = nullptr; +int (*IbvQueryEce)(ibv_qp*, ibv_ece*) = nullptr; +int (*IbvSetEce)(ibv_qp*, ibv_ece*) = nullptr; // NOTE: // ibv_post_send, ibv_post_recv, ibv_poll_cq, ibv_req_notify_cq are all inline function @@ -97,18 +97,18 @@ DEFINE_int32(rdma_port, 1, "The port number to use. For RoCE, it is always 1."); DEFINE_int32(rdma_gid_index, -1, "The GID index to use. -1 means using the last one."); // static const size_t SYSFS_SIZE = 4096; -static ibv_device** g_devices = NULL; -static ibv_context* g_context = NULL; +static ibv_device** g_devices = nullptr; +static ibv_context* g_context = nullptr; static SocketId g_async_socket; -static ibv_pd* g_pd = NULL; -static std::vector* g_mrs = NULL; // mr registered by brpc +static ibv_pd* g_pd = nullptr; +static std::vector* g_mrs = nullptr; // mr registered by brpc static butil::FlatMap* g_user_mrs; // mr registered by user -static butil::Mutex* g_user_mrs_lock = NULL; +static butil::Mutex* g_user_mrs_lock = nullptr; // Store the original IOBuf memalloc and memdealloc functions -static void* (*g_mem_alloc)(size_t) = NULL; -static void (*g_mem_dealloc)(void*) = NULL; +static void* (*g_mem_alloc)(size_t) = nullptr; +static void (*g_mem_dealloc)(void*) = nullptr; namespace { struct IbvDeviceDeleter { @@ -141,32 +141,32 @@ static void GlobalRelease() { } g_user_mrs->clear(); delete g_user_mrs; - g_user_mrs = NULL; + g_user_mrs = nullptr; } delete g_user_mrs_lock; - g_user_mrs_lock = NULL; + g_user_mrs_lock = nullptr; if (g_mrs) { for (size_t i = 0; i < g_mrs->size(); ++i) { IbvDeregMr((*g_mrs)[i]); } delete g_mrs; - g_mrs = NULL; + g_mrs = nullptr; } if (g_pd) { IbvDeallocPd(g_pd); - g_pd = NULL; + g_pd = nullptr; } if (g_context) { IbvCloseDevice(g_context); - g_context = NULL; + g_context = nullptr; } if (g_devices) { IbvFreeDeviceList(g_devices); - g_devices = NULL; + g_devices = nullptr; } } @@ -194,7 +194,7 @@ uint32_t RdmaRegisterMemory(void* buf, size_t size) { static void* BlockAllocate(size_t len) { if (len == 0) { errno = EINVAL; - return NULL; + return nullptr; } void* ptr = AllocBlock(len); if (!ptr) { @@ -349,11 +349,11 @@ static void OnRdmaAsyncEvent(Socket* m) { // Soft-load an OPTIONAL symbol: if the symbol is missing (e.g. the // installed libibverbs predates rdma-core v35 which introduced the ECE -// APIs), leave the function pointer NULL and continue instead of failing +// APIs), leave the function pointer nullptr and continue instead of failing // the whole RDMA initialization. Callers MUST null-check before use. #define LoadSymbolOptional(handle, func, symbol) \ *(void**)(&func) = dlsym(handle, symbol); \ - LOG_IF(WARNING, func == NULL) \ + LOG_IF(WARNING, func == nullptr) \ << "Optional symbol not found (feature disabled): " << symbol; static int ReadRdmaDynamicLib() { @@ -530,28 +530,13 @@ static void GlobalRdmaInitializeOrDieImpl() { ExitWithError(); } - g_user_mrs_lock = new (std::nothrow) butil::Mutex; - if (!g_user_mrs_lock) { - PLOG(WARNING) << "Fail to construct g_user_mrs_lock"; - ExitWithError(); - } - - g_user_mrs = new (std::nothrow) butil::FlatMap(); - if (!g_user_mrs) { - PLOG(WARNING) << "Fail to construct g_user_mrs"; - ExitWithError(); - } - + g_user_mrs_lock = new butil::Mutex; + g_user_mrs = new butil::FlatMap(); if (g_user_mrs->init(65536) < 0) { PLOG(WARNING) << "Fail to initialize g_user_mrs"; ExitWithError(); } - - g_mrs = new (std::nothrow) std::vector; - if (!g_mrs) { - PLOG(ERROR) << "Fail to allocate a RDMA MR list"; - ExitWithError(); - } + g_mrs = new std::vector; ibv_device_attr attr; if (IbvQueryDevice(g_context, &attr) != 0) { @@ -637,7 +622,7 @@ uint32_t RegisterMemoryForRdma(void* buf, size_t len) { } void DeregisterMemoryForRdma(void* buf) { - ibv_mr* mr = NULL; + ibv_mr* mr = nullptr; { BAIDU_SCOPED_LOCK(*g_user_mrs_lock); ibv_mr** mr_ptr = g_user_mrs->seek(buf); diff --git a/src/brpc/redis_reply.cpp b/src/brpc/redis_reply.cpp index 14c76f4841..256e43c06c 100644 --- a/src/brpc/redis_reply.cpp +++ b/src/brpc/redis_reply.cpp @@ -138,9 +138,27 @@ ParseError RedisReply::ConsumePartialIOBuf(butil::IOBuf& buf, int depth) { " actually=" << len; return PARSE_ERROR_ABSOLUTELY_WRONG; } + // Enforce the cap while still waiting for CRLF, otherwise a peer + // that never sends the terminator can grow buf without bound (like + // RedisCommandParser does for inline commands). buf holds the first + // char plus the payload so far; allow one extra byte for a boundary + // '\r' whose matching '\n' hasn't arrived yet. + if (FLAGS_redis_max_allocation_size < 0 || + len > (size_t)FLAGS_redis_max_allocation_size + 2) { + LOG(ERROR) << "simple string exceeds max allocation size! max=" + << FLAGS_redis_max_allocation_size + << ", actually=" << len - 1; + return PARSE_ERROR_ABSOLUTELY_WRONG; + } return PARSE_ERROR_NOT_ENOUGH_DATA; } const size_t len = str.size() - 1; + if (FLAGS_redis_max_allocation_size < 0 || + len > (size_t)FLAGS_redis_max_allocation_size) { + LOG(ERROR) << "simple string exceeds max allocation size! max=" + << FLAGS_redis_max_allocation_size << ", actually=" << len; + return PARSE_ERROR_ABSOLUTELY_WRONG; + } if (len < sizeof(_data.short_str)) { // SSO short strings, including empty string. _type = (fc == '-' ? REDIS_REPLY_ERROR : REDIS_REPLY_STATUS); diff --git a/src/brpc/server.h b/src/brpc/server.h index 4fbe304fde..08083037ac 100644 --- a/src/brpc/server.h +++ b/src/brpc/server.h @@ -224,7 +224,7 @@ struct ServerOptions { // Force ssl for all connections of the port to Start(). bool force_ssl; - // the server socket mode uses tcp or rdma or other + // Transport used by accepted sockets. // Default: SOCKET_MODE_TCP SocketMode socket_mode; diff --git a/src/brpc/socket.h b/src/brpc/socket.h index 7c53058941..e7ceb9dce3 100644 --- a/src/brpc/socket.h +++ b/src/brpc/socket.h @@ -61,10 +61,21 @@ class RdmaHandshakeServerV2; class RdmaHandshakeClientV3; class RdmaHandshakeServerV3; } + +namespace urma { +class UrmaEndpoint; +class UrmaConnect; +class UrmaHandshakeClientV2; +class UrmaHandshakeServerV2; +class UrmaHandshakeClientV3; +class UrmaHandshakeServerV3; +} + namespace ubring { class UBShmEndpoint; class UBConnect; } + class Socket; class AuthContext; class EventDispatcher; @@ -334,6 +345,12 @@ friend class rdma::RdmaHandshakeClientV2; friend class rdma::RdmaHandshakeServerV2; friend class rdma::RdmaHandshakeClientV3; friend class rdma::RdmaHandshakeServerV3; +friend class urma::UrmaEndpoint; +friend class urma::UrmaConnect; +friend class urma::UrmaHandshakeClientV2; +friend class urma::UrmaHandshakeServerV2; +friend class urma::UrmaHandshakeClientV3; +friend class urma::UrmaHandshakeServerV3; friend class HealthCheckTask; friend class OnAppHealthCheckDone; friend class HealthCheckManager; @@ -344,6 +361,7 @@ friend void DereferenceSocket(Socket*); friend class Transport; friend class TcpTransport; friend class RdmaTransport; +friend class UrmaTransport; friend class TransportFactory; class SharedPart; struct WriteRequest; @@ -353,7 +371,7 @@ friend class TransportFactory; // NOTE: User cannot create Socket from constructor. Use Create() // instead. It's public just because of requirement of ResourcePool. explicit Socket(Forbidden); - ~Socket() override; + ~Socket(); // Write `msg' into this Socket and clear it. The `msg' should be an // intact request or response. To prevent messages from interleaving diff --git a/src/brpc/socket_mode.h b/src/brpc/socket_mode.h index b4ac7dfbca..1ea12a57e3 100644 --- a/src/brpc/socket_mode.h +++ b/src/brpc/socket_mode.h @@ -21,7 +21,9 @@ namespace brpc { enum SocketMode { SOCKET_MODE_TCP = 0, SOCKET_MODE_RDMA = 1, - SOCKET_MODE_UBRING = 2 + SOCKET_MODE_UBRING = 2, + SOCKET_MODE_URMA = 3 }; -} // namespace brpc -#endif //BRPC_SOCKET_MODE_H \ No newline at end of file +} // namespace brpc + +#endif // BRPC_SOCKET_MODE_H diff --git a/src/brpc/span.cpp b/src/brpc/span.cpp index 1863f01a9f..d5807121d7 100644 --- a/src/brpc/span.cpp +++ b/src/brpc/span.cpp @@ -206,6 +206,7 @@ std::shared_ptr Span::CreateClientSpan(const std::string& full_method_name return nullptr; } std::shared_ptr span(span_raw, SpanDeleter()); + span->_submitted.store(false, butil::memory_order_relaxed); span->_log_id = 0; span->_base_cid = INVALID_BTHREAD_ID; span->_ending_cid = INVALID_BTHREAD_ID; // Client Span uses ending_cid @@ -248,6 +249,7 @@ std::shared_ptr Span::CreateBthreadSpan(const std::string& full_method_nam return nullptr; } std::shared_ptr span(span_raw, SpanDeleter()); + span->_submitted.store(false, butil::memory_order_relaxed); span->_log_id = 0; span->_base_cid = INVALID_BTHREAD_ID; span->_ending_tid = INVALID_BTHREAD; // Bthread Span uses ending_tid @@ -298,6 +300,7 @@ std::shared_ptr Span::CreateServerSpan( return nullptr; } std::shared_ptr span(span_raw, SpanDeleter()); + span->_submitted.store(false, butil::memory_order_relaxed); span->_trace_id = (trace_id ? trace_id : GenerateTraceId()); span->_span_id = (span_id ? span_id : GenerateSpanId()); span->_parent_span_id = parent_span_id; @@ -335,7 +338,9 @@ void Span::ResetServerSpanName(const std::string& full_method_name) { } void Span::submit(int64_t cpuwide_us) { - // Note: this method is not called for client-side spans. + // Called for server spans and root client spans (those without a local + // parent). Child client spans are serialized under their parent via + // _client_list instead. EndAsParent(); // If memory allocation fails, the server span will not be submitted for persistence. // The server span will be destroyed later when its shared_ptr refcount drops to zero @@ -581,12 +586,10 @@ inline int GetSpanDB(butil::intrusive_ptr* db) { } void Span::Submit(std::shared_ptr span, int64_t cpuwide_time_us) { - // Only submit spans without a local parent (i.e., server spans). - // Server spans hold shared_ptr references to their child spans (via _client_list), - // ensuring child spans remain alive until the server span is submitted and dumped. - // Client spans are not submitted here because their lifetime is managed by their - // parent server span. - if (span->local_parent().expired()) { + // Submit root spans without a local parent. Server spans and root client + // spans are submitted independently; child client spans with a live local + // parent are serialized under the parent to avoid duplicate submissions. + if (span->local_parent().expired() && span->try_mark_submitted()) { span->submit(cpuwide_time_us); } } @@ -787,7 +790,8 @@ leveldb::Status SpanDB::Index(std::shared_ptr span, std::string* val // be modified by other threads, which could lead to inconsistent data when // serializing to database. for (auto it = all_child_spans.rbegin(); it != all_child_spans.rend(); ++it) { - if (*it && it->get() != span.get() && !(*it)->is_active()) { + if (*it && it->get() != span.get() && !(*it)->is_active() && + (*it)->try_mark_submitted()) { RpczSpan* child_proto = value_proto.add_client_spans(); Span2Proto((*it).get(), child_proto); } diff --git a/src/brpc/span.h b/src/brpc/span.h index efa394b548..c6b3306cdd 100644 --- a/src/brpc/span.h +++ b/src/brpc/span.h @@ -28,6 +28,7 @@ #include #include #include +#include "butil/atomicops.h" #include "butil/macros.h" #include "butil/endpoint.h" #include "butil/string_splitter.h" @@ -198,6 +199,11 @@ friend class SpanContainer; void dump_to_db(); void submit(int64_t cpuwide_us); + bool try_mark_submitted() const { + bool expected = false; + return _submitted.compare_exchange_strong( + expected, true, butil::memory_order_relaxed); + } bvar::CollectorSpeedLimit* speed_limit(); bvar::CollectorPreprocessor* preprocessor(); @@ -252,6 +258,8 @@ friend class SpanContainer; // Also protects against concurrent iteration (e.g., CountClientSpans, SpanDB::Index) // while the list is being modified. mutable pthread_spinlock_t _client_list_spinlock; + + mutable butil::atomic _submitted; }; class SpanContainer : public bvar::Collected { diff --git a/src/brpc/stream.cpp b/src/brpc/stream.cpp index 2667614d9b..c799f2ffe1 100644 --- a/src/brpc/stream.cpp +++ b/src/brpc/stream.cpp @@ -42,23 +42,21 @@ BRPC_VALIDATE_GFLAG(stream_write_max_segment_size, PositiveInteger); const static butil::IOBuf *TIMEOUT_TASK = (butil::IOBuf*)-1L; -Stream::Stream() - : _host_socket(NULL) - , _fake_socket_weak_ref(NULL) +Stream::Stream(Forbidden f) + : VersionedRefWithId(f) + , _host_socket(NULL) , _connected(false) - , _closed(false) , _error_code(0) , _produced(0) , _remote_consumed(0) + , _socket_unconsumed_size(0) , _cur_buf_size(0) , _local_consumed(0) , _atomic_local_consumed(0) , _parse_rpc_response(false) , _pending_buf(NULL) , _start_idle_timer_us(0) - , _idle_timer(0) -{ - _connect_meta.on_connect = NULL; + , _idle_timer(0) { CHECK_EQ(0, bthread_mutex_init(&_connect_mutex, NULL)); CHECK_EQ(0, bthread_mutex_init(&_congestion_control_mutex, NULL)); } @@ -72,289 +70,262 @@ Stream::~Stream() { CHECK(_host_socket == NULL); bthread_mutex_destroy(&_connect_mutex); bthread_mutex_destroy(&_congestion_control_mutex); - bthread_id_list_destroy(&_writable_wait_list); } int Stream::Create(const StreamOptions &options, - const StreamSettings *remote_settings, + const StreamSettings* remote_settings, StreamId *id, bool parse_rpc_response) { - Stream* s = new Stream(); - s->_host_socket = NULL; - s->_fake_socket_weak_ref = NULL; - s->_connected = false; - s->_options = options; - s->_closed = false; - s->_error_code = 0; - s->_cur_buf_size = options.max_buf_size > 0 ? options.max_buf_size : 0; + return VersionedRefWithId::Create( + id, options, remote_settings, parse_rpc_response); +} + +int Stream::OnCreated(const StreamOptions& options, + const StreamSettings* remote_settings, + bool parse_rpc_response) { + _host_socket = NULL; + _connected.store(false, butil::memory_order_relaxed); + _options = options; + _error_code = 0; + _error_text.clear(); + _pending_writes.clear(); + _produced = 0; + _remote_consumed = 0; + _socket_unconsumed_size = 0; + _local_consumed = 0; + _atomic_local_consumed.store(0, butil::memory_order_relaxed); + _parse_rpc_response = parse_rpc_response; + _pending_buf = NULL; + _start_idle_timer_us = 0; + _idle_timer = 0; + _remote_settings.Clear(); + + _cur_buf_size = options.max_buf_size > 0 ? options.max_buf_size : 0; if (options.max_buf_size > 0 && options.min_buf_size > options.max_buf_size) { // set 0 if min_buf_size is invalid. - s->_options.min_buf_size = 0; + _options.min_buf_size = 0; LOG(WARNING) << "options.min_buf_size is larger than options.max_buf_size, it will be set to 0."; } - if (FLAGS_socket_max_streams_unconsumed_bytes > 0 && s->_options.min_buf_size > 0) { - s->_cur_buf_size = s->_options.min_buf_size; + if (FLAGS_socket_max_streams_unconsumed_bytes > 0 && _options.min_buf_size > 0) { + _cur_buf_size = _options.min_buf_size; } if (remote_settings != NULL) { - s->_remote_settings.MergeFrom(*remote_settings); - } - s->_parse_rpc_response = parse_rpc_response; - if (bthread_id_list_init(&s->_writable_wait_list, 8, 8/*FIXME*/)) { - delete s; - return -1; + _remote_settings.MergeFrom(*remote_settings); } + + CHECK_EQ(0, bthread_id_list_init(&_writable_wait_list, 8, 8/*FIXME*/)); + bthread::ExecutionQueueOptions q_opt; q_opt.bthread_attr = FLAGS_usercode_in_pthread ? BTHREAD_ATTR_PTHREAD : BTHREAD_ATTR_NORMAL; - if (bthread::execution_queue_start(&s->_consumer_queue, &q_opt, Consume, s) != 0) { + if (bthread::execution_queue_start(&_consumer_queue, &q_opt, Consume, this) != 0) { LOG(FATAL) << "Fail to create ExecutionQueue"; - delete s; return -1; } - SocketOptions sock_opt; - sock_opt.conn = s; - SocketId fake_sock_id; - if (Socket::Create(sock_opt, &fake_sock_id) != 0) { - s->BeforeRecycle(NULL); - return -1; - } - SocketUniquePtr ptr; - CHECK_EQ(0, Socket::Address(fake_sock_id, &ptr)); - s->_fake_socket_weak_ref = ptr.get(); - s->_id = fake_sock_id; - *id = s->id(); + + // The consumer queue holds one reference to this Stream. + AddReference(); return 0; } -void Stream::BeforeRecycle(Socket *) { - // No one holds reference now, so we don't need lock here - bthread_id_list_reset(&_writable_wait_list, ECONNRESET); - if (_connected) { - // Send CLOSE frame - RPC_VLOG << "Send close frame"; - CHECK(_host_socket != NULL); - policy::SendStreamClose(_host_socket, - _remote_settings.stream_id(), id()); +void Stream::OnFailed(int error_code, const std::string& error_text) { + bool connected = false; + { + // Record the error for on_failed callback fired in Consume(), and discard + // any writes buffered before connecting. + BAIDU_SCOPED_LOCK(_connect_mutex); + _error_code = error_code; + _error_text = error_text; + connected = _connected.load(butil::memory_order_relaxed); + _pending_writes.clear(); } - if (_host_socket) { - _host_socket->RemoveStream(id()); + // Wake up all threads blocked on writable. + bthread_id_list_reset(&_writable_wait_list, ECONNRESET); + + // Serialize the host Socket membership removal with SetHostSocket(). + // SetFailed() marks this Stream failed before entering OnFailed(), so a + // later SetHostSocket() observes Failed() and cannot add it back. + { + BAIDU_SCOPED_LOCK(_connect_mutex); + if (connected) { + RPC_VLOG << "Send close frame"; + CHECK(_host_socket != NULL); + policy::SendStreamClose( + _host_socket, _remote_settings.stream_id(), id()); + } + if (_host_socket != NULL) { + if (FLAGS_socket_max_streams_unconsumed_bytes > 0) { + BAIDU_SCOPED_LOCK(_congestion_control_mutex); + if (_socket_unconsumed_size != 0) { + _host_socket->_total_streams_unconsumed_size.fetch_sub( + _socket_unconsumed_size, butil::memory_order_relaxed); + _socket_unconsumed_size = 0; + } + } + _host_socket->RemoveStream(id()); + } } - // The instance is to be deleted in the consumer thread + // Stop the consumer queue. Consume() will fire on_failed/on_closed and + // release the reference held by the queue, which may recycle this instance. bthread::execution_queue_stop(_consumer_queue); } -ssize_t Stream::CutMessageIntoFileDescriptor(int /*fd*/, - butil::IOBuf **data_list, - size_t size) { +void Stream::BeforeRecycled() { + if (_pending_buf != NULL) { + delete _pending_buf; + _pending_buf = NULL; + } + + _pending_writes.clear(); + bthread_id_list_destroy(&_writable_wait_list); + if (_host_socket != NULL) { + DereferenceSocket(_host_socket); + _host_socket = NULL; + } +} + +std::string Stream::OnDescription() const { + BAIDU_SCOPED_LOCK(_connect_mutex); + if (_host_socket != NULL) { + return _host_socket->description(); + } else { + return "host_socket=NULL"; + } +} + +int Stream::WritePacked(const butil::IOBuf& data, + const StreamWriteOptions* options) { if (_host_socket == NULL) { CHECK(false) << "Not connected"; errno = EBADF; return -1; } if (!_remote_settings.writable()) { - LOG(WARNING) << "The remote side of Stream=" << id() + LOG(WARNING) << "The remote side of Stream=" << id() << "->" << _remote_settings.stream_id() << "@" << _host_socket->remote_side() << " doesn't have a handler"; errno = EBADF; return -1; } - butil::IOBuf out; - ssize_t len = 0; - ssize_t unwritten_data_size = 0; - for (size_t i = 0; i < size; ++i) { - butil::IOBuf *data = data_list[i]; - size_t length = data->length(); - if (length > FLAGS_stream_write_max_segment_size) { - if (unwritten_data_size) { - WriteToHostSocket(&out); - unwritten_data_size = 0; - out.clear(); - } - // segmenting large data into multiple parts - butil::IOBuf segment_buf; - bool has_continuation = true; - while (has_continuation) { - data->cutn(&segment_buf, FLAGS_stream_write_max_segment_size); - StreamFrameMeta fm; - fm.set_stream_id(_remote_settings.stream_id()); - fm.set_source_stream_id(id()); - fm.set_frame_type(FRAME_TYPE_DATA); - has_continuation = !data->empty(); - fm.set_has_continuation(has_continuation); - policy::PackStreamMessage(&out, fm, &segment_buf); - len += segment_buf.length(); - segment_buf.clear(); - WriteToHostSocket(&out); - out.clear(); - } - } else { - if (unwritten_data_size + length > FLAGS_stream_write_max_segment_size) { - WriteToHostSocket(&out); - unwritten_data_size = 0; - out.clear(); - } - unwritten_data_size += length; - StreamFrameMeta fm; - fm.set_stream_id(_remote_settings.stream_id()); - fm.set_source_stream_id(id()); - fm.set_frame_type(FRAME_TYPE_DATA); - fm.set_has_continuation(false); - policy::PackStreamMessage(&out, fm, data_list[i]); - len += length; - data_list[i]->clear(); - } - } - - if (!out.empty()) { - WriteToHostSocket(&out); - } - return len; -} - -void Stream::WriteToHostSocket(butil::IOBuf* b) { - BRPC_HANDLE_EOVERCROWDED(_host_socket->Write(b)); -} - -ssize_t Stream::CutMessageIntoSSLChannel(SSL*, butil::IOBuf**, size_t) { - CHECK(false) << "Stream does support SSL"; - errno = EINVAL; - return -1; -} -void* Stream::RunOnConnect(void *arg) { - ConnectMeta* meta = (ConnectMeta*)arg; - if (meta->ec == 0) { - meta->on_connect(Socket::STREAM_FAKE_FD, 0, meta->arg); - } else { - meta->on_connect(-1, meta->ec, meta->arg); - } - delete meta; - return NULL; -} + Socket::WriteOptions wopt; + wopt.write_in_background = options != NULL && options->write_in_background; -int Stream::Connect(Socket* ptr, const timespec*, - int (*on_connect)(int, int, void *), void *data) { - CHECK_EQ(ptr->id(), _id); - bthread_mutex_lock(&_connect_mutex); - if (_connect_meta.on_connect != NULL) { - CHECK(false) << "Connect is supposed to be called once"; - bthread_mutex_unlock(&_connect_mutex); + // Pack the whole message (splitting large data into multiple STRM frames) + // into a SINGLE IOBuf, then hand it to Socket::Write in one shot. + butil::IOBuf remaining(data); + butil::IOBuf out; + bool has_continuation = true; + do { + butil::IOBuf segment; + remaining.cutn(&segment, FLAGS_stream_write_max_segment_size); + has_continuation = !remaining.empty(); + StreamFrameMeta fm; + fm.set_stream_id(_remote_settings.stream_id()); + fm.set_source_stream_id(id()); + fm.set_frame_type(FRAME_TYPE_DATA); + fm.set_has_continuation(has_continuation); + policy::PackStreamMessage(&out, fm, &segment); + } while (has_continuation); + + if (BRPC_HANDLE_EOVERCROWDED(_host_socket->Write(&out, &wopt)) != 0) { + // Stream may be closed by peer before. + LOG(WARNING) << "Fail to write to host socket of stream=" << id() + << ", " << berror(); return -1; } - _connect_meta.on_connect = on_connect; - _connect_meta.arg = data; - if (_connected) { - ConnectMeta* meta = new ConnectMeta; - meta->on_connect = _connect_meta.on_connect; - meta->arg = _connect_meta.arg; - meta->ec = _connect_meta.ec; - bthread_mutex_unlock(&_connect_mutex); - bthread_t tid; - if (bthread_start_urgent(&tid, &BTHREAD_ATTR_NORMAL, RunOnConnect, meta) != 0) { - LOG(FATAL) << "Fail to start bthread, " << berror(); - RunOnConnect(meta); - } - return 0; - } - bthread_mutex_unlock(&_connect_mutex); return 0; } -void Stream::SetConnected() { - return SetConnected(NULL); -} - -void Stream::SetConnected(const StreamSettings* remote_settings) { - bthread_mutex_lock(&_connect_mutex); - if (_closed) { - bthread_mutex_unlock(&_connect_mutex); - return; - } - if (_connected) { - CHECK(false); - bthread_mutex_unlock(&_connect_mutex); - return; - } - CHECK(_host_socket != NULL); - if (remote_settings != NULL) { - CHECK(!_remote_settings.IsInitialized()); - _remote_settings.MergeFrom(*remote_settings); - } else { - CHECK(_remote_settings.IsInitialized()); - } - CHECK(_host_socket != NULL); - RPC_VLOG << "stream=" << id() << " is connected to stream_id=" - << _remote_settings.stream_id() << " at host_socket=" << *_host_socket; - _connected.store(true, butil::memory_order_release); - _connect_meta.ec = 0; - TriggerOnConnectIfNeed(); - if (remote_settings == NULL) { - // Start the timer at server-side - // Client-side timer would triggered in Consume after received the first - // message which is the very RPC response - StartIdleTimer(); - } else { - // send first feedback for client-side stream if it already consumed data - if (_remote_settings.need_feedback()) { - auto consumed_bytes = _atomic_local_consumed.load(butil::memory_order_acquire); - if (consumed_bytes > 0) - SendFeedback(consumed_bytes); - } - } +void Stream::WriteToHostSocket(butil::IOBuf* b) { + BRPC_HANDLE_EOVERCROWDED(_host_socket->Write(b)); } -void Stream::TriggerOnConnectIfNeed() { - if (_connect_meta.on_connect != NULL) { - ConnectMeta* meta = new ConnectMeta; - meta->on_connect = _connect_meta.on_connect; - meta->arg = _connect_meta.arg; - meta->ec = _connect_meta.ec; - bthread_mutex_unlock(&_connect_mutex); - bthread_t tid; - if (bthread_start_urgent(&tid, &BTHREAD_ATTR_NORMAL, RunOnConnect, meta) != 0) { - LOG(FATAL) << "Fail to start bthread, " << berror(); - RunOnConnect(meta); - } - return; +inline void Stream::RollbackProduced(size_t data_length) { + if (_cur_buf_size > 0) { + BAIDU_SCOPED_LOCK(_congestion_control_mutex); + _produced -= data_length; } - bthread_mutex_unlock(&_connect_mutex); } int Stream::AppendIfNotFull(const butil::IOBuf &data, const StreamWriteOptions* options) { + if (Failed()) { + errno = ECONNRESET; + return -1; + } + + size_t data_length = data.length(); if (_cur_buf_size > 0) { std::unique_lock lck(_congestion_control_mutex); if (_produced >= _remote_consumed + _cur_buf_size) { const size_t saved_produced = _produced; const size_t saved_remote_consumed = _remote_consumed; lck.unlock(); - RPC_VLOG << "Stream=" << _id << " is full" + RPC_VLOG << "Stream=" << id() << " is full" << "_produced=" << saved_produced << " _remote_consumed=" << saved_remote_consumed << " gap=" << saved_produced - saved_remote_consumed << " max_buf_size=" << _cur_buf_size; return 1; } - _produced += data.length(); + _produced += data_length; } - size_t data_length = data.length(); - butil::IOBuf copied_data(data); - Socket::WriteOptions wopt; - wopt.write_in_background = options != NULL && options->write_in_background; - const int rc = _fake_socket_weak_ref->Write(&copied_data, &wopt); - if (rc != 0) { - // Stream may be closed by peer before - LOG(WARNING) << "Fail to write to _fake_socket, " << berror(); - BAIDU_SCOPED_LOCK(_congestion_control_mutex); - _produced -= data_length; + // Fast path (the common case): once connected, write directly WITHOUT + // taking _connect_mutex. `_connected` is a one-way transition published + // by SetConnected() after flushing pending writes, so ordering is preserved + // and this path stays lock-free (besides the optional congestion window). + if (_connected.load(butil::memory_order_acquire)) { + if (WritePacked(data, options) != 0) { + RollbackProduced(data_length); + return -1; + } + if (FLAGS_socket_max_streams_unconsumed_bytes > 0) { + BAIDU_SCOPED_LOCK(_congestion_control_mutex); + if (!Failed()) { + _host_socket->_total_streams_unconsumed_size.fetch_add( + data_length, butil::memory_order_relaxed); + _socket_unconsumed_size += data_length; + } + } + return 0; + } + + // Slow path (rare): not connected yet, so the remote stream id is unknown. + // Buffer the raw data and options under `_connect_mutex`. SetConnected() + // will flush it. + { + BAIDU_SCOPED_LOCK(_connect_mutex); + if (Failed()) { + RollbackProduced(data_length); + return -1; + } + if (!_connected.load(butil::memory_order_acquire)) { + _pending_writes.emplace_back(data, options); + return 0; + } + // Connected between the two checks; fall through to a direct write. + // Ordering holds: reaching here means we acquired `_connect_mutex`, + // which SetConnected() releases only after it has flushed all pending + // writes (enqueued into the host socket) and published `_connected=true`. + // Hence, this direct write is necessarily enqueued after those pending writes. + } + + if (WritePacked(data, options) != 0) { + RollbackProduced(data_length); return -1; } if (FLAGS_socket_max_streams_unconsumed_bytes > 0) { - _host_socket->_total_streams_unconsumed_size += data_length; + BAIDU_SCOPED_LOCK(_congestion_control_mutex); + if (!Failed()) { + _host_socket->_total_streams_unconsumed_size.fetch_add( + data_length, butil::memory_order_relaxed); + _socket_unconsumed_size += data_length; + } } return 0; } @@ -362,7 +333,7 @@ int Stream::AppendIfNotFull(const butil::IOBuf &data, void Stream::SetRemoteConsumed(size_t new_remote_consumed) { CHECK(_cur_buf_size > 0); bthread_id_list_t tmplist; - bthread_id_list_init(&tmplist, 0, 0); + CHECK_EQ(0, bthread_id_list_init(&tmplist, 0, 0)); bthread_mutex_lock(&_congestion_control_mutex); if (_remote_consumed >= new_remote_consumed) { bthread_mutex_unlock(&_congestion_control_mutex); @@ -370,16 +341,28 @@ void Stream::SetRemoteConsumed(size_t new_remote_consumed) { } const bool was_full = _produced >= _remote_consumed + _cur_buf_size; - if (FLAGS_socket_max_streams_unconsumed_bytes > 0) { - _host_socket->_total_streams_unconsumed_size -= new_remote_consumed - _remote_consumed; - if (_host_socket->_total_streams_unconsumed_size > FLAGS_socket_max_streams_unconsumed_bytes) { + if (FLAGS_socket_max_streams_unconsumed_bytes > 0 && _host_socket != NULL) { + const size_t consumed_delta = new_remote_consumed - _remote_consumed; + const size_t accounted_delta = + std::min(consumed_delta, _socket_unconsumed_size); + if (accounted_delta != 0) { + _host_socket->_total_streams_unconsumed_size.fetch_sub( + accounted_delta, butil::memory_order_relaxed); + _socket_unconsumed_size -= accounted_delta; + } + const int64_t total_unconsumed = _host_socket->_total_streams_unconsumed_size.load( + butil::memory_order_relaxed); + if (total_unconsumed > FLAGS_socket_max_streams_unconsumed_bytes) { if (_options.min_buf_size > 0) { _cur_buf_size = _options.min_buf_size; } else { _cur_buf_size /= 2; } - LOG(INFO) << "stream consumers on socket " << _host_socket->id() << " is crowded, " << "cut stream " << id() << " buffer to " << _cur_buf_size; - } else if (_produced >= new_remote_consumed + _cur_buf_size && (_options.max_buf_size <= 0 || _cur_buf_size < (size_t)_options.max_buf_size)) { + LOG(INFO) << "stream consumers on socket " << _host_socket->id() + << " is crowded, cut stream " << id() + << " buffer to " << _cur_buf_size; + } else if (_produced >= new_remote_consumed + _cur_buf_size && + (_options.max_buf_size <= 0 || _cur_buf_size < (size_t)_options.max_buf_size)) { if (_options.max_buf_size > 0 && _cur_buf_size * 2 > (size_t)_options.max_buf_size) { _cur_buf_size = _options.max_buf_size; } else { @@ -496,15 +479,123 @@ int Stream::Wait(const timespec* due_time) { return rc; } +void Stream::SetConnected() { + return SetConnected(NULL); +} + +void Stream::SetConnected(const StreamSettings* remote_settings) { + bthread_mutex_lock(&_connect_mutex); + if (Failed()) { + bthread_mutex_unlock(&_connect_mutex); + return; + } + if (_connected.load(butil::memory_order_relaxed)) { + // SetConnected() may be driven more than once (and concurrently) for + // the same stream, notably for extra streams in batch creation. It must + // be idempotent: guarded by _connect_mutex, only the first call takes + // effect and later calls simply return. + bthread_mutex_unlock(&_connect_mutex); + return; + } + CHECK(_host_socket != NULL); + if (remote_settings != NULL) { + CHECK(!_remote_settings.IsInitialized()); + _remote_settings.MergeFrom(*remote_settings); + } else { + CHECK(_remote_settings.IsInitialized()); + } + RPC_VLOG << "stream=" << id() << " is connected to stream_id=" + << _remote_settings.stream_id() << " at host_socket=" << *_host_socket; + + // Flush writes buffered before connecting FIRST, while _connected is still + // false so concurrent AppendIfNotFull() take the slow path and block on + // _connect_mutex. Only after flushing do we publish _connected=true, so + // subsequent lock-free fast-path writes are strictly ordered after these + // pending writes. + std::vector pending; + pending.swap(_pending_writes); + for (size_t i = 0; i < pending.size(); ++i) { + if (Failed()) { + size_t unsent_size = 0; + for (size_t j = i; j < pending.size(); ++j) { + unsent_size += pending[j].data.length(); + } + RollbackProduced(unsent_size); + bthread_mutex_unlock(&_connect_mutex); + return; + } + + size_t len = pending[i].data.length(); + if (WritePacked(pending[i].data, &pending[i].options) != 0) { + int error_code = errno != 0 ? errno : EIO; + // The congestion window accounted for every pending write when it + // was accepted. Keep the successfully enqueued prefix accounted, + // but roll back the failed write and the unsent suffix. + size_t unsent_size = 0; + for (size_t j = i; j < pending.size(); ++j) { + unsent_size += pending[j].data.length(); + } + RollbackProduced(unsent_size); + bthread_mutex_unlock(&_connect_mutex); + VersionedRefWithId::SetFailed( + error_code, "Failed to flush pending writes during connection"); + return; + } + if (FLAGS_socket_max_streams_unconsumed_bytes > 0) { + BAIDU_SCOPED_LOCK(_congestion_control_mutex); + if (!Failed()) { + _host_socket->_total_streams_unconsumed_size.fetch_add( + len, butil::memory_order_relaxed); + _socket_unconsumed_size += len; + } + } + } + + // Check both before and after publishing. The second check closes the + // window in which SetFailed() can bump the version between the first check + // and the store. If failure happens after the second check, connection was + // published first and OnFailed() will observe and close it normally. + if (Failed()) { + bthread_mutex_unlock(&_connect_mutex); + return; + } + _connected.store(true, butil::memory_order_release); + if (Failed()) { + _connected.store(false, butil::memory_order_relaxed); + bthread_mutex_unlock(&_connect_mutex); + return; + } + bthread_mutex_unlock(&_connect_mutex); + + if (remote_settings == NULL) { + // Start the timer at server-side + // Client-side timer would triggered in Consume after received the first + // message which is the very RPC response + StartIdleTimer(); + } else { + // send first feedback for client-side stream if it already consumed data + if (_remote_settings.need_feedback()) { + auto consumed_bytes = _atomic_local_consumed.load(butil::memory_order_acquire); + if (consumed_bytes > 0) + SendFeedback(consumed_bytes); + } + } +} + int Stream::OnReceived(const StreamFrameMeta& fm, butil::IOBuf *buf, Socket* sock) { - if (_host_socket == NULL) { + if (!_connected.load(butil::memory_order_acquire)) { + // Before connection is published, let the locked slow path initialize + // the host socket or confirm that another thread already did so. if (SetHostSocket(sock) != 0) { return -1; } } + switch (fm.frame_type()) { case FRAME_TYPE_FEEDBACK: - SetRemoteConsumed(fm.feedback().consumed_size()); + if (_connected.load(butil::memory_order_acquire)) { + SetRemoteConsumed(fm.feedback().consumed_size()); + } CHECK(buf->empty()); break; case FRAME_TYPE_DATA: @@ -516,7 +607,7 @@ int Stream::OnReceived(const StreamFrameMeta& fm, butil::IOBuf *buf, Socket* soc _pending_buf->swap(*buf); } if (!fm.has_continuation()) { - butil::IOBuf *tmp = _pending_buf; + butil::IOBuf* tmp = _pending_buf; _pending_buf = NULL; int rc = bthread::execution_queue_execute(_consumer_queue, tmp); if (rc != 0) { @@ -583,12 +674,10 @@ int Stream::Consume(void *meta, bthread::TaskIterator& iter) { Stream* s = (Stream*)meta; s->StopIdleTimer(); if (iter.is_queue_stopped()) { - scoped_ptr recycled_stream(s); - // Indicating the queue was closed. - if (s->_host_socket) { - DereferenceSocket(s->_host_socket); - s->_host_socket = NULL; - } + // The consumer queue is stopped (the stream was SetFailed). Fire the + // user callbacks, then release the reference held by the queue (which + // was added in OnCreated). This may recycle the instance via + // BeforeRecycled(), so do not touch `s' afterwards. if (s->_options.handler != NULL) { int error_code; std::string error_text; @@ -603,8 +692,10 @@ int Stream::Consume(void *meta, bthread::TaskIterator& iter) { } s->_options.handler->on_closed(s->id()); } + DereferenceVersionedRefWithId(s); return 0; } + DEFINE_SMALL_ARRAY(butil::IOBuf*, buf_list, s->_options.messages_in_batch, 256); MessageBatcher mb(buf_list, s->_options.messages_in_batch, s); bool has_timeout_task = false; @@ -661,18 +752,24 @@ void Stream::SendFeedback(int64_t _consumed_bytes) { WriteToHostSocket(&out); } -int Stream::SetHostSocket(Socket *host_socket) { - std::call_once(_set_host_socket_flag, [this, host_socket]() { - SocketUniquePtr ptr; - host_socket->ReAddress(&ptr); - // TODO add *this to host socke - if (ptr->AddStream(id()) != 0) { - CHECK(false) << id() << " fail to add stream to host socket"; - return; - } - _host_socket = ptr.release(); - }); - return _host_socket != NULL ? 0 : -1; +int Stream::SetHostSocket(Socket* host_socket) { + BAIDU_SCOPED_LOCK(_connect_mutex); + if (Failed()) { + return -1; + } + if (_host_socket != NULL) { + return 0; + } + + SocketUniquePtr ptr; + host_socket->ReAddress(&ptr); + if (ptr->AddStream(id()) != 0) { + CHECK(false) << id() << " fail to add stream to host socket"; + return -1; + } + + _host_socket = ptr.release(); + return 0; } void Stream::FillSettings(StreamSettings *settings) { @@ -707,49 +804,50 @@ void Stream::StopIdleTimer() { } } -void Stream::Close(int error_code, const char* reason_fmt, ...) { - _fake_socket_weak_ref->SetFailed(); - bthread_mutex_lock(&_connect_mutex); - if (_closed) { - bthread_mutex_unlock(&_connect_mutex); +void Stream::CloseV(int error_code, const char* reason_fmt, va_list ap) { + if (Failed()) { return; } - _closed = true; - _error_code = error_code; + std::string error_text; + butil::string_vappendf(&error_text, reason_fmt, ap); + VersionedRefWithId::SetFailed(error_code, error_text); +} + +void Stream::Close(int error_code, const char* reason_fmt, ...) { va_list ap; va_start(ap, reason_fmt); - butil::string_vappendf(&_error_text, reason_fmt, ap); + CloseV(error_code, reason_fmt, ap); va_end(ap); +} - if (_connected) { - bthread_mutex_unlock(&_connect_mutex); - return; +int Stream::SetFailedV(StreamId id, int error_code, + const char* reason_fmt, va_list ap) { + StreamUniquePtr stream_ptr; + if (AddressFailedAsWell(id, &stream_ptr) == -1) { + // Don't care recycled stream. + return 0; } - _connect_meta.ec = ECONNRESET; - // Trigger on connect to release the reference of socket - return TriggerOnConnectIfNeed(); + stream_ptr->CloseV(error_code, reason_fmt, ap); + return 0; } int Stream::SetFailed(StreamId id, int error_code, const char* reason_fmt, ...) { - SocketUniquePtr ptr; - if (Socket::AddressFailedAsWell(id, &ptr) == -1) { - // Don't care recycled stream - return 0; - } - Stream* s = (Stream*)ptr->conn(); va_list ap; va_start(ap, reason_fmt); - s->Close(error_code, reason_fmt, ap); + int rc = SetFailedV(id, error_code, reason_fmt, ap); va_end(ap); - return 0; + return rc; } int Stream::SetFailed(const StreamIds& ids, int error_code, const char* reason_fmt, ...) { va_list ap; va_start(ap, reason_fmt); - for(size_t i = 0; i< ids.size(); ++i) { - Stream::SetFailed(ids[i], error_code, reason_fmt, ap); + for (auto id : ids) { + va_list ap_copy; + va_copy(ap_copy, ap); + SetFailedV(id, error_code, reason_fmt, ap_copy); + va_end(ap_copy); } va_end(ap); return 0; @@ -779,13 +877,13 @@ void Stream::HandleRpcResponse(butil::IOBuf* response_buffer) { policy::ProcessRpcResponse(msg); } -int StreamWrite(StreamId stream_id, const butil::IOBuf &message, +int StreamWrite(StreamId stream_id, const butil::IOBuf& message, const StreamWriteOptions* options) { - SocketUniquePtr ptr; - if (Socket::Address(stream_id, &ptr) != 0) { + StreamUniquePtr stream_ptr; + if (Stream::Address(stream_id, &stream_ptr) != 0) { return EINVAL; } - Stream* s = (Stream*)ptr->conn(); + Stream* s = stream_ptr.get(); const int rc = s->AppendIfNotFull(message, options); if (rc == 0) { return 0; @@ -795,15 +893,15 @@ int StreamWrite(StreamId stream_id, const butil::IOBuf &message, void StreamWait(StreamId stream_id, const timespec *due_time, void (*on_writable)(StreamId, void*, int), void *arg) { - SocketUniquePtr ptr; - if (Socket::Address(stream_id, &ptr) != 0) { + StreamUniquePtr stream_ptr; + if (Stream::Address(stream_id, &stream_ptr) != 0) { Stream::WritableMeta* wm = new Stream::WritableMeta; wm->id = stream_id; wm->arg= arg; wm->has_timer = false; wm->on_writable = on_writable; wm->error_code = EINVAL; - const bthread_attr_t* attr = + const bthread_attr_t* attr = FLAGS_usercode_in_pthread ? &BTHREAD_ATTR_PTHREAD : &BTHREAD_ATTR_NORMAL; bthread_t tid; @@ -813,16 +911,16 @@ void StreamWait(StreamId stream_id, const timespec *due_time, } return; } - Stream* s = (Stream*)ptr->conn(); + Stream* s = stream_ptr.get(); return s->Wait(on_writable, arg, due_time); } int StreamWait(StreamId stream_id, const timespec* due_time) { - SocketUniquePtr ptr; - if (Socket::Address(stream_id, &ptr) != 0) { + StreamUniquePtr stream_ptr; + if (Stream::Address(stream_id, &stream_ptr) != 0) { return EINVAL; } - Stream* s = (Stream*)ptr->conn(); + Stream* s = stream_ptr.get(); return s->Wait(due_time); } diff --git a/src/brpc/stream.h b/src/brpc/stream.h index 36c0def70f..73e7aff52f 100644 --- a/src/brpc/stream.h +++ b/src/brpc/stream.h @@ -19,17 +19,18 @@ #ifndef BRPC_STREAM_H #define BRPC_STREAM_H +#include #include "butil/iobuf.h" #include "butil/scoped_generic.h" -#include "brpc/socket_id.h" +#include "brpc/versioned_ref_with_id.h" namespace brpc { class Controller; -typedef SocketId StreamId; +typedef VRefId StreamId; using StreamIds = std::vector; -const StreamId INVALID_STREAM_ID = (StreamId)-1L; +const StreamId INVALID_STREAM_ID = INVALID_VREF_ID; namespace detail { struct StreamIdTraits; @@ -134,7 +135,7 @@ int StreamAccept(StreamIds& response_stream, Controller& cntl, // - EAGAIN: |stream_id| is created with positive |max_buf_size| and buf size // which the remote side hasn't consumed yet excceeds the number. // - EINVAL: |stream_id| is invalied or has been closed -int StreamWrite(StreamId stream_id, const butil::IOBuf &message, +int StreamWrite(StreamId stream_id, const butil::IOBuf& message, const StreamWriteOptions* options = NULL); // Write util the pending buffer size is less than |max_buf_size| or orrur diff --git a/src/brpc/stream_impl.h b/src/brpc/stream_impl.h index 284b33ca33..f9ae065dab 100644 --- a/src/brpc/stream_impl.h +++ b/src/brpc/stream_impl.h @@ -19,42 +19,42 @@ #ifndef BRPC_STREAM_IMPL_H #define BRPC_STREAM_IMPL_H -#include +#include +#include #include "bthread/bthread.h" #include "bthread/execution_queue.h" #include "brpc/socket.h" #include "brpc/stream.h" +#include "brpc/versioned_ref_with_id.h" #include "brpc/streaming_rpc_meta.pb.h" namespace brpc { -class BAIDU_CACHELINE_ALIGNMENT Stream : public SocketConnection { +// Stream is implemented on top of VersionedRefWithId, so that StreamId +// is a self-contained versioned reference id and no longer depends on a fake +// Socket. The instance is managed by a ResourcePool: it is reused rather than +// re-constructed, thus all per-stream state must be (re)initialized in +// OnCreated() and cleaned up in OnFailed()/BeforeRecycled(). +class BAIDU_CACHELINE_ALIGNMENT Stream : public VersionedRefWithId { public: - // |--------------------------------------------------| - // |----------- Implement SocketConnection -----------| - // |--------------------------------------------------| - - int Connect(Socket* ptr, const timespec* due_time, - int (*on_connect)(int, int, void *), void *data); - ssize_t CutMessageIntoFileDescriptor(int, butil::IOBuf **data_list, - size_t size); - ssize_t CutMessageIntoSSLChannel(SSL*, butil::IOBuf**, size_t); - void BeforeRecycle(Socket *); - - // --------------------- SocketConnection -------------- + // NOTE: Users cannot create Stream from constructor. Use Create() instead. + // It's public only because of the requirement of ResourcePool. + explicit Stream(Forbidden); + ~Stream(); + // Write `msg' into this stream. Returns 0 on success, 1 when the stream is + // full, -1 on error. int AppendIfNotFull(const butil::IOBuf& msg, const StreamWriteOptions* options = NULL); static int Create(const StreamOptions& options, - const StreamSettings *remote_settings, + const StreamSettings* remote_settings, StreamId *id, bool parse_rpc_response = true); - StreamId id() { return _id; } int OnReceived(const StreamFrameMeta& fm, butil::IOBuf *buf, Socket* sock); void SetRemoteSettings(const StreamSettings& remote_settings) { _remote_settings.MergeFrom(remote_settings); } - int SetHostSocket(Socket *host_socket); + int SetHostSocket(Socket* host_socket); void SetConnected(); void SetConnected(const StreamSettings *remote_settings); @@ -62,6 +62,7 @@ class BAIDU_CACHELINE_ALIGNMENT Stream : public SocketConnection { const timespec *due_time); int Wait(const timespec* due_time); void FillSettings(StreamSettings *settings); + static int SetFailed(StreamId id, int error_code, const char* reason_fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); static int SetFailed(const StreamIds& ids, int error_code, const char* reason_fmt, ...) @@ -73,12 +74,21 @@ class BAIDU_CACHELINE_ALIGNMENT Stream : public SocketConnection { friend void StreamWait(StreamId stream_id, const timespec *due_time, void (*on_writable)(StreamId, void*, int), void *arg); friend class MessageBatcher; -friend struct butil::DefaultDeleter; - Stream(); - ~Stream(); - int Init(const StreamOptions options); +friend class VersionedRefWithId; + + // Initialize (or reset for a reused instance) the stream. + // Returns 0 on success, non-zero on failure. + int OnCreated(const StreamOptions& options, + const StreamSettings* remote_settings, + bool parse_rpc_response); + // Called once when SetFailed() succeeds. Performs the close actions + // (wake up waiters, send CLOSE frame, stop the consumer queue, etc.). + void OnFailed(int error_code, const std::string& error_text); + // Called right before the instance is recycled to the ResourcePool. + void BeforeRecycled(); + std::string OnDescription() const; + void SetRemoteConsumed(size_t _remote_consumed); - void TriggerOnConnectIfNeed(); void Wait(void (*on_writable)(StreamId, void*, int), void* arg, const timespec* due_time, bool new_thread, bthread_id_t *join_id); void SendFeedback(int64_t _consumed_bytes); @@ -86,17 +96,20 @@ friend struct butil::DefaultDeleter; void StopIdleTimer(); void HandleRpcResponse(butil::IOBuf* response_buffer); void WriteToHostSocket(butil::IOBuf* b); + // Pack `data` into one or more STRM DATA frames (splitting large data into + // segments) and write them into the host socket in a single Write. + int WritePacked(const butil::IOBuf& data, const StreamWriteOptions* options); + // Roll back `_produced` by `data_length` (under `_congestion_control_mutex`) + // when a write fails. No-op when the congestion window is disabled. + void RollbackProduced(size_t data_length); static int Consume(void *meta, bthread::TaskIterator& iter); static int TriggerOnWritable(bthread_id_t id, void *data, int error_code); static void *RunOnWritable(void* arg); - static void* RunOnConnect(void* arg); - struct ConnectMeta { - int (*on_connect)(int, int, void*); - int ec; - void* arg; - }; + static int SetFailedV(StreamId id, int error_code, + const char* reason_fmt, va_list ap); + void CloseV(int error_code, const char* reason_fmt, va_list ap); struct WritableMeta { void (*on_writable)(StreamId, void*, int); @@ -108,21 +121,36 @@ friend struct butil::DefaultDeleter; bthread_timer_t timer; }; - Socket* _host_socket; // Every stream within a Socket holds a reference - Socket* _fake_socket_weak_ref; // Not holding reference - StreamId _id; + struct PendingWrite { + butil::IOBuf data; + StreamWriteOptions options; + + PendingWrite() = default; + explicit PendingWrite(const butil::IOBuf& d, const StreamWriteOptions* opts) + : data(d) { + if (opts != NULL) { + options = *opts; + } + } + }; + + Socket* _host_socket; // Every stream within a Socket holds a reference. StreamOptions _options; - bthread_mutex_t _connect_mutex; - ConnectMeta _connect_meta; + mutable bthread_mutex_t _connect_mutex; butil::atomic _connected; - bool _closed; - int _error_code; - std::string _error_text; + int _error_code; + std::string _error_text; + // Writes buffered before the stream is connected (the remote stream id + // is unknown until then). Flushed in SetConnected(). + std::vector _pending_writes; bthread_mutex_t _congestion_control_mutex; size_t _produced; size_t _remote_consumed; + // Bytes of this Stream currently included in the host Socket's aggregate + // unconsumed counter. Protected by _congestion_control_mutex. + size_t _socket_unconsumed_size; size_t _cur_buf_size; bthread_id_list_t _writable_wait_list; @@ -132,12 +160,13 @@ friend struct butil::DefaultDeleter; bool _parse_rpc_response; bthread::ExecutionQueueId _consumer_queue; - butil::IOBuf *_pending_buf; + butil::IOBuf* _pending_buf; int64_t _start_idle_timer_us; bthread_timer_t _idle_timer; - std::once_flag _set_host_socket_flag; }; +typedef VersionedRefWithIdUniquePtr StreamUniquePtr; + } // namespace brpc diff --git a/src/brpc/transport_factory.cpp b/src/brpc/transport_factory.cpp index 36fdaaed05..31bb168801 100644 --- a/src/brpc/transport_factory.cpp +++ b/src/brpc/transport_factory.cpp @@ -16,29 +16,35 @@ // under the License. #include "brpc/transport_factory.h" -#include "brpc/tcp_transport.h" #include "brpc/rdma_transport.h" +#include "brpc/tcp_transport.h" #include "brpc/ubshm_transport.h" +#include "brpc/urma_transport.h" namespace brpc { -int TransportFactory::ContextInitOrDie(SocketMode mode, bool serverOrNot, const void* _options) { + +int TransportFactory::ContextInitOrDie( + SocketMode mode, bool server_or_not, const void* options) { if (mode == SOCKET_MODE_TCP) { return 0; } #if BRPC_WITH_RDMA - else if (mode == SOCKET_MODE_RDMA) { - return RdmaTransport::ContextInitOrDie(serverOrNot, _options); + if (mode == SOCKET_MODE_RDMA) { + return RdmaTransport::ContextInitOrDie(server_or_not, options); } #endif -#if BRPC_WITH_UBRING - else if (mode == SOCKET_MODE_UBRING) { - return UBShmTransport::ContextInitOrDie(serverOrNot, _options); +#if BRPC_WITH_URMA + if (mode == SOCKET_MODE_URMA) { + return UrmaTransport::ContextInitOrDie(server_or_not, options); } #endif - else { - LOG(ERROR) << "unknown transport type " << mode; - return 1; +#if BRPC_WITH_UBRING + if (mode == SOCKET_MODE_UBRING) { + return UBShmTransport::ContextInitOrDie(server_or_not, options); } +#endif + LOG(ERROR) << "Unknown transport type " << mode; + return 1; } std::unique_ptr TransportFactory::CreateTransport(SocketMode mode) { @@ -46,18 +52,22 @@ std::unique_ptr TransportFactory::CreateTransport(SocketMode mode) { return std::unique_ptr(new TcpTransport()); } #if BRPC_WITH_RDMA - else if (mode == SOCKET_MODE_RDMA) { + if (mode == SOCKET_MODE_RDMA) { return std::unique_ptr(new RdmaTransport()); } #endif +#if BRPC_WITH_URMA + if (mode == SOCKET_MODE_URMA) { + return std::unique_ptr(new UrmaTransport()); + } +#endif #if BRPC_WITH_UBRING - else if (mode == SOCKET_MODE_UBRING) { + if (mode == SOCKET_MODE_UBRING) { return std::unique_ptr(new UBShmTransport()); } #endif - else { - LOG(ERROR) << "socket_mode set error"; - return nullptr; - } + LOG(ERROR) << "Unknown transport type " << mode; + return nullptr; } -} // namespace brpc \ No newline at end of file + +} // namespace brpc diff --git a/src/brpc/transport_factory.h b/src/brpc/transport_factory.h index d933a130e1..84b047daac 100644 --- a/src/brpc/transport_factory.h +++ b/src/brpc/transport_factory.h @@ -22,13 +22,16 @@ #include "brpc/transport.h" namespace brpc { -// TransportFactory to create transport instance with socket_mode {TCP, RDMA} + +// Creates transport instances for a SocketMode. class TransportFactory { public: - static int ContextInitOrDie(SocketMode mode, bool serverOrNot, const void* _options); + static int ContextInitOrDie(SocketMode mode, bool server_or_not, + const void* options); // Create transport instance with socket mode. static std::unique_ptr CreateTransport(SocketMode mode); }; -} // namespace brpc -#endif //BRPC_TRANSPORT_FACTORY_H \ No newline at end of file +} // namespace brpc + +#endif // BRPC_TRANSPORT_FACTORY_H diff --git a/src/brpc/ubshm/common/common.h b/src/brpc/ubshm/common/common.h index f5bffa14b9..c64ae9843f 100644 --- a/src/brpc/ubshm/common/common.h +++ b/src/brpc/ubshm/common/common.h @@ -130,9 +130,9 @@ static inline uint64_t GetCurNanoSeconds(void) { #define FREE_PTR(ptr) \ do { \ - if ((ptr) != NULL) { \ + if ((ptr) != nullptr) { \ free(ptr); \ - (ptr) = NULL; \ + (ptr) = nullptr; \ } \ } while (0) diff --git a/src/brpc/ubshm/common/thread_lock.h b/src/brpc/ubshm/common/thread_lock.h index 3c274ce0cd..0233955168 100644 --- a/src/brpc/ubshm/common/thread_lock.h +++ b/src/brpc/ubshm/common/thread_lock.h @@ -30,7 +30,7 @@ extern "C" { static inline void UnlockMutex(pthread_mutex_t **mtx) { - if (LIKELY(mtx != NULL && *mtx != NULL)) { + if (LIKELY(mtx != nullptr && *mtx != nullptr)) { pthread_mutex_unlock(*mtx); } else { LOG(ERROR) << "Invalid input for mtx."; diff --git a/src/brpc/ubshm/shm/shm_ipc.cpp b/src/brpc/ubshm/shm/shm_ipc.cpp index a63e9cdd7c..f0a9d7ea1c 100644 --- a/src/brpc/ubshm/shm/shm_ipc.cpp +++ b/src/brpc/ubshm/shm/shm_ipc.cpp @@ -91,10 +91,10 @@ RETURN_CODE IpcShmLocalMalloc(SHM *shm) return SHM_ERR; } - shm->addr = (uint8_t*)mmap(NULL, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + shm->addr = (uint8_t*)mmap(nullptr, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shm->addr == (uint8_t*)MAP_FAILED) { LOG(ERROR) << "IPC map shm=" << shm->name << " length=" << shm->len << " failed, ret(" << errno << ")."; - shm->addr = NULL; + shm->addr = nullptr; close(fd); shm_unlink(shm->name); return SHM_ERR; @@ -106,7 +106,7 @@ RETURN_CODE IpcShmLocalMalloc(SHM *shm) RETURN_CODE IpcShmMunmap(SHM *shm) { - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(INFO) << "IPC unmap shm=" << shm->name << " already unmapped."; return UBRING_OK; } @@ -117,7 +117,7 @@ RETURN_CODE IpcShmMunmap(SHM *shm) return SHM_ERR; } - shm->addr = NULL; + shm->addr = nullptr; LOG(INFO) << "IPC unmap shm=" << shm->name << " length=" << shm->len << " success."; return UBRING_OK; } @@ -133,7 +133,7 @@ RETURN_CODE IpcShmFree(SHM *shm) } if (errno == ENOENT) { LOG(INFO) << "IPC free shm=" << shm->name << " already deleted."; - shm->addr = NULL; + shm->addr = nullptr; return SHM_ERR_NOT_FOUND; } LOG_EVERY_SECOND(ERROR) << "IPC free shm=" << shm->name << " failed, errno=" << errno; @@ -144,7 +144,7 @@ RETURN_CODE IpcShmFree(SHM *shm) RETURN_CODE IpcShmLocalFree(SHM *shm) { - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(INFO) << "IPC free local shm=" << shm->name << " already freed."; return SHM_ERR_NOT_FOUND; } @@ -153,7 +153,7 @@ RETURN_CODE IpcShmLocalFree(SHM *shm) if (ret != UBRING_OK) { LOG(WARNING) << "IPC unmap shm=" << shm->name << " failed, ret=" << ret; } else { - shm->addr = NULL; + shm->addr = nullptr; } ret = shm_unlink(shm->name); @@ -164,13 +164,13 @@ RETURN_CODE IpcShmLocalFree(SHM *shm) } if (errno == ENOENT) { LOG(INFO) << "IPC delete shm=" << shm->name << " already deleted by peer."; - shm->addr = NULL; + shm->addr = nullptr; return SHM_ERR_NOT_FOUND; } LOG_EVERY_SECOND(ERROR) << "IPC delete shm=" << shm->name << " failed, ret=" << ret; return SHM_ERR; } - shm->addr = NULL; + shm->addr = nullptr; LOG(INFO) << "IPC free local shm=" << shm->name << " success."; return UBRING_OK; } @@ -188,10 +188,10 @@ RETURN_CODE IpcShmRemoteMalloc(SHM *shm) return SHM_ERR; } - shm->addr = (uint8_t*)mmap(NULL, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + shm->addr = (uint8_t*)mmap(nullptr, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shm->addr == (uint8_t*)MAP_FAILED) { LOG(ERROR) << "IPC map shm=" << shm->name << " failed, ret=" << errno; - shm->addr = NULL; + shm->addr = nullptr; close(fd); return SHM_ERR; } @@ -213,10 +213,10 @@ RETURN_CODE IpcShmLocalMmap(SHM *shm, int prot) return SHM_ERR; } - shm->addr = (uint8_t*)mmap(NULL, shm->len, prot, MAP_SHARED, fd, 0); + shm->addr = (uint8_t*)mmap(nullptr, shm->len, prot, MAP_SHARED, fd, 0); if (shm->addr == (uint8_t*)MAP_FAILED) { LOG(ERROR) << "IPC map shm=" << shm->name << " failed, ret=" << errno; - shm->addr = NULL; + shm->addr = nullptr; close(fd); return SHM_ERR; } @@ -228,7 +228,7 @@ RETURN_CODE IpcShmLocalMmap(SHM *shm, int prot) RETURN_CODE IpcShmRemoteFree(SHM *shm) { - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(INFO) << "IPC free remote shm=" << shm->name << " already freed."; return UBRING_OK; } @@ -239,7 +239,7 @@ RETURN_CODE IpcShmRemoteFree(SHM *shm) return SHM_ERR; } - shm->addr = NULL; + shm->addr = nullptr; LOG(INFO) << "IPC free remote shm=" << shm->name << " success."; return UBRING_OK; } diff --git a/src/brpc/ubshm/shm/shm_mgr.cpp b/src/brpc/ubshm/shm/shm_mgr.cpp index 9535cc1a90..ea01113e54 100644 --- a/src/brpc/ubshm/shm/shm_mgr.cpp +++ b/src/brpc/ubshm/shm/shm_mgr.cpp @@ -31,7 +31,7 @@ DEFINE_int32(ub_shm_type, 1, "shm type: 1-ipc; 2-ub_ring"); static SHM_TYPE g_shm_type; static bool CheckInputShmParam(SHM *shm) { - if (shm == NULL) { + if (shm == nullptr) { LOG(ERROR) << "Input Param shm is NULL."; return false; } @@ -114,7 +114,7 @@ RETURN_CODE ShmLocalCalloc(SHM *shm) { LOG(ERROR) << "Failed to alloc local shm."; return rc; } - if (UNLIKELY(shm->addr == NULL)) { + if (UNLIKELY(shm->addr == nullptr)) { LOG(ERROR) << "Local shm=" << shm->name << " allocated with NULL address."; ShmFree(shm); return SHM_ERR; diff --git a/src/brpc/ubshm/shm/shm_ubs.cpp b/src/brpc/ubshm/shm/shm_ubs.cpp index f1da0fc7a7..2d06b0a15b 100644 --- a/src/brpc/ubshm/shm/shm_ubs.cpp +++ b/src/brpc/ubshm/shm/shm_ubs.cpp @@ -36,7 +36,7 @@ namespace brpc { namespace ubring { -#define UBRING_MK_UBSM(ret, fn, args) ret (*fn) args = NULL +#define UBRING_MK_UBSM(ret, fn, args) ret (*fn) args = nullptr #include "brpc/ubshm/ubs_mem/declare_shm_ubs.h" #define SHM_RIGHT_MODE 0666 #define UBRING_REGION_NAME_PREFIX "UbrONE2ALLRegion" @@ -47,7 +47,7 @@ DEFINE_int32(ub_flying_io_timeout, 5, "Waiting time for stopping data" "sending and receiving when the link is disconnected."); char g_region_name[MAX_REGION_NAME_DESC_LENGTH] = {0}; int g_shm_timer_fd = 0; -ShmList *g_shm_list = NULL; +ShmList *g_shm_list = nullptr; static RETURN_CODE UbsShmInterfacesLoad(void); char hostname[MAX_HOST_NAME_DESC_LENGTH]; @@ -60,7 +60,7 @@ RETURN_CODE UbsShmInterfacesLoad(void) #elif defined(OS_MACOSX) void* dlhandler = dlopen(ubsm_sdk_location, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); #endif - if (dlhandler == NULL) { + if (dlhandler == nullptr) { LOG(ERROR) << "Dlopen libubsm_sdk.so in " << ubsm_sdk_location << " failed, error:" << dlerror(); return UBRING_ERR; } @@ -72,11 +72,11 @@ RETURN_CODE UbsShmInterfacesLoad(void) #define UBRING_MK_UBSM(ret, fn, args) \ do { \ - if ((fn) != NULL) { \ + if ((fn) != nullptr) { \ break; \ } \ UBRING_MK_UBSM_OPTIONAL(ret, fn, args); \ - if ((fn) == NULL) { \ + if ((fn) == nullptr) { \ LOG(ERROR) << "Fail load ubs_mem func " << #fn <<" error:" << dlerror(); \ return UBRING_ERR; \ } \ @@ -84,7 +84,7 @@ RETURN_CODE UbsShmInterfacesLoad(void) #include "brpc/ubshm/ubs_mem/declare_shm_ubs.h" dlclose(dlhandler); - dlhandler = NULL; + dlhandler = nullptr; #endif return UBRING_OK; } @@ -155,7 +155,7 @@ do { } } while (0); - ret = ubsmem_shmem_map(NULL, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, shm->name, 0, (void**)&(shm->addr)); + ret = ubsmem_shmem_map(nullptr, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, shm->name, 0, (void**)&(shm->addr)); if (ret != UBSM_OK) { LOG(ERROR) << "Ubs map shm=" << shm->name << " failed, ret=" << ret; if (ret == UBSM_ERR_NOT_FOUND) { @@ -174,7 +174,7 @@ do { RETURN_CODE UbsShmMunmap(SHM *shm) { // unmap - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(ERROR) << "Ubs input shm param is invalid, addr is NULL."; return SHM_ERR_INPUT_INVALID; } @@ -196,7 +196,7 @@ RETURN_CODE UbsShmMunmap(SHM *shm) RETURN_CODE UbsShmFree(SHM *shm) { - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(ERROR) << "Ubs input shm param is invalid, addr is NULL."; return SHM_ERR_INPUT_INVALID; } @@ -214,7 +214,7 @@ RETURN_CODE UbsShmFree(SHM *shm) LOG(ERROR) << "Ubs free shm="<< shm->name << " failed, ret=" << ret; return SHM_ERR; } - shm->addr = NULL; + shm->addr = nullptr; LOG(INFO) << "Ubs free shm=" << shm->name << " length=" << shm->len << " success."; return UBRING_OK; } @@ -222,7 +222,7 @@ RETURN_CODE UbsShmFree(SHM *shm) RETURN_CODE UbsShmLocalFree(SHM *shm) { // unmap - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(ERROR) << "Ubs input shm param is invalid, addr is NULL."; return SHM_ERR_INPUT_INVALID; } @@ -247,14 +247,14 @@ RETURN_CODE UbsShmLocalFree(SHM *shm) LOG(ERROR) << "Ubs delete shm=" << shm->name << " failed, ret=" << ret; return SHM_ERR; } - shm->addr = NULL; + shm->addr = nullptr; LOG(INFO) << "Ubs free local shm=" << shm->name << " length=" << shm->len << " success."; return UBRING_OK; } RETURN_CODE UbsShmRemoteMalloc(SHM *shm) { - int ret = ubsmem_shmem_map(NULL, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, shm->name, 0, (void**)&(shm->addr)); + int ret = ubsmem_shmem_map(nullptr, shm->len, PROT_READ | PROT_WRITE, MAP_SHARED, shm->name, 0, (void**)&(shm->addr)); if (ret != UBSM_OK) { LOG(ERROR) << "Ubs map Shm=" << shm->name << " failed, ret=" << ret; return SHM_ERR; @@ -266,7 +266,7 @@ RETURN_CODE UbsShmRemoteMalloc(SHM *shm) RETURN_CODE UbsShmLocalMmap(SHM *shm, int prot) { - int ret = ubsmem_shmem_map(NULL, shm->len, prot, MAP_SHARED, shm->name, 0, (void**)&(shm->addr)); + int ret = ubsmem_shmem_map(nullptr, shm->len, prot, MAP_SHARED, shm->name, 0, (void**)&(shm->addr)); if (ret != UBSM_OK) { LOG(ERROR) << "Ubs map Shm=" << shm->name << " failed, ret=" << ret; return SHM_ERR; @@ -279,7 +279,7 @@ RETURN_CODE UbsShmLocalMmap(SHM *shm, int prot) RETURN_CODE UbsShmRemoteFree(SHM *shm) { // unmap - if (shm->addr == NULL) { + if (shm->addr == nullptr) { LOG(ERROR) << "Ubs input shm param is invalid, addr is NULL."; return SHM_ERR_INPUT_INVALID; } @@ -393,16 +393,16 @@ RETURN_CODE UbsShmFini(void) static void DeleteShmToList(ShmList* shm_list) { - if (shm_list == NULL || shm_list->head == NULL) { + if (shm_list == nullptr || shm_list->head == nullptr) { return; } ShmListNode *cur_node = shm_list->head; shm_list->head = cur_node->next; - if (shm_list->head != NULL) { - shm_list->head->prev = NULL; + if (shm_list->head != nullptr) { + shm_list->head->prev = nullptr; } else { - shm_list->tail = NULL; + shm_list->tail = nullptr; } LOG(INFO) << "Delete shm to list, name=" << cur_node->shm.name << " size=" << shm_list->size; FREE_PTR(cur_node); @@ -412,26 +412,26 @@ static void DeleteShmToList(ShmList* shm_list) void *UbsShmCallback(void* args) { ShmList *shm_list = (ShmList*)args; - if (UNLIKELY(shm_list == NULL)) { + if (UNLIKELY(shm_list == nullptr)) { LOG(ERROR) << "Shm list is null."; - return NULL; + return nullptr; } LOCK_GUARD(shm_list->shm_lock); - while (shm_list->head != NULL) { + while (shm_list->head != nullptr) { SHM shm = shm_list->head->shm; - if (shm.addr == NULL) { + if (shm.addr == nullptr) { LOG(ERROR) << "Ubs input shm param is invalid, addr is NULL."; - return NULL; + return nullptr; } int ret = ubsmem_shmem_unmap(shm.addr, shm.len); if (ret != UBSM_OK) { if (ret == UBSM_ERR_NET) { - return NULL; + return nullptr; } LOG(ERROR) << "Ubs unmap shm=" << shm.name << " length=" << shm.len << " failed, ret=" << ret; - return NULL; + return nullptr; } LOG(INFO) << "Ubs unmap shm=" << shm.name << " length=" << shm.len << " success."; @@ -439,13 +439,13 @@ void *UbsShmCallback(void* args) if (ret != UBSM_OK) { DeleteShmToList(shm_list); LOG(ERROR) << "Ubs delete shm=" << shm.name << " failed, ret=" << ret; - return NULL; + return nullptr; } DeleteShmToList(shm_list); LOG(INFO) << "Ubs free local shm=" << shm.name << " length=" << shm.len << " success."; } - return NULL; + return nullptr; } RETURN_CODE UbsShmAddTimer(ShmList *shm_list) @@ -468,15 +468,15 @@ RETURN_CODE UbsShmAddTimer(ShmList *shm_list) RETURN_CODE InitShmTimer(ShmList **shm_list) { *shm_list = (ShmList *)malloc(sizeof(ShmList)); - if (*shm_list == NULL) { + if (*shm_list == nullptr) { LOG(ERROR) << "Malloc shm list failed."; return UBRING_ERR; } - (*shm_list)->head = NULL; - (*shm_list)->tail = NULL; + (*shm_list)->head = nullptr; + (*shm_list)->tail = nullptr; (*shm_list)->size = 0; - if (pthread_mutex_init(&(*shm_list)->shm_lock, NULL) != 0) { + if (pthread_mutex_init(&(*shm_list)->shm_lock, nullptr) != 0) { LOG(ERROR) << "Init shm list mutex failed."; FREE_PTR(*shm_list); return UBRING_ERR; @@ -493,14 +493,14 @@ RETURN_CODE InitShmTimer(ShmList **shm_list) RETURN_CODE DestroyShmTimer(ShmList *shm_list) { DeleteTimerSafe((uint32_t)g_shm_timer_fd); - if (shm_list == NULL) { + if (shm_list == nullptr) { LOG(WARNING) << "Shm list is null."; return UBRING_ERR; } ShmListNode* current = shm_list->head; ShmListNode* next; - while (current != NULL) { + while (current != nullptr) { next = current->next; free(current); current = next; @@ -512,14 +512,14 @@ RETURN_CODE DestroyShmTimer(ShmList *shm_list) RETURN_CODE IsExistInShmList(ShmList *shm_list, const SHM *shm) { - if (UNLIKELY(shm_list == NULL || shm == NULL)) { + if (UNLIKELY(shm_list == nullptr || shm == nullptr)) { LOG(ERROR) << "Shm list or shm is null."; return UBRING_ERR; } LOCK_GUARD(shm_list->shm_lock); ShmListNode *cur_node = shm_list->head; - while (cur_node != NULL) { + while (cur_node != nullptr) { if (strcmp(cur_node->shm.name, shm->name) == 0 && cur_node->shm.len == shm->len) { return UBRING_OK; } @@ -530,7 +530,7 @@ RETURN_CODE IsExistInShmList(ShmList *shm_list, const SHM *shm) RETURN_CODE AddShmToList(ShmList *shm_list, SHM *shm) { - if (shm_list == NULL || shm == NULL) { + if (shm_list == nullptr || shm == nullptr) { LOG(ERROR) << "Shm list or shm is null."; return UBRING_ERR; } @@ -541,14 +541,14 @@ RETURN_CODE AddShmToList(ShmList *shm_list, SHM *shm) } ShmListNode *new_shm_node = (ShmListNode *)malloc(sizeof(ShmListNode)); - if (new_shm_node == NULL) { + if (new_shm_node == nullptr) { LOG(ERROR) << "Malloc shm node failed."; return UBRING_ERR; } memcpy(&new_shm_node->shm, shm, sizeof(SHM)); LOCK_GUARD(shm_list->shm_lock); - new_shm_node->next = NULL; + new_shm_node->next = nullptr; new_shm_node->prev = shm_list->tail; if (shm_list->tail) { shm_list->tail->next = new_shm_node; diff --git a/src/brpc/ubshm/timer/timer_mgr.cpp b/src/brpc/ubshm/timer/timer_mgr.cpp index e57be93185..b5e0c9ef3b 100644 --- a/src/brpc/ubshm/timer/timer_mgr.cpp +++ b/src/brpc/ubshm/timer/timer_mgr.cpp @@ -31,7 +31,7 @@ namespace ubring { int32_t g_epoll_fd = -1; std::atomic g_total_timer_num(0); -TimerFdCtx *g_timer_fd_ctx_map = NULL; +TimerFdCtx *g_timer_fd_ctx_map = nullptr; uint32_t g_max_system_fd = 0; static pthread_t g_epoll_execute_thread = 0; static int32_t g_timer_module_initialized = 0; @@ -44,7 +44,7 @@ static int timerfd_settime_macosx(int fd, int flags, #endif static RETURN_CODE DeleteTimerInner(uint32_t fd) { - if (g_timer_fd_ctx_map == NULL) { + if (g_timer_fd_ctx_map == nullptr) { return UBRING_OK; } @@ -58,26 +58,26 @@ static RETURN_CODE DeleteTimerInner(uint32_t fd) { } g_timer_fd_ctx_map[fd].status = TIMER_CONTEXT_NOT_USING; - g_timer_fd_ctx_map[fd].cb = NULL; - g_timer_fd_ctx_map[fd].args = NULL; + g_timer_fd_ctx_map[fd].cb = nullptr; + g_timer_fd_ctx_map[fd].args = nullptr; g_timer_fd_ctx_map[fd].periodical = 0; g_timer_fd_ctx_map[fd].fd = 0; pthread_spin_unlock(&g_timer_fd_ctx_map[fd].spin_lock); #if defined(OS_LINUX) - epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, (int)fd, NULL); + epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, (int)fd, nullptr); #elif defined(OS_MACOSX) struct kevent evt; - EV_SET(&evt, fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); - kevent(g_epoll_fd, &evt, 1, NULL, 0, NULL); + EV_SET(&evt, fd, EVFILT_TIMER, EV_DELETE, 0, 0, nullptr); + kevent(g_epoll_fd, &evt, 1, nullptr, 0, nullptr); #endif uint64_t exp = 0; read((int)fd, &exp, sizeof(exp)); close((int)fd); - std::atomic_fetch_sub(&g_total_timer_num, 1); + std::atomic_fetch_sub(&g_total_timer_num, 1U); return UBRING_OK; } @@ -92,7 +92,7 @@ static RETURN_CODE StartTimeEpoll(void) { return UBRING_ERR; } - int ret = pthread_create(&g_epoll_execute_thread, NULL, TimerEpoll, NULL); + int ret = pthread_create(&g_epoll_execute_thread, nullptr, TimerEpoll, nullptr); if (UNLIKELY(ret != 0)) { LOG(ERROR) << "Failed to create thread err=" << ret; return UBRING_ERR; @@ -101,7 +101,7 @@ static RETURN_CODE StartTimeEpoll(void) { } static RETURN_CODE TimerSpinLocksInit(void) { - if (g_timer_fd_ctx_map == NULL) { + if (g_timer_fd_ctx_map == nullptr) { LOG(ERROR) << "Timer module is not fully initialized."; return UBRING_ERR; } @@ -150,7 +150,7 @@ RETURN_CODE TimerInit(void) { } g_max_system_fd = (uint32_t)rlim.rlim_cur; - if (g_timer_fd_ctx_map == NULL) { + if (g_timer_fd_ctx_map == nullptr) { g_timer_fd_ctx_map = (TimerFdCtx *)malloc(sizeof(TimerFdCtx) * g_max_system_fd); if (UNLIKELY(!g_timer_fd_ctx_map)) { LOG(ERROR) << "Fail to malloc space for timer modules. errno=%d", errno; @@ -161,7 +161,7 @@ RETURN_CODE TimerInit(void) { if (ret != UBRING_OK) { LOG(ERROR) << "Failed to init main data structure of Time Module. ret=" << ret; free(g_timer_fd_ctx_map); - g_timer_fd_ctx_map = NULL; + g_timer_fd_ctx_map = nullptr; return UBRING_ERR; } } @@ -169,7 +169,7 @@ RETURN_CODE TimerInit(void) { RETURN_CODE ret = StartTimeEpoll(); if (ret != UBRING_OK) { LOG(ERROR) << "Failed to start Timer Epoll. ret=" << ret; - if (LIKELY(g_timer_fd_ctx_map != NULL)) { + if (LIKELY(g_timer_fd_ctx_map != nullptr)) { FREE_PTR(g_timer_fd_ctx_map); } return UBRING_ERR; @@ -181,12 +181,12 @@ RETURN_CODE TimerInit(void) { void *UnifiedCallback(void *args) { TimerFdCtx *ctx = (TimerFdCtx *)args; if (pthread_spin_lock(&ctx->spin_lock) != 0) { - return NULL; + return nullptr; } if (ctx->status == TIMER_CONTEXT_NOT_USING) { pthread_spin_unlock(&ctx->spin_lock); - return NULL; + return nullptr; } void *(*cb)(void *) = ctx->cb; @@ -202,7 +202,7 @@ void *UnifiedCallback(void *args) { if (!is_periodical) { DeleteTimerInner(fd); } - return NULL; + return nullptr; } void *TimerEpoll(void *args) { @@ -224,7 +224,7 @@ void *TimerEpoll(void *args) { TIMER_EPOLL_WAIT_TIMEOUT); #elif defined(OS_MACOSX) struct timespec timeout = {0, TIMER_EPOLL_WAIT_TIMEOUT * 1000000}; - int32_t ready_num = kevent(g_epoll_fd, NULL, 0, ready_events, MAX_TIMER, &timeout); + int32_t ready_num = kevent(g_epoll_fd, nullptr, 0, ready_events, MAX_TIMER, &timeout); #endif if (UNLIKELY(ready_num == -1)) { @@ -268,11 +268,11 @@ void *TimerEpoll(void *args) { } } } - return NULL; + return nullptr; } void DeleteTimerSafe(uint32_t fd) { - if (g_timer_fd_ctx_map == NULL) { + if (g_timer_fd_ctx_map == nullptr) { return; } @@ -286,30 +286,30 @@ void DeleteTimerSafe(uint32_t fd) { } g_timer_fd_ctx_map[fd].status = TIMER_CONTEXT_NOT_USING; - g_timer_fd_ctx_map[fd].cb = NULL; - g_timer_fd_ctx_map[fd].args = NULL; + g_timer_fd_ctx_map[fd].cb = nullptr; + g_timer_fd_ctx_map[fd].args = nullptr; g_timer_fd_ctx_map[fd].periodical = 0; g_timer_fd_ctx_map[fd].fd = 0; pthread_spin_unlock(&g_timer_fd_ctx_map[fd].spin_lock); #if defined(OS_LINUX) - epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, (int)fd, NULL); + epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, (int)fd, nullptr); #elif defined(OS_MACOSX) struct kevent evt; - EV_SET(&evt, fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); - kevent(g_epoll_fd, &evt, 1, NULL, 0, NULL); + EV_SET(&evt, fd, EVFILT_TIMER, EV_DELETE, 0, 0, nullptr); + kevent(g_epoll_fd, &evt, 1, nullptr, 0, nullptr); #endif uint64_t exp = 0; read((int)fd, &exp, sizeof(exp)); close((int)fd); - std::atomic_fetch_sub(&g_total_timer_num, 1); + std::atomic_fetch_sub(&g_total_timer_num, 1U); } void DeleteTimer(uint32_t fd) { - if (g_timer_fd_ctx_map == NULL) { + if (g_timer_fd_ctx_map == nullptr) { LOG(WARNING) << "The timer is not initialized."; return; } @@ -355,8 +355,8 @@ int32_t TimerStart(const itimerspec *time, void *(*cb)(void *), void *args) { uint64_t timeout_nsec = time->it_value.tv_sec * 1000000000ULL + time->it_value.tv_nsec; uint64_t interval_nsec = time->it_interval.tv_sec * 1000000000ULL + time->it_interval.tv_nsec; EV_SET(&event, timer_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, - timeout_nsec / 1000000, NULL); - int32_t ret = kevent(g_epoll_fd, &event, 1, NULL, 0, NULL); + timeout_nsec / 1000000, nullptr); + int32_t ret = kevent(g_epoll_fd, &event, 1, nullptr, 0, nullptr); #endif if (UNLIKELY(ret != 0)) { @@ -365,26 +365,26 @@ int32_t TimerStart(const itimerspec *time, void *(*cb)(void *), void *args) { return -1; } - std::atomic_fetch_add(&g_total_timer_num, 1); + std::atomic_fetch_add(&g_total_timer_num, 1U); #if defined(OS_LINUX) - ret = timerfd_settime(timer_fd, 0, time, NULL); + ret = timerfd_settime(timer_fd, 0, time, nullptr); #elif defined(OS_MACOSX) - ret = timerfd_settime_macosx(timer_fd, 0, time, NULL); + ret = timerfd_settime_macosx(timer_fd, 0, time, nullptr); #endif if (UNLIKELY(ret != 0)) { #if defined(OS_LINUX) - if (epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, timer_fd, NULL) != 0) { + if (epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, timer_fd, nullptr) != 0) { #elif defined(OS_MACOSX) struct kevent evt; - EV_SET(&evt, timer_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); - if (kevent(g_epoll_fd, &evt, 1, NULL, 0, NULL) != 0) { + EV_SET(&evt, timer_fd, EVFILT_TIMER, EV_DELETE, 0, 0, nullptr); + if (kevent(g_epoll_fd, &evt, 1, nullptr, 0, nullptr) != 0) { #endif LOG(ERROR) << "Failed to delete the timer fd=" << timer_fd << " with errno=" << errno; } CloseTimerFd(timer_fd); - std::atomic_fetch_sub(&g_total_timer_num, 1); + std::atomic_fetch_sub(&g_total_timer_num, 1U); LOG(ERROR) << "Failed to set timer"; return -1; } @@ -397,8 +397,8 @@ uint32_t GetActiveTimerNum(void) { } void CloseTimerFd(int fd) { - g_timer_fd_ctx_map[fd].cb = NULL; - g_timer_fd_ctx_map[fd].args = NULL; + g_timer_fd_ctx_map[fd].cb = nullptr; + g_timer_fd_ctx_map[fd].args = nullptr; g_timer_fd_ctx_map[fd].status = TIMER_CONTEXT_NOT_USING; g_timer_fd_ctx_map[fd].fd = 0; g_timer_fd_ctx_map[fd].periodical = 0; @@ -421,7 +421,7 @@ void TimerModuleDestroy(void) { g_epoll_fd = -1; g_total_timer_num = 0; g_timer_module_initialized = 0; - int32_t ret = pthread_join(g_epoll_execute_thread, NULL); + int32_t ret = pthread_join(g_epoll_execute_thread, nullptr); if (ret != EOK) { LOG(ERROR) << "Failed to join pthread, during destroying timer module. ret=" << ret; return; @@ -437,7 +437,7 @@ RETURN_CODE TimerFdCtxValidate(uint32_t fd) { LOG(ERROR) << "TimerFd=" << fd << " has wrong status=" << g_timer_fd_ctx_map[fd].status; return UBRING_ERR; } - if (g_timer_fd_ctx_map[fd].cb == NULL) { + if (g_timer_fd_ctx_map[fd].cb == nullptr) { LOG(ERROR) << "The callback is not set."; return UBRING_ERR; } @@ -457,7 +457,7 @@ static int timerfd_create_macosx(int clockid, int flags) { static int timerfd_settime_macosx(int fd, int flags, const itimerspec *new_value, itimerspec *old_value) { - if (old_value != NULL) { + if (old_value != nullptr) { memset(old_value, 0, sizeof(itimerspec)); } return 0; diff --git a/src/brpc/ubshm/ub_endpoint.cpp b/src/brpc/ubshm/ub_endpoint.cpp index ea965a45b3..45794fdc6e 100644 --- a/src/brpc/ubshm/ub_endpoint.cpp +++ b/src/brpc/ubshm/ub_endpoint.cpp @@ -66,7 +66,7 @@ static uint16_t g_ub_impl_version = 1; static const uint32_t ACK_MSG_UB_OK = 0x1; -static butil::Mutex* g_ubring_resource_mutex = NULL; +static butil::Mutex* g_ubring_resource_mutex = nullptr; void HelloMessage::Serialize(void* data) const { char* current_pos = static_cast(data); @@ -149,7 +149,7 @@ void UBConnect::StartConnect(const Socket* socket, void (*done)(int err, void* data), void* data) { auto* ub_transport = static_cast(socket->_transport.get()); - CHECK(ub_transport->_ub_ep != NULL); + CHECK(ub_transport->_ub_ep != nullptr); SocketUniquePtr s; if (Socket::Address(socket->id(), &s) != 0) { return; @@ -211,7 +211,7 @@ static void TryReadOnTcpDuringRdmaEst(Socket* s) { void UBShmEndpoint::OnNewDataFromTcp(Socket* m) { auto* ub_transport = static_cast(m->_transport.get()); UBShmEndpoint* ep = ub_transport->GetUBShmEp(); - CHECK(ep != NULL); + CHECK(ep != nullptr); int progress = Socket::PROGRESS_INIT; while (true) { @@ -267,7 +267,7 @@ bool HelloNegotiationValid(HelloMessage& msg) { static const int WAIT_TIMEOUT_MS = 50; int UBShmEndpoint::ReadFromFd(void* data, size_t len) { - CHECK(data != NULL); + CHECK(data != nullptr); int nr = 0; size_t received = 0; do { @@ -295,7 +295,7 @@ int UBShmEndpoint::ReadFromFd(void* data, size_t len) { } int UBShmEndpoint::WriteToFd(void* data, size_t len) { - CHECK(data != NULL); + CHECK(data != nullptr); int nw = 0; size_t written = 0; do { @@ -341,14 +341,14 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { ep->_state = C_ALLOC_SHM; auto* ub_transport = static_cast(s->_transport.get()); size_t local_shm_len = (size_t)(FLAGS_data_queue_size) * MB_TO_BYTE; - SHM local_trx_shm = {NULL, local_shm_len, 0, {0}, (uint32_t)s->fd()}; + SHM local_trx_shm = {nullptr, local_shm_len, 0, {0}, (uint32_t)s->fd()}; auto shm_name_str = butil::endpoint2str(s->local_side()); const char* shm_name = shm_name_str.c_str(); if (ep->AllocateClientResources(&local_trx_shm, shm_name) < 0) { LOG(WARNING) << "Fallback to tcp:" << s->description(); ub_transport->_ub_state = UBShmTransport::UB_OFF; ep->_state = FALLBACK_TCP; - return NULL; + return nullptr; } ep->_state = C_HELLO_SEND; @@ -366,7 +366,7 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } LOG_IF(INFO, FLAGS_ub_trace_verbose) << "client handshake message : " << local_msg.toString(); @@ -377,14 +377,14 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } if (memcmp(data, MAGIC_STR, MAGIC_STR_LEN) != 0) { LOG(WARNING) << "Read unexpected data during handshake:" << s->description(); s->SetFailed(EPROTO, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(EPROTO)); ep->_state = FAILED; - return NULL; + return nullptr; } if (ep->ReadFromFd(data, HELLO_MSG_LEN_MIN - MAGIC_STR_LEN) < 0) { @@ -393,7 +393,7 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } HelloMessage remote_msg; remote_msg.Deserialize(data); @@ -403,7 +403,7 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(EPROTO, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(EPROTO)); ep->_state = FAILED; - return NULL; + return nullptr; } if (remote_msg.msg_len > HELLO_MSG_LEN_MIN) { @@ -438,7 +438,7 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } if (ub_transport->_ub_state == UBShmTransport::UB_ON) { @@ -454,7 +454,7 @@ void* UBShmEndpoint::ProcessHandshakeAtClient(void* arg) { errno = 0; - return NULL; + return nullptr; } void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { @@ -473,7 +473,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } auto* ub_transport = static_cast(s->_transport.get()); if (memcmp(data, MAGIC_STR, MAGIC_STR_LEN) != 0) { @@ -484,7 +484,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { ep->_state = FALLBACK_TCP; ub_transport->_ub_state = UBShmTransport::UB_OFF; ep->TryReadOnTcp(); - return NULL; + return nullptr; } if (ep->ReadFromFd(data, g_ub_hello_msg_len - MAGIC_STR_LEN) < 0) { @@ -493,7 +493,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } HelloMessage remote_msg; @@ -505,7 +505,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { s->SetFailed(EPROTO, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(EPROTO)); ep->_state = FAILED; - return NULL; + return nullptr; } if (remote_msg.msg_len > HELLO_MSG_LEN_MIN) { // TODO: Read Hello Message customized header @@ -518,17 +518,17 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { ub_transport->_ub_state = UBShmTransport::UB_OFF; } else { ep->_state = S_ALLOC_SHM; - ubring::SHM remote_trx_shm = {NULL, remote_msg.len, 0, {0}, (uint32_t)ep->_socket->fd()}; + ubring::SHM remote_trx_shm = {nullptr, remote_msg.len, 0, {0}, (uint32_t)ep->_socket->fd()}; strncpy(remote_trx_shm.name, remote_msg.shm_name, SHM_MAX_NAME_BUFF_LEN); size_t local_shm_len = (size_t)(FLAGS_data_queue_size) * MB_TO_BYTE; // server-side shared memory name - ubring::SHM local_trx_shm = {NULL, local_shm_len, 0, {0}, (uint32_t)ep->_socket->fd()}; + ubring::SHM local_trx_shm = {nullptr, local_shm_len, 0, {0}, (uint32_t)ep->_socket->fd()}; char client_name[SHM_MAX_NAME_BUFF_LEN]; strncpy(client_name, remote_msg.shm_name, SHM_MAX_NAME_BUFF_LEN); char *client_ip_port = strrchr(client_name, '_'); - if (client_ip_port != NULL) { + if (client_ip_port != nullptr) { *client_ip_port = '\0'; } int result = snprintf(local_trx_shm.name, SHM_MAX_NAME_BUFF_LEN, "%s_%s", @@ -564,7 +564,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { s->SetFailed(saved_errno, "Fail to complete ub handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } ep->_state = S_ACK_WAIT; @@ -574,7 +574,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { s->SetFailed(saved_errno, "Fail to complete ubring handshake from %s: %s", s->description().c_str(), berror(saved_errno)); ep->_state = FAILED; - return NULL; + return nullptr; } uint32_t* tmp = (uint32_t*)data; @@ -586,7 +586,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { s->SetFailed(EPROTO, "Fail to complete ub handshake from %s: %s", s->description().c_str(), berror(EPROTO)); ep->_state = FAILED; - return NULL; + return nullptr; } else { ub_transport->_ub_state = UBShmTransport::UB_ON; ep->_state = ESTABLISHED; @@ -602,7 +602,7 @@ void* UBShmEndpoint::ProcessHandshakeAtServer(void* arg) { } ep->TryReadOnTcp(); - return NULL; + return nullptr; } bool UBShmEndpoint::IsWritable() const { @@ -671,7 +671,7 @@ int UBShmEndpoint::AllocateClientResources(ubring::SHM* local_trx_shm, const cha return 0; } - CHECK(_ub_ring == NULL); + CHECK(_ub_ring == nullptr); // TODO: Pooling management _ub_ring = new UBRing(); @@ -696,7 +696,7 @@ int UBShmEndpoint::AllocateServerResources(ubring::SHM* remote_trx_shm, ubring:: return 0; } - CHECK(_ub_ring == NULL); + CHECK(_ub_ring == nullptr); // TODO: Pooling management _ub_ring = new UBRing(); @@ -725,7 +725,7 @@ void UBShmEndpoint::DeallocateResources() { if (INVALID_SOCKET_ID != _cq_sid) { SocketUniquePtr s; if (Socket::Address(_cq_sid, &s) == 0) { - s->_user = NULL; + s->_user = nullptr; s->_fd = -1; s->SetFailed(); } @@ -914,7 +914,7 @@ void UBShmEndpoint::PollingModeRelease(bthread_tag_t tag) { auto& running = group.running; running.store(false, std::memory_order_relaxed); for (int i = 0; i < FLAGS_ub_poller_num; ++i) { - bthread_join(pollers[i].tid, NULL); + bthread_join(pollers[i].tid, nullptr); } } diff --git a/src/brpc/ubshm/ub_endpoint.h b/src/brpc/ubshm/ub_endpoint.h index bf9e61c5d7..03c5134522 100644 --- a/src/brpc/ubshm/ub_endpoint.h +++ b/src/brpc/ubshm/ub_endpoint.h @@ -68,8 +68,8 @@ class UBConnect : public AppConnect { private: void Run(); - void (*_done)(int, void*){NULL}; - void* _data{NULL}; + void (*_done)(int, void*){nullptr}; + void* _data{nullptr}; }; class BAIDU_CACHELINE_ALIGNMENT UBShmEndpoint : public SocketUser { diff --git a/src/brpc/ubshm/ub_helper.cpp b/src/brpc/ubshm/ub_helper.cpp index b88e656adc..230ca71bac 100644 --- a/src/brpc/ubshm/ub_helper.cpp +++ b/src/brpc/ubshm/ub_helper.cpp @@ -31,7 +31,7 @@ namespace brpc { namespace ubring { -void* g_handle_ub = NULL; +void* g_handle_ub = nullptr; bool g_skip_ub_init = false; butil::atomic g_ub_available(false); diff --git a/src/brpc/ubshm/ub_ring.cpp b/src/brpc/ubshm/ub_ring.cpp index 7008314437..72df015409 100644 --- a/src/brpc/ubshm/ub_ring.cpp +++ b/src/brpc/ubshm/ub_ring.cpp @@ -122,7 +122,7 @@ RETURN_CODE UBRing::UbrTrxClose() { } RETURN_CODE UBRing::UbrAddCloseTimer() { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { LOG(ERROR) << "Trx add close timer failed, trx is null."; return UBRING_ERR; } @@ -196,7 +196,7 @@ void* UBRing::UbrTrxCloseCallback(void* args) { } RETURN_CODE UBRing::UbrAddHBTimer() { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { LOG(ERROR) << "Trx add heartbeat timer failed, trx is null."; return UBRING_ERR; } @@ -227,7 +227,7 @@ RETURN_CODE UBRing::UbrPassiveClearTrx(UbrTrx *trx, int fd, PASSIVE_DISC_TYPE ty trx->ubr_tx.trx_state = UBR_STATE_CLOSED; trx->ubr_rx.trx_state = UBR_STATE_CLOSED; DeleteTimerSafe((uint32_t)trx->timer_fd); - const char *type_name = NULL; + const char *type_name = nullptr; if (type == UBR_HEARTBEAT) { DeleteTimer((uint32_t)trx->hb_timer_fd); type_name = "Trx heartbeat"; @@ -253,42 +253,42 @@ RETURN_CODE UBRing::UbrPassiveClearTrx(UbrTrx *trx, int fd, PASSIVE_DISC_TYPE ty void* UBRing::UbrTrxHBCallback(void* args) { auto* trx = (UbrTrx*) args; if (UNLIKELY(UbrTrxCallbackCheck(trx) != UBRING_OK)) { - return NULL; + return nullptr; } auto* local_data_status = (UbrDataStatusQMsg *)trx->ubr_tx.local_data_status_q.addr; auto* remote_data_status = (UbrDataStatusQMsg *)trx->ubr_rx.remote_data_status_q.addr; - if (UNLIKELY(local_data_status == NULL || remote_data_status == NULL)) { + if (UNLIKELY(local_data_status == nullptr || remote_data_status == nullptr)) { LOG(ERROR) << "Heartbeat error, datastatus is NULL."; - return NULL; + return nullptr; } if (trx->ubr_tx.trx_state != UBR_STATE_CONNECTED || trx->ubr_rx.trx_state != UBR_STATE_CONNECTED) { LOG_EVERY_SECOND(INFO) << "Heartbeat cannot be started, wait connected state."; - return NULL; + return nullptr; } remote_data_status->heart_beat = 1; if (local_data_status->heart_beat == 1) { local_data_status->heart_beat = 0; trx->ubr_tx.hb_retry_cnt = 0; - return NULL; + return nullptr; } ++trx->ubr_tx.hb_retry_cnt; if (trx->ubr_tx.hb_retry_cnt <= FLAGS_ub_hb_retry_cnt) { - return NULL; + return nullptr; } int fd = (int)trx->local_shm.fd; LOG(INFO) << "Hlc heartbeat, start to clear trx resource. hb_timer_fd=" << fd << ", shm_name=" << trx->local_shm.name; UbrPassiveClearTrx(trx, fd, UBR_HEARTBEAT); LOG(INFO) << "Hlc heartbeat clear trx resource finish."; - return NULL; + return nullptr; } RETURN_CODE UBRing::UbrAddAsynClearTimer(UbrTrx *trx) { - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Trx add close timer failed, trx is null."; return UBRING_ERR; } @@ -314,9 +314,9 @@ RETURN_CODE UBRing::UbrAddAsynClearTimer(UbrTrx *trx) { void *UBRing::UbrAsynClearCallback(void *args) { auto* trx = (UbrTrx*) args; - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Trx close, trx is null."; - return NULL; + return nullptr; } if (UNLIKELY(UbrTrxFreeShm(trx) != UBRING_OK)) { @@ -326,7 +326,7 @@ void *UBRing::UbrAsynClearCallback(void *args) if (UNLIKELY(UBRingManager::ReleaseUbrTrxFromMgr(trx) != UBRING_OK)) { LOG(ERROR) << "Trx close, release shm " << trx->local_shm.name << " trx failed."; } - return NULL; + return nullptr; } int UBRing::UbrTrxSend(const void *buf, uint32_t buf_len) @@ -539,11 +539,11 @@ ssize_t UBRing::UbrTrxReadvBlockMode(const struct iovec *iov, int iovcnt) RETURN_CODE UBRing::IsUbrTrxReadable(uint32_t ep_event) { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { LOG(ERROR) << "The trx to be checked is NULL."; return UBRING_ERR; } - if (UNLIKELY(_trx->local_shm.addr == NULL)) { + if (UNLIKELY(_trx->local_shm.addr == nullptr)) { LOG(ERROR) << "The trx local_shm to be checked is NULL."; return UBRING_ERR; } @@ -574,19 +574,19 @@ RETURN_CODE UBRing::IsUbrTrxReadable(uint32_t ep_event) RETURN_CODE UBRing::IsUbrTrxWriteable(uint32_t ep_event) { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { LOG(ERROR) << "The trx to be checked is NULL."; return UBRING_ERR; } - if (UNLIKELY(_trx->local_shm.addr == NULL)) { + if (UNLIKELY(_trx->local_shm.addr == nullptr)) { LOG(ERROR) << "The trx local_shm to be checked is NULL."; return UBRING_ERR; } - if (UNLIKELY((UbrEventQMsg *)_trx->ubr_tx.local_tx_event_q.addr == NULL)) { + if (UNLIKELY((UbrEventQMsg *)_trx->ubr_tx.local_tx_event_q.addr == nullptr)) { LOG(ERROR) << "The trx local_tx_event_q addr is NULL."; return UBRING_ERR; } - if (UNLIKELY((UbrEventQMsg *)_trx->ubr_tx.local_data_status_q.addr == NULL)) { + if (UNLIKELY((UbrEventQMsg *)_trx->ubr_tx.local_data_status_q.addr == nullptr)) { LOG(ERROR) << "The trx local_data_status_q addr is NULL."; return UBRING_ERR; } @@ -628,7 +628,7 @@ RETURN_CODE UBRing::UbrSetTimeout(UbrTaskStep task_type, int timeout) RETURN_CODE UBRing::UbrTrxFreeShm(UbrTrx *trx) { - if (trx == NULL) { + if (trx == nullptr) { LOG(ERROR) << "Trx is NULL."; return UBRING_ERR; } @@ -650,7 +650,7 @@ RETURN_CODE UBRing::UbrTrxFreeShm(UbrTrx *trx) } RETURN_CODE remote_rc = UBRING_OK; - if (trx->remote_shm.addr != NULL) { + if (trx->remote_shm.addr != nullptr) { remote_rc = ShmRemoteFree(&trx->remote_shm); } if (remote_rc != UBRING_OK) { @@ -662,7 +662,7 @@ RETURN_CODE UBRing::UbrTrxFreeShm(UbrTrx *trx) RETURN_CODE UBRing::UbrUnlinkLocalShm() { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { return UBRING_ERR; } RETURN_CODE rc = ShmFree(&_trx->local_shm); @@ -675,7 +675,7 @@ RETURN_CODE UBRing::UbrUnlinkLocalShm() void UBRing::PreWriteAddr(uint8_t *addr, size_t len) { - if (addr == NULL) { + if (addr == nullptr) { return; } @@ -699,7 +699,7 @@ void UBRing::PreWriteAddr(uint8_t *addr, size_t len) void UBRing::PrewriteUbrTx(UbrTx *tx) { - if (tx == NULL) { + if (tx == nullptr) { return; } PreWriteAddr(tx->remote_data_q.addr, tx->capacity * sizeof(UbrMsgFormat)); @@ -707,7 +707,7 @@ void UBRing::PrewriteUbrTx(UbrTx *tx) void UBRing::PrewriteUbrRx(UbrRx *rx) { - if (rx == NULL) { + if (rx == nullptr) { return; } PreWriteAddr(rx->local_data_q.addr, rx->capacity * sizeof(UbrMsgFormat)); @@ -715,11 +715,11 @@ void UBRing::PrewriteUbrRx(UbrRx *rx) RETURN_CODE UBRing::UbrTrxMapLocalShm(SHM *local_shm) { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { LOG(ERROR) << "Trx map Shared memory failed, trx is null."; return UBRING_ERR; } - if (UNLIKELY(local_shm == NULL || local_shm->addr == NULL)) { + if (UNLIKELY(local_shm == nullptr || local_shm->addr == nullptr)) { LOG(ERROR) << "Trx map Shared memory failed, local_shm is null or addr is NULL."; return UBRING_ERR; } @@ -738,11 +738,11 @@ RETURN_CODE UBRing::UbrTrxMapLocalShm(SHM *local_shm) RETURN_CODE UBRing::UbrTrxMapRemoteShm(SHM *remote_shm) { - if (UNLIKELY(_trx == NULL)) { + if (UNLIKELY(_trx == nullptr)) { LOG(ERROR) << "Trx map Shared memory failed, trx is null."; return UBRING_ERR; } - if (UNLIKELY(remote_shm == NULL || remote_shm->addr == NULL)) { + if (UNLIKELY(remote_shm == nullptr || remote_shm->addr == nullptr)) { LOG(ERROR) << "Trx map Shared memory failed, remote_shm is null or addr is NULL."; return UBRING_ERR; } @@ -866,7 +866,7 @@ RETURN_CODE UBRing::UbrMapRemoteShmAddTimer(SHM *local_trx_shm, const char *loca size_t remote_server_len = UBR_MSG_LEN * (((UbrDataStatusQMsg *)(_trx->ubr_tx.local_data_status_q.addr))->tail + 1) + UBR_MSG_LEN * ((DATAQ_ADDR_OFFSET / UBR_MSG_LEN) + 1); - SHM remote_trx_shm = {NULL, remote_server_len, 0, {0}, local_trx_shm->fd}; + SHM remote_trx_shm = {nullptr, remote_server_len, 0, {0}, local_trx_shm->fd}; int result = snprintf(remote_trx_shm.name, SHM_MAX_NAME_BUFF_LEN, "%s_%s_%s", @@ -906,7 +906,7 @@ RETURN_CODE UBRing::UbrMapRemoteShmAddTimer(SHM *local_trx_shm, const char *loca RETURN_CODE UBRing::ApplyAndMapLocalShm(SHM *local_trx_shm, const char *local_name) { - if (UNLIKELY(_trx == NULL || local_trx_shm == NULL)) { + if (UNLIKELY(_trx == nullptr || local_trx_shm == nullptr)) { LOG(ERROR) << "Trx map Shared memory failed, trx is null, local_name=" << local_name; return UBRING_ERR; } @@ -988,7 +988,7 @@ RETURN_CODE UBRing::WritevHasEnoughSpace(size_t buf_len) RETURN_CODE UBRing::UbrClearResourceCheck(UbrTrx *trx, uint64_t start_time, UbrCloseType close_type) { - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Trx close failed, trx is null."; return UBRING_ERR; } @@ -1031,7 +1031,7 @@ RETURN_CODE UBRing::ClearTrxResource(UbrTrx *trx, uint64_t start_time, UbrCloseT RETURN_CODE UBRing::UbrTrxCloseCheck(UbrTrx *trx) { - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Trx close failed, client trx is null."; return UBRING_ERR; } diff --git a/src/brpc/ubshm/ub_ring.h b/src/brpc/ubshm/ub_ring.h index c08c90801a..f1a5cf14ff 100644 --- a/src/brpc/ubshm/ub_ring.h +++ b/src/brpc/ubshm/ub_ring.h @@ -96,11 +96,11 @@ class UBRing : public butil::IReader { static inline RETURN_CODE CheckTrxConnectParam(const char *listener_name, const char *local_name) { - if (UNLIKELY(listener_name == NULL)) { + if (UNLIKELY(listener_name == nullptr)) { LOG(ERROR) << "The request listener name is null."; return UBRING_ERR; } - if (UNLIKELY(local_name == NULL)) { + if (UNLIKELY(local_name == nullptr)) { LOG(ERROR) << "The request trx shared memory name is null."; return UBRING_ERR; } @@ -126,12 +126,12 @@ class UBRing : public butil::IReader { } static RETURN_CODE CheckTrxRecvParam(UbrTrx *trx, const void *buf, uint32_t buf_len) { - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Trx recv failed, trx is null."; return UBRING_ERR; } - if (UNLIKELY((UbrEventQMsg *)trx->ubr_rx.local_rx_event_q.addr == NULL)) { + if (UNLIKELY((UbrEventQMsg *)trx->ubr_rx.local_rx_event_q.addr == nullptr)) { LOG(ERROR) << "Trx send failed, local_tx_event_q addr is NULL."; return UBRING_ERR; } @@ -140,7 +140,7 @@ class UBRing : public butil::IReader { LOG(ERROR) << "Trx recv failed, trx is not connected statep=" << trx->ubr_rx.trx_state; return UBR_NOT_CONNECTED; } - if (UNLIKELY(buf == NULL)) { + if (UNLIKELY(buf == nullptr)) { LOG(ERROR) << "Trx recv failed, buf is null."; return UBRING_ERR; } @@ -167,19 +167,19 @@ class UBRing : public butil::IReader { static RETURN_CODE UbrTrxCallbackCheck(UbrTrx *trx) { - if (trx == NULL) { + if (trx == nullptr) { LOG(ERROR) << "Trx close callback failed, trx is null."; return UBRING_ERR; } - if (UNLIKELY(trx->local_shm.addr == NULL)) { + if (UNLIKELY(trx->local_shm.addr == nullptr)) { LOG(ERROR) << "Trx close failed, local_shm addr is NULL."; return UBRING_ERR; } - if (UNLIKELY(trx->ubr_rx.local_rx_event_q.addr == NULL)) { + if (UNLIKELY(trx->ubr_rx.local_rx_event_q.addr == nullptr)) { LOG(ERROR) << "Trx close failed, local_rx_event_q addr is NULL."; return UBRING_ERR; } - if (UNLIKELY(trx->ubr_tx.local_tx_event_q.addr == NULL)) { + if (UNLIKELY(trx->ubr_tx.local_tx_event_q.addr == nullptr)) { LOG(ERROR) << "Trx close failed, local_tx_event_q addr is NULL."; return UBRING_ERR; } diff --git a/src/brpc/ubshm/ub_ring_manager.cpp b/src/brpc/ubshm/ub_ring_manager.cpp index 6656e33726..64f2434eba 100644 --- a/src/brpc/ubshm/ub_ring_manager.cpp +++ b/src/brpc/ubshm/ub_ring_manager.cpp @@ -36,7 +36,7 @@ uint64_t g_ub_event_cnt = 0; uint64_t g_ubr_listener_num = 0; RETURN_CODE UBRingManager::GetUbrDealMsgMaxCnt(const uint32_t capacity, uint32_t *deal_msg_max_cnt) { - if (UNLIKELY(deal_msg_max_cnt == NULL)) { + if (UNLIKELY(deal_msg_max_cnt == nullptr)) { LOG(ERROR) << "Get update factor failed, deal_msg_max_cnt is null."; return UBRING_ERR; } @@ -52,8 +52,8 @@ RETURN_CODE UBRingManager::UbrMgrDefault() { g_ubr_mgr.trx_num = 0; g_ubr_mgr.trx_cap = FLAGS_ubr_max_managed_num; - g_ubr_mgr.trx_mgr_unit_status = NULL; - g_ubr_mgr.trx_mgr = NULL; + g_ubr_mgr.trx_mgr_unit_status = nullptr; + g_ubr_mgr.trx_mgr = nullptr; return UBRING_OK; } @@ -68,8 +68,8 @@ RETURN_CODE UBRingManager::UbrMgrInit() { g_ubr_mgr.trx_mgr = (UbrTrx *)malloc(trx_mgr_size); size_t trx_mgr_status_size = g_ubr_mgr.trx_cap * sizeof(UbrMgrUnitStatus); g_ubr_mgr.trx_mgr_unit_status = (UbrMgrUnitStatus *)malloc(trx_mgr_status_size); - if (UNLIKELY(g_ubr_mgr.trx_mgr == NULL || - g_ubr_mgr.trx_mgr_unit_status == NULL)) { + if (UNLIKELY(g_ubr_mgr.trx_mgr == nullptr || + g_ubr_mgr.trx_mgr_unit_status == nullptr)) { LOG(ERROR) << "Ubr manager memory allocation failed."; UbrMgrFini(); return UBRING_ERR; @@ -96,12 +96,12 @@ void UBRingManager::UbrMgrFini() { } RETURN_CODE UBRingManager::AcquireUbrTrxFromMgr(UbrTrx **trx) { - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Acquire trx failed, trx is null."; return UBRING_ERR; } - if (UNLIKELY(g_ubr_mgr.trx_mgr == NULL)) { + if (UNLIKELY(g_ubr_mgr.trx_mgr == nullptr)) { LOG(ERROR) << "Acquire trx failed, trx_mgr is null."; return UBRING_ERR; } @@ -131,17 +131,17 @@ RETURN_CODE UBRingManager::AcquireUbrTrxFromMgr(UbrTrx **trx) { } RETURN_CODE UBRingManager::ReleaseUbrTrxFromMgr(UbrTrx *trx) { - if (UNLIKELY(trx == NULL)) { + if (UNLIKELY(trx == nullptr)) { LOG(ERROR) << "Release trx failed, trx is null."; return UBRING_ERR; } - trx->local_shm.addr = NULL; - trx->ubr_tx.local_tx_event_q.addr = NULL; - trx->ubr_tx.local_data_status_q.addr = NULL; - trx->ubr_rx.local_rx_event_q.addr = NULL; - trx->ubr_rx.remote_data_status_q.addr = NULL; - if (UNLIKELY(g_ubr_mgr.trx_mgr == NULL)) { + trx->local_shm.addr = nullptr; + trx->ubr_tx.local_tx_event_q.addr = nullptr; + trx->ubr_tx.local_data_status_q.addr = nullptr; + trx->ubr_rx.local_rx_event_q.addr = nullptr; + trx->ubr_rx.remote_data_status_q.addr = nullptr; + if (UNLIKELY(g_ubr_mgr.trx_mgr == nullptr)) { LOG(ERROR) << "Release trx failed, trx_mgr is null."; return UBRING_ERR; } @@ -167,14 +167,14 @@ void UBRingManager::LinkInfoInit(void) { size_t link_info_mgr_size = FLAGS_ubr_max_managed_num * sizeof(UbrLinkInfo); g_link_info_mgr.all_link_info = (UbrLinkInfo*) malloc(link_info_mgr_size); - if (g_link_info_mgr.all_link_info == NULL) { + if (g_link_info_mgr.all_link_info == nullptr) { LOG(ERROR) << "all_link_info is NULL"; LinkInfoFini(); return; } g_link_info_mgr.link_mgr_unit_status = (UbrMgrUnitStatus*) malloc(link_info_mgr_size); - if (g_link_info_mgr.link_mgr_unit_status == NULL) { + if (g_link_info_mgr.link_mgr_unit_status == nullptr) { LinkInfoFini(); return; } @@ -184,7 +184,7 @@ void UBRingManager::LinkInfoInit(void) { } void UBRingManager::LinkInfoFini(void) { - if (g_link_info_mgr.link_mgr_unit_status == NULL || g_link_info_mgr.all_link_info == NULL) { + if (g_link_info_mgr.link_mgr_unit_status == nullptr || g_link_info_mgr.all_link_info == nullptr) { LOG(ERROR) << "LinkInfo is NULL"; return; } @@ -198,12 +198,12 @@ void UBRingManager::LinkInfoFini(void) { } void UBRingManager::AcquireLinkInfoToMgr(const char *listener_name, UbrTrx *trx) { - if (listener_name == NULL || trx == NULL) { + if (listener_name == nullptr || trx == nullptr) { LOG(ERROR) << "LinkInfo acquire fail."; return; } - if (g_link_info_mgr.link_mgr_unit_status == NULL || g_link_info_mgr.all_link_info == NULL) { + if (g_link_info_mgr.link_mgr_unit_status == nullptr || g_link_info_mgr.all_link_info == nullptr) { LOG(ERROR) << "LinkInfo is NULL."; return; } @@ -220,7 +220,7 @@ void UBRingManager::AcquireLinkInfoToMgr(const char *listener_name, UbrTrx *trx) } void UBRingManager::ReleaseLinkInfoFromMgr(UbrTrx *trx) { - if (trx == NULL || g_link_info_mgr.link_mgr_unit_status == NULL) { + if (trx == nullptr || g_link_info_mgr.link_mgr_unit_status == nullptr) { LOG(ERROR) << "LinkInfo release fail."; return; } @@ -235,11 +235,11 @@ void UBRingManager::ReleaseLinkInfoFromMgr(UbrTrx *trx) { int32_t UBRingManager::UbEventCallback(const char *shm_name) { - if (UNLIKELY(shm_name == NULL)) { + if (UNLIKELY(shm_name == nullptr)) { LOG(ERROR) << "Ub event callback failed, shm name is null."; return UBRING_ERR; } - if (UNLIKELY(g_ubr_mgr.trx_mgr == NULL)) { + if (UNLIKELY(g_ubr_mgr.trx_mgr == nullptr)) { LOG(ERROR) << "Ub event callback failed, trx mgr is null."; return UBRING_ERR; } diff --git a/src/brpc/ubshm/ubs_mem/ubs_mem.h b/src/brpc/ubshm/ubs_mem/ubs_mem.h index 6466dba67f..d5c1ab6814 100644 --- a/src/brpc/ubshm/ubs_mem/ubs_mem.h +++ b/src/brpc/ubshm/ubs_mem/ubs_mem.h @@ -122,7 +122,7 @@ SHMEM_API int ubsmem_shmem_deallocate(const char *name); /** * Map item in UBSMSHMEM to the local virtual address space, and return its pointer. - * @param addr - The starting address for the new mapping is specified in addr, If addr is NULL, then + * @param addr - The starting address for the new mapping is specified in addr, If addr is nullptr, then * the kernel chooses the (page-aligned) address at which to create the mapping * @param length - The length argument specifies the length of the mapping (which must be greater than 0) * @param prot - same as mmap, describes the desired memory protection of the mapping (and must not conflict with diff --git a/src/brpc/urma/mock_urma.cpp b/src/brpc/urma/mock_urma.cpp new file mode 100644 index 0000000000..266c08b19a --- /dev/null +++ b/src/brpc/urma/mock_urma.cpp @@ -0,0 +1,713 @@ +// 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. + +// Link-time mock of the URMA user-level C API, modeled on Mooncake's +// mock_urma.cpp. It compiles against upstream UMDK headers and is linked into +// brpc when liburma.so is unavailable. It lets CI run UrmaTransport unit tests +// without URMA hardware. +// +// Design (same as Mooncake): +// - Link-time substitution: the symbols are literally named urma_create_jfc +// etc.; the linker picks this TU when liburma is absent. +// - Per-object state is held in anonymous-namespace maps keyed on the opaque +// pointer returned to the caller. Membership is checked on delete so misuse +// returns URMA_EINVAL rather than crashes. +// - Completion path: posted recv WRs remain pending until a SEND targets the +// corresponding mock jetty. Payload and immediate data are copied into the +// remote recv WR and both local-send and remote-recv completions are queued. +// - Device-name contract: device->name == "mock_urma_device" so tests can +// match it with --urma_device=mock_urma_device. + +#if BRPC_WITH_URMA + +#include "urma_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +struct JfcState { + std::mutex mutex; + std::deque completions; + bool event_pending{false}; +}; + +struct PendingRecv { + uint64_t addr; + uint32_t len; + uint64_t user_ctx; +}; + +std::shared_mutex g_rw_mutex; +bool initialized = false; +std::vector device_list; +std::map context_map; +std::map jfce_map; +std::map jfc_state_map; +std::map jfr_map; +// Side-table: JFR -> the JFC it was created with (used to route recv +// completions to the right JfcState, since the JFR is an opaque handle). +std::map jfr_jfc_map; +std::map> jfr_recv_map; +std::map seg_map; +std::map jetty_map; +std::map jetty_id_map; +std::map target_jetty_map; +std::atomic next_jetty_id{1}; + +void PushCompletion(urma_jfc_t* jfc, JfcState* state, + const urma_cr_t& completion) { + bool signal = false; + { + std::lock_guard lock(state->mutex); + state->completions.push_back(completion); + if (!state->event_pending) { + state->event_pending = true; + signal = true; + } + } + if (signal && jfc && jfc->jfc_cfg.jfce && + jfc->jfc_cfg.jfce->fd >= 0) { + uint64_t one = 1; + (void)write(jfc->jfc_cfg.jfce->fd, &one, sizeof(one)); + } +} + +urma_device_attr_t mock_device_attr = { + .guid = {.raw = {10}}, + .dev_cap = {}, + .port_cnt = 1, + .port_attr = {{.max_mtu = URMA_MTU_4096, + .state = URMA_PORT_ACTIVE, + .active_width = URMA_LINK_X1, + .active_speed = URMA_SP_100G, + .active_mtu = URMA_MTU_4096}}, + .reserved_jetty_id_min = 0, + .reserved_jetty_id_max = 1024}; + +urma_eid_info_t mock_eid_info = { + .eid = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10}}, + .eid_index = 0}; + +} // namespace + +extern "C" { + +urma_status_t urma_init(urma_init_attr_t *init_attr) { + std::unique_lock lock(g_rw_mutex); + if (initialized) { + return URMA_EEXIST; + } + initialized = true; + return URMA_SUCCESS; +} + +urma_status_t urma_uninit(void) { + std::unique_lock lock(g_rw_mutex); + initialized = false; + for (auto device : device_list) { + delete device; + } + device_list.clear(); + context_map.clear(); + jfce_map.clear(); + for (auto &kv : jfc_state_map) { + delete kv.second; + } + jfc_state_map.clear(); + jfr_map.clear(); + jfr_jfc_map.clear(); + jfr_recv_map.clear(); + seg_map.clear(); + jetty_map.clear(); + jetty_id_map.clear(); + target_jetty_map.clear(); + next_jetty_id.store(1); + return URMA_SUCCESS; +} + +urma_device_t **urma_get_device_list(int *num_devices) { + { + std::shared_lock lock(g_rw_mutex); + if (!initialized) { + *num_devices = 0; + return nullptr; + } + if (!device_list.empty()) { + *num_devices = device_list.size(); + urma_device_t **devices = new urma_device_t *[device_list.size()]; + for (size_t i = 0; i < device_list.size(); ++i) { + devices[i] = device_list[i]; + } + return devices; + } + } + { + std::unique_lock write_lock(g_rw_mutex); + if (!initialized) { + *num_devices = 0; + return nullptr; + } + if (device_list.empty()) { + urma_device_t *device = new urma_device_t; + strcpy(device->name, "mock_urma_device"); + strcpy(device->path, "/sys/class/infiniband/mock_device"); + device->type = URMA_TRANSPORT_UB; + device->ops = nullptr; + device->sysfs_dev = nullptr; + device_list.push_back(device); + } + *num_devices = device_list.size(); + urma_device_t **devices = new urma_device_t *[device_list.size()]; + for (size_t i = 0; i < device_list.size(); ++i) { + devices[i] = device_list[i]; + } + return devices; + } +} + +urma_device_t *urma_get_device_by_name(char *dev_name) { + { + std::shared_lock lock(g_rw_mutex); + if (!initialized) { + return nullptr; + } + if (!device_list.empty()) { + for (auto device : device_list) { + if (strcmp(device->name, dev_name) == 0) { + return device; + } + } + return device_list[0]; + } + } + { + std::unique_lock write_lock(g_rw_mutex); + if (!initialized) { + return nullptr; + } + if (device_list.empty()) { + auto *device = new urma_device_t; + strcpy(device->name, "mock_urma_device"); + strcpy(device->path, "/sys/class/infiniband/mock_device"); + device->type = URMA_TRANSPORT_UB; + device->ops = nullptr; + device->sysfs_dev = nullptr; + device_list.push_back(device); + } + for (auto device : device_list) { + if (strcmp(device->name, dev_name) == 0) { + return device; + } + } + return device_list.empty() ? nullptr : device_list[0]; + } +} + +void urma_free_device_list(urma_device_t **device_list) { + if (device_list) { + delete[] device_list; + } +} + +urma_status_t urma_query_device(urma_device_t *device, + urma_device_attr_t *attr) { + if (!device || !attr) { + return URMA_EINVAL; + } + mock_device_attr.dev_cap.max_jfc = 1024; + mock_device_attr.dev_cap.max_jetty = 1024; + mock_device_attr.dev_cap.max_jfs_sge = 8; + mock_device_attr.dev_cap.max_jfr_sge = 8; + memcpy(attr, &mock_device_attr, sizeof(urma_device_attr_t)); + return URMA_SUCCESS; +} + +urma_eid_info_t *urma_get_eid_list(urma_device_t *device, uint32_t *eid_cnt) { + if (!device || !eid_cnt) { + return nullptr; + } + *eid_cnt = 1; + auto *eid_list = new urma_eid_info_t[1]; + memcpy(eid_list, &mock_eid_info, sizeof(urma_eid_info_t)); + return eid_list; +} + +void urma_free_eid_list(urma_eid_info_t *eid_list) { + if (eid_list) { + delete[] eid_list; + } +} + +urma_context_t *urma_create_context(urma_device_t *device, uint32_t eid_index) { + std::unique_lock lock(g_rw_mutex); + if (!device) { + return nullptr; + } + urma_context_t *ctx = new urma_context_t; + ctx->async_fd = 0; + ctx->dev = device; + context_map[ctx] = 1; + return ctx; +} + +urma_status_t urma_delete_context(urma_context_t *ctx) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || context_map.find(ctx) == context_map.end()) { + return URMA_EINVAL; + } + context_map.erase(ctx); + delete ctx; + return URMA_SUCCESS; +} + +urma_jfce_t *urma_create_jfce(urma_context_t *ctx) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || context_map.find(ctx) == context_map.end()) { + return nullptr; + } + // Allocate a real nonblocking eventfd so brpc's event-mode CQ socket can + // be exercised by the mock as well. + urma_jfce_t *jfce = new urma_jfce_t{}; + jfce->urma_ctx = ctx; + jfce->fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (jfce->fd < 0) { + delete jfce; + return nullptr; + } + jfce_map[jfce] = 1; + return jfce; +} + +urma_status_t urma_delete_jfce(urma_jfce_t *jfce) { + std::unique_lock lock(g_rw_mutex); + if (!jfce || jfce_map.find(jfce) == jfce_map.end()) { + return URMA_EINVAL; + } + jfce_map.erase(jfce); + close(jfce->fd); + delete jfce; + return URMA_SUCCESS; +} + +urma_jfc_t *urma_create_jfc(urma_context_t *ctx, urma_jfc_cfg_t *cfg) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { + return nullptr; + } + urma_jfc_t *jfc = new urma_jfc_t; + memset(&jfc->jfc_id.eid, 0, sizeof(urma_eid_t)); + jfc->jfc_id.eid.raw[0] = 1; + jfc->jfc_id.uasid = 0; + jfc->jfc_id.id = 1; + jfc->handle = cfg->user_ctx; + jfc->comp_events_acked = 0; + jfc->async_events_acked = 0; + jfc->jfc_cfg = *cfg; + jfc_state_map[jfc] = new JfcState(); + return jfc; +} + +urma_status_t urma_delete_jfc(urma_jfc_t *jfc) { + std::unique_lock lock(g_rw_mutex); + if (!jfc || jfc_state_map.find(jfc) == jfc_state_map.end()) { + return URMA_EINVAL; + } + delete jfc_state_map[jfc]; + jfc_state_map.erase(jfc); + delete jfc; + return URMA_SUCCESS; +} + +urma_jfr_t *urma_create_jfr(urma_context_t *ctx, urma_jfr_cfg_t *cfg) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { + return nullptr; + } + // Opaque handle (avoids partially initializing urma_jfr_t's pthread + // members). brpc's endpoint reads back jfr_cfg.jfc from the stored cfg + // pointer below, so we keep a side-table mapping jfr -> cfg.jfc. + urma_jfr_t *jfr = reinterpret_cast(new int(1)); + jfr_map[jfr] = 1; + // Stash the JFC for urma_post_jfr_wr's completion routing. + jfr_jfc_map[jfr] = cfg->jfc; + jfr_recv_map[jfr] = {}; + return jfr; +} + +urma_status_t urma_delete_jfr(urma_jfr_t *jfr) { + std::unique_lock lock(g_rw_mutex); + if (!jfr || jfr_map.find(jfr) == jfr_map.end()) { + return URMA_EINVAL; + } + jfr_map.erase(jfr); + jfr_jfc_map.erase(jfr); + jfr_recv_map.erase(jfr); + delete reinterpret_cast(jfr); + return URMA_SUCCESS; +} + +urma_target_seg_t *urma_register_seg(urma_context_t *ctx, urma_seg_cfg_t *cfg) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { + return nullptr; + } + urma_target_seg_t *seg = new urma_target_seg_t; + memset(&seg->seg.ubva.eid, 0, sizeof(urma_eid_t)); + seg->seg.ubva.eid.raw[0] = 1; + seg->seg.ubva.uasid = 0; + seg->seg.ubva.va = cfg->va; + seg->seg.len = cfg->len; + seg->seg.token_id = cfg->token_value.token; + seg_map[seg] = 1; + return seg; +} + +urma_status_t urma_unregister_seg(urma_target_seg_t *seg) { + std::unique_lock lock(g_rw_mutex); + if (!seg || seg_map.find(seg) == seg_map.end()) { + return URMA_EINVAL; + } + seg_map.erase(seg); + delete seg; + return URMA_SUCCESS; +} + +urma_target_seg_t *urma_import_seg(urma_context_t *ctx, urma_seg_t *seg, + urma_token_t *token_value, uint64_t addr, + urma_import_seg_flag_t flag) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || !seg || !token_value || + context_map.find(ctx) == context_map.end()) { + return nullptr; + } + urma_target_seg_t *tseg = new urma_target_seg_t; + tseg->seg = *seg; + *token_value = {.token = seg->token_id}; + seg_map[tseg] = 1; + return tseg; +} + +urma_status_t urma_unimport_seg(urma_target_seg_t *tseg) { + std::unique_lock lock(g_rw_mutex); + if (!tseg || seg_map.find(tseg) == seg_map.end()) { + return URMA_EINVAL; + } + seg_map.erase(tseg); + delete tseg; + return URMA_SUCCESS; +} + +urma_status_t urma_get_async_event(urma_context_t *ctx, + urma_async_event_t *event) { + if (!ctx || !event) { + return URMA_EINVAL; + } + std::shared_lock lock(g_rw_mutex); + if (context_map.find(ctx) == context_map.end()) { + return URMA_EINVAL; + } + return URMA_ETIMEOUT; +} + +void urma_ack_async_event(urma_async_event_t *event) {} + +urma_jetty_t *urma_create_jetty(urma_context_t *ctx, urma_jetty_cfg_t *cfg) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { + return nullptr; + } + urma_jetty_t *jetty = new urma_jetty_t; + memset(&jetty->jetty_id.eid, 0, sizeof(urma_eid_t)); + jetty->jetty_id.eid.raw[0] = 1; + jetty->jetty_id.uasid = 0; + jetty->jetty_id.id = next_jetty_id.fetch_add(1); + jetty->jetty_cfg = *cfg; + jetty->remote_jetty = nullptr; + jetty_map[jetty] = 1; + jetty_id_map[jetty->jetty_id.id] = jetty; + return jetty; +} + +urma_status_t urma_delete_jetty(urma_jetty_t *jetty) { + std::unique_lock lock(g_rw_mutex); + if (!jetty || jetty_map.find(jetty) == jetty_map.end()) { + return URMA_EINVAL; + } + jetty_id_map.erase(jetty->jetty_id.id); + jetty_map.erase(jetty); + delete jetty; + return URMA_SUCCESS; +} + +urma_status_t urma_unbind_jetty(urma_jetty_t *jetty) { + std::unique_lock lock(g_rw_mutex); + if (!jetty || jetty_map.find(jetty) == jetty_map.end()) { + return URMA_EINVAL; + } + jetty->remote_jetty = nullptr; + return URMA_SUCCESS; +} + +urma_target_jetty_t *urma_import_jetty(urma_context_t *ctx, + urma_rjetty_t *rjetty, + urma_token_t *token_value) { + std::unique_lock lock(g_rw_mutex); + if (!ctx || !rjetty || !token_value || + context_map.find(ctx) == context_map.end()) { + return nullptr; + } + urma_target_jetty_t *tjetty = new urma_target_jetty_t; + tjetty->id = rjetty->jetty_id; + target_jetty_map[tjetty] = 1; + *token_value = {.token = 1}; + return tjetty; +} + +urma_status_t urma_unimport_jetty(urma_target_jetty_t *tjetty) { + std::unique_lock lock(g_rw_mutex); + if (!tjetty || target_jetty_map.find(tjetty) == target_jetty_map.end()) { + return URMA_EINVAL; + } + target_jetty_map.erase(tjetty); + delete tjetty; + return URMA_SUCCESS; +} + +urma_status_t urma_bind_jetty(urma_jetty_t *jetty, + urma_target_jetty_t *tjetty) { + std::unique_lock lock(g_rw_mutex); + if (!jetty || !tjetty || jetty_map.find(jetty) == jetty_map.end() || + target_jetty_map.find(tjetty) == target_jetty_map.end()) { + return URMA_EINVAL; + } + jetty->remote_jetty = tjetty; + return URMA_SUCCESS; +} + +urma_status_t urma_modify_jetty(urma_jetty_t *jetty, urma_jetty_attr_t *attr) { + std::shared_lock lock(g_rw_mutex); + if (!jetty || !attr || jetty_map.find(jetty) == jetty_map.end()) { + return URMA_EINVAL; + } + return URMA_SUCCESS; +} + +urma_status_t urma_post_jetty_send_wr(urma_jetty_t *jetty, urma_jfs_wr_t *wr, + urma_jfs_wr_t **bad_wr) { + std::shared_lock read_lock(g_rw_mutex); + auto local_it = jetty_map.find(jetty); + auto local_jfc_it = + jetty ? jfc_state_map.find(jetty->jetty_cfg.jfs_cfg.jfc) + : jfc_state_map.end(); + if (!jetty || !wr || local_it == jetty_map.end() || + local_jfc_it == jfc_state_map.end()) { + if (bad_wr) { + *bad_wr = wr; + } + return URMA_EINVAL; + } + JfcState* local_state = local_jfc_it->second; + read_lock.unlock(); + + for (urma_jfs_wr_t* current = wr; current; current = current->next) { + if (!current->tjetty) { + if (bad_wr) { + *bad_wr = current; + } + return URMA_EINVAL; + } + + urma_cr_t send_cr{}; + send_cr.status = URMA_CR_SUCCESS; + send_cr.user_ctx = current->user_ctx; + send_cr.flag.bs.s_r = 0; + if (current->flag.bs.complete_enable) { + PushCompletion(jetty->jetty_cfg.jfs_cfg.jfc, + local_state, send_cr); + } + + PendingRecv recv{}; + urma_jfc_t* remote_jfc = nullptr; + { + std::unique_lock lock(g_rw_mutex); + auto remote_it = jetty_id_map.find(current->tjetty->id.id); + if (remote_it == jetty_id_map.end()) { + continue; + } + urma_jfr_t* remote_jfr = + remote_it->second->jetty_cfg.shared.jfr; + auto recv_it = jfr_recv_map.find(remote_jfr); + auto jfc_it = jfr_jfc_map.find(remote_jfr); + if (recv_it == jfr_recv_map.end() || recv_it->second.empty() || + jfc_it == jfr_jfc_map.end()) { + continue; + } + recv = recv_it->second.front(); + recv_it->second.pop_front(); + remote_jfc = jfc_it->second; + } + + uint32_t copied = 0; + for (uint32_t i = 0; + i < current->send.src.num_sge && copied < recv.len; ++i) { + const urma_sge_t& sge = current->send.src.sge[i]; + const uint32_t n = std::min(sge.len, recv.len - copied); + std::memcpy(reinterpret_cast(recv.addr + copied), + reinterpret_cast(sge.addr), n); + copied += n; + } + + JfcState* remote_state = nullptr; + { + std::shared_lock lock(g_rw_mutex); + auto state_it = jfc_state_map.find(remote_jfc); + if (state_it != jfc_state_map.end()) { + remote_state = state_it->second; + } + } + if (remote_state) { + urma_cr_t recv_cr{}; + recv_cr.status = URMA_CR_SUCCESS; + recv_cr.user_ctx = recv.user_ctx; + recv_cr.flag.bs.s_r = 1; + recv_cr.completion_len = copied; + recv_cr.opcode = + current->opcode == URMA_OPC_SEND_IMM + ? URMA_CR_OPC_SEND_WITH_IMM + : URMA_CR_OPC_SEND; + recv_cr.imm_data = current->send.imm_data; + PushCompletion(remote_jfc, remote_state, recv_cr); + } + } + if (bad_wr) { + *bad_wr = nullptr; + } + return URMA_SUCCESS; +} + +urma_status_t urma_post_jfr_wr(urma_jfr_t *jfr, urma_jfr_wr_t *wr, + urma_jfr_wr_t **bad_wr) { + std::unique_lock lock(g_rw_mutex); + auto recv_it = jfr_recv_map.find(jfr); + if (!jfr || !wr || recv_it == jfr_recv_map.end()) { + if (bad_wr) { + *bad_wr = wr; + } + return URMA_EINVAL; + } + for (urma_jfr_wr_t* current = wr; current; current = current->next) { + if (current->src.num_sge == 0 || !current->src.sge) { + if (bad_wr) { + *bad_wr = current; + } + return URMA_EINVAL; + } + recv_it->second.push_back(PendingRecv{ + current->src.sge[0].addr, + current->src.sge[0].len, + current->user_ctx}); + } + if (bad_wr) { + *bad_wr = nullptr; + } + return URMA_SUCCESS; +} + +urma_status_t urma_post_jetty_recv_wr(urma_jetty_t *jetty, + urma_jfr_wr_t *wr, + urma_jfr_wr_t **bad_wr) { + urma_jfr_t* shared_jfr = nullptr; + { + std::shared_lock lock(g_rw_mutex); + if (!jetty || jetty_map.find(jetty) == jetty_map.end()) { + if (bad_wr) { + *bad_wr = wr; + } + return URMA_EINVAL; + } + shared_jfr = jetty->jetty_cfg.shared.jfr; + } + return urma_post_jfr_wr(shared_jfr, wr, bad_wr); +} + +int urma_poll_jfc(urma_jfc_t *jfc, int num_entries, urma_cr_t *cr_list) { + JfcState* state = nullptr; + { + std::shared_lock lock(g_rw_mutex); + auto it = jfc_state_map.find(jfc); + if (it == jfc_state_map.end()) { + return -1; + } + state = it->second; + } + std::lock_guard lock(state->mutex); + int count = 0; + while (count < num_entries && !state->completions.empty()) { + cr_list[count++] = state->completions.front(); + state->completions.pop_front(); + } + if (state->completions.empty()) { + state->event_pending = false; + } + return count; +} + +urma_status_t urma_rearm_jfc(urma_jfc_t*, bool) { + return URMA_SUCCESS; +} + +int urma_wait_jfc(urma_jfce_t* jfce, uint32_t jfc_cnt, int, + urma_jfc_t* jfcs[]) { + if (!jfce || !jfcs || jfc_cnt == 0) { + errno = EINVAL; + return -1; + } + uint64_t value = 0; + (void)read(jfce->fd, &value, sizeof(value)); + std::shared_lock lock(g_rw_mutex); + uint32_t count = 0; + for (const auto& item : jfc_state_map) { + if (count >= jfc_cnt || item.first->jfc_cfg.jfce != jfce) { + continue; + } + std::lock_guard state_lock(item.second->mutex); + if (item.second->event_pending) { + jfcs[count++] = item.first; + item.second->event_pending = false; + } + } + return static_cast(count); +} + +void urma_ack_jfc(urma_jfc_t*[], uint32_t[], uint32_t) { +} + +} // extern "C" + +#endif // BRPC_WITH_URMA diff --git a/src/brpc/urma/urma_bonding.h b/src/brpc/urma/urma_bonding.h new file mode 100644 index 0000000000..6332db8495 --- /dev/null +++ b/src/brpc/urma/urma_bonding.h @@ -0,0 +1,35 @@ +// 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. + +#ifndef BRPC_URMA_URMA_BONDING_H +#define BRPC_URMA_URMA_BONDING_H + +// urma_ubagg.h is a provider-private extension and is not shipped by every +// UMDK installation. Keep the dependency optional so non-bonding devices and +// mock builds continue to work. +#if defined(__has_include) +#if __has_include("urma_ubagg.h") +#include "urma_ubagg.h" +#define BRPC_URMA_HAS_BONDING_EXT 1 +#endif +#endif + +#ifndef BRPC_URMA_HAS_BONDING_EXT +#define BRPC_URMA_HAS_BONDING_EXT 0 +#endif + +#endif // BRPC_URMA_URMA_BONDING_H diff --git a/src/brpc/urma/urma_endpoint.cpp b/src/brpc/urma/urma_endpoint.cpp new file mode 100644 index 0000000000..78aa225989 --- /dev/null +++ b/src/brpc/urma/urma_endpoint.cpp @@ -0,0 +1,1846 @@ +// 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. + +#include "brpc/urma/urma_endpoint.h" + +#if BRPC_WITH_URMA + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "butil/atomicops.h" +#include "butil/iobuf.h" +#include "butil/logging.h" +#include "butil/macros.h" +#include "butil/sys_byteorder.h" +#include "butil/time.h" +#include "bthread/bthread.h" +#include "bthread/butex.h" + +#include "urma_api.h" + +#include "brpc/input_messenger.h" +#include "brpc/socket.h" +#include "brpc/urma/urma_bonding.h" +#include "brpc/urma/urma_handshake.h" +#include "brpc/urma/urma_handshake.pb.h" +#include "brpc/urma/urma_helper.h" +#include "brpc/urma_transport.h" + +DECLARE_int32(task_group_ntags); + +namespace brpc { +namespace urma { + +// Flags used here are declared in urma_endpoint.h (urma_use_polling, +// urma_poller_num, urma_disable_bthread). Declare the rest here. +DECLARE_int32(urma_sq_size); +DECLARE_int32(urma_rq_size); +DECLARE_int32(urma_cqe_poll_once); +DECLARE_bool(urma_recv_zerocopy); +DECLARE_int32(urma_zerocopy_min_size); +DECLARE_int32(urma_prepared_jetty_cnt); +DECLARE_bool(urma_poller_yield); + +// ---- Constants shared with the handshake module ---- +static const int WAIT_TIMEOUT_MS = 50; +static const size_t HELLO_ACK_LEN = 4; +static const uint32_t HELLO_ACK_URMA_OK = 0x1; +static const size_t IOBUF_BLOCK_HEADER_LEN = sizeof(butil::IOBuf::Block); + +// ---- Globals: prepared jetty pool + poller groups ---- +struct PreparedJetty { + UrmaResource* res; +}; +static butil::Mutex g_prepared_mutex; +static UrmaResource* g_prepared_list = nullptr; // singly-linked +static int g_prepared_cnt = 0; + +static int PreparedJettyCount() { + const int requested = + std::max(0, std::min(FLAGS_urma_prepared_jetty_cnt, 1024)); + if (requested == 0) { + return 0; + } + + struct rlimit nofile; + if (getrlimit(RLIMIT_NOFILE, &nofile) != 0 || + nofile.rlim_cur == RLIM_INFINITY) { + return requested; + } + + // In event mode each prepared JFCE consumes a file descriptor. Keep room + // for one TCP fd per future URMA connection and for brpc/system internals. + static const rlim_t kReservedFdCount = 64; + const rlim_t max_prepared = + nofile.rlim_cur > kReservedFdCount + ? (nofile.rlim_cur - kReservedFdCount) / 2 + : 0; + if (max_prepared >= static_cast(requested)) { + return requested; + } + + LOG(WARNING) << "Cap URMA prepared jetty count from " << requested + << " to " << max_prepared + << " due to RLIMIT_NOFILE=" << nofile.rlim_cur; + return static_cast(max_prepared); +} + +std::vector UrmaEndpoint::_poller_groups; + +// ============================================================================ +// UrmaResource lifecycle. +// ============================================================================ + +UrmaResource::~UrmaResource() { + if (remote_jetty) { + urma_unimport_jetty(remote_jetty); + } + if (remote_seg) { + urma_unimport_seg(remote_seg); + } + if (jetty) { + urma_delete_jetty(jetty); + } + if (jfr) { + urma_delete_jfr(jfr); + } + if (jfc) { + urma_delete_jfc(jfc); + } + if (jfce) { + urma_delete_jfce(jfce); + } +} + +// ============================================================================ +// Constructor / destructor / Reset. +// ============================================================================ + +UrmaEndpoint::UrmaEndpoint(Socket* s) + : _socket(s), + _state(UNINIT), + _handshake_version(0), + _resource(nullptr) { + _sq_size = static_cast( + std::max(16, std::min(4096, static_cast(FLAGS_urma_sq_size)))); + _rq_size = static_cast( + std::max(16, std::min(4096, static_cast(FLAGS_urma_rq_size)))); + _read_butex = bthread::butex_create_checked>(); + _read_butex->store(0, butil::memory_order_relaxed); +} + +UrmaEndpoint::~UrmaEndpoint() { + DeallocateResources(); + if (_read_butex) { + bthread::butex_destroy(_read_butex); + _read_butex = nullptr; + } +} + +void UrmaEndpoint::Reset() { + DeallocateResources(); + _state = UNINIT; + _handshake_version = 0; + _remote_recv_block_size = 0; + _local_window_capacity = 0; + _remote_window_capacity = 0; + _remote_rq_window_size.store(0, butil::memory_order_relaxed); + _sq_window_size.store(0, butil::memory_order_relaxed); + _new_rq_wrs.store(0, butil::memory_order_relaxed); + _sq_imm_window_size = 0; + _sq_current = 0; + _sq_sent = 0; + _rq_received = 0; + _pending_received_bytes.store(0, butil::memory_order_relaxed); + _sbuf.clear(); + _rbuf.clear(); + _rbuf_data.clear(); + _read_butex->store(0, butil::memory_order_relaxed); +} + +// ============================================================================ +// Handshake IO helpers (ReadFromFd / WriteToFd / PushBackToReadBuf). +// Modeled on RdmaEndpoint::ReadFromFdLoop / WriteToFdLoop. +// ============================================================================ + +int UrmaEndpoint::ReadFromFd(void* data, size_t len) { + char* p = static_cast(data); + size_t received = 0; + while (received < len) { + const int expected_val = _read_butex->load(butil::memory_order_acquire); + const timespec duetime = butil::milliseconds_from_now(WAIT_TIMEOUT_MS); + const int fd = _socket->fd(); + const ssize_t nr = read(fd, p + received, len - received); + if (nr < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + int rc = bthread::butex_wait(_read_butex, expected_val, &duetime); + if (rc < 0 && errno != EWOULDBLOCK && errno != ETIMEDOUT) { + return -1; + } + continue; + } + return -1; + } + if (nr == 0) { + errno = EEOF; + return -1; + } + received += nr; + } + return 0; +} + +void UrmaEndpoint::PushBackToReadBuf(const void* data, size_t len) { + _socket->_read_buf.append(data, len); +} + +int UrmaEndpoint::WriteToFd(void* data, size_t len) { + char* p = static_cast(data); + size_t written = 0; + while (written < len) { + const timespec duetime = butil::milliseconds_from_now(WAIT_TIMEOUT_MS); + const int fd = _socket->fd(); + const ssize_t nw = write(fd, p + written, len - written); + if (nw >= 0) { + written += nw; + continue; + } + if (errno != EAGAIN && errno != EWOULDBLOCK) { + return -1; + } + if (_socket->WaitEpollOut(fd, true, &duetime) != 0 && errno != ETIMEDOUT) { + return -1; + } + } + return 0; +} + +// ============================================================================ +// Hello builders / parsers. +// ============================================================================ + +void UrmaEndpoint::MakeLocalParsedHello(ParsedHello* out) const { + *out = ParsedHello{}; // value-initialize (avoids memset on non-trivial type) + out->buffer_size = static_cast(GetUrmaRecvBlockSize()); + out->recv_buffer_cnt = _rq_size - 1; + if (_resource && _resource->jetty) { + out->jetty_id = _resource->jetty->jetty_id.id; + out->uasid = _resource->jetty->jetty_id.uasid; + const urma_eid_t* local_eid = GetUrmaLocalEid(); + const uint8_t* advertised_eid = + local_eid != nullptr + ? local_eid->raw + : _resource->jetty->jetty_id.eid.raw; + std::memcpy(out->eid, advertised_eid, 16); + } + out->tp_type = static_cast(URMA_CTP); + // Pool segment: flatten g_pool_seg's seg fields. + urma_target_seg_t* pool = GetPoolSegFor(nullptr); + if (pool) { + std::memcpy(out->seg_eid, pool->seg.ubva.eid.raw, 16); + out->seg_uasid = pool->seg.ubva.uasid; + out->seg_va = pool->seg.ubva.va; + out->seg_len = pool->seg.len; + out->seg_token_id = pool->seg.token_id; + } +} + +void UrmaEndpoint::FillLocalHelloV2(v2_wire::HelloMessage* out) const { + *out = v2_wire::HelloMessage{}; // value-initialize + out->msg_len = v2_wire::HELLO_PACKET_LEN; + out->hello_ver = v2_wire::HELLO_V2_VERSION; + out->impl_ver = v2_wire::IMPL_V2_VERSION; + ParsedHello p; + MakeLocalParsedHello(&p); + out->buffer_size = p.buffer_size; + out->recv_buffer_cnt = p.recv_buffer_cnt; + out->jetty_id = p.jetty_id; + std::memcpy(out->eid, p.eid, 16); + out->uasid = p.uasid; + out->tp_type = p.tp_type; + std::memcpy(out->seg_eid, p.seg_eid, 16); + out->seg_uasid = p.seg_uasid; + out->seg_va = p.seg_va; + out->seg_len = p.seg_len; + out->seg_token_id = p.seg_token_id; +} + +void UrmaEndpoint::FillLocalHelloV3(UrmaHello* out) const { + ParsedHello p; + MakeLocalParsedHello(&p); + out->set_buffer_size(p.buffer_size); + out->set_recv_buffer_cnt(p.recv_buffer_cnt); + out->set_jetty_id(p.jetty_id); + out->set_eid(p.eid, 16); + out->set_uasid(p.uasid); + out->set_tp_type(p.tp_type); + out->set_seg_eid(p.seg_eid, 16); + out->set_seg_uasid(p.seg_uasid); + out->set_seg_va(p.seg_va); + out->set_seg_len(p.seg_len); + out->set_seg_token_id(p.seg_token_id); +} + +int UrmaEndpoint::WriteHelloV3(const UrmaHello& msg) { + butil::IOBuf packet; + packet.append("URM3", 4); + std::string body; + if (!msg.SerializeToString(&body)) { + LOG(ERROR) << "Fail to serialize UrmaHello"; + return -1; + } + uint32_t pb_size_be = butil::HostToNet32(static_cast(body.size())); + packet.append(&pb_size_be, sizeof(pb_size_be)); + packet.append(body); + return WriteToFd(packet); +} + +int UrmaEndpoint::WriteToFd(butil::IOBuf& data) { + // Write out the IOBuf in a single WriteToFd-style loop. + while (!data.empty()) { + const timespec duetime = butil::milliseconds_from_now(WAIT_TIMEOUT_MS); + const int fd = _socket->fd(); + const ssize_t nw = data.cut_into_file_descriptor(fd); + if (nw >= 0) { + continue; + } + if (errno != EAGAIN && errno != EWOULDBLOCK) { + return -1; + } + if (_socket->WaitEpollOut(fd, true, &duetime) != 0 && errno != ETIMEDOUT) { + return -1; + } + } + return 0; +} + +int UrmaEndpoint::ReadAndParseHelloV3(ParsedHello* out, bool* negotiated) { + *negotiated = false; + uint32_t pb_size_be = 0; + if (ReadFromFd(&pb_size_be, sizeof(pb_size_be)) < 0) { + return -1; + } + const uint32_t pb_size = butil::NetToHost32(pb_size_be); + if (pb_size == 0 || pb_size > 4096) { + return 0; + } + std::string body(pb_size, '\0'); + if (ReadFromFd(&body[0], pb_size) < 0) { + return -1; + } + UrmaHello msg; + if (!msg.ParseFromArray(body.data(), static_cast(body.size()))) { + return 0; + } + if (msg.eid().size() != 16 || msg.seg_eid().size() != 16) { + return 0; + } + out->buffer_size = msg.buffer_size(); + out->recv_buffer_cnt = msg.recv_buffer_cnt(); + out->jetty_id = msg.jetty_id(); + std::memcpy(out->eid, msg.eid().data(), 16); + out->uasid = msg.uasid(); + out->tp_type = static_cast(msg.tp_type()); + std::memcpy(out->seg_eid, msg.seg_eid().data(), 16); + out->seg_uasid = msg.seg_uasid(); + out->seg_va = msg.seg_va(); + out->seg_len = msg.seg_len(); + out->seg_token_id = msg.seg_token_id(); + if (!ValidHello(*out)) { + return 0; + } + *negotiated = true; + return 0; +} + +// ============================================================================ +// Allocate / deallocate per-connection resources. +// ============================================================================ + +int UrmaEndpoint::AllocateResources() { + if (_resource) { + return 0; + } + urma_context_t* ctx = GetUrmaContext(); + if (!ctx) { + errno = ENODEV; + return -1; + } + + _resource = new (std::nothrow) UrmaResource(); + if (!_resource) { + return -1; + } + + // Try the prepared pool first (sized sq/rq match). + if (_sq_size <= static_cast(FLAGS_urma_sq_size) && + _rq_size <= static_cast(FLAGS_urma_rq_size)) { + BAIDU_SCOPED_LOCK(g_prepared_mutex); + if (g_prepared_list) { + UrmaResource* next = g_prepared_list->next; + delete _resource; + _resource = g_prepared_list; + g_prepared_list = next; + _resource->next = nullptr; + --g_prepared_cnt; + } + } + + if (!_resource->jfc) { + // The SDK requires every JFC to reference a JFCE. Polling mode does + // not arm or consume it, but still supplies the required object. + _resource->jfce = urma_create_jfce(ctx); + if (!_resource->jfce || + (!FLAGS_urma_use_polling && _resource->jfce->fd < 0)) { + LOG(ERROR) << "Fail to create a usable URMA JFCE"; + errno = ENODEV; + return -1; + } + + urma_jfc_cfg_t jfc_cfg{}; + jfc_cfg.depth = static_cast(_sq_size + _rq_size); + jfc_cfg.jfce = _resource->jfce; + _resource->jfc = urma_create_jfc(ctx, &jfc_cfg); + if (!_resource->jfc) { + PLOG(ERROR) << "urma_create_jfc"; + return -1; + } + + urma_jfr_cfg_t jfr_cfg{}; + jfr_cfg.depth = static_cast(_rq_size); + jfr_cfg.trans_mode = URMA_TM_RM; + jfr_cfg.max_sge = 1; + jfr_cfg.min_rnr_timer = URMA_TYPICAL_MIN_RNR_TIMER; + jfr_cfg.jfc = _resource->jfc; + _resource->jfr = urma_create_jfr(ctx, &jfr_cfg); + if (!_resource->jfr) { + PLOG(ERROR) << "urma_create_jfr"; + return -1; + } + + urma_jetty_cfg_t jetty_cfg{}; + jetty_cfg.flag.bs.share_jfr = 1; + jetty_cfg.jfs_cfg.depth = static_cast(_sq_size); + jetty_cfg.jfs_cfg.trans_mode = URMA_TM_RM; + jetty_cfg.jfs_cfg.priority = GetUrmaJettyPriority(); + jetty_cfg.jfs_cfg.max_sge = + static_cast(GetUrmaMaxSge()); + jetty_cfg.jfs_cfg.rnr_retry = URMA_TYPICAL_RNR_RETRY; + jetty_cfg.jfs_cfg.err_timeout = URMA_TYPICAL_ERR_TIMEOUT; + jetty_cfg.jfs_cfg.jfc = _resource->jfc; + jetty_cfg.shared.jfr = _resource->jfr; + jetty_cfg.shared.jfc = _resource->jfc; + _resource->jetty = urma_create_jetty(ctx, &jetty_cfg); + if (!_resource->jetty) { + PLOG(ERROR) << "urma_create_jetty"; + return -1; + } + } + + _sbuf.resize(_sq_size - RESERVED_WR_NUM); + _rbuf.resize(_rq_size); + _rbuf_data.resize(_rq_size, nullptr); + + // Wrap the JFCE fd in a brpc Socket so PollCq is driven by epoll. + if (!FLAGS_urma_use_polling) { + if (!_resource->jfce || _resource->jfce->fd < 0) { + LOG(ERROR) << "Prepared URMA resource has no usable JFCE"; + errno = ENODEV; + return -1; + } + if (ReqNotifyCq() != 0) { + return -1; + } + SocketOptions options; + options.user = this; + options.keytable_pool = _socket->keytable_pool(); + options.fd = _resource->jfce->fd; + options.on_edge_triggered_events = PollCq; + if (Socket::Create(options, &_cq_sid) < 0) { + PLOG(ERROR) << "Fail to create CQ socket"; + return -1; + } + } else { + // Polling mode: synthetic carrier socket (no fd). + SocketOptions options; + options.user = this; + options.keytable_pool = _socket->keytable_pool(); + options.on_edge_triggered_events = PollCq; + if (Socket::Create(options, &_cq_sid) < 0) { + PLOG(ERROR) << "Fail to create CQ socket (polling)"; + return -1; + } + PollerAddCqSid(); + } + return 0; +} + +void UrmaEndpoint::DeallocateResources() { + if (!_resource) { + return; + } + + if (FLAGS_urma_use_polling) { + PollerRemoveCqSid(); + } + + // Tear down the CQ socket so the EventDispatcher stops calling PollCq. + if (_cq_sid != INVALID_SOCKET_ID) { + SocketUniquePtr s; + if (Socket::Address(_cq_sid, &s) == 0) { + if (s->fd() >= 0) { + s->_io_event.RemoveConsumer(s->_fd); + } + s->_user = nullptr; // Do not release user (this UrmaEndpoint). + s->_fd = -1; // Already removed fd from epoll. + s->SetFailed(); + } + _cq_sid = INVALID_SOCKET_ID; + } + + // Reusing a Jetty requires a driver-supported RESET plus a complete JFC + // drain. Until that lifecycle is implemented, prepared resources are + // one-shot: they accelerate connection setup but are destroyed on close. + delete _resource; + _resource = nullptr; +} + +// ============================================================================ +// ImportPeer: the critical import_seg-before-import_jetty sequence. +// ============================================================================ + +int UrmaEndpoint::ImportPeer(const ParsedHello& peer) { + urma_context_t* ctx = GetUrmaContext(); + if (!ctx) { + errno = ENODEV; + return -1; + } + + // 1. urma_import_seg FIRST so the kernel establishes TP routing for the + // remote EID. Without this the first SEND is rejected by hardware with + // URMA_CR_RNR_RETRY_CNT_EXC_ERR. + urma_seg_t peer_seg{}; + std::memcpy(peer_seg.ubva.eid.raw, peer.seg_eid, 16); + peer_seg.ubva.uasid = peer.seg_uasid; + peer_seg.ubva.va = peer.seg_va; + peer_seg.len = peer.seg_len; + peer_seg.token_id = peer.seg_token_id; + urma_token_t seg_token{}; + urma_import_seg_flag_t seg_flag{}; + seg_flag.bs.cacheable = URMA_NON_CACHEABLE; + seg_flag.bs.access = URMA_ACCESS_READ | URMA_ACCESS_WRITE | URMA_ACCESS_ATOMIC; + seg_flag.bs.mapping = URMA_SEG_NOMAP; + _resource->remote_seg = urma_import_seg(ctx, &peer_seg, &seg_token, 0, seg_flag); + if (!_resource->remote_seg) { + PLOG(ERROR) << "urma_import_seg failed"; + return -1; + } + + // 2. urma_import_jetty. + urma_rjetty_t remote{}; + std::memcpy(remote.jetty_id.eid.raw, peer.eid, 16); + remote.jetty_id.uasid = peer.uasid; + remote.jetty_id.id = peer.jetty_id; + remote.trans_mode = URMA_TM_RM; + remote.type = URMA_JETTY; + if (peer.tp_type > static_cast(URMA_UTP)) { + errno = EPROTO; + return -1; + } + remote.tp_type = static_cast(peer.tp_type); + + urma_token_t token{}; + const bool use_bonding_extension = + IsUrmaBondingDevice() && remote.trans_mode == URMA_TM_RM; + errno = 0; + if (use_bonding_extension) { +#if BRPC_URMA_HAS_BONDING_EXT + // The bonding provider needs the local jetty to associate its send + // path with the imported target. A plain import may return success + // without setting that association, leaving traffic one-way only. + bondp_rjetty_t bonding_remote{}; + bonding_remote.base = remote; + bonding_remote.base.flag.bs.has_drv_ext = 1; + bonding_remote.jetty = _resource->jetty; + _resource->remote_jetty = + urma_import_jetty(ctx, &bonding_remote.base, &token); +#else + LOG(ERROR) << "Bonding remote jetty import requires provider header " + "urma_ubagg.h"; + errno = ENOTSUP; +#endif + } else { + _resource->remote_jetty = urma_import_jetty(ctx, &remote, &token); + } + if (!_resource->remote_jetty) { + if (errno == 0) { + errno = EIO; + } + char remote_eid[URMA_EID_STR_LEN + 1] = {}; + std::snprintf(remote_eid, sizeof(remote_eid), EID_FMT, + EID_RAW_ARGS(peer.eid)); + PLOG(ERROR) << "urma_import_jetty failed" + << " remote_eid=" << remote_eid + << " remote_uasid=" << peer.uasid + << " remote_jetty_id=" << peer.jetty_id + << " trans_mode=" << remote.trans_mode + << " tp_type=" << remote.tp_type + << " bonding_extension=" << use_bonding_extension; + return -1; + } + return 0; +} + +// ============================================================================ +// Send / recv data path. +// ============================================================================ + +// Private IOBuf accessor mirroring RdmaIOBuf: reach into IOBuf block refs to +// build a urma_sge_t directly, without memcpy. +class UrmaIOBuf : private butil::IOBuf { + friend class ::brpc::urma::UrmaEndpoint; +public: + using butil::IOBuf::_ref_num; + using butil::IOBuf::_ref_at; + using butil::IOBuf::fetch1; + using butil::IOBuf::get_first_data_meta; + using butil::IOBuf::cutn; + // Build the SGE for the current head block. + // Returns bytes added, or -1 (errno set). + ssize_t cut_into_sglist(urma_sge_t* sglist, size_t* sge_index, + butil::IOBuf* to, size_t max_sge, + size_t max_len) { + size_t len = 0; + while (*sge_index < max_sge && len < max_len && _ref_num() != 0) { + butil::IOBuf::BlockRef const& r = _ref_at(0); + const void* start = fetch1(); + urma_target_seg_t* tseg = + GetPoolSegFor(const_cast(start)); + if (!tseg) { + // User-registered memory: look up the seg handle. + uint64_t meta = get_first_data_meta(); + if (meta != 0) { + tseg = reinterpret_cast( + static_cast(meta)); + } + } + if (!tseg) { + errno = ERDMAMEM; + return -1; + } + size_t this_len = r.length; + if (len + this_len > max_len) { + this_len = max_len - len; + } + sglist[*sge_index].addr = reinterpret_cast(start); + sglist[*sge_index].len = static_cast(this_len); + sglist[*sge_index].tseg = tseg; + cutn(to, this_len); + len += this_len; + (*sge_index)++; + } + return static_cast(len); + } +}; + +ssize_t UrmaEndpoint::CutFromIOBufList(butil::IOBuf** from, size_t ndata) { + if (!_resource || !_resource->jetty || !_resource->remote_jetty) { + errno = ENOTCONN; + return -1; + } + int max_sge = GetUrmaMaxSge(); + if (max_sge < 1) { + max_sge = 1; + } + + urma_sge_t* sglist = static_cast( + alloca(sizeof(urma_sge_t) * max_sge)); + if (!sglist) { + errno = ENOMEM; + return -1; + } + + size_t current = 0; + ssize_t total_len = 0; + while (current < ndata) { + uint16_t remote_wnd = _remote_rq_window_size.load(butil::memory_order_relaxed); + uint16_t sq_wnd = _sq_window_size.load(butil::memory_order_relaxed); + if (remote_wnd == 0 || sq_wnd == 0) { + if (total_len > 0) { + break; + } + errno = EAGAIN; + return -1; + } + butil::IOBuf* to = &_sbuf[_sq_current]; + size_t sge_index = 0; + size_t this_len = 0; + size_t max_len = _remote_recv_block_size > 0 + ? _remote_recv_block_size + : GetUrmaRecvBlockSize(); + while (sge_index < static_cast(max_sge) && + this_len < max_len && current < ndata) { + auto* data = reinterpret_cast(from[current]); + if (data->empty()) { + ++current; + continue; + } + ssize_t n = data->cut_into_sglist(sglist, &sge_index, to, + max_sge, max_len - this_len); + if (n < 0) { + return -1; + } + this_len += n; + } + if (sge_index == 0) { + break; + } + + urma_sg_t sg{sglist, static_cast(sge_index)}; + urma_jfs_wr_t wr{}; + std::memset(&wr, 0, sizeof(wr)); + // Send payload with URMA_OPC_SEND. Receive credits are flushed + // separately by SendImm() after SendAck() reaches its threshold. + // Piggybacking credits turns every payload into SEND_IMM and can + // produce asymmetric completions with the bonding provider. + wr.opcode = URMA_OPC_SEND; + wr.flag.bs.complete_enable = 1; + wr.tjetty = _resource->remote_jetty; + wr.send.src = sg; + wr.user_ctx = 1; + urma_jfs_wr_t* bad_wr = nullptr; + const uint16_t sq_slot = _sq_current; + const uint32_t local_jetty_id = _resource->jetty->jetty_id.id; + const uint32_t remote_jetty_id = _resource->remote_jetty->id.id; + + // Reserve both credits before making the WR visible to the provider. + // In polling mode a completion (and even the peer's receive-credit + // ACK) can be processed by another thread before post_send returns. + // Decrementing after post therefore creates a transient capacity + 1 + // window and makes the strict credit check tear down a healthy + // connection. + _remote_rq_window_size.fetch_sub(1, butil::memory_order_relaxed); + _sq_window_size.fetch_sub(1, butil::memory_order_relaxed); + int rc = urma_post_jetty_send_wr(_resource->jetty, &wr, &bad_wr); + if (rc != URMA_SUCCESS) { + const int provider_errno = errno; + _remote_rq_window_size.fetch_add(1, butil::memory_order_relaxed); + _sq_window_size.fetch_add(1, butil::memory_order_relaxed); + LOG(WARNING) << "urma_post_jetty_send_wr failed: " << rc + << ", provider_errno=" << provider_errno + << " (" << berror(provider_errno) << ')' + << ", bad_wr=" << static_cast(bad_wr) + << ", bad_is_current=" << (bad_wr == &wr) + << ", sq_slot=" << sq_slot + << ", local_jetty_id=" << local_jetty_id + << ", remote_jetty_id=" << remote_jetty_id + << ", state=" << GetStateStr() + << ", sq_window=" << sq_wnd + << ", remote_rq_window=" << remote_wnd + << ", num_sge=" << sge_index + << ", configured_max_sge=" << GetUrmaMaxSge() + << ", payload_size=" << this_len + << " on " << _socket->description(); + errno = rc; + return -1; + } + _sq_current = (_sq_current + 1) % (_sq_size - RESERVED_WR_NUM); + total_len += static_cast(this_len); + } + return total_len; +} + +bool UrmaEndpoint::IsWritable() const { + return _remote_rq_window_size.load(butil::memory_order_relaxed) > 0 && + _sq_window_size.load(butil::memory_order_relaxed) > 0; +} + +// ============================================================================ +// Recv path. +// ============================================================================ + +int UrmaEndpoint::DoPostRecv(void* block, size_t block_size) { + urma_target_seg_t* tseg = GetPoolSegFor(block); + if (!tseg) { + errno = ERDMAMEM; + return -1; + } + urma_sge_t sge{reinterpret_cast(block), + static_cast(block_size), tseg, nullptr}; + urma_sg_t sg{&sge, 1}; + urma_jfr_wr_t wr{sg, 0, nullptr}; + urma_jfr_wr_t* bad = nullptr; + // Use the shared-JFR path on every device, including bonding. The bonding + // provider owns physical receive scheduling for the JFR; a local + // jetty-to-target association is not part of the RM receive API. + const urma_status_t status = + urma_post_jfr_wr(_resource->jfr, &wr, &bad); + if (status != URMA_SUCCESS) { + LOG(WARNING) << "Failed to post URMA receive WR: status=" << status + << " bonding=" << IsUrmaBondingDevice() + << " bad_wr=" << static_cast(bad) + << " bad_is_current=" << (bad == &wr) + << " local_jetty_id=" << _resource->jetty->jetty_id.id + << " provider_associated_remote=" + << static_cast( + _resource->jetty->remote_jetty) + << " state=" << GetStateStr() + << " on " << _socket->description(); + errno = status; + return -1; + } + return 0; +} + +int UrmaEndpoint::PostRecv(uint32_t num, bool zerocopy) { + for (uint32_t i = 0; i < num; ++i) { + size_t block_size = GetUrmaRecvBlockSize(); + if (zerocopy) { + _rbuf[_rq_received].clear(); + butil::IOBufAsZeroCopyOutputStream zcis( + &_rbuf[_rq_received], block_size + IOBUF_BLOCK_HEADER_LEN); + void* data = nullptr; + int size = 0; + if (!zcis.Next(&data, &size) || !data || + size < static_cast(block_size)) { + errno = ENOMEM; + return -1; + } + _rbuf_data[_rq_received] = data; + if (DoPostRecv(data, block_size) < 0) { + return -1; + } + } else { + if (_rbuf_data[_rq_received] == nullptr) { + _rbuf[_rq_received].clear(); + butil::IOBufAsZeroCopyOutputStream zcos( + &_rbuf[_rq_received], + block_size + IOBUF_BLOCK_HEADER_LEN); + void* data = nullptr; + int size = 0; + if (!zcos.Next(&data, &size) || !data || + size < static_cast(block_size)) { + errno = ENOMEM; + return -1; + } + _rbuf_data[_rq_received] = data; + } + if (DoPostRecv(_rbuf_data[_rq_received], block_size) < 0) { + return -1; + } + } + _rq_received = (_rq_received + 1) % _rq_size; + } + return 0; +} + +int UrmaEndpoint::SendImm(uint32_t imm) { + if (imm == 0) { + return 0; + } + if (!_resource || !_resource->jetty || !_resource->remote_jetty) { + errno = ENOTCONN; + return -1; + } + if (_sq_imm_window_size == 0) { + errno = EAGAIN; + return -1; + } + // Empty-payload SEND_IMM flushes peer-side receive credit. Connection + // lifetime is owned by the TCP fd, so this is not an EOF marker. + urma_jfs_wr_t wr{}; + std::memset(&wr, 0, sizeof(wr)); + wr.opcode = URMA_OPC_SEND_IMM; + wr.flag.bs.complete_enable = 1; + wr.flag.bs.solicited_enable = 1; + wr.tjetty = _resource->remote_jetty; + wr.send.imm_data = imm; + wr.user_ctx = 0; // 0 == pure ack (HandleCompletion reuses budget). + urma_jfs_wr_t* bad = nullptr; + // Reserve the ACK-only SQ slot before posting for the same reason as the + // data windows in CutFromIOBufList: polling may observe its completion as + // soon as the provider accepts the WR. + --_sq_imm_window_size; + const urma_status_t status = + urma_post_jetty_send_wr(_resource->jetty, &wr, &bad); + if (status != URMA_SUCCESS) { + const int provider_errno = errno; + ++_sq_imm_window_size; + _new_rq_wrs.fetch_add(imm, butil::memory_order_relaxed); + LOG(WARNING) << "Failed to post URMA credit ACK: status=" << status + << " provider_errno=" << provider_errno + << " (" << berror(provider_errno) << ')' + << " bad_wr=" << static_cast(bad) + << " bad_is_current=" << (bad == &wr) + << " imm=" << imm + << " local_jetty_id=" + << _resource->jetty->jetty_id.id + << " remote_jetty_id=" + << _resource->remote_jetty->id.id + << " state=" << GetStateStr() + << " on " << _socket->description(); + errno = status; + return -1; + } + return 0; +} + +int UrmaEndpoint::SendAck(int num) { + const uint16_t old = + _new_rq_wrs.fetch_add(num, butil::memory_order_relaxed); + if (old + num > _remote_window_capacity / 2 && + _sq_imm_window_size > 0) { + return SendImm(_new_rq_wrs.exchange(0, butil::memory_order_relaxed)); + } + return 0; +} + +ssize_t UrmaEndpoint::HandleCompletion(const urma_cr_t& cr) { + bool zerocopy = FLAGS_urma_recv_zerocopy; + if (cr.status != URMA_CR_SUCCESS) { + LOG(WARNING) << "URMA completion failed, status=" << cr.status; + errno = EIO; + return -1; + } + if (cr.flag.bs.s_r == 0) { + // Send completion: reclaim SQ window and wake the writer. + if (cr.user_ctx == 0) { + // Pure-ack WR: just replenish the imm budget. + if (_sq_imm_window_size >= RESERVED_WR_NUM) { + LOG(WARNING) + << "URMA credit-ACK completion exceeds reserved SQ " + "window: current=" + << _sq_imm_window_size + << " capacity=" << RESERVED_WR_NUM + << " on " << _socket->description(); + errno = EPROTO; + return -1; + } + _sq_imm_window_size += 1; + SendAck(0); + return 0; + } + uint16_t wnd = 1; // We signal every WR (complete_enable=1). + uint16_t old = + _sq_window_size.load(butil::memory_order_relaxed); + while (true) { + if (old >= _local_window_capacity) { + LOG(WARNING) + << "URMA send completion exceeds SQ window: old=" << old + << " increment=" << wnd + << " capacity=" << _local_window_capacity + << " user_ctx=" << cr.user_ctx + << " on " << _socket->description(); + errno = EPROTO; + return -1; + } + if (_sq_window_size.compare_exchange_weak( + old, static_cast(old + wnd), + butil::memory_order_relaxed)) { + break; + } + } + for (uint16_t i = 0; i < wnd; ++i) { + _sbuf[_sq_sent].clear(); + _sq_sent = (_sq_sent + 1) % (_sq_size - RESERVED_WR_NUM); + } + butil::subtle::MemoryBarrier(); + if (_remote_rq_window_size.load(butil::memory_order_relaxed) >= + _local_window_capacity / 8) { + _socket->WakeAsEpollOut(); + } + return 0; + } + // Recv completion. + if (cr.opcode == URMA_CR_OPC_SEND_WITH_IMM && cr.imm_data > 0) { + if (cr.imm_data > _local_window_capacity) { + LOG(WARNING) << "Invalid URMA receive credit: " << cr.imm_data; + errno = EPROTO; + return -1; + } + const uint16_t acks = static_cast(cr.imm_data); + uint16_t old = + _remote_rq_window_size.load(butil::memory_order_relaxed); + while (true) { + if (old > _local_window_capacity - acks) { + LOG(WARNING) + << "URMA receive credit exceeds window: old=" << old + << " credit=" << acks + << " capacity=" << _local_window_capacity + << " imm=" << cr.imm_data + << " remote_window_capacity=" + << _remote_window_capacity + << " on " << _socket->description(); + errno = EPROTO; + return -1; + } + if (_remote_rq_window_size.compare_exchange_weak( + old, static_cast(old + acks), + butil::memory_order_relaxed)) { + break; + } + } + if (_sq_window_size.load(butil::memory_order_relaxed) > 0) { + _socket->WakeAsEpollOut(); + } + } else if (cr.completion_len == 0) { + LOG(WARNING) << "Zero-length URMA receive without immediate credit"; + errno = EPROTO; + return -1; + } + if (cr.completion_len > GetUrmaRecvBlockSize()) { + LOG(WARNING) << "URMA completion exceeds receive buffer: " + << cr.completion_len; + errno = EPROTO; + return -1; + } + if (cr.completion_len < static_cast(FLAGS_urma_zerocopy_min_size)) { + zerocopy = false; + } + if (zerocopy) { + _rbuf[_rq_received].cutn(&_socket->_read_buf, cr.completion_len); + } else { + _socket->_read_buf.append(_rbuf_data[_rq_received], cr.completion_len); + } + if (PostRecv(1, zerocopy) < 0) { + return -1; + } + if (cr.completion_len > 0) { + SendAck(1); + } + return static_cast(cr.completion_len); +} + +void UrmaEndpoint::DispatchReceivedBytes(SocketUniquePtr& s, ssize_t bytes) { + int64_t pending = _pending_received_bytes.load(butil::memory_order_relaxed); + if (bytes > 0) { + pending = _pending_received_bytes.fetch_add( + bytes, butil::memory_order_acq_rel) + bytes; + } + + const State state = _state.load(butil::memory_order_acquire); + if (state != ESTABLISHED) { + return; + } + + // PollCq and the handshake bthread can both reach this method when the + // state changes to ESTABLISHED. Serialize them so each byte added to + // _socket->_read_buf is reported to InputMessenger exactly once. + std::unique_lock dispatch_lock(_dispatch_mutex); + if (_state.load(butil::memory_order_acquire) != ESTABLISHED) { + return; + } + pending = _pending_received_bytes.exchange( + 0, butil::memory_order_acq_rel); + if (pending <= 0 || s->Failed()) { + return; + } + + auto* messenger = static_cast(s->user()); + if (!messenger) { + LOG(ERROR) << "URMA socket has no InputMessenger: " + << s->description(); + return; + } + + const int64_t received_us = butil::cpuwide_time_us(); + const int64_t base_realtime = butil::gettimeofday_us() - received_us; + InputMessageClosure last_msg; + messenger->ProcessNewMessage(s.get(), static_cast(pending), + false, received_us, base_realtime, last_msg); +} + +void UrmaEndpoint::PollCq(Socket* m) { + auto* ep = static_cast(m->user()); + if (!ep || !ep->_resource || !ep->_resource->jfc) { + return; + } + SocketUniquePtr s; + if (Socket::Address(ep->_socket->id(), &s) != 0) { + return; + } + if (s->Failed()) { + return; + } + + const bool event_mode = !FLAGS_urma_use_polling; + int progress = Socket::PROGRESS_INIT; + while (true) { + urma_jfc_t* event_jfc = nullptr; + if (event_mode) { + const int event_count = ep->WaitCqEvent(s, &event_jfc); + if (event_count < 0) { + return; + } + if (event_count == 0) { + if (!m->MoreReadEvents(&progress)) { + return; + } + continue; + } + } + + ssize_t bytes = 0; + auto drain_cq = [&]() -> int { + while (true) { + const int n = + std::max(1, std::min(FLAGS_urma_cqe_poll_once, 32)); + urma_cr_t crs[32]; + const int cnt = + urma_poll_jfc(ep->_resource->jfc, n, crs); + if (cnt < 0) { + return EIO; + } + if (cnt == 0) { + return 0; + } + for (int i = 0; i < cnt; ++i) { + if (s->Failed()) { + return ECANCELED; + } + const ssize_t nr = ep->HandleCompletion(crs[i]); + if (nr < 0) { + return errno ? errno : EIO; + } + bytes += nr; + } + } + }; + + int completion_error = drain_cq(); + if (event_mode) { + // The bonding provider records which physical JFCs produced CRs + // while bondp_poll_jfc drains the virtual JFC. + // bondp_rearm_jfc consumes that mask, so rearming before the drain + // leaves those physical JFCs unarmed. + uint32_t nevents = 1; + urma_ack_jfc(&event_jfc, &nevents, 1); + if (completion_error == 0) { + if (ep->ReqNotifyCq() != 0) { + return; + } + + // Close the drain/rearm race. A completion that arrived while + // the JFC was unarmed may not produce an edge on every + // provider. The JFC is armed now, so a final nonblocking drain + // is safe. + completion_error = drain_cq(); + } + } + + if (completion_error != 0) { + if (!s->Failed()) { + s->SetFailed(completion_error, "URMA completion error"); + } + return; + } + ep->DispatchReceivedBytes(s, bytes); + + if (!event_mode) { + return; + } + // The bonding JFCE fd is itself an epoll fd aggregating physical + // JFCEs, while brpc watches it with EPOLLET. urma_wait_jfc(..., 1, ...) + // consumes only one aggregated event. Keep draining the inner JFCE + // until it reports no event; otherwise another physical event can + // leave the fd continuously readable and never create a new outer + // edge. The event_count == 0 branch above resets _nevent only after + // the inner queue is empty. + } +} + +// ============================================================================ +// ApplyRemoteHello: size the send/recv windows from the peer's hello. +// ============================================================================ + +void UrmaEndpoint::ApplyRemoteHello(const ParsedHello& remote) { + _remote_recv_block_size = remote.buffer_size; + const uint32_t peer_rq_size = remote.recv_buffer_cnt + 1; + const uint32_t local_capacity = + std::min(_sq_size, peer_rq_size); + _local_window_capacity = static_cast( + local_capacity > RESERVED_WR_NUM + ? local_capacity - RESERVED_WR_NUM + : 0); + _remote_window_capacity = + _rq_size > RESERVED_WR_NUM ? _rq_size - RESERVED_WR_NUM : 0; + _sq_imm_window_size = RESERVED_WR_NUM; + _remote_rq_window_size.store(_local_window_capacity, + butil::memory_order_relaxed); + _sq_window_size.store(_local_window_capacity, butil::memory_order_relaxed); +} + +// ============================================================================ +// OnNewDataFromTcp: edge-triggered dispatcher. +// ============================================================================ + +static void TryReadOnTcpDuringUrmaEst(Socket* socket); + +void UrmaEndpoint::OnNewDataFromTcp(Socket* m) { + auto* tp = static_cast(m->_transport.get()); + if (!tp) { + return; + } + // Access _urma_ep directly (OnNewDataFromTcp is a friend of UrmaTransport); + // GetUrmaEp() CHECKs non-null which would crash on TCP-fallback sockets. + UrmaEndpoint* ep = tp->_urma_ep; + if (!ep) { + // No URMA endpoint: pure TCP path. + InputMessenger::OnNewMessages(m); + return; + } + int progress = 0; + while (true) { + const State state = + ep->_state.load(butil::memory_order_acquire); + if (state == UNINIT) { + if (!m->CreatedByConnect()) { + // Server side: kick off the handshake bthread. + if (!IsUrmaAvailable()) { + ep->_state = FALLBACK_TCP; + tp->_urma_state = UrmaTransport::URMA_OFF; + InputMessenger::OnNewMessages(m); + return; + } + SocketUniquePtr s; + m->ReAddress(&s); + ep->_state = S_HELLO_WAIT; + bthread_t tid; + bthread_attr_t attr = BTHREAD_ATTR_NORMAL; + bthread_attr_set_name(&attr, "UrmaServerHandshake"); + if (bthread_start_background(&tid, &attr, + ProcessHandshakeAtServer, ep) != 0) { + ep->_state = UNINIT; + LOG(FATAL) << "Fail to start UrmaServerHandshake bthread"; + } else { + s.release(); + } + return; + } + // Client side: handled by ProcessHandshakeAtClient. + return; + } else if (state < ESTABLISHED) { + // During handshake: wake the handshake bthread parked in ReadFromFd. + ep->_read_butex->fetch_add(1, butil::memory_order_release); + bthread::butex_wake(ep->_read_butex); + return; + } else if (state == FALLBACK_TCP) { + InputMessenger::OnNewMessages(m); + return; + } else if (state == ESTABLISHED) { + TryReadOnTcpDuringUrmaEst(m); + return; + } + if (!m->MoreReadEvents(&progress)) { + break; + } + } +} + +inline void UrmaEndpoint::TryReadOnTcp() { + if (_state.load(butil::memory_order_acquire) == FALLBACK_TCP) { + InputMessenger::OnNewMessages(_socket); + } +} + +static void TryReadOnTcpDuringUrmaEst(Socket* socket) { + int progress = Socket::PROGRESS_INIT; + while (true) { + uint8_t byte = 0; + const ssize_t nr = read(socket->fd(), &byte, 1); + if (nr < 0) { + if (errno != EAGAIN) { + const int saved_errno = errno; + socket->SetFailed(saved_errno, "Fail to read URMA TCP fd: %s", + berror(saved_errno)); + return; + } + if (!socket->MoreReadEvents(&progress)) { + return; + } + } else if (nr == 0) { + socket->SetEOF(); + return; + } else { + socket->SetFailed( + EPROTO, "Unexpected TCP data after URMA was established"); + return; + } + } +} + +void UrmaEndpoint::FallbackToTcp(UrmaTransport* transport, bool process_tcp) { + transport->_urma_state = UrmaTransport::URMA_OFF; + _state.store(FALLBACK_TCP, butil::memory_order_release); + DeallocateResources(); + if (process_tcp) { + TryReadOnTcp(); + } +} + +void UrmaEndpoint::FailHandshake(UrmaTransport* transport, int error, + const char* reason) { + LOG(ERROR) << "URMA handshake failed in state=" << GetStateStr() + << " on " << _socket->description() + << ": " << reason << ", error=" << error + << " (" << berror(error) << ')'; + transport->_urma_state = UrmaTransport::URMA_OFF; + _state.store(FAILED, butil::memory_order_release); + DeallocateResources(); + auto* connect = + static_cast(_socket->_app_connect.get()); + if (connect) { + connect->_error = error; + } + _socket->SetFailed(error, "URMA handshake failed: %s", reason); +} + +// ============================================================================ +// Handshake state machines (client / server). Run in a background bthread. +// ============================================================================ + +void* UrmaEndpoint::ProcessHandshakeAtClient(void* arg) { + auto* ep = static_cast(arg); + SocketUniquePtr s(ep->_socket); + auto* tp = static_cast(s->_transport.get()); + UrmaConnect::RunGuard guard(static_cast(s->_app_connect.get())); + if (!IsUrmaAvailable()) { + ep->FallbackToTcp(tp, true); + return nullptr; + } + ep->_state = C_ALLOC_RES; + if (ep->AllocateResources() < 0) { + ep->FallbackToTcp(tp, true); + return nullptr; + } + // Prepost the shared JFR before sending the client hello so the peer sees + // a ready receive queue as soon as its import completes. + if (ep->PostRecv(ep->_rq_size, FLAGS_urma_recv_zerocopy) < 0) { + ep->FallbackToTcp(tp, true); + return nullptr; + } + ep->_state = C_HELLO_SEND; + std::unique_ptr hs(CreateClientHandshake(ep)); + ep->_handshake_version = hs->ProtocolVersion(); + if (hs->SendLocalHello() < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "send client hello"); + return nullptr; + } + ep->_state = C_HELLO_WAIT; + ParsedHello remote; + bool negotiated = false; + if (hs->ReceiveAndParseRemoteHello(&remote, &negotiated) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "read server hello"); + return nullptr; + } + if (!negotiated) { + ep->FallbackToTcp(tp, true); + return nullptr; + } + ep->ApplyRemoteHello(remote); + ep->_state = C_IMPORT_PEER; + if (ep->ImportPeer(remote) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "import server resources"); + return nullptr; + } + ep->_state = C_ACK_SEND; + uint32_t flags = HELLO_ACK_URMA_OK; + uint32_t flags_be = butil::HostToNet32(flags); + if (ep->WriteToFd(&flags_be, HELLO_ACK_LEN) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "send client ack"); + return nullptr; + } + tp->_urma_state = UrmaTransport::URMA_ON; + ep->_state = ESTABLISHED; + ep->DispatchReceivedBytes(s, 0); + return nullptr; +} + +void* UrmaEndpoint::ProcessHandshakeAtServer(void* arg) { + auto* ep = static_cast(arg); + SocketUniquePtr s(ep->_socket); + auto* tp = static_cast(s->_transport.get()); + UrmaConnect::RunGuard guard(static_cast(s->_app_connect.get())); + ep->_state = S_HELLO_WAIT; + uint8_t magic[v2_wire::MAGIC_STR_LEN]; + if (ep->ReadFromFd(magic, v2_wire::MAGIC_STR_LEN) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "read client magic"); + return nullptr; + } + std::unique_ptr hs(CreateServerHandshakeByMagic(ep, magic)); + if (!hs) { + // Not an URMA peer: push the magic back and fall back to TCP. + ep->PushBackToReadBuf(magic, v2_wire::MAGIC_STR_LEN); + ep->FallbackToTcp(tp, true); + return nullptr; + } + ep->_handshake_version = hs->ProtocolVersion(); + ParsedHello remote; + bool negotiated = false; + if (hs->ReceiveAndParseRemoteHello(&remote, &negotiated) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "read client hello"); + return nullptr; + } + if (!negotiated) { + ep->FailHandshake(tp, EPROTO, "invalid client hello"); + return nullptr; + } + ep->_state = S_ALLOC_RES; + if (ep->AllocateResources() < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "allocate server resources"); + return nullptr; + } + const bool bonding = IsUrmaBondingDevice(); + if (!bonding && + ep->PostRecv(ep->_rq_size, FLAGS_urma_recv_zerocopy) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "post server receives"); + return nullptr; + } + ep->ApplyRemoteHello(remote); + ep->_state = S_IMPORT_PEER; + if (ep->ImportPeer(remote) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "import client resources"); + return nullptr; + } + if (bonding && + ep->PostRecv(ep->_rq_size, FLAGS_urma_recv_zerocopy) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "post server receives"); + return nullptr; + } + ep->_state = S_HELLO_SEND; + if (hs->SendLocalHello() < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "send server hello"); + return nullptr; + } + ep->_state = S_ACK_WAIT; + uint32_t flags_be = 0; + if (ep->ReadFromFd(&flags_be, HELLO_ACK_LEN) < 0) { + const int saved_errno = errno ? errno : EIO; + ep->FailHandshake(tp, saved_errno, "read client ack"); + return nullptr; + } + uint32_t flags = butil::NetToHost32(flags_be); + bool client_ack_ok = (flags & HELLO_ACK_URMA_OK) != 0; + if (client_ack_ok) { + if (tp->_urma_state.load(butil::memory_order_acquire) == + UrmaTransport::URMA_OFF) { + // Protocol breakdown: client wants URMA but we already fell back. + ep->FailHandshake(tp, EPROTO, "client ack mismatch"); + return nullptr; + } + tp->_urma_state = UrmaTransport::URMA_ON; + ep->_state = ESTABLISHED; + ep->DispatchReceivedBytes(s, 0); + } else { + ep->FallbackToTcp(tp, true); + } + return nullptr; +} + +// ============================================================================ +// UrmaConnect: drives the client handshake bthread. +// ============================================================================ + +void UrmaConnect::StartConnect(const Socket* socket, + void (*done)(int, void*), void* data) { + SocketUniquePtr s; + if (Socket::Address(socket->id(), &s) != 0) { + return; + } + _done = done; + _data = data; + _error = 0; + auto* tp = static_cast(socket->_transport.get()); + if (!tp) { + Run(); + return; + } + if (!tp->_urma_ep || !IsUrmaAvailable()) { + // Fall back to TCP immediately. + if (tp->_urma_ep) { + tp->_urma_ep->_state = UrmaEndpoint::FALLBACK_TCP; + } + tp->_urma_state = UrmaTransport::URMA_OFF; + Run(); + return; + } + bthread_t tid; + bthread_attr_t attr = BTHREAD_ATTR_NORMAL; + bthread_attr_set_name(&attr, "UrmaClientHandshake"); + if (bthread_start_background(&tid, &attr, + UrmaEndpoint::ProcessHandshakeAtClient, + tp->_urma_ep) != 0) { + tp->_urma_ep->_state = UrmaEndpoint::FALLBACK_TCP; + tp->_urma_state = UrmaTransport::URMA_OFF; + Run(); + } else { + // ProcessHandshakeAtClient adopts this reference in its + // SocketUniquePtr constructor. + s.release(); + } +} + +void UrmaConnect::StopConnect(Socket*) {} + +void UrmaConnect::Run() { + if (_done) { + auto cb = _done; + _done = nullptr; + cb(_error, _data); + } +} + +// ============================================================================ +// Debug / polling-mode stubs. +// ============================================================================ + +std::string UrmaEndpoint::GetStateStr() const { + switch (_state.load(butil::memory_order_acquire)) { + case UNINIT: return "UNINIT"; + case C_ALLOC_RES: return "C_ALLOC_RES"; + case C_HELLO_SEND: return "C_HELLO_SEND"; + case C_HELLO_WAIT: return "C_HELLO_WAIT"; + case C_IMPORT_PEER: return "C_IMPORT_PEER"; + case C_ACK_SEND: return "C_ACK_SEND"; + case S_HELLO_WAIT: return "S_HELLO_WAIT"; + case S_ALLOC_RES: return "S_ALLOC_RES"; + case S_IMPORT_PEER: return "S_IMPORT_PEER"; + case S_HELLO_SEND: return "S_HELLO_SEND"; + case S_ACK_WAIT: return "S_ACK_WAIT"; + case ESTABLISHED: return "ESTABLISHED"; + case FALLBACK_TCP: return "FALLBACK_TCP"; + case FAILED: return "FAILED"; + } + return "UNKNOWN"; +} + +void UrmaEndpoint::DebugInfo(std::ostream& os, butil::StringPiece) const { + os << "state=" << GetStateStr() + << " sq_size=" << _sq_size << " rq_size=" << _rq_size + << " remote_recv_block_size=" << _remote_recv_block_size + << " sq_window=" << _sq_window_size.load(butil::memory_order_relaxed) + << " remote_rq_window=" << _remote_rq_window_size.load(butil::memory_order_relaxed) + << " handshake_version=" << _handshake_version; +} + +int UrmaEndpoint::WaitCqEvent(SocketUniquePtr& s, + urma_jfc_t** event_jfc) { + if (!_resource || !_resource->jfce || !_resource->jfc) { + errno = ENODEV; + return -1; + } + *event_jfc = nullptr; + int count = urma_wait_jfc(_resource->jfce, 1, 0, event_jfc); + if (count < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { + return 0; + } + const int saved_errno = errno; + PLOG(ERROR) << "Fail to wait URMA JFC event from " + << s->description(); + s->SetFailed(saved_errno, "Fail to wait URMA JFC event: %s", + berror(saved_errno)); + return -1; + } + if (count == 0) { + return 0; + } + if (*event_jfc != _resource->jfc) { + LOG(ERROR) << "Unexpected URMA JFC event on " << s->description(); + errno = EPROTO; + s->SetFailed(EPROTO, "Unexpected URMA JFC event"); + return -1; + } + return 1; +} + +int UrmaEndpoint::ReqNotifyCq() { + if (!_resource || !_resource->jfc) { + errno = ENODEV; + return -1; + } + const int rc = urma_rearm_jfc(_resource->jfc, false); + if (rc != URMA_SUCCESS) { + errno = rc; + PLOG(WARNING) << "Fail to rearm URMA JFC"; + _socket->SetFailed(rc, "Fail to rearm URMA JFC: %s", berror(rc)); + return -1; + } + return 0; +} + +int UrmaEndpoint::PollingModeInitialize( + bthread_tag_t tag, std::function callback, + std::function init_fn, std::function release_fn) { + if (!FLAGS_urma_use_polling) { + return 0; + } + if (tag >= _poller_groups.size() || + _poller_groups[tag].pollers.empty()) { + errno = EINVAL; + return -1; + } + auto& group = _poller_groups[tag]; + bool expected = false; + if (!group.running.compare_exchange_strong(expected, true)) { + return 0; + } + struct FnArgs { + Poller* poller; + butil::atomic* running; + }; + auto fn = [](void* p) -> void* { + std::unique_ptr args(static_cast(p)); + Poller* poller = args->poller; + butil::atomic* running = args->running; + std::unordered_set cq_sids; + CqSidOp op; + + if (poller->init_fn) { + poller->init_fn(); + } + while (running->load(butil::memory_order_relaxed)) { + while (poller->op_queue.Dequeue(op)) { + if (op.type == CqSidOp::ADD) { + cq_sids.emplace(op.sid); + } else { + cq_sids.erase(op.sid); + } + } + for (SocketId sid : cq_sids) { + SocketUniquePtr s; + if (Socket::Address(sid, &s) == 0) { + PollCq(s.get()); + } + } + if (poller->callback) { + poller->callback(); + } + if (FLAGS_urma_poller_yield || cq_sids.empty()) { + bthread_yield(); + } + } + if (poller->release_fn) { + poller->release_fn(); + } + return nullptr; + }; + + auto& pollers = group.pollers; + for (size_t i = 0; i < pollers.size(); ++i) { + pollers[i].callback = callback; + pollers[i].init_fn = init_fn; + pollers[i].release_fn = release_fn; + std::unique_ptr args(new (std::nothrow) + FnArgs{&pollers[i], &group.running}); + if (!args) { + group.running.store(false, butil::memory_order_relaxed); + for (size_t j = 0; j < i; ++j) { + bthread_join(pollers[j].tid, nullptr); + pollers[j].tid = INVALID_BTHREAD; + } + errno = ENOMEM; + return -1; + } + bthread_attr_t attr = FLAGS_urma_disable_bthread + ? BTHREAD_ATTR_PTHREAD + : BTHREAD_ATTR_NORMAL; + attr.tag = tag; + bthread_attr_set_name(&attr, "UrmaPolling"); + const int rc = bthread_start_background( + &pollers[i].tid, &attr, fn, args.get()); + if (rc != 0) { + group.running.store(false, butil::memory_order_relaxed); + for (size_t j = 0; j < i; ++j) { + bthread_join(pollers[j].tid, nullptr); + pollers[j].tid = INVALID_BTHREAD; + } + errno = rc; + return -1; + } + args.release(); + } + return 0; +} + +void UrmaEndpoint::PollingModeRelease(bthread_tag_t tag) { + if (!FLAGS_urma_use_polling || tag >= _poller_groups.size()) { + return; + } + auto& group = _poller_groups[tag]; + group.running.store(false, butil::memory_order_relaxed); + for (auto& poller : group.pollers) { + if (poller.tid != INVALID_BTHREAD) { + bthread_join(poller.tid, nullptr); + poller.tid = INVALID_BTHREAD; + } + } +} + +void UrmaEndpoint::PollerAddCqSid() { + if (_cq_sid == INVALID_SOCKET_ID || _poller_groups.empty()) { + return; + } + _poller_tag = bthread_self_tag(); + if (_poller_tag >= _poller_groups.size()) { + return; + } + auto& pollers = _poller_groups[_poller_tag].pollers; + if (pollers.empty()) { + return; + } + const size_t index = + butil::fmix32(_cq_sid) % pollers.size(); + pollers[index].op_queue.Enqueue( + CqSidOp{CqSidOp::ADD, _cq_sid}); +} + +void UrmaEndpoint::PollerRemoveCqSid() { + if (_cq_sid == INVALID_SOCKET_ID || _poller_groups.empty() || + _poller_tag >= _poller_groups.size()) { + return; + } + auto& pollers = _poller_groups[_poller_tag].pollers; + if (pollers.empty()) { + return; + } + const size_t index = + butil::fmix32(_cq_sid) % pollers.size(); + pollers[index].op_queue.Enqueue( + CqSidOp{CqSidOp::REMOVE, _cq_sid}); +} + +int UrmaEndpoint::GlobalInitialize() { + // Pre-allocate the prepared jetty pool. Skipped if URMA init is skipped + // (unit-test mode). + if (FLAGS_urma_use_polling && _poller_groups.empty()) { + if (FLAGS_urma_poller_num <= 0) { + LOG(ERROR) << "urma_poller_num must be positive"; + errno = EINVAL; + return -1; + } + size_t ntags = static_cast(FLAGS_task_group_ntags); + if (ntags == 0) { + ntags = 1; + } + _poller_groups = std::vector(ntags); + } + if (g_prepared_cnt > 0) { + return 0; + } + urma_context_t* ctx = GetUrmaContext(); + if (!ctx) { + return 0; + } + const int prepared_jetty_count = PreparedJettyCount(); + for (int i = 0; i < prepared_jetty_count; ++i) { + auto* r = new (std::nothrow) UrmaResource(); + if (!r) { + break; + } + r->jfce = urma_create_jfce(ctx); + if (!r->jfce || + (!FLAGS_urma_use_polling && r->jfce->fd < 0)) { + delete r; + break; + } + urma_jfc_cfg_t jfc_cfg{}; + jfc_cfg.depth = static_cast(FLAGS_urma_sq_size + FLAGS_urma_rq_size); + jfc_cfg.jfce = r->jfce; + r->jfc = urma_create_jfc(ctx, &jfc_cfg); + if (!r->jfc) { + delete r; + break; + } + urma_jfr_cfg_t jfr_cfg{}; + jfr_cfg.depth = static_cast(FLAGS_urma_rq_size); + jfr_cfg.trans_mode = URMA_TM_RM; + jfr_cfg.max_sge = 1; + jfr_cfg.min_rnr_timer = URMA_TYPICAL_MIN_RNR_TIMER; + jfr_cfg.jfc = r->jfc; + r->jfr = urma_create_jfr(ctx, &jfr_cfg); + if (!r->jfr) { + delete r; + break; + } + urma_jetty_cfg_t jetty_cfg{}; + jetty_cfg.flag.bs.share_jfr = 1; + jetty_cfg.jfs_cfg.depth = static_cast(FLAGS_urma_sq_size); + jetty_cfg.jfs_cfg.trans_mode = URMA_TM_RM; + jetty_cfg.jfs_cfg.priority = GetUrmaJettyPriority(); + jetty_cfg.jfs_cfg.max_sge = + static_cast(GetUrmaMaxSge()); + jetty_cfg.jfs_cfg.rnr_retry = URMA_TYPICAL_RNR_RETRY; + jetty_cfg.jfs_cfg.err_timeout = URMA_TYPICAL_ERR_TIMEOUT; + jetty_cfg.jfs_cfg.jfc = r->jfc; + jetty_cfg.shared.jfr = r->jfr; + jetty_cfg.shared.jfc = r->jfc; + r->jetty = urma_create_jetty(ctx, &jetty_cfg); + if (!r->jetty) { + delete r; + break; + } + r->next = g_prepared_list; + g_prepared_list = r; + ++g_prepared_cnt; + } + return 0; +} + +void UrmaEndpoint::GlobalRelease() { + { + BAIDU_SCOPED_LOCK(g_prepared_mutex); + while (g_prepared_list) { + UrmaResource* next = g_prepared_list->next; + delete g_prepared_list; + g_prepared_list = next; + } + g_prepared_cnt = 0; + } + for (size_t tag = 0; tag < _poller_groups.size(); ++tag) { + PollingModeRelease(static_cast(tag)); + } +} + +} // namespace urma +} // namespace brpc + +#endif // BRPC_WITH_URMA diff --git a/src/brpc/urma/urma_endpoint.h b/src/brpc/urma/urma_endpoint.h new file mode 100644 index 0000000000..0b87d06d24 --- /dev/null +++ b/src/brpc/urma/urma_endpoint.h @@ -0,0 +1,355 @@ +// 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. + +#ifndef BRPC_URMA_ENDPOINT_H +#define BRPC_URMA_ENDPOINT_H + +#include +#include +#include +#include + +#include "butil/atomicops.h" +#include "butil/containers/mpsc_queue.h" +#include "butil/iobuf.h" +#include "butil/macros.h" +#include "butil/synchronization/lock.h" +#include "bthread/types.h" + +#include "brpc/socket.h" + +#if BRPC_WITH_URMA + +#include "urma_api.h" +#include "urma_types.h" +#include "brpc/urma/urma_handshake.h" +#include "brpc/urma/urma_handshake.pb.h" + +namespace brpc { + +class UrmaTransport; + +namespace urma { + +class UrmaHandshake; +struct ParsedHello; + +DECLARE_bool(urma_use_polling); +DECLARE_int32(urma_poller_num); +DECLARE_bool(urma_disable_bthread); + +// Per-connection application-level connect object. Returned by +// UrmaTransport::Connect(); its StartConnect spawns the client-side handshake +// bthread that drives the URMA negotiation over the already-connected TCP fd. +class UrmaConnect : public AppConnect { + friend class UrmaEndpoint; +public: + void StartConnect(const Socket* socket, + void (*done)(int err, void* data), void* data) override; + void StopConnect(Socket*) override; + + struct RunGuard { + explicit RunGuard(UrmaConnect* rc) : this_rc(rc) {} + ~RunGuard() { if (this_rc) this_rc->Run(); } + UrmaConnect* this_rc; + }; + +private: + void Run(); + void (*_done)(int, void*){nullptr}; + void* _data{nullptr}; + int _error{0}; +}; + +// POD holder for the URMA kernel objects backing one connection: +// - the send jetty (JFS), shared-JFR jetty, JFR, JFC, and (event mode) JFCE +// - the imported peer jetty and peer segment +// Mirrors the role of rdma::RdmaResource, but the URMA object graph is a +// little different (no separate QP/CQ split). +struct UrmaResource { + UrmaResource* next{nullptr}; // singly-linked list for the prepared pool + + urma_jfc_t* jfc{nullptr}; + urma_jfce_t* jfce{nullptr}; // event mode only; null in polling mode + urma_jfr_t* jfr{nullptr}; + urma_jetty_t* jetty{nullptr}; + // Imported peer objects (created per-connection, not pooled). + urma_target_jetty_t* remote_jetty{nullptr}; + urma_target_seg_t* remote_seg{nullptr}; + + UrmaResource() = default; + ~UrmaResource(); + DISALLOW_COPY_AND_ASSIGN(UrmaResource); +}; + +// One per Socket. Carries the handshake state machine, the send/recv +// windows, and the registered buffer bookkeeping. Cache-line padded to avoid +// false sharing between connections. +class BAIDU_CACHELINE_ALIGNMENT UrmaEndpoint : public SocketUser { + friend class UrmaConnect; + friend class Socket; + friend class UrmaTransport; + friend class UrmaHandshakeClientV2; + friend class UrmaHandshakeServerV2; + friend class UrmaHandshakeClientV3; + friend class UrmaHandshakeServerV3; + friend int DrainBytes(UrmaEndpoint*, size_t); + friend int ReadBodyAndNegotiate(UrmaEndpoint*, ParsedHello*, bool*); + +public: + explicit UrmaEndpoint(Socket* s); + ~UrmaEndpoint() override; + + // ---- Global initialization / release ---- + // Pre-allocate the prepared Jetty pool. Called once at GlobalUrmaInitializeOrDie. + static int GlobalInitialize(); + static void GlobalRelease(); + + // ---- Per-connection lifecycle ---- + // Reset the endpoint back to UNINIT for reuse. + void Reset(); + + // ---- Data path (called by UrmaTransport) ---- + // Cut data from the IOBuf list and post it via URMA SEND. + // Returns bytes sent, or -1 (errno set; EAGAIN when windows are full). + ssize_t CutFromIOBufList(butil::IOBuf** data, size_t ndata); + + // Whether the endpoint can post more sends (both windows non-empty). + bool IsWritable() const; + + // For debug: dump endpoint state to @os. + void DebugInfo(std::ostream& os, + butil::StringPiece connector = "\n") const; + + // Edge-triggered callback installed on the TCP socket when the transport + // is URMA. Dispatches on _state (see the .cpp for the full state machine): + // UNINIT (server) -> start the server handshake bthread + // < ESTABLISHED -> wake the handshake bthread parked in ReadFromFd + // FALLBACK_TCP -> hand off to InputMessenger::OnNewMessages + // ESTABLISHED -> drain stray TCP bytes + static void OnNewDataFromTcp(Socket* m); + + // CQ completion poller: the edge-triggered callback for the CQ socket + // (whose user is this endpoint). Drains urma_poll_jfc and feeds the + // completions into HandleCompletion, then calls InputMessenger. Event mode + // also drains the aggregated JFCE until urma_wait_jfc reports no event, + // then calls Socket::MoreReadEvents so later JFCE edges can start the + // callback again. + static void PollCq(Socket* m); + + // Initialize the per-tag polling infrastructure (polling mode). + static int PollingModeInitialize(bthread_tag_t tag, + std::function callback, + std::function init_fn, + std::function release_fn); + static void PollingModeRelease(bthread_tag_t tag); + + // ---- Handshake IO helpers (also used by urma_handshake.cpp) ---- + // Read at most @len bytes from the TCP fd into @data; waits on _read_butex + // on EAGAIN. Returns 0 on success, -1 on IO error (errno set). + int ReadFromFd(void* data, size_t len); + // Push @len bytes back into _socket->_read_buf so the TCP input messenger + // can re-parse them (used on fallback when the magic is not "URMA"). + void PushBackToReadBuf(const void* data, size_t len); + // Write at most @len bytes from @data to the TCP fd; waits on + // _epollout_butex on EAGAIN. Returns 0 on success, -1 on IO error. + int WriteToFd(void* data, size_t len); + // Write an IOBuf to the TCP fd (used by v3 protobuf handshake). + int WriteToFd(butil::IOBuf& data); + + // ---- Hello builders/parsers (used by urma_handshake.cpp) ---- + // Fill the v2 binary HelloMessage with this endpoint's local params. + void FillLocalHelloV2(v2_wire::HelloMessage* out) const; + // Fill the v3 protobuf UrmaHello with this endpoint's local params. + void FillLocalHelloV3(UrmaHello* out) const; + // Write "URM3" + 4B big-endian pb_size + protobuf bytes. + int WriteHelloV3(const UrmaHello& msg); + // Read pb_size (4B) + protobuf bytes; parse; validate. Sets *negotiated + // to false (returns 0) if the message is invalid. + int ReadAndParseHelloV3(ParsedHello* out, bool* negotiated); + + // Apply the peer's negotiated parameters (window sizes, peer jetty/seg). + void ApplyRemoteHello(const ParsedHello& remote); + +private: + enum State { + UNINIT = 0x0, + C_ALLOC_RES = 0x1, // client: allocate Jetty/JFC/JFR + C_HELLO_SEND = 0x2, + C_HELLO_WAIT = 0x3, + C_IMPORT_PEER = 0x4, // urma_import_seg then urma_import_jetty + C_ACK_SEND = 0x5, + S_HELLO_WAIT = 0x11, + S_ALLOC_RES = 0x12, + S_IMPORT_PEER = 0x13, + S_HELLO_SEND = 0x14, + S_ACK_WAIT = 0x15, + ESTABLISHED = 0x100, + FALLBACK_TCP = 0x200, + FAILED = 0x300 + }; + + // Process handshake at the client / server (run in a background bthread). + static void* ProcessHandshakeAtClient(void* arg); + static void* ProcessHandshakeAtServer(void* arg); + + // Allocate / deallocate the per-connection URMA resources (JFCE/JFC/JFR/ + // Jetty, plus the CQ socket). Returns 0 on success. + int AllocateResources(); + void DeallocateResources(); + + // Import the peer's jetty and buffer-pool segment. CRITICAL: + // urma_import_seg is called BEFORE urma_import_jetty, otherwise the kernel + // does not establish the transport-path routing for the remote EID and + // the first SEND is rejected with URMA_CR_RNR_RETRY_CNT_EXC_ERR. + // Returns 0 on success. + int ImportPeer(const ParsedHello& peer); + + // Post @num recv WRs into the local JFR. If @zerocopy, use a fresh pool + // buffer; otherwise reuse the fixed _rbuf slot. Returns 0 on success. + int PostRecv(uint32_t num, bool zerocopy); + + // Post a single recv WR pointing at @block of @block_size. + int DoPostRecv(void* block, size_t block_size); + + // Send a pure-ACK URMA_OPC_SEND_IMM WR with no payload. @imm carries the + // number of receive WRs reposted for peer-side flow-control credit. + int SendImm(uint32_t imm); + // Batched credit ack: if _new_rq_wrs is above the threshold, flush it via + // a standalone SendImm. @num is the number of new recv WRs to add. + int SendAck(int num); + + // Handle one completion record. For SEND completions: reclaim the SQ + // window and wake the writer. For RECV completions: cut the payload into + // _socket->_read_buf, repost the recv WR, and ack. Returns bytes received + // (0 for send completions), or -1 on error (errno set). + ssize_t HandleCompletion(const urma_cr_t& cr); + + // Queue received bytes for InputMessenger. CQ receive completions can + // arrive while the server is still waiting for the final TCP handshake + // ACK. Keep those bytes in _socket->_read_buf and dispatch them only after + // ESTABLISHED, matching the connection-ready boundary seen by user code. + void DispatchReceivedBytes(SocketUniquePtr& s, ssize_t bytes); + + // Consume one async event from the JFCE fd (event mode only). The caller + // drains completions before acknowledge/rearm because the bonding provider + // uses poll_jfc to record which physical JFCs must be rearmed. + int WaitCqEvent(SocketUniquePtr& s, urma_jfc_t** event_jfc); + + // Request completion notification (event mode only). + int ReqNotifyCq(); + + // Add/remove the CQ socket id to/from the poller (polling mode only). + void PollerAddCqSid(); + void PollerRemoveCqSid(); + + inline void TryReadOnTcp(); + void FallbackToTcp(UrmaTransport* transport, bool process_tcp); + void FailHandshake(UrmaTransport* transport, int error, + const char* reason); + + // Construct a ParsedHello from local state (used by SendLocalHello). + void MakeLocalParsedHello(ParsedHello* out) const; + + std::string GetStateStr() const; + + // Not owned. + Socket* _socket; + + // Handshake state. + butil::atomic _state{UNINIT}; + int _handshake_version{0}; // 0 = unnegotiated; 2 = v2; 3 = v3 + butil::atomic _pending_received_bytes{0}; + butil::Mutex _dispatch_mutex; + + // The URMA resources (jetty / jfc / jfr / jfce / imported peer objects). + UrmaResource* _resource{nullptr}; + + // The SocketId wrapping the JFCE fd (event mode) or a synthetic carrier + // (polling mode). PollCq is the edge-triggered callback on this socket. + SocketId _cq_sid{INVALID_SOCKET_ID}; + + // ---- Send / recv window bookkeeping ---- + uint16_t _sq_size{0}; // local JFS depth + uint16_t _rq_size{0}; // local JFR depth + + // Per-WR send buffers (own the IOBuf until the SEND completes). + std::vector _sbuf; + // Per-WR recv buffers (zero-copy targets). + std::vector _rbuf; + std::vector _rbuf_data; + // Peer's advertised recv buffer size (caps each WR's payload). + uint32_t _remote_recv_block_size{0}; + + // Flow-control windows (atomic; producer decrements, completion handler + // increments). + uint16_t _local_window_capacity{0}; + uint16_t _remote_window_capacity{0}; + butil::atomic _remote_rq_window_size{0}; // WRs we can send + butil::atomic _sq_window_size{0}; // WRs we can post + butil::atomic _new_rq_wrs{0}; // new recv WRs (to ack) + uint16_t _sq_imm_window_size{0}; // budget for pure-ack WRs + + // SQ producer / consumer indices. + uint16_t _sq_current{0}; + uint16_t _sq_sent{0}; + // RQ consumer index. + uint16_t _rq_received{0}; + + // Butex for waking the handshake bthread parked in ReadFromFd. + butil::atomic* _read_butex{nullptr}; + + // Reserved WR slots for pure-ack IMM WRs. + static constexpr uint16_t RESERVED_WR_NUM = 3; + + // Cq socket id operation (polling mode registration queue). + struct CqSidOp { + enum OpType { ADD, REMOVE } type; + SocketId sid; + }; + struct BAIDU_CACHELINE_ALIGNMENT Poller { + bthread_t tid{INVALID_BTHREAD}; + butil::MPSCQueue> op_queue; + std::function callback; + std::function init_fn; + std::function release_fn; + }; + struct BAIDU_CACHELINE_ALIGNMENT PollerGroup { + PollerGroup() : pollers(FLAGS_urma_poller_num), running(false) {} + std::vector pollers; + butil::atomic running; + }; + static std::vector _poller_groups; + bthread_tag_t _poller_tag{0}; + + DISALLOW_COPY_AND_ASSIGN(UrmaEndpoint); +}; + +} // namespace urma +} // namespace brpc + +#else // BRPC_WITH_URMA + +namespace brpc { +namespace urma { +class UrmaEndpoint {}; +} // namespace urma +} // namespace brpc + +#endif // BRPC_WITH_URMA + +#endif // BRPC_URMA_ENDPOINT_H diff --git a/src/brpc/urma/urma_handshake.cpp b/src/brpc/urma/urma_handshake.cpp new file mode 100644 index 0000000000..07a02f3bc1 --- /dev/null +++ b/src/brpc/urma/urma_handshake.cpp @@ -0,0 +1,356 @@ +// 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. + +#include "brpc/urma/urma_handshake.h" + +#if BRPC_WITH_URMA + +#include +#include +#include + +#include + +#include "butil/atomicops.h" +#include "butil/iobuf.h" // IOBuf, IOPortal, IOBufAsZeroCopy* +#include "butil/logging.h" +#include "butil/sys_byteorder.h" + +#include "brpc/socket.h" +#include "brpc/urma/urma_endpoint.h" +#include "brpc/urma/urma_helper.h" +#include "brpc/urma/urma_handshake.pb.h" +#include "brpc/urma_transport.h" + +namespace brpc { +namespace urma { + +DEFINE_int32(urma_client_handshake_version, 2, + "Client handshake version: 2 = binary, 3 = protobuf"); + +// ============================================================================ +// v2 binary HelloMessage. +// On-wire layout (network byte order, tightly packed body of 82 bytes): +// +// offset field size +// 0 msg_len 2B (full packet length incl. magic) +// 2 hello_ver 2B +// 4 impl_ver 2B +// 6 buffer_size 4B +// 10 recv_buffer_cnt 4B +// 14 jetty_id 4B +// 18 eid 16B (raw, no swap) +// 34 uasid 4B +// 38 tp_type 1B +// 39 pad 3B +// 42 seg_eid 16B (raw) +// 58 seg_uasid 4B +// 62 seg_va 8B +// 70 seg_len 8B +// 78 seg_token_id 4B +// total = 82 bytes body. +// +// Full packet = magic "URMA" (4B) + body (82B) = 86 bytes. +// ============================================================================ + +namespace v2_wire { + +void HelloMessage::Serialize(void* buf) const { + uint8_t* p = static_cast(buf); + auto write16 = [&p](uint16_t value) { + value = butil::HostToNet16(value); + std::memcpy(p, &value, sizeof(value)); + p += sizeof(value); + }; + auto write32 = [&p](uint32_t value) { + value = butil::HostToNet32(value); + std::memcpy(p, &value, sizeof(value)); + p += sizeof(value); + }; + auto write64 = [&p](uint64_t value) { + value = butil::HostToNet64(value); + std::memcpy(p, &value, sizeof(value)); + p += sizeof(value); + }; + + write16(msg_len); + write16(hello_ver); + write16(impl_ver); + write32(buffer_size); + write32(recv_buffer_cnt); + write32(jetty_id); + std::memcpy(p, eid, sizeof(eid)); + p += sizeof(eid); + write32(uasid); + *p++ = tp_type; + std::memset(p, 0, sizeof(pad)); + p += sizeof(pad); + std::memcpy(p, seg_eid, sizeof(seg_eid)); + p += sizeof(seg_eid); + write32(seg_uasid); + write64(seg_va); + write64(seg_len); + write32(seg_token_id); +} + +void HelloMessage::Deserialize(const void* buf) { + const uint8_t* p = static_cast(buf); + auto read16 = [&p]() { + uint16_t value; + std::memcpy(&value, p, sizeof(value)); + p += sizeof(value); + return butil::NetToHost16(value); + }; + auto read32 = [&p]() { + uint32_t value; + std::memcpy(&value, p, sizeof(value)); + p += sizeof(value); + return butil::NetToHost32(value); + }; + auto read64 = [&p]() { + uint64_t value; + std::memcpy(&value, p, sizeof(value)); + p += sizeof(value); + return butil::NetToHost64(value); + }; + + msg_len = read16(); + hello_ver = read16(); + impl_ver = read16(); + buffer_size = read32(); + recv_buffer_cnt = read32(); + jetty_id = read32(); + std::memcpy(eid, p, sizeof(eid)); + p += sizeof(eid); + uasid = read32(); + tp_type = *p++; + p += sizeof(pad); + std::memcpy(seg_eid, p, sizeof(seg_eid)); + p += sizeof(seg_eid); + seg_uasid = read32(); + seg_va = read64(); + seg_len = read64(); + seg_token_id = read32(); +} + +} // namespace v2_wire + +// ============================================================================ +// Shared helpers. +// ============================================================================ + +namespace { + +constexpr uint32_t MIN_BUFFER_SIZE = 1024; +// Three SQ entries are reserved for flow-control messages. The advertised +// receive count must leave at least one data WR after those reservations. +constexpr uint32_t MIN_BUFFER_CNT = 3; +constexpr uint32_t MAX_BUFFER_CNT = 65535; +constexpr uint32_t MAX_V3_PB_SIZE = 4096; + +} // namespace + +bool ValidHello(const ParsedHello& h) { + if (h.buffer_size < MIN_BUFFER_SIZE) { + return false; + } + if (h.recv_buffer_cnt < MIN_BUFFER_CNT || h.recv_buffer_cnt > MAX_BUFFER_CNT) { + return false; + } + if (h.jetty_id == 0) { + return false; + } + if (h.tp_type > static_cast(URMA_UTP)) { + return false; + } + if (h.seg_len == 0 || h.seg_va == 0) { + return false; + } + return true; +} + +// File-local (not in the anonymous namespace so it can be friend-declared +// from urma_endpoint.h's UrmaEndpoint). Reads the body following the magic +// and translates it into ParsedHello. +int ReadBodyAndNegotiate(UrmaEndpoint* ep, ParsedHello* out, bool* negotiated) { + *negotiated = false; + uint8_t body[v2_wire::HELLO_BODY_LEN]; + if (ep->ReadFromFd(body, v2_wire::HELLO_BODY_LEN) < 0) { + return -1; + } + v2_wire::HelloMessage m; + m.Deserialize(body); + if (m.msg_len < v2_wire::HELLO_MSG_LEN_MIN || + m.msg_len > v2_wire::HELLO_MSG_LEN_MAX || + m.hello_ver != v2_wire::HELLO_V2_VERSION || + m.impl_ver != v2_wire::IMPL_V2_VERSION) { return 0; } + ParsedHello p; + p.buffer_size = m.buffer_size; + p.recv_buffer_cnt = m.recv_buffer_cnt; + p.jetty_id = m.jetty_id; + std::memcpy(p.eid, m.eid, 16); + p.uasid = m.uasid; + p.tp_type = m.tp_type; + std::memcpy(p.seg_eid, m.seg_eid, 16); + p.seg_uasid = m.seg_uasid; + p.seg_va = m.seg_va; + p.seg_len = m.seg_len; + p.seg_token_id = m.seg_token_id; + if (!ValidHello(p)) { + return 0; + } + // Drain trailing bytes if msg_len advertises more than the fixed body. + if (m.msg_len > v2_wire::HELLO_PACKET_LEN) { + if (DrainBytes(ep, m.msg_len - v2_wire::HELLO_PACKET_LEN) < 0) { + return -1; + } + } + *out = p; + *negotiated = true; + return 0; +} + +int DrainBytes(UrmaEndpoint* ep, size_t n) { + char buf[4096]; + while (n > 0) { + size_t want = std::min(n, sizeof(buf)); + if (ep->ReadFromFd(buf, want) < 0) { + return -1; + } + n -= want; + } + return 0; +} + +// ============================================================================ +// v2 client / server. +// ============================================================================ + +int UrmaHandshakeClientV2::SendLocalHello() { + v2_wire::HelloMessage m; + _ep->FillLocalHelloV2(&m); + uint8_t packet[v2_wire::HELLO_PACKET_LEN]; + std::memcpy(packet, "URMA", 4); + m.Serialize(packet + 4); + return _ep->WriteToFd(packet, v2_wire::HELLO_PACKET_LEN); +} + +int UrmaHandshakeClientV2::ReceiveAndParseRemoteHello(ParsedHello* out, + bool* negotiated) { + *negotiated = false; + uint8_t magic[v2_wire::MAGIC_STR_LEN]; + if (_ep->ReadFromFd(magic, v2_wire::MAGIC_STR_LEN) < 0) { + return -1; + } + if (std::memcmp(magic, "URMA", 4) != 0) { + // Peer is not URMA-capable; push the magic back so the TCP input + // messenger can re-parse it. + _ep->PushBackToReadBuf(magic, v2_wire::MAGIC_STR_LEN); + return 0; + } + return ReadBodyAndNegotiate(_ep, out, negotiated); +} + +int UrmaHandshakeServerV2::ReceiveAndParseRemoteHello(ParsedHello* out, + bool* negotiated) { + return ReadBodyAndNegotiate(_ep, out, negotiated); +} + +int UrmaHandshakeServerV2::SendLocalHello() { + v2_wire::HelloMessage m; + _ep->FillLocalHelloV2(&m); + auto* tp = static_cast(_ep->_socket->_transport.get()); + if (tp->_urma_state.load(butil::memory_order_acquire) == + UrmaTransport::URMA_OFF) { + // Tell the client we are not URMA-capable: zero the version fields so + // the client's version check fails and it falls back to TCP. + m.hello_ver = 0; + m.impl_ver = 0; + m.jetty_id = 0; + m.buffer_size = 0; + } + uint8_t packet[v2_wire::HELLO_PACKET_LEN]; + std::memcpy(packet, "URMA", 4); + m.Serialize(packet + 4); + return _ep->WriteToFd(packet, v2_wire::HELLO_PACKET_LEN); +} + +// ============================================================================ +// v3 protobuf ("URM3"). The protobuf (de)serialization lives on the endpoint +// because it touches UrmaEndpoint private state; the classes here just call +// FillLocalHelloV3 / WriteHelloV3 / ReadAndParseHelloV3. +// ============================================================================ + +int UrmaHandshakeClientV3::SendLocalHello() { + UrmaHello msg; + _ep->FillLocalHelloV3(&msg); + return _ep->WriteHelloV3(msg); +} + +int UrmaHandshakeClientV3::ReceiveAndParseRemoteHello(ParsedHello* out, + bool* negotiated) { + *negotiated = false; + uint8_t magic[v2_wire::MAGIC_STR_LEN]; + if (_ep->ReadFromFd(magic, v2_wire::MAGIC_STR_LEN) < 0) { + return -1; + } + if (std::memcmp(magic, "URM3", 4) != 0) { + _ep->PushBackToReadBuf(magic, v2_wire::MAGIC_STR_LEN); + return 0; + } + return _ep->ReadAndParseHelloV3(out, negotiated); +} + +int UrmaHandshakeServerV3::ReceiveAndParseRemoteHello(ParsedHello* out, + bool* negotiated) { + return _ep->ReadAndParseHelloV3(out, negotiated); +} + +int UrmaHandshakeServerV3::SendLocalHello() { + UrmaHello msg; + _ep->FillLocalHelloV3(&msg); + // v3 has no zero-out path; the client rejects jetty_id==0 via ValidHello. + return _ep->WriteHelloV3(msg); +} + +// ============================================================================ +// Factories. +// ============================================================================ + +UrmaHandshake* CreateClientHandshake(UrmaEndpoint* ep) { + switch (FLAGS_urma_client_handshake_version) { + case 3: return new UrmaHandshakeClientV3(ep); + case 2: + default: return new UrmaHandshakeClientV2(ep); + } +} + +UrmaHandshake* CreateServerHandshakeByMagic(UrmaEndpoint* ep, + const uint8_t magic[v2_wire::MAGIC_STR_LEN]) { + if (std::memcmp(magic, "URMA", 4) == 0) { + return new UrmaHandshakeServerV2(ep); + } + if (std::memcmp(magic, "URM3", 4) == 0) { + return new UrmaHandshakeServerV3(ep); + } + return nullptr; +} + +} // namespace urma +} // namespace brpc + +#endif // BRPC_WITH_URMA diff --git a/src/brpc/urma/urma_handshake.h b/src/brpc/urma/urma_handshake.h new file mode 100644 index 0000000000..f406bfa1b9 --- /dev/null +++ b/src/brpc/urma/urma_handshake.h @@ -0,0 +1,180 @@ +// 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. + +#ifndef BRPC_URMA_HANDSHAKE_H +#define BRPC_URMA_HANDSHAKE_H + +#include +#include + +#if BRPC_WITH_URMA + +#include "urma_types.h" + +namespace brpc { +namespace urma { + +class UrmaEndpoint; + +// Wire-format-agnostic view of a peer's hello message. Both v2 (binary) and +// v3 (protobuf) translate the bytes on the wire into this struct. The endpoint +// then uses ApplyRemoteHello to size its send/recv windows and to drive +// urma_import_seg / urma_import_jetty. +struct ParsedHello { + uint32_t buffer_size = 0; // peer recv buffer size in bytes (per WR) + uint32_t recv_buffer_cnt = 0; // peer recv buffer count (RQ depth - 1) + uint32_t jetty_id = 0; // peer jetty id + uint8_t eid[16] = {0}; // peer EID (network order) + uint32_t uasid = 0; // peer uasid + uint8_t tp_type = 0; // urma_tp_type_t: URMA_RTP / URMA_CTP / URMA_UTP + + // Flattened peer buffer-pool segment. + uint8_t seg_eid[16] = {0}; // EID owning the peer segment + uint32_t seg_uasid = 0; // uasid owning the peer segment + uint64_t seg_va = 0; // segment virtual address + uint64_t seg_len = 0; // segment length in bytes + uint32_t seg_token_id = 0; // segment token id +}; + +// Validate all values that influence resource import and queue/window sizing. +// Both v2 and v3 handshakes must pass this check before negotiation succeeds. +bool ValidHello(const ParsedHello& hello); + +// v2 binary wire layout. The full on-wire packet is: +// [ "URMA" 4B ][ HelloMessage body 82B ] => 86 bytes total. +// (msg_len = 86 includes the magic prefix and the body, matching RDMA's +// convention where msg_len covers the whole packet.) +namespace v2_wire { + +constexpr size_t MAGIC_STR_LEN = 4; +constexpr size_t HELLO_BODY_LEN = 82; +constexpr size_t HELLO_PACKET_LEN = MAGIC_STR_LEN + HELLO_BODY_LEN; // 86 +constexpr size_t HELLO_MSG_LEN_MIN = HELLO_PACKET_LEN; +constexpr size_t HELLO_MSG_LEN_MAX = 4096; +constexpr uint16_t HELLO_V2_VERSION = 2; +constexpr uint16_t IMPL_V2_VERSION = 1; + +// The serializable struct. Aligned so it can be reinterpreted as raw bytes. +struct HelloMessage { + uint16_t msg_len; // total packet length (incl. magic) + uint16_t hello_ver; + uint16_t impl_ver; + uint32_t buffer_size; + uint32_t recv_buffer_cnt; + uint32_t jetty_id; + uint8_t eid[16]; + uint32_t uasid; + uint8_t tp_type; + uint8_t pad[3]; // keep the struct 4-byte aligned + uint8_t seg_eid[16]; + uint32_t seg_uasid; + uint64_t seg_va; + uint64_t seg_len; + uint32_t seg_token_id; + + void Serialize(void* buf) const; // host -> network order, write to buf + void Deserialize(const void* buf); // network -> host order, read from buf +}; + +} // namespace v2_wire + +// Abstract handshake strategy. v2 speaks binary; v3 speaks protobuf ("URM3"). +class UrmaHandshake { +public: + virtual ~UrmaHandshake() = default; + virtual int ProtocolVersion() const = 0; + + // Send our local hello over the TCP fd held by the endpoint. + // Returns 0 on success, -1 on failure (errno set). + virtual int SendLocalHello() = 0; + + // Read the peer's hello and parse it into @out. Sets @negotiated to true + // if the peer is URMA-capable and the message validates; false (with + // return 0) to signal a graceful fall-back to TCP. + // Returns -1 on IO error (errno set). + virtual int ReceiveAndParseRemoteHello(ParsedHello* out, bool* negotiated) = 0; +}; + +// v2 binary handshake (magic "URMA"). +class UrmaHandshakeClientV2 : public UrmaHandshake { +public: + explicit UrmaHandshakeClientV2(UrmaEndpoint* ep) : _ep(ep) {} + int ProtocolVersion() const override { return 2; } + int SendLocalHello() override; + int ReceiveAndParseRemoteHello(ParsedHello* out, bool* negotiated) override; + +private: + UrmaEndpoint* _ep; +}; + +class UrmaHandshakeServerV2 : public UrmaHandshake { +public: + explicit UrmaHandshakeServerV2(UrmaEndpoint* ep) : _ep(ep) {} + int ProtocolVersion() const override { return 2; } + int SendLocalHello() override; + int ReceiveAndParseRemoteHello(ParsedHello* out, bool* negotiated) override; + +private: + UrmaEndpoint* _ep; +}; + +// v3 protobuf handshake (magic "URM3"). +class UrmaHandshakeClientV3 : public UrmaHandshake { +public: + explicit UrmaHandshakeClientV3(UrmaEndpoint* ep) : _ep(ep) {} + int ProtocolVersion() const override { return 3; } + int SendLocalHello() override; + int ReceiveAndParseRemoteHello(ParsedHello* out, bool* negotiated) override; + +private: + UrmaEndpoint* _ep; +}; + +class UrmaHandshakeServerV3 : public UrmaHandshake { +public: + explicit UrmaHandshakeServerV3(UrmaEndpoint* ep) : _ep(ep) {} + int ProtocolVersion() const override { return 3; } + int SendLocalHello() override; + int ReceiveAndParseRemoteHello(ParsedHello* out, bool* negotiated) override; + +private: + UrmaEndpoint* _ep; +}; + +// Client-side factory: picks v2/v3 based on --urma_client_handshake_version. +UrmaHandshake* CreateClientHandshake(UrmaEndpoint* ep); + +// Server-side factory: dispatches on the first 4 bytes read from the TCP fd. +// Returns nullptr if the magic is not "URMA"/"URM3" (caller falls back to TCP). +// @magic is the first MAGIC_STR_LEN bytes already read from the fd. +UrmaHandshake* CreateServerHandshakeByMagic(UrmaEndpoint* ep, + const uint8_t magic[v2_wire::MAGIC_STR_LEN]); + +// Drain @n bytes from the TCP fd (used when msg_len > HELLO_MSG_LEN_MIN). +int DrainBytes(UrmaEndpoint* ep, size_t n); + +// Read the body following the magic and translate to ParsedHello. Friend of +// UrmaEndpoint. Returns -1 on IO error; 0 with *negotiated=false on invalid +// (peer not URMA-capable); 0 with *negotiated=true on success. +int ReadBodyAndNegotiate(UrmaEndpoint* ep, ParsedHello* out, bool* negotiated); + +} // namespace urma +} // namespace brpc + +#endif // BRPC_WITH_URMA + +#endif // BRPC_URMA_HANDSHAKE_H diff --git a/src/brpc/urma/urma_handshake.proto b/src/brpc/urma/urma_handshake.proto new file mode 100644 index 0000000000..f6d4a6d1ea --- /dev/null +++ b/src/brpc/urma/urma_handshake.proto @@ -0,0 +1,47 @@ +// 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. + +syntax = "proto2"; + +package brpc.urma; + +option java_package = "com.brpc.urma"; +option java_outer_classname = "UrmaHandshakeProto"; + +// Wire-level handshake message exchanged between two UrmaTransport peers +// after the TCP connection is established. The first 4 bytes on the wire +// are the magic "URM3" (v3) followed by a 4-byte big-endian length prefix +// and then the protobuf-encoded UrmaHello. +message UrmaHello { + required uint32 buffer_size = 1; // recv buffer size in bytes (per WR) + required uint32 recv_buffer_cnt = 2; // number of recv buffers posted + required uint32 jetty_id = 3; // local jetty id + required bytes eid = 4; // 16-byte local EID (network order) + required uint32 uasid = 5; // local uasid + required uint32 tp_type = 6; // urma_tp_type_t + + // Flattened peer buffer-pool segment (urma_seg_t + token). The receiver + // calls urma_import_seg with these fields BEFORE urma_import_jetty, so + // the kernel establishes the transport path (TP) routing for the remote + // EID. Otherwise the first SEND is rejected by hardware with + // URMA_CR_RNR_RETRY_CNT_EXC_ERR (status=10). + required bytes seg_eid = 7; // 16-byte EID owning the segment + required uint32 seg_uasid = 8; // uasid owning the segment + required uint64 seg_va = 9; // segment virtual address + required uint64 seg_len = 10; // segment length in bytes + required uint32 seg_token_id = 11; // segment token id +} diff --git a/src/brpc/urma/urma_helper.cpp b/src/brpc/urma/urma_helper.cpp new file mode 100644 index 0000000000..648316f1ae --- /dev/null +++ b/src/brpc/urma/urma_helper.cpp @@ -0,0 +1,787 @@ +// 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. + +#include "brpc/urma/urma_helper.h" + +#if BRPC_WITH_URMA + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "butil/atomicops.h" +#include "butil/containers/flat_map.h" +#include "butil/iobuf.h" +#include "butil/logging.h" +#include "butil/macros.h" +#include "butil/scoped_lock.h" +#include "butil/synchronization/lock.h" + +#include "urma_api.h" +#include "urma_types.h" +#include "brpc/urma/urma_bonding.h" +#include "brpc/urma/urma_endpoint.h" + +DECLARE_int32(task_group_ntags); + +namespace butil { +namespace iobuf { +// declared in iobuf.cpp +extern void* (*blockmem_allocate)(size_t); +extern void (*blockmem_deallocate)(void*); +} +} + +namespace brpc { +namespace urma { + +DEFINE_bool(urma_use_polling, false, + "Use busy polling to poll JFC, instead of event mode"); +DEFINE_int32(urma_poller_num, 1, + "Number of poller bthreads per bthread tag (polling mode only)"); +DEFINE_bool(urma_disable_bthread, false, + "Run the message-processing callback inline (no bthread spawned)"); + +DEFINE_int32(urma_sq_size, 128, + "Depth of the local send jetty (JFS). [16, 4096]"); +DEFINE_int32(urma_rq_size, 128, + "Depth of the local recv jetty (JFR). [16, 4096]"); +DEFINE_int32(urma_cqe_poll_once, 32, + "Max completion entries polled per urma_poll_jfc call"); +DEFINE_bool(urma_recv_zerocopy, true, + "Use zero-copy for receives larger than --urma_zerocopy_min_size"); +DEFINE_int32(urma_zerocopy_min_size, 512, + "Receives smaller than this many bytes are copied (not zero-copy)"); + +DEFINE_string(urma_device, "", + "The name of the URMA device to use. Empty means the first one."); +DEFINE_int32(urma_max_sge, 0, + "Max SGEs per WR. 0 means the device maximum."); +DEFINE_int32(urma_bonding_mode, 0, + "Bonding mode for bonding devices: 0=standalone, " + "1=active-backup, 2=balance."); +DEFINE_int32(urma_bonding_level, 0, + "Bonding level for bonding devices: 0=IODIE, 1=port."); +DEFINE_int32(urma_prepared_jetty_cnt, 8, + "Requested number of pre-allocated Jetty+CQ sets for fast " + "connect; capped automatically according to RLIMIT_NOFILE"); + +DEFINE_int32(urma_buffer_size, 8 * 1024, + "Per-buffer size in the URMA buffer pool (bytes). " + "Must match IOBuf block size to keep zero-copy working."); +DEFINE_int32(urma_buffer_count, 65536, + "Number of buffers in the URMA buffer pool."); + +DEFINE_bool(urma_poller_yield, false, + "Yield (bthread_yield) in the busy poll loop to let other " + "bthreads run"); + + +// Set to true to skip real URMA hardware initialization (unit tests). When +// true, GlobalUrmaInitializeOrDie() returns without touching liburma and the +// endpoint builds its state machine without posting real WRs. +bool g_skip_urma_init = false; +butil::atomic g_urma_available(false); + +// ============================================================================ +// Global URMA state (single device / single context chosen at init time). +// ============================================================================ + +static urma_device_t* g_device = nullptr; +static urma_context_t* g_context = nullptr; +static urma_eid_t g_local_eid{}; +static bool g_has_local_eid = false; +static urma_device_attr_t g_device_attr{}; +static int g_max_sge = 1; +static size_t g_recv_block_size = 8 * 1024; +static bool g_is_bonding_device = false; +// Prefer the device capability table and retain priority 6 as a compatibility +// fallback for CTP providers that do not report a priority. +static uint8_t g_jetty_priority = 6; +// urma_init/urma_uninit manage process-global liburma state. Only uninitialize +// it when this helper performed the successful initialization; URMA_EEXIST +// means another component owns that state. +static bool g_owns_urma_init = false; + +// The single registered segment backing the buffer pool. The whole pool is +// one urma_register_seg call, sliced into fixed-size buffers. urma_target_seg_t +// is the per-buffer handle carried by urma_sge_t.tseg on the send/recv path. +static urma_target_seg_t* g_pool_seg = nullptr; +static void* g_pool_base = nullptr; +static size_t g_pool_size = 0; +static size_t g_pool_buffer_size = 0; + +// User-registered segments (RegisterMemoryForUrma). Keyed by buffer address. +struct UserSeg { + urma_target_seg_t* tseg = nullptr; + void* base = nullptr; + size_t len = 0; +}; +static butil::FlatMap* g_user_segs = nullptr; +static butil::Mutex* g_user_segs_lock = nullptr; + +// Original IOBuf allocator (saved so we can restore it on release). +static void* (*g_mem_alloc_orig)(size_t) = nullptr; +static void (*g_mem_dealloc_orig)(void*) = nullptr; +static size_t g_default_block_size_orig = 0; + +namespace { + +// Round up to the page size. +size_t PageSize() { + long ps = sysconf(_SC_PAGESIZE); + return ps > 0 ? static_cast(ps) : 4096; +} + +size_t AlignUp(size_t v, size_t align) { + return (v + align - 1) / align * align; +} + +bool IsBondingDeviceName(const char* name) { + return name != nullptr && strncmp(name, "bonding", 7) == 0; +} + +union urma_tp_type_en TpTypeCapability(urma_tp_type_t tp_type) { + union urma_tp_type_en capability{}; + switch (tp_type) { + case URMA_RTP: + capability.bs.rtp = 1; + break; + case URMA_CTP: + capability.bs.ctp = 1; + break; + case URMA_UTP: + capability.bs.utp = 1; + break; + } + return capability; +} + +bool ConfigureBondingMode(const std::string& device_name) { + const char* context_device_name = + g_context != nullptr && g_context->dev != nullptr + ? g_context->dev->name + : nullptr; + g_is_bonding_device = + IsBondingDeviceName(device_name.c_str()) || + IsBondingDeviceName(context_device_name); + if (!g_is_bonding_device) { + return true; + } + +#if BRPC_URMA_HAS_BONDING_EXT + if (FLAGS_urma_bonding_mode < 0 || + FLAGS_urma_bonding_mode >= BONDP_BONDING_MODE_MAX || + FLAGS_urma_bonding_level < 0 || + FLAGS_urma_bonding_level >= BONDP_BONDING_LEVEL_MAX) { + LOG(ERROR) << "Invalid URMA bonding configuration: mode=" + << FLAGS_urma_bonding_mode + << " level=" << FLAGS_urma_bonding_level; + errno = EINVAL; + return false; + } + + bondp_set_bonding_mode_in_t bond_in{}; + bond_in.bonding_mode = + static_cast(FLAGS_urma_bonding_mode); + bond_in.bonding_level = + static_cast(FLAGS_urma_bonding_level); + + urma_user_ctl_in_t ctl_in{}; + ctl_in.addr = reinterpret_cast(&bond_in); + ctl_in.len = static_cast(sizeof(bond_in)); + ctl_in.opcode = BONDP_USER_CTL_SET_BONDING_MODE; + urma_user_ctl_out_t ctl_out{}; + const urma_status_t status = urma_user_ctl(g_context, &ctl_in, &ctl_out); + if (status != URMA_SUCCESS) { + LOG(ERROR) << "urma_user_ctl(SET_BONDING_MODE) failed: status=" + << status << " device=" << device_name + << " mode=" << FLAGS_urma_bonding_mode + << " level=" << FLAGS_urma_bonding_level + << ". It must run before segment/JFC/JFR creation"; + errno = status > 0 ? status : EIO; + return false; + } + return true; +#else + LOG(ERROR) << "URMA bonding device " << device_name + << " requires provider header urma_ubagg.h"; + errno = ENOTSUP; + return false; +#endif +} + +} // namespace + +// ============================================================================ +// Buffer pool: one registered segment, sliced into fixed-size buffers. +// ============================================================================ + +namespace { + +// Shard the free list to reduce contention between allocator threads. +constexpr size_t kShardCount = 64; +struct BufferPool { + butil::Mutex mutexes[kShardCount]; + std::vector free_lists[kShardCount]; + std::vector in_use; // 0/1 per buffer + butil::atomic outstanding{0}; + + size_t buffer_count() const { + return in_use.size(); + } +}; +BufferPool* g_pool = nullptr; + +size_t ShardFor(void* buf) { + auto* base = static_cast(buf); + auto offset = static_cast(base - static_cast(g_pool_base)); + auto idx = offset / g_pool_buffer_size; + return idx % kShardCount; +} + +size_t PreferredShard() { + // Hash the current thread id across shards. pthread_self() returns an + // opaque pthread_t; cast through uintptr_t to get a hashable value. + auto tid = static_cast(reinterpret_cast(pthread_self())); + return tid % kShardCount; +} + +void* PoolAllocate(size_t size) { + if (BAIDU_UNLIKELY(g_skip_urma_init)) { + return g_mem_alloc_orig ? g_mem_alloc_orig(size) : malloc(size); + } + // Only serve the configured buffer size; callers always ask for that. + if (size > g_pool_buffer_size) { + // Larger than a single buffer -- fall back to the system allocator. + return g_mem_alloc_orig ? g_mem_alloc_orig(size) : malloc(size); + } + auto start = PreferredShard(); + for (size_t i = 0; i < kShardCount; ++i) { + auto shard = (start + i) % kShardCount; + BAIDU_SCOPED_LOCK(g_pool->mutexes[shard]); + auto& fl = g_pool->free_lists[shard]; + if (fl.empty()) { + continue; + } + void* buf = fl.back(); + fl.pop_back(); + auto idx = (static_cast(buf) - + static_cast(g_pool_base)) / g_pool_buffer_size; + if (idx < g_pool->in_use.size()) { + g_pool->in_use[idx] = 1; + } + g_pool->outstanding.fetch_add(1, butil::memory_order_relaxed); + return buf; + } + LOG_EVERY_SECOND(WARNING) + << "URMA buffer pool exhausted; falling back to malloc"; + return g_mem_alloc_orig ? g_mem_alloc_orig(size) : malloc(size); +} + +void PoolDeallocate(void* buf) { + if (BAIDU_UNLIKELY(g_skip_urma_init)) { + if (g_mem_dealloc_orig) { + g_mem_dealloc_orig(buf); + } else { + free(buf); + } + return; + } + auto* base = static_cast(g_pool_base); + auto* p = static_cast(buf); + if (!base || p < base || p >= base + g_pool_size || + static_cast(p - base) % g_pool_buffer_size != 0) { + // Not a pool buffer -- hand back to the original allocator. + if (g_mem_dealloc_orig) { + g_mem_dealloc_orig(buf); + } else { + free(buf); + } + return; + } + auto shard = ShardFor(buf); + BAIDU_SCOPED_LOCK(g_pool->mutexes[shard]); + auto idx = static_cast(p - base) / g_pool_buffer_size; + if (idx < g_pool->in_use.size()) { + if (!g_pool->in_use[idx]) { + LOG(WARNING) << "double-free of URMA pool buffer " << buf; + return; + } + g_pool->in_use[idx] = 0; + } + g_pool->free_lists[shard].push_back(buf); + if (g_pool->outstanding.load(butil::memory_order_relaxed) > 0) { + g_pool->outstanding.fetch_sub(1, butil::memory_order_relaxed); + } +} + +// Register the pool: mmap one large region and urma_register_seg it. +bool InitPool() { + if (g_pool_buffer_size == 0 || g_pool == nullptr) { + return false; + } + size_t count = g_pool->buffer_count(); + if (count == 0) { + return false; + } + size_t raw = g_pool_buffer_size * count; + size_t page = PageSize(); + g_pool_size = AlignUp(raw, page); + + g_pool_base = mmap(nullptr, g_pool_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (g_pool_base == MAP_FAILED) { + PLOG(WARNING) << "Fail to mmap URMA buffer pool"; + g_pool_base = nullptr; + return false; + } + + urma_reg_seg_flag_t flag{}; + flag.bs.token_policy = URMA_TOKEN_NONE; + flag.bs.cacheable = URMA_NON_CACHEABLE; + flag.bs.access = URMA_ACCESS_READ | URMA_ACCESS_WRITE | URMA_ACCESS_ATOMIC; + + urma_seg_cfg_t cfg{}; + cfg.va = reinterpret_cast(g_pool_base); + cfg.len = g_pool_size; + cfg.token_id = nullptr; + cfg.token_value = {}; + cfg.flag = flag; + cfg.user_ctx = reinterpret_cast(g_pool_base); + cfg.iova = 0; + + errno = 0; + g_pool_seg = urma_register_seg(g_context, &cfg); + if (!g_pool_seg) { + PLOG(WARNING) << "Fail to urma_register_seg"; + munmap(g_pool_base, g_pool_size); + g_pool_base = nullptr; + return false; + } + g_pool->in_use.assign(count, 0); + for (size_t i = 0; i < count; ++i) { + auto shard = i % kShardCount; + g_pool->free_lists[shard].push_back( + static_cast(g_pool_base) + i * g_pool_buffer_size); + } + return true; +} + +} // namespace + +// Exposed to urma_endpoint.cpp: return the per-buffer target_seg pointer. +// All pool buffers share the same segment, so we return g_pool_seg for any +// pool address; the per-WR length selects the slice. +urma_target_seg_t* GetPoolSegFor(void* buf) { + if (g_skip_urma_init || !g_pool_seg || !g_pool_base) { + return nullptr; + } + if (buf == nullptr) { + return g_pool_seg; + } + const uintptr_t base = reinterpret_cast(g_pool_base); + const uintptr_t p = reinterpret_cast(buf); + if (p >= base && p - base < g_pool_size) { + return g_pool_seg; + } + return nullptr; +} + +static void GlobalRelease() { + g_urma_available.store(false, butil::memory_order_release); + if (g_mem_alloc_orig) { + butil::iobuf::blockmem_allocate = g_mem_alloc_orig; + g_mem_alloc_orig = nullptr; + } + if (g_mem_dealloc_orig) { + butil::iobuf::blockmem_deallocate = g_mem_dealloc_orig; + g_mem_dealloc_orig = nullptr; + } + if (g_default_block_size_orig != 0) { + butil::SetDefaultBlockSize(g_default_block_size_orig); + g_default_block_size_orig = 0; + } + UrmaEndpoint::GlobalRelease(); + if (g_pool_seg) { + urma_unregister_seg(g_pool_seg); + g_pool_seg = nullptr; + } + if (g_pool_base) { + munmap(g_pool_base, g_pool_size); + g_pool_base = nullptr; + g_pool_size = 0; + } + delete g_pool; + g_pool = nullptr; + delete g_user_segs; + g_user_segs = nullptr; + delete g_user_segs_lock; + g_user_segs_lock = nullptr; + if (g_context) { + urma_delete_context(g_context); + g_context = nullptr; + } + g_local_eid = urma_eid_t{}; + g_has_local_eid = false; + g_is_bonding_device = false; + g_jetty_priority = 6; + if (g_owns_urma_init) { + const urma_status_t status = urma_uninit(); + if (status != URMA_SUCCESS) { + LOG(WARNING) << "Fail to urma_uninit: " << status; + } + g_owns_urma_init = false; + } + g_device = nullptr; +} + +// ============================================================================ +// Global initialization. +// ============================================================================ + +static bool GlobalUrmaInitializeImpl() { + if (BAIDU_UNLIKELY(g_skip_urma_init)) { + g_urma_available.store(true, butil::memory_order_release); + return true; + } + if (FLAGS_urma_sq_size < 16 || FLAGS_urma_sq_size > 4096 || + FLAGS_urma_rq_size < 16 || FLAGS_urma_rq_size > 4096 || + FLAGS_urma_buffer_size < 1024 || FLAGS_urma_buffer_count <= 0 || + FLAGS_urma_poller_num <= 0) { + LOG(ERROR) << "Invalid URMA queue, buffer, or poller configuration"; + errno = EINVAL; + return false; + } + + urma_init_attr_t init_attr{}; + const urma_status_t status = urma_init(&init_attr); + if (status != URMA_SUCCESS && status != URMA_EEXIST) { + if (status == URMA_FAIL) { + LOG(ERROR) << "Fail to urma_init: " << status + << " (URMA_FAIL). liburma returns URMA_FAIL when it " + "cannot load a provider, or when URMA was already " + "initialized by another component. Verify readable " + "provider libraries under /usr/lib64/urma, loaded " + "URMA kernel drivers, and that urma_init is called " + "only once per process"; + } else { + LOG(ERROR) << "Fail to urma_init: " << status; + } + return false; + } + g_owns_urma_init = (status == URMA_SUCCESS); + + int num_devices = 0; + urma_device_t** devices = urma_get_device_list(&num_devices); + if (!devices || num_devices <= 0) { + LOG(ERROR) << "No URMA device found"; + urma_free_device_list(devices); + return false; + } + urma_device_t* found = nullptr; + for (int i = 0; i < num_devices; ++i) { + if (FLAGS_urma_device.empty() || + std::string(devices[i]->name) == FLAGS_urma_device) { + found = devices[i]; + break; + } + } + if (!found) { + LOG(ERROR) << "URMA device not found: " << FLAGS_urma_device; + urma_free_device_list(devices); + return false; + } + g_device = found; + + const std::string device_name = found->name; + if (urma_query_device(found, &g_device_attr) != URMA_SUCCESS) { + LOG(ERROR) << "Fail to urma_query_device"; + urma_free_device_list(devices); + g_device = nullptr; + return false; + } + const int ctp_priority = + FindUrmaPriorityForTpType(g_device_attr, URMA_CTP); + if (ctp_priority >= 0) { + g_jetty_priority = static_cast(ctp_priority); + } else { + LOG(WARNING) << "URMA device does not report a CTP priority; " + "falling back to compatibility priority " + << static_cast(g_jetty_priority); + } + uint32_t eid_cnt = 0; + urma_eid_info_t* eids = urma_get_eid_list(found, &eid_cnt); + if (!eids || eid_cnt == 0) { + LOG(ERROR) << "Fail to urma_get_eid_list"; + urma_free_eid_list(eids); + urma_free_device_list(devices); + g_device = nullptr; + return false; + } + // Retain the exact EID used to create the context and advertise it in the + // handshake. This matters for a bonding virtual device whose jetty can + // carry a provider-selected physical EID. + g_local_eid = eids[0].eid; + g_has_local_eid = true; + g_context = urma_create_context(found, eids[0].eid_index); + urma_free_eid_list(eids); + urma_free_device_list(devices); + g_device = nullptr; + if (!g_context) { + LOG(ERROR) << "Fail to urma_create_context"; + return false; + } + // The bonding provider only accepts SET_BONDING_MODE while the context + // has no dependent resource. This must precede register_seg/JFC/JFR. + if (!ConfigureBondingMode(device_name)) { + return false; + } + uint32_t device_max_sge = g_device_attr.dev_cap.max_jfs_sge; + if (device_max_sge == 0) { + device_max_sge = 1; + } + // urma_jfs_cfg_t::max_sge is uint8_t. + if (device_max_sge > 255) { + device_max_sge = 255; + } + g_max_sge = static_cast(device_max_sge); + if (FLAGS_urma_max_sge > 0) { + if (FLAGS_urma_max_sge > g_max_sge) { + LOG(WARNING) << "Cap urma_max_sge from " << FLAGS_urma_max_sge + << " to device/config limit " << g_max_sge; + } else { + g_max_sge = FLAGS_urma_max_sge; + } + } + g_recv_block_size = + static_cast(FLAGS_urma_buffer_size) - + sizeof(butil::IOBuf::Block); + + // User-segment table. + g_user_segs_lock = new (std::nothrow) butil::Mutex; + g_user_segs = new (std::nothrow) butil::FlatMap(); + if (!g_user_segs_lock || !g_user_segs || + g_user_segs->init(65536) < 0) { + LOG(ERROR) << "Fail to init g_user_segs"; + return false; + } + + // Buffer pool. + g_pool = new BufferPool(); + g_pool_buffer_size = static_cast(FLAGS_urma_buffer_size); + // Resize the pool's per-shard vectors to hold the configured count. + size_t count = static_cast(FLAGS_urma_buffer_count); + g_pool->in_use.assign(count, 0); + for (size_t s = 0; s < kShardCount; ++s) { + g_pool->free_lists[s].reserve(count / kShardCount + 1); + } + if (!InitPool()) { + LOG(ERROR) << "Fail to init URMA buffer pool"; + return false; + } + + // Hijack IOBuf allocation so every IOBuf block is backed by a registered + // segment. This makes the send path trivial: any IOBuf can be posted + // directly as an urma_sge_t pointing at g_pool_seg. + g_mem_alloc_orig = butil::iobuf::blockmem_allocate; + g_mem_dealloc_orig = butil::iobuf::blockmem_deallocate; + g_default_block_size_orig = butil::GetDefaultBlockSize(); + butil::iobuf::blockmem_allocate = PoolAllocate; + butil::iobuf::blockmem_deallocate = PoolDeallocate; + butil::SetDefaultBlockSize(g_pool_buffer_size); + + if (UrmaEndpoint::GlobalInitialize() != 0) { + LOG(ERROR) << "Fail to initialize URMA endpoint resources"; + return false; + } + + g_urma_available.store(true, butil::memory_order_release); + // Do not register GlobalRelease with atexit. IOBuf keeps blocks in + // thread-local chains whose destructors may run after atexit handlers. + // Unmapping the registered pool here would leave those TLS chains + // pointing into unmapped memory. The process reclaims global URMA + // resources on exit; GlobalRelease remains available for init rollback. + LOG(INFO) << "URMA initialized: device=" << device_name + << " bonding=" << g_is_bonding_device + << " max_sge=" << g_max_sge + << " buffer_size=" << g_pool_buffer_size + << " buffer_count=" << g_pool->buffer_count(); + return true; +} + +static butil::atomic g_init_once{0}; +static butil::Mutex g_init_mutex; + +void GlobalUrmaInitializeOrDie() { + int expected = 0; + if (g_init_once.load(butil::memory_order_acquire) == 2) { + return; + } + if (g_init_once.compare_exchange_strong(expected, 1, + butil::memory_order_acq_rel)) { + BAIDU_SCOPED_LOCK(g_init_mutex); + if (!GlobalUrmaInitializeImpl()) { + LOG(WARNING) << "URMA initialization failed; falling back to TCP"; + GlobalRelease(); + } + g_init_once.store(2, butil::memory_order_release); + } else { + // Wait for the other thread to finish init. + while (g_init_once.load(butil::memory_order_acquire) != 2) { + // spin briefly + } + } +} + +bool IsUrmaAvailable() { + return g_urma_available.load(butil::memory_order_acquire); +} + +void GlobalDisableUrma() { + g_urma_available.store(false, butil::memory_order_release); +} + +bool SupportedByUrma(const std::string& protocol) { + return protocol == "baidu_std"; +} + +urma_context_t* GetUrmaContext() { return g_context; } +const urma_eid_t* GetUrmaLocalEid() { + return g_has_local_eid ? &g_local_eid : nullptr; +} +bool IsUrmaBondingDevice() { return g_is_bonding_device; } +int FindUrmaPriorityForTpType(const urma_device_attr_t& attr, + urma_tp_type_t tp_type) { + const union urma_tp_type_en expected = TpTypeCapability(tp_type); + for (int priority = 0; priority <= URMA_MAX_PRIORITY; ++priority) { + if (attr.dev_cap.priority_info[priority].tp_type.value == + expected.value) { + return priority; + } + } + return -1; +} +uint8_t GetUrmaJettyPriority() { return g_jetty_priority; } +int GetUrmaMaxSge() { return g_max_sge; } +size_t GetUrmaRecvBlockSize() { return g_recv_block_size; } + +// ============================================================================ +// Polling mode (per bthread tag). +// ============================================================================ + +bool InitPollingModeWithTag(bthread_tag_t tag, + std::function callback, + std::function init_fn, + std::function release_fn) { + if (BAIDU_UNLIKELY(g_skip_urma_init)) { + return true; + } + return UrmaEndpoint::PollingModeInitialize( + tag, std::move(callback), std::move(init_fn), + std::move(release_fn)) == 0; +} + +void ReleasePollingModeWithTag(bthread_tag_t tag) { + UrmaEndpoint::PollingModeRelease(tag); +} + +// ============================================================================ +// User memory registration. +// ============================================================================ + +uint64_t RegisterMemoryForUrma(void* buf, size_t len) { + if (BAIDU_UNLIKELY(g_skip_urma_init) || !g_context) { + return 0; + } + urma_reg_seg_flag_t flag{}; + flag.bs.token_policy = URMA_TOKEN_NONE; + flag.bs.cacheable = URMA_NON_CACHEABLE; + flag.bs.access = URMA_ACCESS_READ | URMA_ACCESS_WRITE | URMA_ACCESS_ATOMIC; + + urma_seg_cfg_t cfg{}; + cfg.va = reinterpret_cast(buf); + cfg.len = len; + cfg.token_id = nullptr; + cfg.token_value = {}; + cfg.flag = flag; + cfg.user_ctx = reinterpret_cast(buf); + cfg.iova = 0; + + errno = 0; + urma_target_seg_t* tseg = urma_register_seg(g_context, &cfg); + if (!tseg) { + PLOG(WARNING) << "Fail to urma_register_seg for user memory"; + return 0; + } + BAIDU_SCOPED_LOCK(*g_user_segs_lock); + UserSeg us; + us.tseg = tseg; + us.base = buf; + us.len = len; + if (!g_user_segs->insert(buf, us)) { + LOG(WARNING) << "Fail to insert user seg (duplicate?)"; + urma_unregister_seg(tseg); + return 0; + } + return static_cast(reinterpret_cast(tseg)); +} + +void DeregisterMemoryForUrma(void* buf) { + if (BAIDU_UNLIKELY(g_skip_urma_init) || !g_user_segs) { + return; + } + BAIDU_SCOPED_LOCK(*g_user_segs_lock); + UserSeg* us = g_user_segs->seek(buf); + if (!us) { + return; + } + urma_unregister_seg(us->tseg); + g_user_segs->erase(buf); +} + +} // namespace urma +} // namespace brpc + +#else // BRPC_WITH_URMA + +#include + +#include "butil/logging.h" + +namespace brpc { +namespace urma { + +void GlobalUrmaInitializeOrDie() { + LOG(FATAL) << "URMA is not compiled in. Rebuild with -DWITH_URMA=ON."; + exit(1); +} + +} // namespace urma +} // namespace brpc + +#endif // BRPC_WITH_URMA diff --git a/src/brpc/urma/urma_helper.h b/src/brpc/urma/urma_helper.h new file mode 100644 index 0000000000..871f1a6354 --- /dev/null +++ b/src/brpc/urma/urma_helper.h @@ -0,0 +1,119 @@ +// 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. + +#ifndef BRPC_URMA_HELPER_H +#define BRPC_URMA_HELPER_H + +#include +#include +#include +#include + +#include "bthread/types.h" +#include "butil/atomicops.h" + +#if BRPC_WITH_URMA + +#include "urma_api.h" +#include "urma_types.h" + +namespace brpc { +DECLARE_bool(usercode_in_coroutine); +DECLARE_bool(usercode_in_pthread); +namespace urma { + +// Initialize the URMA environment. Failure disables URMA globally so +// individual sockets transparently fall back to TCP. +void GlobalUrmaInitializeOrDie(); + +// Initialize URMA polling mode for a given bthread tag. +// Returns false on failure. +bool InitPollingModeWithTag(bthread_tag_t tag, + std::function callback = nullptr, + std::function init_fn = nullptr, + std::function release_fn = nullptr); + +void ReleasePollingModeWithTag(bthread_tag_t tag); + +// Register the given user buffer for URMA access. +// Returns the (opaque, non-zero) target segment handle stored in the user-mr +// table; 0 on failure. To use the memory in an IOBuf, append it via +// append_user_data_with_meta and pass the returned handle as the data meta. +uint64_t RegisterMemoryForUrma(void* buf, size_t len); + +// Deregister a previously registered user buffer. +void DeregisterMemoryForUrma(void* buf); + +// Return the target segment for a buffer-pool address. Passing nullptr returns +// the segment backing the whole pool. Returns nullptr for any other address. +urma_target_seg_t* GetPoolSegFor(void* buf); + +// Get the global URMA context (the urma_context_t created on the selected +// device / EID). Returns nullptr if URMA is not initialized. +urma_context_t* GetUrmaContext(); + +// Get the EID selected when the global context was created. This is the +// device EID that must be advertised to peers, especially for bonding +// devices where a created jetty may expose a provider-specific physical EID. +// Returns nullptr if URMA is not initialized. +const urma_eid_t* GetUrmaLocalEid(); + +// Return true when the selected URMA device is a bonding provider device. +bool IsUrmaBondingDevice(); + +// Find the priority whose advertised transport-path capability exactly +// matches @tp_type. Returns -1 when the device does not report one. +int FindUrmaPriorityForTpType(const urma_device_attr_t& attr, + urma_tp_type_t tp_type); + +// Return the priority selected for the CTP jettys created by brpc. +uint8_t GetUrmaJettyPriority(); + +// If the URMA environment is available. +bool IsUrmaAvailable(); + +// Disable URMA for the remaining lifetime of the process. +void GlobalDisableUrma(); + +// If the given protocol is supported by UrmaTransport. +// Currently only "baidu_std" is supported. +bool SupportedByUrma(const std::string& protocol); + +// Return the configured recv buffer size (one URMA recv WR's payload size). +size_t GetUrmaRecvBlockSize(); + +// Return max_sge supported by the device. +int GetUrmaMaxSge(); + +} // namespace urma +} // namespace brpc + +#else // BRPC_WITH_URMA + +namespace brpc { +namespace urma { + +// Initialize the URMA environment. +// Exit the process if initialization fails. +void GlobalUrmaInitializeOrDie(); + +} // namespace urma +} // namespace brpc + +#endif // BRPC_WITH_URMA + +#endif // BRPC_URMA_HELPER_H diff --git a/src/brpc/urma_transport.cpp b/src/brpc/urma_transport.cpp new file mode 100644 index 0000000000..311786e8eb --- /dev/null +++ b/src/brpc/urma_transport.cpp @@ -0,0 +1,248 @@ +// 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. + +#include "brpc/urma_transport.h" + +#if BRPC_WITH_URMA + +#include + +#include "butil/iobuf.h" +#include "butil/logging.h" +#include "bthread/bthread.h" +#include "bthread/types.h" + +#include "brpc/event_dispatcher.h" +#include "brpc/input_messenger.h" +#include "brpc/socket.h" +#include "brpc/tcp_transport.h" +#include "brpc/urma/urma_endpoint.h" +#include "brpc/urma/urma_helper.h" + +namespace brpc { + +// Defined in urma_helper.cpp. +DECLARE_bool(urma_use_polling); +DECLARE_bool(urma_disable_bthread); + +void UrmaTransport::Init(Socket* socket, const SocketOptions& options) { + CHECK(_urma_ep == nullptr); + if (options.socket_mode == SOCKET_MODE_URMA) { + _urma_ep = new (std::nothrow) urma::UrmaEndpoint(socket); + if (!_urma_ep) { + const int saved_errno = errno; + PLOG(ERROR) << "Fail to create UrmaEndpoint"; + socket->SetFailed(saved_errno, "Fail to create UrmaEndpoint: %s", + berror(saved_errno)); + } + _urma_state = URMA_UNKNOWN; + } else { + _urma_state = URMA_OFF; + socket->_socket_mode = SOCKET_MODE_TCP; + } + _socket = socket; + _default_connect = options.app_connect; + _on_edge_trigger = options.on_edge_triggered_events; + if (options.need_on_edge_trigger && _on_edge_trigger == nullptr) { + _on_edge_trigger = urma::UrmaEndpoint::OnNewDataFromTcp; + } + _tcp_transport = std::make_shared(); + _tcp_transport->Init(socket, options); +} + +void UrmaTransport::Release() { + if (_urma_ep) { + delete _urma_ep; + _urma_ep = nullptr; + } +} + +int UrmaTransport::Reset(int32_t /*expected_nref*/) { + if (_urma_ep) { + _urma_ep->Reset(); + } + _urma_state = URMA_UNKNOWN; + return 0; +} + +std::shared_ptr UrmaTransport::Connect() { + if (_default_connect == nullptr) { + return std::make_shared(); + } + return _default_connect; +} + +int UrmaTransport::CutFromIOBuf(butil::IOBuf* buf) { + if (_urma_ep && + _urma_state.load(butil::memory_order_acquire) != URMA_OFF) { + butil::IOBuf* data_arr[1] = {buf}; + return _urma_ep->CutFromIOBufList(data_arr, 1); + } else { + return _tcp_transport->CutFromIOBuf(buf); + } +} + +ssize_t UrmaTransport::CutFromIOBufList(butil::IOBuf** buf, size_t ndata) { + if (_urma_ep && + _urma_state.load(butil::memory_order_acquire) != URMA_OFF) { + return _urma_ep->CutFromIOBufList(buf, ndata); + } else { + return _tcp_transport->CutFromIOBufList(buf, ndata); + } +} + +int UrmaTransport::WaitEpollOut(butil::atomic* epollout_butex, + bool pollin, const timespec duetime) { + if (_urma_state.load(butil::memory_order_acquire) == URMA_ON) { + const int expected_val = + epollout_butex->load(butil::memory_order_acquire); + CHECK(_urma_ep != nullptr); + if (!_urma_ep->IsWritable()) { + // Same caveat as RDMA: URMA cannot detect failure by writing, so + // after a failed butex wait we must re-check _socket->Failed(). + int rc = + bthread::butex_wait(epollout_butex, expected_val, &duetime); + if (rc < 0 && errno != EWOULDBLOCK && errno != ETIMEDOUT) { + const int saved_errno = errno; + PLOG(ERROR) << "Fail to wait epollout butex"; + if (_socket->SetFailed(saved_errno, "Fail to wait epollout butex: %s", + berror(saved_errno))) { + return 1; + } + } + if (_socket->Failed()) { + return 1; + } + return 0; + } + return 0; + } + return _tcp_transport->WaitEpollOut(epollout_butex, pollin, duetime); +} + +void UrmaTransport::ProcessEvent(bthread_attr_t attr) { + // Identical to TcpTransport/RdmaTransport: dispatch OnEdge(_socket) on a + // bthread, falling back to inline invocation on bthread_start failure. + bthread_t tid; + if (FLAGS_usercode_in_coroutine) { + OnEdge(_socket); + } else if (!EventDispatcherUnsched()) { + auto rc = bthread_start_urgent(&tid, &attr, OnEdge, _socket); + if (rc != 0) { + LOG(FATAL) << "Fail to start ProcessEvent"; + OnEdge(_socket); + } + } else if (bthread_start_background(&tid, &attr, OnEdge, _socket) != 0) { + LOG(FATAL) << "Fail to start ProcessEvent"; + OnEdge(_socket); + } +} + +void UrmaTransport::QueueMessage(InputMessageClosure& input_msg, + int* num_bthread_created, bool last_msg) { + if (last_msg && !urma::FLAGS_urma_use_polling) { + return; + } + InputMessageBase* to_run_msg = input_msg.release(); + if (!to_run_msg) { + return; + } + if (urma::FLAGS_urma_disable_bthread) { + Transport::ProcessInputMessage(to_run_msg); + return; + } + bthread_t th; + bthread_attr_t tmp = + (FLAGS_usercode_in_pthread ? BTHREAD_ATTR_PTHREAD : BTHREAD_ATTR_NORMAL) | + BTHREAD_NOSIGNAL; + tmp.keytable_pool = _socket->keytable_pool(); + tmp.tag = bthread_self_tag(); + bthread_attr_set_name(&tmp, "ProcessInputMessage"); + if (!FLAGS_usercode_in_coroutine && bthread_start_background( + &th, &tmp, Transport::ProcessInputMessage, to_run_msg) == 0) { + ++*num_bthread_created; + } else { + Transport::ProcessInputMessage(to_run_msg); + } +} + +void UrmaTransport::Debug(std::ostream& os) { + if (_urma_state.load(butil::memory_order_acquire) == URMA_ON && + _urma_ep) { + _urma_ep->DebugInfo(os); + } +} + +int UrmaTransport::ContextInitOrDie(bool server_or_not, const void* options) { + if (server_or_not) { + if (!OptionsAvailableOverUrma( + static_cast(options))) { + return -1; + } + urma::GlobalUrmaInitializeOrDie(); + if (!urma::InitPollingModeWithTag( + static_cast(options)->bthread_tag)) { + return -1; + } + } else { + if (!OptionsAvailableForUrma( + static_cast(options))) { + return -1; + } + urma::GlobalUrmaInitializeOrDie(); + if (!urma::InitPollingModeWithTag(bthread_self_tag())) { + return -1; + } + } + return 0; +} + +bool UrmaTransport::OptionsAvailableForUrma(const ChannelOptions* opt) { + if (opt->has_ssl_options()) { + LOG(WARNING) << "Cannot use SSL and URMA at the same time"; + return false; + } + if (!urma::SupportedByUrma(opt->protocol.name())) { + LOG(WARNING) << "Cannot use " << opt->protocol.name() << " over URMA"; + return false; + } + return true; +} + +bool UrmaTransport::OptionsAvailableOverUrma(const ServerOptions* opt) { + if (opt->rtmp_service) { + LOG(WARNING) << "RTMP is not supported by URMA"; + return false; + } + if (opt->has_ssl_options()) { + LOG(WARNING) << "SSL is not supported by URMA"; + return false; + } + if (opt->nshead_service) { + LOG(WARNING) << "NSHEAD is not supported by URMA"; + return false; + } + if (opt->mongo_service_adaptor) { + LOG(WARNING) << "MONGO is not supported by URMA"; + return false; + } + return true; +} + +} // namespace brpc + +#endif // BRPC_WITH_URMA diff --git a/src/brpc/urma_transport.h b/src/brpc/urma_transport.h new file mode 100644 index 0000000000..9a496d56be --- /dev/null +++ b/src/brpc/urma_transport.h @@ -0,0 +1,84 @@ +// 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. + +#ifndef BRPC_URMA_TRANSPORT_H +#define BRPC_URMA_TRANSPORT_H + +#if BRPC_WITH_URMA + +#include "brpc/channel.h" +#include "brpc/socket.h" +#include "brpc/transport.h" +#include "brpc/urma/urma_endpoint.h" + +namespace brpc { + +// UrmaTransport is the Transport subclass for URMA (openEuler Unified Remote +// Memory Access). It composes a TcpTransport for fallback (mirroring the +// RdmaTransport / UBShmTransport design) and delegates the URMA data path to +// the per-connection urma::UrmaEndpoint. Negotiation runs over the TCP fd and +// resolves _urma_state to URMA_ON or URMA_OFF. +class UrmaTransport : public Transport { + friend class TransportFactory; + friend class urma::UrmaEndpoint; + friend class urma::UrmaConnect; + friend class urma::UrmaHandshakeServerV2; + friend class urma::UrmaHandshakeClientV2; + friend class urma::UrmaHandshakeServerV3; + friend class urma::UrmaHandshakeClientV3; + +public: + void Init(Socket* socket, const SocketOptions& options) override; + void Release() override; + int Reset(int32_t expected_nref) override; + std::shared_ptr Connect() override; + int CutFromIOBuf(butil::IOBuf* buf) override; + ssize_t CutFromIOBufList(butil::IOBuf** buf, size_t ndata) override; + int WaitEpollOut(butil::atomic* epollout_butex, bool pollin, + const timespec duetime) override; + void ProcessEvent(bthread_attr_t attr) override; + void QueueMessage(InputMessageClosure& input_msg, int* num_bthread_created, + bool last_msg) override; + void Debug(std::ostream& os) override; + + urma::UrmaEndpoint* GetUrmaEp() { + CHECK(_urma_ep != nullptr); + return _urma_ep; + } + + static int ContextInitOrDie(bool server_or_not, const void* options); + +private: + static bool OptionsAvailableForUrma(const ChannelOptions* opt); + static bool OptionsAvailableOverUrma(const ServerOptions* opt); + + // The on/off state of URMA. UNKNOWN until the handshake resolves. + enum UrmaState { + URMA_ON, + URMA_OFF, + URMA_UNKNOWN + }; + + urma::UrmaEndpoint* _urma_ep = nullptr; + butil::atomic _urma_state{URMA_UNKNOWN}; + std::shared_ptr _tcp_transport; +}; + +} // namespace brpc + +#endif // BRPC_WITH_URMA +#endif // BRPC_URMA_TRANSPORT_H diff --git a/src/brpc/versioned_ref_with_id.h b/src/brpc/versioned_ref_with_id.h index f77d5afa83..3793e2185e 100644 --- a/src/brpc/versioned_ref_with_id.h +++ b/src/brpc/versioned_ref_with_id.h @@ -89,35 +89,74 @@ typename std::enable_if::value, Ret>::type ReturnEmpty() { template typename std::enable_if::value, Ret>::type ReturnEmpty() {} -// Call func_name of class_type if class_type implements func_name, -// otherwise call default function. -#define WRAPPER_OF(class_type, func_name, return_type) \ - struct func_name ## Wrapper { \ - template \ +// Detect whether a type implements the member function `func_name' callable +// with Args..., exposing the result as a compile-time boolean: +// HasMember_::value +// The detector is decoupled from the caller so that it can also be reused in +// standalone static_assert to enforce interface contracts. +#define BRPC_DEFINE_MEMBER_DETECTOR(func_name) \ + template \ + struct HasMember##func_name { \ + template \ static auto Test(int) -> decltype( \ - std::declval().func_name(std::declval()...), std::true_type()); \ - template \ + std::declval().func_name(std::declval()...), std::true_type()); \ + template \ static auto Test(...) -> std::false_type; \ - \ - template \ - typename std::enable_if(0))::value, return_type>::type \ - Call(class_type* obj, Args&&... args) { \ + static constexpr bool value = decltype(Test(0))::value; \ + } + +// Define a static caller `Call' that invokes `obj->func_name(...)' +// if the type implements it, otherwise returns a default-constructed value. +// Requires the detector defined by BRPC_DEFINE_MEMBER_DETECTOR(func_name). +// On C++20, an inline `requires' expression is used directly (no separate +// detector needed); +// On C++17, a single `if constexpr' branch with the detector; +// on C++11/14, two SFINAE overloads so that the body referencing a +// possibly-missing member is never instantiated. +#if __cplusplus >= 202002L +#define BRPC_DEFINE_OPTIONAL_CALLER(func_name, return_type) \ + template \ + static return_type Call##func_name(U* obj, Args&&... args) { \ + if constexpr (requires { obj->func_name(std::forward(args)...); }) { \ + BAIDU_CASSERT((butil::is_result_same< \ + return_type, decltype(&U::func_name), U, Args...>::value), \ + "Params or return type mismatch"); \ + return obj->func_name(std::forward(args)...); \ + } else { \ + return ReturnEmpty(); \ + } \ + } +#elif __cplusplus >= 201703L +#define BRPC_DEFINE_OPTIONAL_CALLER(func_name, return_type) \ + template \ + static return_type Call##func_name(U* obj, Args&&... args) { \ + if constexpr (HasMember##func_name::value) { \ BAIDU_CASSERT((butil::is_result_same< \ - return_type, decltype(&T::func_name), T, Args...>::value), \ + return_type, decltype(&U::func_name), U, Args...>::value), \ "Params or return type mismatch"); \ - return obj->func_name(std::forward(args)...); \ - } \ - \ - template \ - typename std::enable_if(0))::value, return_type>::type \ - Call(class_type* obj, Args&&...) { \ + return obj->func_name(std::forward(args)...); \ + } else { \ return ReturnEmpty(); \ } \ } - -#define WRAPPER_CALL(func_name, obj, ...) func_name ## Wrapper().Call(obj, ## __VA_ARGS__) +#else +#define BRPC_DEFINE_OPTIONAL_CALLER(func_name, return_type) \ + template \ + static typename std::enable_if< \ + HasMember##func_name::value, return_type>::type \ + Call##func_name(U* obj, Args&&... args) { \ + BAIDU_CASSERT((butil::is_result_same< \ + return_type, decltype(&U::func_name), U, Args...>::value), \ + "Params or return type mismatch"); \ + return obj->func_name(std::forward(args)...); \ + } \ + template \ + static typename std::enable_if< \ + !HasMember##func_name::value, return_type>::type \ + Call##func_name(U*, Args&&...) { \ + return ReturnEmpty(); \ + } +#endif // VersionedRefWithId is an efficient data structure, which can be find // in O(1)-time by VRefId. @@ -205,7 +244,11 @@ class VersionedRefWithId { , _this_id(0) , _additional_ref_status(ADDITIONAL_REF_USING) {} - virtual ~VersionedRefWithId() = default; + // Non-virtual on purpose: CRTP static polymorphism needs no vtable, and + // instances are always recycled via return_resource() (never deleted + // through a base pointer), so a virtual destructor would only add a + // useless vptr and hurt cacheline layout. + ~VersionedRefWithId() = default; DISALLOW_COPY_AND_ASSIGN(VersionedRefWithId); // Create a VersionedRefWithId, put the identifier into `id'. @@ -219,14 +262,14 @@ class VersionedRefWithId { // of scope (w/o explicit std::move). User can still access `ptr' // after calling ptr->SetFailed() before release of `ptr'. // This function is wait-free. - // Returns 0 on success, -1 when the Socket was SetFailed(). + // Returns 0 on success, -1 when the object was SetFailed(). static int Address(VRefId id, VersionedRefWithIdUniquePtr* ptr); - // Returns 0 on success, 1 on failed socket, -1 on recycled. + // Returns 0 on success, 1 on failed object, -1 on recycled. static int AddressFailedAsWell(VRefId id, VersionedRefWithIdUniquePtr* ptr); // Re-address current VersionedRefWithId into `ptr'. - // Always succeed even if this socket is failed. + // Always succeed even if this object is failed. void ReAddress(VersionedRefWithIdUniquePtr* ptr); // Returns signed 32-bit referenced-count. @@ -239,12 +282,12 @@ class VersionedRefWithId { // Any later Address() of the identifier shall return NULL. The // VersionedRefWithId is NOT recycled after calling this function, // instead it will be recycled when no one references it. Internal - // fields of the Socket are still accessible after calling this + // fields of the object are still accessible after calling this // function. Calling SetFailed() of a VersionedRefWithId more than // once is OK. // T::OnFailed() will be called when SetFailed() successfully. // This function is lock-free. - // Returns -1 when the Socket was already SetFailed(), 0 otherwise. + // Returns -1 when the object was already SetFailed(), 0 otherwise. template static int SetFailedById(VRefId id, Args&&... args); @@ -301,7 +344,7 @@ friend void DereferenceVersionedRefWithId<>(T* r); _versioned_ref.fetch_add(1, butil::memory_order_release); } - // Make this socket addressable again. + // Make this object addressable again. // If nref is less than `at_least_nref', VersionedRefWithId was // abandoned during revival and cannot be revived. void Revive(int32_t at_least_nref); @@ -310,17 +353,21 @@ friend void DereferenceVersionedRefWithId<>(T* r); typedef butil::ResourceId resource_id_t; // 1. When `failed_as_well=true', returns 0 on success, - // 1 on failed socket, -1 on recycled. + // 1 on failed object, -1 on recycled. // 2. When `failed_as_well=true', returns 0 on success, - // -1 when the Socket was SetFailed(). + // -1 when the object was SetFailed(). static int AddressImpl(VRefId id, bool failed_as_well, VersionedRefWithIdUniquePtr* ptr); - // Callback wrapper of Derived classes. - WRAPPER_OF(T, OnFailed, void); - WRAPPER_OF(T, BeforeAdditionalRefReleased, void); - WRAPPER_OF(T, AfterRevived, void); - WRAPPER_OF(T, OnDescription, std::string); + // Detectors + static callers for optional Derived-class callbacks. + BRPC_DEFINE_MEMBER_DETECTOR(OnFailed); + BRPC_DEFINE_OPTIONAL_CALLER(OnFailed, void); + BRPC_DEFINE_MEMBER_DETECTOR(BeforeAdditionalRefReleased); + BRPC_DEFINE_OPTIONAL_CALLER(BeforeAdditionalRefReleased, void); + BRPC_DEFINE_MEMBER_DETECTOR(AfterRevived); + BRPC_DEFINE_OPTIONAL_CALLER(AfterRevived, void); + BRPC_DEFINE_MEMBER_DETECTOR(OnDescription); + BRPC_DEFINE_OPTIONAL_CALLER(OnDescription, std::string); // unsigned 32-bit version + signed 32-bit referenced-count. // Meaning of version: @@ -329,14 +376,14 @@ friend void DereferenceVersionedRefWithId<>(T* r); // of a VersionedRefWithId on the slot, the version is added with 1 twice. // This is also the version encoded in VRefId. // * Failed version: = created version + 1, SetFailed()-ed but returned. - // * Other versions: the socket is already recycled. + // * Other versions: the object is already recycled. butil::atomic BAIDU_CACHELINE_ALIGNMENT _versioned_ref; // The unique identifier. VRefId _this_id; // Indicates whether additional reference has increased, // decreased, or is increasing. // additional ref status: - // `Socket'、`Create': REF_USING + // constructor / `Create': REF_USING // `SetFailed': REF_USING -> REF_RECYCLED // `Revive' REF_RECYCLED -> REF_REVIVING -> REF_USING butil::atomic _additional_ref_status; @@ -444,7 +491,7 @@ int VersionedRefWithId::AddressImpl( // Addressed a free slot. } } else { - CHECK(false) << "Over dereferenced SocketId=" << id; + CHECK(false) << "Over dereferenced VRefId=" << id; } } return -1; @@ -488,7 +535,7 @@ int VersionedRefWithId::SetFailedImpl(Args&&... args) { butil::memory_order_release, butil::memory_order_relaxed)) { // Call T::OnFailed() to notify the failure of T. - WRAPPER_CALL(OnFailed, static_cast(this), std::forward(args)...); + CallOnFailed(static_cast(this), std::forward(args)...); // Deref additionally which is added at creation so that this // queue's reference will hit 0(recycle) when no one addresses it. ReleaseAdditionalReference(); @@ -507,7 +554,7 @@ int VersionedRefWithId::ReleaseAdditionalReference() { expect, ADDITIONAL_REF_RECYCLED, butil::memory_order_relaxed, butil::memory_order_relaxed)) { - WRAPPER_CALL(BeforeAdditionalRefReleased, static_cast(this)); + CallBeforeAdditionalRefReleased(static_cast(this)); return Dereference(); } @@ -529,7 +576,7 @@ int VersionedRefWithId::Dereference() { if (nref > 1) { return 0; } - if (__builtin_expect(nref == 1, 1)) { + if (BAIDU_LIKELY(nref == 1)) { const uint32_t ver = VersionOfVRef(vref); const uint32_t id_ver = VersionOfVRefId(id); // Besides first successful SetFailed() adds 1 to version, one of @@ -541,9 +588,9 @@ int VersionedRefWithId::Dereference() { // // Note: `ver == id_ver' means this VersionedRefWithId has been `SetRecycle' // before rather than `SetFailed'; `ver == ide_ver+1' means we - // had `SetFailed' this socket before. We should destroy the - // socket under both situation - if (__builtin_expect(ver == id_ver || ver == id_ver + 1, 1)) { + // had `SetFailed' this object before. We should destroy the + // object under both situation + if (BAIDU_LIKELY(ver == id_ver || ver == id_ver + 1)) { // sees nref:1->0, try to set version=id_ver+2,--nref. // No retry: if version changes, the slot is already returned by // another one who sees nref:1->0 concurrently; if nref changes, @@ -590,7 +637,7 @@ void VersionedRefWithId::Revive(int32_t at_least_nref) { int32_t nref = NRefOfVRef(vref); if (nref < at_least_nref) { - // Set the status to REF_RECYCLED since no one uses this socket + // Set the status to REF_RECYCLED since no one uses this object _additional_ref_status.store( ADDITIONAL_REF_RECYCLED, butil::memory_order_relaxed); CHECK_EQ(1, nref); @@ -606,7 +653,7 @@ void VersionedRefWithId::Revive(int32_t at_least_nref) { // Set the status to REF_USING since we add additional ref again _additional_ref_status.store( ADDITIONAL_REF_USING, butil::memory_order_relaxed); - WRAPPER_CALL(AfterRevived, static_cast(this)); + CallAfterRevived(static_cast(this)); return; } } @@ -617,8 +664,7 @@ std::string VersionedRefWithId::description() const { std::string result; result.reserve(128); butil::string_appendf(&result, "%s{id=%" PRIu64 " ", butil::class_name(), id()); - result.append(WRAPPER_CALL( - OnDescription, const_cast(static_cast(this)))); + result.append(CallOnDescription(const_cast(static_cast(this)))); butil::string_appendf(&result, "} (%p)", this); return result; } diff --git a/src/bthread/execution_queue_inl.h b/src/bthread/execution_queue_inl.h index ddf7bc6ba2..9c12e19256 100644 --- a/src/bthread/execution_queue_inl.h +++ b/src/bthread/execution_queue_inl.h @@ -348,11 +348,10 @@ inline ExecutionQueueOptions::ExecutionQueueOptions() {} template -inline int execution_queue_start( - ExecutionQueueId* id, - const ExecutionQueueOptions* options, - int (*execute)(void* meta, TaskIterator&), - void* meta) { +inline int execution_queue_start(ExecutionQueueId* id, + const ExecutionQueueOptions* options, + int (*execute)(void* meta, TaskIterator&), + void* meta) { return ExecutionQueue::create(id, options, execute, meta); } @@ -364,7 +363,7 @@ execution_queue_address(ExecutionQueueId id) { template inline int execution_queue_execute(ExecutionQueueId id, - typename butil::add_const_reference::type task) { + typename butil::add_const_reference::type task) { return execution_queue_execute(id, task, NULL); } @@ -377,9 +376,8 @@ inline int execution_queue_execute(ExecutionQueueId id, template inline int execution_queue_execute(ExecutionQueueId id, - typename butil::add_const_reference::type task, - const TaskOptions* options, - TaskHandle* handle) { + typename butil::add_const_reference::type task, + const TaskOptions* options, TaskHandle* handle) { typename ExecutionQueue::scoped_ptr_t ptr = ExecutionQueue::address(id); if (ptr != NULL) { @@ -390,21 +388,18 @@ inline int execution_queue_execute(ExecutionQueueId id, } template -inline int execution_queue_execute(ExecutionQueueId id, - T&& task) { +inline int execution_queue_execute(ExecutionQueueId id, T&& task) { return execution_queue_execute(id, std::forward(task), NULL); } template -inline int execution_queue_execute(ExecutionQueueId id, - T&& task, +inline int execution_queue_execute(ExecutionQueueId id, T&& task, const TaskOptions* options) { return execution_queue_execute(id, std::forward(task), options, NULL); } template -inline int execution_queue_execute(ExecutionQueueId id, - T&& task, +inline int execution_queue_execute(ExecutionQueueId id, T&& task, const TaskOptions* options, TaskHandle* handle) { typename ExecutionQueue::scoped_ptr_t diff --git a/src/bthread/task_group.cpp b/src/bthread/task_group.cpp index 72a6b91836..777d7514a3 100644 --- a/src/bthread/task_group.cpp +++ b/src/bthread/task_group.cpp @@ -1018,8 +1018,11 @@ void TaskGroup::priority_to_run(void* args_in) { if (args->meta->priority_index < 0) { return g->push_rq(args->meta->tid); } - return g->control()->push_ed_priority_queue( + g->control()->push_ed_priority_queue( args->tag, args->meta->priority_index, args->meta->tid); + + ++g->_nsignaled; + g->control()->signal_task(1, args->tag); } struct SleepArgs { diff --git a/src/butil/arena.cpp b/src/butil/arena.cpp index 9c66217e62..dc07d8d75a 100644 --- a/src/butil/arena.cpp +++ b/src/butil/arena.cpp @@ -29,19 +29,19 @@ ArenaOptions::ArenaOptions() {} Arena::Arena(const ArenaOptions& options) - : _cur_block(NULL) - , _isolated_blocks(NULL) + : _cur_block(nullptr) + , _isolated_blocks(nullptr) , _block_size(options.initial_block_size) , _options(options) { } Arena::~Arena() { - while (_cur_block != NULL) { + while (_cur_block != nullptr) { Block* const saved_next = _cur_block->next; free(_cur_block); _cur_block = saved_next; } - while (_isolated_blocks != NULL) { + while (_isolated_blocks != nullptr) { Block* const saved_next = _isolated_blocks->next; free(_isolated_blocks); _isolated_blocks = saved_next; @@ -79,7 +79,7 @@ void* Arena::allocate_in_other_blocks(size_t n) { // Waste the left space. At most 1/4 of allocated spaces are wasted. // Grow the block size gradually. - if (_cur_block != NULL) { + if (_cur_block != nullptr) { _block_size = std::min(2 * _block_size, _options.max_block_size); } size_t new_size = _block_size; @@ -87,10 +87,10 @@ void* Arena::allocate_in_other_blocks(size_t n) { new_size = n; } Block* b = (Block*)malloc(offsetof(Block, data) + new_size); - if (NULL == b) { - return NULL; + if (nullptr == b) { + return nullptr; } - b->next = NULL; + b->next = nullptr; b->alloc_size = n; b->size = new_size; if (_cur_block) { diff --git a/src/butil/arena.h b/src/butil/arena.h index 03693a723d..d188c52d36 100644 --- a/src/butil/arena.h +++ b/src/butil/arena.h @@ -72,7 +72,7 @@ class Arena { }; inline void* Arena::allocate(size_t n) { - if (_cur_block != NULL && _cur_block->left_space() >= n) { + if (_cur_block != nullptr && _cur_block->left_space() >= n) { void* ret = _cur_block->data + _cur_block->alloc_size; _cur_block->alloc_size += n; return ret; diff --git a/src/butil/at_exit.cc b/src/butil/at_exit.cc index 1c06ec1ebd..64b9cf3cd9 100644 --- a/src/butil/at_exit.cc +++ b/src/butil/at_exit.cc @@ -17,7 +17,7 @@ namespace butil { // version of the constructor, and if we are building a dynamic library we may // end up with multiple AtExitManagers on the same process. We don't protect // this for thread-safe access, since it will only be modified in testing. -static AtExitManager* g_top_manager = NULL; +static AtExitManager* g_top_manager = nullptr; AtExitManager::AtExitManager() : next_manager_(g_top_manager) { // If multiple modules instantiate AtExitManagers they'll end up living in this diff --git a/src/butil/binary_printer.h b/src/butil/binary_printer.h index 068ef24daf..ddf36ed8fa 100644 --- a/src/butil/binary_printer.h +++ b/src/butil/binary_printer.h @@ -36,10 +36,10 @@ class ToPrintable { : _iobuf(&b), _max_length(max_length) {} ToPrintable(const StringPiece& str, size_t max_length = DEFAULT_MAX_LENGTH) - : _iobuf(NULL), _str(str), _max_length(max_length) {} + : _iobuf(nullptr), _str(str), _max_length(max_length) {} ToPrintable(const void* data, size_t n, size_t max_length = DEFAULT_MAX_LENGTH) - : _iobuf(NULL), _str((const char*)data, n), _max_length(max_length) {} + : _iobuf(nullptr), _str((const char*)data, n), _max_length(max_length) {} void Print(std::ostream& os) const; diff --git a/src/butil/bit_array.h b/src/butil/bit_array.h index 3bcc694844..0deec88c77 100644 --- a/src/butil/bit_array.h +++ b/src/butil/bit_array.h @@ -33,7 +33,7 @@ namespace butil { // Create an array with at least |nbit| bits. The array is not cleared. inline uint64_t* bit_array_malloc(size_t nbit) { if (!nbit) { - return NULL; + return nullptr; } return (uint64_t*)malloc(BIT_ARRAY_LEN(nbit)/*different from /8*/); } diff --git a/src/butil/class_name.cpp b/src/butil/class_name.cpp index 0312c4b782..ace0495c63 100644 --- a/src/butil/class_name.cpp +++ b/src/butil/class_name.cpp @@ -35,10 +35,10 @@ std::string demangle(const char* name) { // A region of memory, allocated with malloc, of *length bytes, // into which the demangled name is stored. If output_buffer is // not long enough, it is expanded using realloc. output_buffer - // may instead be NULL; in that case, the demangled name is placed + // may instead be nullptr; in that case, the demangled name is placed // in a region of memory allocated with malloc. // length - // If length is non-NULL, the length of the buffer containing the + // If length is non-nullptr, the length of the buffer containing the // demangled name is placed in *length. // status // *status is set to one of the following values: @@ -48,7 +48,7 @@ std::string demangle(const char* name) { // mangling rules. // -3: One of the arguments is invalid. int status = 0; - char* buf = abi::__cxa_demangle(name, NULL, NULL, &status); + char* buf = abi::__cxa_demangle(name, nullptr, nullptr, &status); if (status == 0 && buf) { std::string s(buf); free(buf); diff --git a/src/butil/comlog_sink.cc b/src/butil/comlog_sink.cc index c645447171..cd02b22033 100644 --- a/src/butil/comlog_sink.cc +++ b/src/butil/comlog_sink.cc @@ -62,7 +62,7 @@ int ComlogLayout::format(comspace::Event *evt) { } time_t t = evt->_print_time.tv_sec; - struct tm local_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL}; + struct tm local_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; #if _MSC_VER >= 1400 localtime_s(&local_tm, &t); #else @@ -148,7 +148,7 @@ ComlogSinkOptions::ComlogSinkOptions() } ComlogSink::ComlogSink() - : _init(false), _dev(NULL) { + : _init(false), _dev(nullptr) { } int ComlogSink::SetupFromConfig(const std::string& conf_path_str) { @@ -266,7 +266,7 @@ int ComlogSink::SetupDevice(com_device_t* dev, const char* type, const char* fil ComlogLayoutOptions layout_options; layout_options.shorter_log_level = _options.shorter_log_level; ComlogLayout* layout = new (std::nothrow) ComlogLayout(&layout_options); - if (layout == NULL) { + if (layout == nullptr) { LOG(FATAL) << "Fail to new layout"; return -1; } @@ -322,7 +322,7 @@ int ComlogSink::Setup(const ComlogSinkOptions* options) { int dev_num = (_options.enable_wf_device ? 2 : 1); _dev = new (std::nothrow) com_device_t[dev_num]; - if (NULL == _dev) { + if (nullptr == _dev) { LOG(FATAL) << "Fail to new com_device_t"; return -1; } @@ -336,7 +336,7 @@ int ComlogSink::Setup(const ComlogSinkOptions* options) { return -1; } } - if (com_openlog(_options.process_name.c_str(), _dev, dev_num, NULL) != 0) { + if (com_openlog(_options.process_name.c_str(), _dev, dev_num, nullptr) != 0) { LOG(ERROR) << "Fail to com_openlog"; return -1; } @@ -354,7 +354,7 @@ void ComlogSink::Unload() { // reference the layout after com_closelog. //delete _dev->layout; delete [] _dev; - _dev = NULL; + _dev = nullptr; } } diff --git a/src/butil/comlog_sink.h b/src/butil/comlog_sink.h index 6444ff6309..f02adf90d2 100644 --- a/src/butil/comlog_sink.h +++ b/src/butil/comlog_sink.h @@ -110,7 +110,7 @@ struct ComlogSinkOptions { // logging::SetLogSink(ComlogSink::GetInstance()); // // [ Setup from ComlogSinkOptions ] -// if (logging::ComlogSink::GetInstance()->Setup(NULL/*default options*/) != 0) { +// if (logging::ComlogSink::GetInstance()->Setup(nullptr/*default options*/) != 0) { // LOG(ERROR) << "Fail to setup comlog"; // return -1; // } diff --git a/src/butil/containers/bounded_queue.h b/src/butil/containers/bounded_queue.h index 55f06e1e90..cf093cdf6f 100644 --- a/src/butil/containers/bounded_queue.h +++ b/src/butil/containers/bounded_queue.h @@ -84,14 +84,14 @@ class BoundedQueue { , _cap(0) , _start(0) , _ownership(NOT_OWN_STORAGE) - , _items(NULL) { + , _items(nullptr) { }; ~BoundedQueue() { clear(); if (_ownership == OWNS_STORAGE) { free(_items); - _items = NULL; + _items = nullptr; } } @@ -124,7 +124,7 @@ class BoundedQueue { if (_count < _cap) { return new ((T*)_items + _mod(_start + _count++, _cap)) T(); } - return NULL; + return nullptr; } // Push |item| into top side of this queue @@ -147,7 +147,7 @@ class BoundedQueue { ++_count; return new ((T*)_items + _start) T(); } - return NULL; + return nullptr; } // Pop top-most item from this queue @@ -209,52 +209,52 @@ class BoundedQueue { _start = 0; } - // Get address of top-most item, NULL if queue is empty - T* top() { - return _count ? ((T*)_items + _start) : NULL; + // Get address of top-most item, nullptr if queue is empty + T* top() { + return _count ? ((T*)_items + _start) : nullptr; } - const T* top() const { - return _count ? ((const T*)_items + _start) : NULL; + const T* top() const { + return _count ? ((const T*)_items + _start) : nullptr; } // Randomly access item from top side. // top(0) == top(), top(size()-1) == bottom() - // Returns NULL if |index| is out of range. + // Returns nullptr if |index| is out of range. T* top(size_t index) { if (index < _count) { return (T*)_items + _mod(_start + index, _cap); } - return NULL; // including _count == 0 + return nullptr; // including _count == 0 } const T* top(size_t index) const { if (index < _count) { return (const T*)_items + _mod(_start + index, _cap); } - return NULL; // including _count == 0 + return nullptr; // including _count == 0 } - // Get address of bottom-most item, NULL if queue is empty - T* bottom() { - return _count ? ((T*)_items + _mod(_start + _count - 1, _cap)) : NULL; + // Get address of bottom-most item, nullptr if queue is empty + T* bottom() { + return _count ? ((T*)_items + _mod(_start + _count - 1, _cap)) : nullptr; } const T* bottom() const { - return _count ? ((const T*)_items + _mod(_start + _count - 1, _cap)) : NULL; + return _count ? ((const T*)_items + _mod(_start + _count - 1, _cap)) : nullptr; } // Randomly access item from bottom side. // bottom(0) == bottom(), bottom(size()-1) == top() - // Returns NULL if |index| is out of range. + // Returns nullptr if |index| is out of range. T* bottom(size_t index) { if (index < _count) { return (T*)_items + _mod(_start + _count - index - 1, _cap); } - return NULL; // including _count == 0 + return nullptr; // including _count == 0 } const T* bottom(size_t index) const { if (index < _count) { return (const T*)_items + _mod(_start + _count - index - 1, _cap); } - return NULL; // including _count == 0 + return nullptr; // including _count == 0 } bool empty() const { return !_count; } @@ -270,7 +270,7 @@ class BoundedQueue { size_t max_capacity() const { return (1UL << (sizeof(_cap) * 8)) - 1; } // True if the queue was constructed successfully. - bool initialized() const { return _items != NULL; } + bool initialized() const { return _items != nullptr; } // Swap internal fields with another queue. void swap(BoundedQueue& rhs) { diff --git a/src/butil/containers/doubly_buffered_data.h b/src/butil/containers/doubly_buffered_data.h index 8ba54ac051..410da3f0a4 100644 --- a/src/butil/containers/doubly_buffered_data.h +++ b/src/butil/containers/doubly_buffered_data.h @@ -94,7 +94,7 @@ class DoublyBufferedData { class ScopedPtr { friend class DoublyBufferedData; public: - ScopedPtr() : _data(NULL), _index(0), _w(NULL) {} + ScopedPtr() : _data(nullptr), _index(0), _w(nullptr) {} ~ScopedPtr() { if (_w) { if (AllowBthreadSuspended) { @@ -202,7 +202,7 @@ class DoublyBufferedData::WrapperTLSGroup { struct BAIDU_CACHELINE_ALIGNMENT ThreadBlock { WrapperSharedPtr at(size_t offset) { - if (NULL == _data[offset]) { + if (nullptr == _data[offset]) { _data[offset] = std::make_shared(); } return _data[offset]; @@ -237,9 +237,9 @@ class DoublyBufferedData::WrapperTLSGroup { static WrapperSharedPtr get_or_create_tls_data(WrapperTLSId id) { if (BAIDU_UNLIKELY(id < 0)) { CHECK(false) << "Invalid id=" << id; - return NULL; + return nullptr; } - if (_s_tls_blocks == NULL) { + if (_s_tls_blocks == nullptr) { _s_tls_blocks = new std::vector; butil::thread_atexit(_destroy_tls_blocks); } @@ -249,7 +249,7 @@ class DoublyBufferedData::WrapperTLSGroup { _s_tls_blocks->resize(std::max(block_id + 1, 32ul)); } ThreadBlock* tb = (*_s_tls_blocks)[block_id]; - if (tb == NULL) { + if (tb == nullptr) { tb = new ThreadBlock; (*_s_tls_blocks)[block_id] = tb; } @@ -265,7 +265,7 @@ class DoublyBufferedData::WrapperTLSGroup { delete (*_s_tls_blocks)[i]; } delete _s_tls_blocks; - _s_tls_blocks = NULL; + _s_tls_blocks = nullptr; } inline static std::deque& _get_free_ids() { @@ -288,7 +288,7 @@ pthread_mutex_t DoublyBufferedData::WrapperTLSGro template std::deque::WrapperTLSId>* - DoublyBufferedData::WrapperTLSGroup::_s_free_ids = NULL; + DoublyBufferedData::WrapperTLSGroup::_s_free_ids = nullptr; template typename DoublyBufferedData::WrapperTLSId @@ -296,7 +296,7 @@ typename DoublyBufferedData::WrapperTLSId template __thread std::vector::WrapperTLSGroup::ThreadBlock*>* - DoublyBufferedData::WrapperTLSGroup::_s_tls_blocks = NULL; + DoublyBufferedData::WrapperTLSGroup::_s_tls_blocks = nullptr; template class BAIDU_CACHELINE_ALIGNMENT DoublyBufferedData::Wrapper @@ -304,12 +304,12 @@ class BAIDU_CACHELINE_ALIGNMENT DoublyBufferedData typename DoublyBufferedData::WrapperSharedPtr DoublyBufferedData::GetWrapper() { WrapperSharedPtr w = WrapperTLSGroup::get_or_create_tls_data(_wrapper_key); - if (NULL == w) { - return NULL; + if (nullptr == w) { + return nullptr; } if (w->_control == this) { return w; } - if (w->_control != NULL) { + if (w->_control != nullptr) { LOG(FATAL) << "Get wrapper from tls but control != this"; - return NULL; + return nullptr; } try { w->_control = this; @@ -425,7 +425,7 @@ DoublyBufferedData::GetWrapper() { }), _wrappers.end()); } catch (std::exception& e) { - return NULL; + return nullptr; } return w; } @@ -438,11 +438,11 @@ DoublyBufferedData::DoublyBufferedData() "Forbidden to allow bthread suspended with non-Void TLS"); _wrappers.reserve(64); - pthread_mutex_init(&_modify_mutex, NULL); - pthread_mutex_init(&_wrappers_mutex, NULL); + pthread_mutex_init(&_modify_mutex, nullptr); + pthread_mutex_init(&_wrappers_mutex, nullptr); _wrapper_key = WrapperTLSGroup::key_create(); // Initialize _data for some POD types. This is essential for pointer - // types because they should be Read() as NULL before any Modify(). + // types because they should be Read() as nullptr before any Modify(). if (is_integral::value || is_floating_point::value || is_pointer::value || is_member_function_pointer::value) { _data[0] = T(); @@ -459,8 +459,8 @@ DoublyBufferedData::~DoublyBufferedData() { BAIDU_SCOPED_LOCK(_wrappers_mutex); for (size_t i = 0; i < _wrappers.size(); ++i) { WrapperSharedPtr w = _wrappers[i].lock(); - if (NULL != w) { - w->_control = NULL; // hack: disable removal. + if (nullptr != w) { + w->_control = nullptr; // hack: disable removal. } } _wrappers.clear(); @@ -475,7 +475,7 @@ template int DoublyBufferedData::Read( typename DoublyBufferedData::ScopedPtr* ptr) { WrapperSharedPtr w = GetWrapper(); - if (BAIDU_UNLIKELY(w == NULL)) { + if (BAIDU_UNLIKELY(w == nullptr)) { return -1; } @@ -541,7 +541,7 @@ size_t DoublyBufferedData::Modify(Fn&& fn, Args&& std::remove_if(_wrappers.begin(), _wrappers.end(), [bg_index](const WrapperWeakPtr& weak) { WrapperSharedPtr w = weak.lock(); - bool expired = NULL == w; + bool expired = nullptr == w; if (!expired) { // Notify all threads waiting for read done. if (AllowBthreadSuspended) { diff --git a/src/butil/containers/flat_map.h b/src/butil/containers/flat_map.h index 54981b81e9..ca86dfd79c 100644 --- a/src/butil/containers/flat_map.h +++ b/src/butil/containers/flat_map.h @@ -187,12 +187,12 @@ class FlatMap { // Insert a pair of |key| and |value|. If size()*100/bucket_count() is // more than load_factor(), a resize() will be done. - // Returns address of the inserted value, NULL on error. + // Returns address of the inserted value, nullptr on error. mapped_type* insert(const key_type& key, const mapped_type& value); // Insert a pair of {key, value}. If size()*100/bucket_count() is // more than load_factor(), a resize() will be done. - // Returns address of the inserted value, NULL on error. + // Returns address of the inserted value, nullptr on error. mapped_type* insert(const std::pair& kv); // For `_Multi=false'. (Default) @@ -200,12 +200,12 @@ class FlatMap { // Returns: 1 on erased, 0 otherwise. template typename std::enable_if::type - erase(const K2& key, mapped_type* old_value = NULL); + erase(const K2& key, mapped_type* old_value = nullptr); // For `_Multi=true'. // Returns: num of value on erased, 0 otherwise. template typename std::enable_if::type - erase(const K2& key, std::vector* old_values = NULL); + erase(const K2& key, std::vector* old_values = nullptr); // Remove all items. Allocated spaces are NOT returned by system. void clear(); @@ -269,7 +269,7 @@ class FlatMap { const_iterator restore_iterator(const PositionHint&) const; // Always returns true. - bool initialized() const { return _buckets != NULL; } + bool initialized() const { return _buckets != nullptr; } bool empty() const { return _size == 0; } size_t size() const { return _size; } @@ -281,10 +281,10 @@ class FlatMap { struct Bucket { Bucket() : next((Bucket*)-1UL) {} - explicit Bucket(const _K& k) : next(NULL) { + explicit Bucket(const _K& k) : next(nullptr) { element_space_.Init(k); } - Bucket(const Bucket& other) : next(NULL) { + Bucket(const Bucket& other) : next(nullptr) { element_space_.Init(other.element()); } @@ -322,7 +322,7 @@ template friend class SparseFlatMapIterator; struct NewBucketsInfo { NewBucketsInfo() - : buckets(NULL), thumbnail(NULL), nbucket(0) {} + : buckets(nullptr), thumbnail(nullptr), nbucket(0) {} NewBucketsInfo(Bucket* b, uint64_t* t, size_t n) : buckets(b), thumbnail(t), nbucket(n) {} @@ -370,7 +370,7 @@ template friend class SparseFlatMapIterator; for (size_t i = 0; i < nbucket; ++i) { buckets[i].set_invalid(); } - buckets[nbucket].next = NULL; + buckets[nbucket].next = nullptr; if (_Sparse) { bit_array_clear(thumbnail, nbucket); } @@ -431,7 +431,7 @@ class FlatSet { { return _map.insert(key, FlatMapVoid()); } template - size_t erase(const K2& key) { return _map.erase(key, NULL); } + size_t erase(const K2& key) { return _map.erase(key, nullptr); } void clear() { return _map.clear(); } void clear_and_reset_pool() { return _map.clear_and_reset_pool(); } diff --git a/src/butil/containers/flat_map_inl.h b/src/butil/containers/flat_map_inl.h index 93bcbf9d51..d14d0db536 100644 --- a/src/butil/containers/flat_map_inl.h +++ b/src/butil/containers/flat_map_inl.h @@ -88,7 +88,7 @@ template class FlatMapIterator { typedef ptrdiff_t difference_type; typedef typename remove_const::type NonConstValue; - FlatMapIterator() : _node(NULL), _entry(NULL) {} + FlatMapIterator() : _node(nullptr), _entry(nullptr) {} FlatMapIterator(const Map* map, size_t pos) { _entry = map->_buckets + pos; find_and_set_valid_node(); @@ -107,7 +107,7 @@ template class FlatMapIterator { // ++ it FlatMapIterator& operator++() { - if (NULL == _node->next) { + if (nullptr == _node->next) { ++_entry; find_and_set_valid_node(); } else { @@ -156,7 +156,7 @@ template class SparseFlatMapIterator { typedef ptrdiff_t difference_type; typedef typename remove_const::type NonConstValue; - SparseFlatMapIterator() : _node(NULL), _pos(0), _map(NULL) {} + SparseFlatMapIterator() : _node(nullptr), _pos(0), _map(nullptr) {} SparseFlatMapIterator(const Map* map, size_t pos) { _map = map; _pos = pos; @@ -177,7 +177,7 @@ template class SparseFlatMapIterator { // ++ it SparseFlatMapIterator& operator++() { - if (NULL == _node->next) { + if (nullptr == _node->next) { ++_pos; find_and_set_valid_node(); } else { @@ -221,7 +221,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::FlatMap(const hasher& hashfn, : _size(0) , _nbucket(DEFAULT_NBUCKET) , _buckets((Bucket*)(&_default_buckets)) - , _thumbnail(_S ? _default_thumbnail : NULL) + , _thumbnail(_S ? _default_thumbnail : nullptr) , _load_factor(80) , _is_default_load_factor(true) , _hashfn(hashfn) @@ -246,9 +246,9 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::~FlatMap() { clear(); if (!is_default_buckets()) { get_allocator().Free(_buckets); - _buckets = NULL; + _buckets = nullptr; bit_array_free(_thumbnail); - _thumbnail = NULL; + _thumbnail = nullptr; } _nbucket = 0; _load_factor = 0; @@ -304,7 +304,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::operator=( } } } - _buckets[rhs._nbucket].next = NULL; + _buckets[rhs._nbucket].next = nullptr; _size = rhs._size; } else { for (const_iterator it = rhs.begin(); it != rhs.end(); ++it) { @@ -396,7 +396,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::erase(const K2& key, _T* old_value) { if (old_value) { *old_value = first_node.element().second_movable_ref(); } - if (first_node.next == NULL) { + if (first_node.next == nullptr) { first_node.destroy_element(); first_node.set_invalid(); if (_S) { @@ -459,13 +459,13 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::erase( return 0; } - Bucket* new_head = NULL; - Bucket* new_tail = NULL; + Bucket* new_head = nullptr; + Bucket* new_tail = nullptr; Bucket* p = &first_node; size_t total = _size; - while (NULL != p) { + while (nullptr != p) { if (_eql(p->element().first_ref(), key)) { - if (NULL != old_values) { + if (nullptr != old_values) { old_values->push_back(p->element().second_movable_ref()); } Bucket* temp = p; @@ -476,7 +476,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::erase( } --_size; } else { - if (NULL == new_head) { + if (nullptr == new_head) { new_head = p; new_tail = p; } else { @@ -486,10 +486,10 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::erase( p = p->next; } } - if (NULL != new_tail) { - new_tail->next = NULL; + if (nullptr != new_tail) { + new_tail->next = nullptr; } - if (NULL == new_head) { + if (nullptr == new_head) { // Erase all element. first_node.set_invalid(); if (_S) { @@ -514,7 +514,7 @@ void FlatMap<_K, _T, _H, _E, _S, _A, _M>::clear() { return; } _size = 0; - if (NULL != _buckets) { + if (nullptr != _buckets) { for (size_t i = 0; i < _nbucket; ++i) { Bucket& first_node = _buckets[i]; if (first_node.is_valid()) { @@ -530,7 +530,7 @@ void FlatMap<_K, _T, _H, _E, _S, _A, _M>::clear() { } } } - if (NULL != _thumbnail) { + if (nullptr != _thumbnail) { bit_array_clear(_thumbnail, _nbucket); } } @@ -548,7 +548,7 @@ template _T* FlatMap<_K, _T, _H, _E, _S, _A, _M>::seek(const K2& key) const { Bucket& first_node = _buckets[flatmap_mod(_hashfn(key), _nbucket)]; if (!first_node.is_valid()) { - return NULL; + return nullptr; } if (_eql(first_node.element().first_ref(), key)) { return &first_node.element().second_ref(); @@ -560,7 +560,7 @@ _T* FlatMap<_K, _T, _H, _E, _S, _A, _M>::seek(const K2& key) const { } p = p->next; } - return NULL; + return nullptr; } template ::operator[](const key_type& key) { if (_eql(p->element().first_ref(), key)) { return p->element().second_ref(); } - if (NULL == p->next) { + if (nullptr == p->next) { if (is_too_crowded(_size) && resize(_nbucket + 1)) { return operator[](key); } @@ -637,7 +637,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::operator[](const key_type& key) { if (is_too_crowded(_size)) { Bucket *p = &first_node; bool need_scale = false; - while (NULL != p) { + while (nullptr != p) { // Increase the capacity of bucket when // hash collision occur and map is crowded. if (!_eql(p->element().first_ref(), key)) { @@ -731,15 +731,15 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::new_buckets_and_thumbnail(size_t size, auto guard = MakeScopeGuard([buckets, this]() { get_allocator().Free(buckets); }); - if (NULL == buckets) { + if (nullptr == buckets) { LOG(FATAL) << "Fail to new Buckets"; return nullopt; } - uint64_t* thumbnail = NULL; + uint64_t* thumbnail = nullptr; if (_S) { thumbnail = bit_array_malloc(new_nbucket); - if (NULL == thumbnail) { + if (nullptr == thumbnail) { LOG(FATAL) << "Fail to new thumbnail"; return nullopt; } diff --git a/src/butil/containers/linked_list.h b/src/butil/containers/linked_list.h index 7874b65aaf..c15cabdcb5 100644 --- a/src/butil/containers/linked_list.h +++ b/src/butil/containers/linked_list.h @@ -128,7 +128,7 @@ class LinkNode { void RemoveFromList() { this->previous_->next_ = this->next_; this->next_->previous_ = this->previous_; - // next() and previous() return non-NULL if and only this node is not in any + // next() and previous() return non-nullptr if and only this node is not in any // list. this->next_ = this; this->previous_ = this; diff --git a/src/butil/containers/mpsc_queue.h b/src/butil/containers/mpsc_queue.h index 6ba09db376..505b0a27f9 100644 --- a/src/butil/containers/mpsc_queue.h +++ b/src/butil/containers/mpsc_queue.h @@ -32,7 +32,7 @@ template struct BAIDU_CACHELINE_ALIGNMENT MPSCQueueNode { static MPSCQueueNode* const UNCONNECTED; - MPSCQueueNode* next{NULL}; + MPSCQueueNode* next{nullptr}; ManualConstructor data_mem; }; @@ -60,9 +60,9 @@ template > class MPSCQueue { public: MPSCQueue() - : _head(NULL) - , _cur_enqueue_node(NULL) - , _cur_dequeue_node(NULL) {} + : _head(nullptr) + , _cur_enqueue_node(nullptr) + , _cur_dequeue_node(nullptr) {} ~MPSCQueue(); @@ -88,7 +88,7 @@ class MPSCQueue { template MPSCQueue::~MPSCQueue() { - while (DequeueImpl(NULL)); + while (DequeueImpl(nullptr)); } template @@ -114,7 +114,7 @@ void MPSCQueue::EnqueueImpl(MPSCQueueNode* node) { node->next = prev; return; } - node->next = NULL; + node->next = nullptr; _cur_enqueue_node.store(node, memory_order_relaxed); } @@ -129,7 +129,7 @@ bool MPSCQueue::DequeueImpl(T* data) { if (_cur_dequeue_node) { node = _cur_dequeue_node; } else { - node = _cur_enqueue_node.exchange(NULL, memory_order_relaxed); + node = _cur_enqueue_node.exchange(nullptr, memory_order_relaxed); } if (!node) { return false; @@ -151,9 +151,9 @@ bool MPSCQueue::DequeueImpl(T* data) { template void MPSCQueue::ReverseList(MPSCQueueNode* old_head) { - // Try to set _write_head to NULL to mark that it is done. + // Try to set _write_head to nullptr to mark that it is done. MPSCQueueNode* new_head = old_head; - MPSCQueueNode* desired = NULL; + MPSCQueueNode* desired = nullptr; if (_head.compare_exchange_strong( new_head, desired, memory_order_acquire)) { // No one added new requests. @@ -165,7 +165,7 @@ void MPSCQueue::ReverseList(MPSCQueueNode* old_head) { // Someone added new requests. // Reverse the list until old_head. - MPSCQueueNode* tail = NULL; + MPSCQueueNode* tail = nullptr; MPSCQueueNode* p = new_head; do { while (p->next == MPSCQueueNode::UNCONNECTED) { diff --git a/src/butil/containers/scoped_ptr_hash_map.h b/src/butil/containers/scoped_ptr_hash_map.h index a24e8722e0..d69b96a090 100644 --- a/src/butil/containers/scoped_ptr_hash_map.h +++ b/src/butil/containers/scoped_ptr_hash_map.h @@ -78,7 +78,7 @@ class ScopedPtrHashMap { return scoped_ptr(); scoped_ptr ret(it->second); - it->second = NULL; + it->second = nullptr; return ret.Pass(); } @@ -109,11 +109,11 @@ class ScopedPtrHashMap { } // Returns the element in the hash_map that matches the given key. - // If no such element exists it returns NULL. + // If no such element exists it returns nullptr. Value* get(const Key& k) const { const_iterator it = find(k); if (it == end()) - return NULL; + return nullptr; return it->second; } diff --git a/src/butil/containers/small_map.h b/src/butil/containers/small_map.h index 4b619a11dd..83ea6f2bb3 100644 --- a/src/butil/containers/small_map.h +++ b/src/butil/containers/small_map.h @@ -229,10 +229,10 @@ class SmallMap { typedef typename NormalMap::iterator::pointer pointer; typedef typename NormalMap::iterator::reference reference; - inline iterator(): array_iter_(NULL) {} + inline iterator(): array_iter_(nullptr) {} inline iterator& operator++() { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { ++array_iter_; } else { ++hash_iter_; @@ -245,7 +245,7 @@ class SmallMap { return result; } inline iterator& operator--() { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { --array_iter_; } else { --hash_iter_; @@ -258,7 +258,7 @@ class SmallMap { return result; } inline value_type* operator->() const { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { return array_iter_->get(); } else { return hash_iter_.operator->(); @@ -266,7 +266,7 @@ class SmallMap { } inline value_type& operator*() const { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { return *array_iter_->get(); } else { return *hash_iter_; @@ -274,10 +274,10 @@ class SmallMap { } inline bool operator==(const iterator& other) const { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { return array_iter_ == other.array_iter_; } else { - return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; + return other.array_iter_ == nullptr && hash_iter_ == other.hash_iter_; } } @@ -294,7 +294,7 @@ class SmallMap { inline explicit iterator(ManualConstructor* init) : array_iter_(init) {} inline explicit iterator(const typename NormalMap::iterator& init) - : array_iter_(NULL), hash_iter_(init) {} + : array_iter_(nullptr), hash_iter_(init) {} ManualConstructor* array_iter_; typename NormalMap::iterator hash_iter_; @@ -309,13 +309,13 @@ class SmallMap { typedef typename NormalMap::const_iterator::pointer pointer; typedef typename NormalMap::const_iterator::reference reference; - inline const_iterator(): array_iter_(NULL) {} + inline const_iterator(): array_iter_(nullptr) {} // Non-explicit ctor lets us convert regular iterators to const iterators inline const_iterator(const iterator& other) : array_iter_(other.array_iter_), hash_iter_(other.hash_iter_) {} inline const_iterator& operator++() { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { ++array_iter_; } else { ++hash_iter_; @@ -329,7 +329,7 @@ class SmallMap { } inline const_iterator& operator--() { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { --array_iter_; } else { --hash_iter_; @@ -343,7 +343,7 @@ class SmallMap { } inline const value_type* operator->() const { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { return array_iter_->get(); } else { return hash_iter_.operator->(); @@ -351,7 +351,7 @@ class SmallMap { } inline const value_type& operator*() const { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { return *array_iter_->get(); } else { return *hash_iter_; @@ -359,10 +359,10 @@ class SmallMap { } inline bool operator==(const const_iterator& other) const { - if (array_iter_ != NULL) { + if (array_iter_ != nullptr) { return array_iter_ == other.array_iter_; } else { - return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; + return other.array_iter_ == nullptr && hash_iter_ == other.hash_iter_; } } @@ -377,7 +377,7 @@ class SmallMap { : array_iter_(init) {} inline explicit const_iterator( const typename NormalMap::const_iterator& init) - : array_iter_(NULL), hash_iter_(init) {} + : array_iter_(nullptr), hash_iter_(init) {} const ManualConstructor* array_iter_; typename NormalMap::const_iterator hash_iter_; diff --git a/src/butil/containers/stack_container.h b/src/butil/containers/stack_container.h index 5679ab8636..b7c5d9b03c 100644 --- a/src/butil/containers/stack_container.h +++ b/src/butil/containers/stack_container.h @@ -93,14 +93,14 @@ class StackAllocator : public std::allocator { // iff sizeof(T) == sizeof(U). template StackAllocator(const StackAllocator& other) - : source_(NULL) { + : source_(nullptr) { } // This constructor must exist. It creates a default allocator that doesn't // actually have a stack buffer. glibc's std::string() will compare the // current allocator against the default-constructed allocator, so this // should be fast. - StackAllocator() : source_(NULL) { + StackAllocator() : source_(nullptr) { } explicit StackAllocator(Source* source) : source_(source) { @@ -110,7 +110,7 @@ class StackAllocator : public std::allocator { // and the size requested fits. Otherwise, fall through to the standard // allocator. pointer allocate(size_type n, void* hint = 0) { - if (source_ != NULL && !source_->used_stack_buffer_ + if (source_ != nullptr && !source_->used_stack_buffer_ && n <= stack_capacity) { source_->used_stack_buffer_ = true; return source_->stack_buffer(); @@ -127,7 +127,7 @@ class StackAllocator : public std::allocator { // Free: when trying to free the stack buffer, just mark it as free. For // non-stack-buffer pointers, just fall though to the standard allocator. void deallocate(pointer p, size_type n) { - if (source_ != NULL && p == source_->stack_buffer()) + if (source_ != nullptr && p == source_->stack_buffer()) source_->used_stack_buffer_ = false; else std::allocator::deallocate(p, n); diff --git a/src/butil/debug/crash_logging.cc b/src/butil/debug/crash_logging.cc index d17e9c0e5f..6bd2f85cfc 100644 --- a/src/butil/debug/crash_logging.cc +++ b/src/butil/debug/crash_logging.cc @@ -20,7 +20,7 @@ namespace { // Global map of crash key names to registration entries. typedef std::map CrashKeyMap; -CrashKeyMap* g_crash_keys_ = NULL; +CrashKeyMap* g_crash_keys_ = nullptr; // The maximum length of a single chunk. size_t g_chunk_max_length_ = 0; @@ -30,8 +30,8 @@ const char kChunkFormatString[] = "%s-%" PRIuS; // The functions that are called to actually set the key-value pairs in the // crash reportng system. -SetCrashKeyValueFuncT g_set_key_func_ = NULL; -ClearCrashKeyValueFuncT g_clear_key_func_ = NULL; +SetCrashKeyValueFuncT g_set_key_func_ = nullptr; +ClearCrashKeyValueFuncT g_clear_key_func_ = nullptr; // For a given |length|, computes the number of chunks a value of that size // will occupy. @@ -142,7 +142,7 @@ size_t InitCrashKeys(const CrashKey* const keys, size_t count, DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once"; if (!keys) { delete g_crash_keys_; - g_crash_keys_ = NULL; + g_crash_keys_ = nullptr; return 0; } @@ -163,10 +163,10 @@ size_t InitCrashKeys(const CrashKey* const keys, size_t count, const CrashKey* LookupCrashKey(const butil::StringPiece& key) { if (!g_crash_keys_) - return NULL; + return nullptr; CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string()); if (it == g_crash_keys_->end()) - return NULL; + return nullptr; return &(it->second); } @@ -192,10 +192,10 @@ std::vector ChunkCrashKeyValue(const CrashKey& crash_key, void ResetCrashLoggingForTesting() { delete g_crash_keys_; - g_crash_keys_ = NULL; + g_crash_keys_ = nullptr; g_chunk_max_length_ = 0; - g_set_key_func_ = NULL; - g_clear_key_func_ = NULL; + g_set_key_func_ = nullptr; + g_clear_key_func_ = nullptr; } } // namespace debug diff --git a/src/butil/debug/crash_logging.h b/src/butil/debug/crash_logging.h index d1cb131d59..a525f07a4c 100644 --- a/src/butil/debug/crash_logging.h +++ b/src/butil/debug/crash_logging.h @@ -73,7 +73,7 @@ struct BUTIL_EXPORT CrashKey { BUTIL_EXPORT size_t InitCrashKeys(const CrashKey* const keys, size_t count, size_t chunk_max_length); -// Returns the correspnding crash key object or NULL for a given key. +// Returns the correspnding crash key object or nullptr for a given key. BUTIL_EXPORT const CrashKey* LookupCrashKey(const butil::StringPiece& key); // In the platform crash reporting implementation, these functions set and diff --git a/src/butil/debug/debugger_posix.cc b/src/butil/debug/debugger_posix.cc index 0e4635339f..c806b845fc 100644 --- a/src/butil/debug/debugger_posix.cc +++ b/src/butil/debug/debugger_posix.cc @@ -92,13 +92,13 @@ bool BeingDebugged() { size_t info_size = sizeof(info); #if defined(OS_OPENBSD) - if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0) + if (sysctl(mib, arraysize(mib), nullptr, &info_size, nullptr, 0) < 0) return -1; mib[5] = (info_size / sizeof(struct kinfo_proc)); #endif - int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0); + int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, nullptr, 0); DCHECK_EQ(sysctl_result, 0); if (sysctl_result != 0) { is_set = true; diff --git a/src/butil/debug/dump_without_crashing.cc b/src/butil/debug/dump_without_crashing.cc index b4b2efcece..4cf074bda5 100644 --- a/src/butil/debug/dump_without_crashing.cc +++ b/src/butil/debug/dump_without_crashing.cc @@ -10,7 +10,7 @@ namespace { // Pointer to the function that's called by DumpWithoutCrashing() to dump the // process's memory. -void (CDECL *dump_without_crashing_function_)() = NULL; +void (CDECL *dump_without_crashing_function_)() = nullptr; } // namespace diff --git a/src/butil/debug/stack_trace.cc b/src/butil/debug/stack_trace.cc index 97a4cd7683..4dc4995736 100644 --- a/src/butil/debug/stack_trace.cc +++ b/src/butil/debug/stack_trace.cc @@ -25,7 +25,7 @@ const void *const *StackTrace::Addresses(size_t* count) const { *count = count_; if (count_) return trace_; - return NULL; + return nullptr; } size_t StackTrace::CopyAddressTo(void** buffer, size_t max_nframes) const { diff --git a/src/butil/debug/stack_trace.h b/src/butil/debug/stack_trace.h index e812058321..991348b159 100644 --- a/src/butil/debug/stack_trace.h +++ b/src/butil/debug/stack_trace.h @@ -104,7 +104,7 @@ namespace internal { // POSIX doesn't define any async-signal safe function for converting // an integer to ASCII. We'll have to define our own version. // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the -// conversion was successful or NULL otherwise. It never writes more than "sz" +// conversion was successful or nullptr otherwise. It never writes more than "sz" // bytes. Output will be truncated as needed, and a NUL character is always // appended. BUTIL_EXPORT char *itoa_r(intptr_t i, diff --git a/src/butil/debug/stack_trace_posix.cc b/src/butil/debug/stack_trace_posix.cc index 9ef91c2f0b..6b556e9a94 100644 --- a/src/butil/debug/stack_trace_posix.cc +++ b/src/butil/debug/stack_trace_posix.cc @@ -98,7 +98,7 @@ void DemangleSymbols(std::string* text) { // Try to demangle the mangled symbol candidate. int status = 0; scoped_ptr demangled_symbol( - abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status)); + abi::__cxa_demangle(mangled_symbol.c_str(), nullptr, 0, &status)); if (status == 0) { // Demangling is successful. // Remove the mangled symbol. text->erase(mangled_start, mangled_end - mangled_start); @@ -436,7 +436,7 @@ class StringBacktraceOutputHandler : public BacktraceOutputHandler { DISALLOW_COPY_AND_ASSIGN(StringBacktraceOutputHandler); void HandleOutput(const char* output) OVERRIDE { - if (NULL == output) { + if (nullptr == output) { return; } _str.append(output); @@ -686,7 +686,7 @@ class SandboxSymbolizeHelper { // Unregister symbolization callback. void UnregisterCallback() { if (is_initialized_) { - google::InstallSymbolizeOpenObjectFileCallback(NULL); + google::InstallSymbolizeOpenObjectFileCallback(nullptr); is_initialized_ = false; } } @@ -739,7 +739,7 @@ bool EnableInProcessStackDumping() { memset(&sigpipe_action, 0, sizeof(sigpipe_action)); sigpipe_action.sa_handler = SIG_IGN; sigemptyset(&sigpipe_action.sa_mask); - bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0); + bool success = (sigaction(SIGPIPE, &sigpipe_action, nullptr) == 0); // Avoid hangs during backtrace initialization, see above. WarmUpBacktrace(); @@ -750,14 +750,14 @@ bool EnableInProcessStackDumping() { action.sa_sigaction = &StackDumpSignalHandler; sigemptyset(&action.sa_mask); - success &= (sigaction(SIGILL, &action, NULL) == 0); - success &= (sigaction(SIGABRT, &action, NULL) == 0); - success &= (sigaction(SIGFPE, &action, NULL) == 0); - success &= (sigaction(SIGBUS, &action, NULL) == 0); - success &= (sigaction(SIGSEGV, &action, NULL) == 0); + success &= (sigaction(SIGILL, &action, nullptr) == 0); + success &= (sigaction(SIGABRT, &action, nullptr) == 0); + success &= (sigaction(SIGFPE, &action, nullptr) == 0); + success &= (sigaction(SIGBUS, &action, nullptr) == 0); + success &= (sigaction(SIGSEGV, &action, nullptr) == 0); // On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing. #if !defined(OS_LINUX) - success &= (sigaction(SIGSYS, &action, NULL) == 0); + success &= (sigaction(SIGSYS, &action, nullptr) == 0); #endif // !defined(OS_LINUX) return success; @@ -832,11 +832,11 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { // Make sure we can write at least one NUL byte. size_t n = 1; if (n > sz) - return NULL; + return nullptr; if (base < 2 || base > 16) { buf[0] = '\000'; - return NULL; + return nullptr; } char *start = buf; @@ -850,7 +850,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { // Make sure we can write the '-' character. if (++n > sz) { buf[0] = '\000'; - return NULL; + return nullptr; } *start++ = '-'; } @@ -862,7 +862,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { // Make sure there is still enough space left in our output buffer. if (++n > sz) { buf[0] = '\000'; - return NULL; + return nullptr; } // Output the next digit. diff --git a/src/butil/details/extended_endpoint.hpp b/src/butil/details/extended_endpoint.hpp index 36a67719b6..ce42534976 100644 --- a/src/butil/details/extended_endpoint.hpp +++ b/src/butil/details/extended_endpoint.hpp @@ -109,51 +109,51 @@ class ExtendedEndPoint { static ExtendedEndPoint* create(StringPiece sp, EndPoint* ep) { sp.trim_spaces(); if (sp.empty()) { - return NULL; + return nullptr; } if (sp[0] == '[') { size_t colon_pos = sp.find(']'); if (colon_pos == StringPiece::npos || colon_pos == 1 /* [] is invalid */ || ++colon_pos >= sp.size()) { - return NULL; + return nullptr; } StringPiece port_sp = sp.substr(colon_pos); if (port_sp.size() < 2 /* colon and at least one integer */ || port_sp[0] != ':') { - return NULL; + return nullptr; } port_sp.remove_prefix(1); // remove `:' if (port_sp.size() > 5) { // max 65535 - return NULL; + return nullptr; } char buf[6]; buf[port_sp.copy(buf, port_sp.size())] = '\0'; - char* end = NULL; + char* end = nullptr; int port = ::strtol(buf, &end, 10 /* base */); if (end != buf + port_sp.size()) { - return NULL; + return nullptr; } return create(sp.substr(0, colon_pos), port, ep); } else if (sp.starts_with("unix:")) { return create(sp, EXTENDED_ENDPOINT_PORT, ep); } - return NULL; + return nullptr; } static ExtendedEndPoint* create(StringPiece sp, int port, EndPoint* ep) { sp.trim_spaces(); if (sp.empty()) { - return NULL; + return nullptr; } - ExtendedEndPoint* eep = NULL; + ExtendedEndPoint* eep = nullptr; if (sp[0] == '[' && port >= 0 && port <= 65535) { if (sp.back() != ']' || sp.size() == 2 || sp.size() - 2 >= INET6_ADDRSTRLEN) { - return NULL; + return nullptr; } char buf[INET6_ADDRSTRLEN]; buf[sp.copy(buf, sp.size() - 2 /* skip `[' and `]' */, 1 /* skip `[' */)] = '\0'; in6_addr addr; if (inet_pton(AF_INET6, buf, &addr) != 1 /* succ */) { - return NULL; + return nullptr; } eep = new_extended_endpoint(AF_INET6); @@ -170,7 +170,7 @@ class ExtendedEndPoint { } else if (sp.starts_with("unix:")) { // ignore port sp.remove_prefix(5); // remove `unix:' if (sp.empty() || sp.size() >= UDS_PATH_SIZE) { - return NULL; + return nullptr; } eep = new_extended_endpoint(AF_UNIX); if (eep) { @@ -190,7 +190,7 @@ class ExtendedEndPoint { } static ExtendedEndPoint* create(sockaddr_storage* ss, socklen_t size, EndPoint* ep) { - ExtendedEndPoint* eep = NULL; + ExtendedEndPoint* eep = nullptr; if (ss->ss_family == AF_INET6 || ss->ss_family == AF_UNIX) { eep = new_extended_endpoint(ss->ss_family); } @@ -211,7 +211,7 @@ class ExtendedEndPoint { // Get ExtendedEndPoint instance from EndPoint static ExtendedEndPoint* address(const EndPoint& ep) { if (!is_extended(ep)) { - return NULL; + return nullptr; } ::butil::ResourceId id; id.value = ep.ip.s_addr; @@ -310,7 +310,7 @@ class ExtendedEndPoint { return 0; } else if (_u.sa.sa_family == AF_INET6) { sockaddr_in6 sa = _u.in6; - if (getnameinfo((const sockaddr*) &sa, sizeof(sa), host, host_len, NULL, 0, NI_NAMEREQD) != 0) { + if (getnameinfo((const sockaddr*) &sa, sizeof(sa), host, host_len, nullptr, 0, NI_NAMEREQD) != 0) { return -1; } size_t len = ::strlen(host); diff --git a/src/butil/endpoint.cpp b/src/butil/endpoint.cpp index 371b418db4..e0ed2afc5b 100644 --- a/src/butil/endpoint.cpp +++ b/src/butil/endpoint.cpp @@ -115,8 +115,8 @@ void EndPoint::operator=(const EndPoint& rhs) { } int str2ip(const char* ip_str, ip_t* ip) { - // ip_str can be NULL when called by EndPoint(0, ...) - if (ip_str != NULL) { + // ip_str can be nullptr when called by EndPoint(0, ...) + if (ip_str != nullptr) { for (; isspace(*ip_str); ++ip_str); int rc = inet_pton(AF_INET, ip_str, ip); if (rc > 0) { @@ -128,14 +128,14 @@ int str2ip(const char* ip_str, ip_t* ip) { IPStr ip2str(ip_t ip) { IPStr str; - if (inet_ntop(AF_INET, &ip, str._buf, INET_ADDRSTRLEN) == NULL) { + if (inet_ntop(AF_INET, &ip, str._buf, INET_ADDRSTRLEN) == nullptr) { return ip2str(IP_NONE); } return str; } int ip2hostname(ip_t ip, char* host, size_t host_len) { - if (host == NULL || host_len == 0) { + if (host == nullptr || host_len == 0) { errno = EINVAL; return -1; } @@ -145,7 +145,7 @@ int ip2hostname(ip_t ip, char* host, size_t host_len) { sa.sin_port = 0; // useless since we don't need server_name sa.sin_addr = ip; if (getnameinfo((const sockaddr*)&sa, sizeof(sa), - host, host_len, NULL, 0, NI_NAMEREQD) != 0) { + host, host_len, nullptr, 0, NI_NAMEREQD) != 0) { return -1; } // remove baidu-specific domain name (that every name has) @@ -176,7 +176,7 @@ EndPointStr endpoint2str(const EndPoint& point) { } return str; } - if (inet_ntop(AF_INET, &point.ip, str._buf, INET_ADDRSTRLEN) == NULL) { + if (inet_ntop(AF_INET, &point.ip, str._buf, INET_ADDRSTRLEN) == nullptr) { return endpoint2str(EndPoint(IP_NONE, 0)); } char* buf = str._buf + strlen(str._buf); @@ -187,7 +187,7 @@ EndPointStr endpoint2str(const EndPoint& point) { int hostname2ip(const char* hostname, ip_t* ip) { char buf[256]; - if (NULL == hostname) { + if (nullptr == hostname) { if (gethostname(buf, sizeof(buf)) < 0) { return -1; } @@ -202,7 +202,7 @@ int hostname2ip(const char* hostname, ip_t* ip) { // returned hostent is TLS. Check following link for the ref: // https://lists.apple.com/archives/darwin-dev/2006/May/msg00008.html struct hostent* result = gethostbyname(hostname); - if (result == NULL) { + if (result == nullptr) { return -1; } #else @@ -211,9 +211,9 @@ int hostname2ip(const char* hostname, ip_t* ip) { int ret = 0; int error = 0; struct hostent ent; - struct hostent* result = NULL; + struct hostent* result = nullptr; do { - result = NULL; + result = nullptr; error = 0; ret = gethostbyname_r(hostname, &ent, @@ -227,7 +227,7 @@ int hostname2ip(const char* hostname, ip_t* ip) { aux_buf_len *= 2; aux_buf.reset(new char[aux_buf_len]); } while (1); - if (ret != 0 || result == NULL) { + if (ret != 0 || result == nullptr) { return -1; } #endif // defined(OS_MACOSX) @@ -283,7 +283,7 @@ int str2endpoint(const char* str, EndPoint* point) { return -1; } ++i; - char* end = NULL; + char* end = nullptr; point->port = strtol(str + i, &end, 10); if (end == str + i) { return -1; @@ -337,7 +337,7 @@ int hostname2endpoint(const char* str, EndPoint* point) { if (str[i] == ':') { ++i; } - char* end = NULL; + char* end = nullptr; point->port = strtol(str + i, &end, 10); if (end == str + i) { return -1; @@ -455,12 +455,12 @@ int pthread_fd_wait(int fd, unsigned events, } pollfd ufds = { fd, poll_events, 0 }; int64_t abstime_us = -1; - if (NULL != abstime) { + if (nullptr != abstime) { abstime_us = butil::timespec_to_microseconds(*abstime); } while (true) { int diff_ms = -1; - if (NULL != abstime) { + if (nullptr != abstime) { int64_t now_us = butil::gettimeofday_us(); if (abstime_us <= now_us) { errno = ETIMEDOUT; @@ -534,13 +534,13 @@ int tcp_connect(const EndPoint& server, int* self_port, int connect_timeout_ms) return -1; } timespec abstime{}; - timespec* abstime_ptr = NULL; + timespec* abstime_ptr = nullptr; if (connect_timeout_ms > 0) { abstime = butil::milliseconds_from_now(connect_timeout_ms); abstime_ptr = &abstime; } int rc; - if (bthread_timed_connect != NULL) { + if (bthread_timed_connect != nullptr) { rc = bthread_timed_connect(sockfd, (struct sockaddr*)&serv_addr, serv_addr_size, abstime_ptr); } else { @@ -550,7 +550,7 @@ int tcp_connect(const EndPoint& server, int* self_port, int connect_timeout_ms) if (rc < 0) { return -1; } - if (self_port != NULL) { + if (self_port != nullptr) { EndPoint pt; if (get_local_side(sockfd, &pt) == 0) { *self_port = pt.port; diff --git a/src/butil/endpoint.h b/src/butil/endpoint.h index 265a241f82..7d58b8705a 100644 --- a/src/butil/endpoint.h +++ b/src/butil/endpoint.h @@ -61,7 +61,7 @@ struct IPStr { // Example: printf("ip=%s\n", ip2str(some_ip).c_str()); IPStr ip2str(ip_t ip); -// Convert `hostname' to ip_t *ip. If `hostname' is NULL, use hostname +// Convert `hostname' to ip_t *ip. If `hostname' is nullptr, use hostname // of this machine. // `hostname' is typically in this form: `tc-cm-et21.tc' `db-cos-dev.db01' ... // Returns 0 on success, -1 otherwise. @@ -128,12 +128,12 @@ int endpoint2hostname(const EndPoint& point, char* hostname, size_t hostname_len int endpoint2hostname(const EndPoint& point, std::string* host); // Create a TCP socket and connect it to `server'. Write port of this side -// into `self_port' if it's not NULL. +// into `self_port' if it's not nullptr. // Returns the socket descriptor, -1 otherwise and errno is set. int tcp_connect(EndPoint server, int* self_port); // Suspend caller thread until connect(2) on `sockfd' succeeds -// or CLOCK_REALTIME reached `abstime' if `abstime' is not NULL. -// Write port of this side into `self_port' if it's not NULL. +// or CLOCK_REALTIME reached `abstime' if `abstime' is not nullptr. +// Write port of this side into `self_port' if it's not nullptr. // Returns the socket descriptor, -1 otherwise and errno is set. int tcp_connect(const EndPoint& server, int* self_port, int connect_timeout_ms); @@ -153,7 +153,7 @@ int get_local_side(int fd, EndPoint *out); int get_remote_side(int fd, EndPoint *out); // Get sockaddr from endpoint, return -1 on failed -int endpoint2sockaddr(const EndPoint& point, struct sockaddr_storage* ss, socklen_t* size = NULL); +int endpoint2sockaddr(const EndPoint& point, struct sockaddr_storage* ss, socklen_t* size = nullptr); // Create endpoint from sockaddr, return -1 on failed int sockaddr2endpoint(struct sockaddr_storage* ss, socklen_t size, EndPoint* point); diff --git a/src/butil/environment.cc b/src/butil/environment.cc index a46fc75cc6..0978036d6a 100644 --- a/src/butil/environment.cc +++ b/src/butil/environment.cc @@ -63,7 +63,7 @@ class EnvironmentImpl : public butil::Environment { return true; #elif defined(OS_WIN) DWORD value_length = ::GetEnvironmentVariable( - UTF8ToWide(variable_name).c_str(), NULL, 0); + UTF8ToWide(variable_name).c_str(), nullptr, 0); if (value_length == 0) return false; if (result) { @@ -95,7 +95,7 @@ class EnvironmentImpl : public butil::Environment { return !unsetenv(variable_name); #elif defined(OS_WIN) // On success, a nonzero value is returned. - return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL); + return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr); #endif } }; @@ -137,7 +137,7 @@ Environment* Environment::Create() { } bool Environment::HasVar(const char* variable_name) { - return GetVar(variable_name, NULL); + return GetVar(variable_name, nullptr); } #if defined(OS_WIN) diff --git a/src/butil/environment.h b/src/butil/environment.h index b0e99c72f3..ff2869de11 100644 --- a/src/butil/environment.h +++ b/src/butil/environment.h @@ -35,7 +35,7 @@ class BUTIL_EXPORT Environment { // Returns false if the key is unset. virtual bool GetVar(const char* variable_name, std::string* result) = 0; - // Syntactic sugar for GetVar(variable_name, NULL); + // Syntactic sugar for GetVar(variable_name, nullptr); virtual bool HasVar(const char* variable_name); // Returns true on success, otherwise returns false. diff --git a/src/butil/file_util.cc b/src/butil/file_util.cc index 6e47020a54..ccd3e7f8b5 100644 --- a/src/butil/file_util.cc +++ b/src/butil/file_util.cc @@ -178,17 +178,17 @@ bool IsDirectoryEmpty(const FilePath& dir_path) { FILE* CreateAndOpenTemporaryFile(FilePath* path) { FilePath directory; if (!GetTempDir(&directory)) - return NULL; + return nullptr; return CreateAndOpenTemporaryFileInDir(directory, path); } bool CreateDirectory(const FilePath& full_path) { - return CreateDirectoryAndGetError(full_path, NULL); + return CreateDirectoryAndGetError(full_path, nullptr); } bool CreateDirectory(const FilePath& full_path, bool create_parent) { - return CreateDirectoryAndGetError(full_path, NULL, create_parent); + return CreateDirectoryAndGetError(full_path, nullptr, create_parent); } bool CreateDirectoryAndGetError(const FilePath& full_path, @@ -223,13 +223,13 @@ bool TouchFile(const FilePath& path, } bool CloseFile(FILE* file) { - if (file == NULL) + if (file == nullptr) return true; return fclose(file) == 0; } bool TruncateFile(FILE* file) { - if (file == NULL) + if (file == nullptr) return false; long current_offset = ftell(file); if (current_offset == -1) diff --git a/src/butil/file_util.h b/src/butil/file_util.h index 4eb164b24d..1a235937cb 100644 --- a/src/butil/file_util.h +++ b/src/butil/file_util.h @@ -90,7 +90,7 @@ BUTIL_EXPORT bool Move(const FilePath& from_path, const FilePath& to_path); // if it doesn't exist. Prefer this function over Move when dealing with // temporary files. On Windows it preserves attributes of the target file. // Returns true on success, leaving *error unchanged. -// Returns false on failure and sets *error appropriately, if it is non-NULL. +// Returns false on failure and sets *error appropriately, if it is non-nullptr. BUTIL_EXPORT bool ReplaceFile(const FilePath& from_path, const FilePath& to_path, File::Error* error); @@ -141,7 +141,7 @@ BUTIL_EXPORT bool TextContentsEqual(const FilePath& filename1, // components ('..') is treated as a read error and |contents| is set to empty. // In case of I/O error, |contents| holds the data that could be read from the // file before the error occurred. -// |contents| may be NULL, in which case this function is useful for its side +// |contents| may be nullptr, in which case this function is useful for its side // effect of priming the disk cache (could be used for unit tests). BUTIL_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents); @@ -152,7 +152,7 @@ BUTIL_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents); // file before the error occurred. When the file size exceeds |max_size|, the // function returns false with |contents| holding the file truncated to // |max_size|. -// |contents| may be NULL, in which case this function is useful for its side +// |contents| may be nullptr, in which case this function is useful for its side // effect of priming the disk cache (could be used for unit tests). BUTIL_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents, @@ -232,7 +232,7 @@ BUTIL_EXPORT bool CreateTemporaryFileInDir(const FilePath& dir, // Create and open a temporary file. File is opened for read/write. // The full path is placed in |path|. -// Returns a handle to the opened file or NULL if an error occurred. +// Returns a handle to the opened file or nullptr if an error occurred. BUTIL_EXPORT FILE* CreateAndOpenTemporaryFile(FilePath* path); // Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|. @@ -259,7 +259,7 @@ BUTIL_EXPORT bool CreateTemporaryDirInDir(const FilePath& base_dir, // Returns 'true' on successful creation, or if the directory already exists. // The directory is readable for all the users. // Returns true on success, leaving *error unchanged. -// Returns false on failure and sets *error appropriately, if it is non-NULL. +// Returns false on failure and sets *error appropriately, if it is non-nullptr. BUTIL_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path, File::Error* error); BUTIL_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path, @@ -309,7 +309,7 @@ BUTIL_EXPORT bool TouchFile(const FilePath& path, const Time& last_accessed, const Time& last_modified); -// Wrapper for fopen-like calls. Returns non-NULL FILE* on success. +// Wrapper for fopen-like calls. Returns non-nullptr FILE* on success. BUTIL_EXPORT FILE* OpenFile(const FilePath& filename, const char* mode); // Closes file opened by OpenFile. Returns true on success. diff --git a/src/butil/file_util_mac.mm b/src/butil/file_util_mac.mm index 25a731b912..387f9ebbef 100644 --- a/src/butil/file_util_mac.mm +++ b/src/butil/file_util_mac.mm @@ -19,7 +19,7 @@ bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) { ThreadRestrictions::AssertIOAllowed(); return (copyfile(from_path.value().c_str(), - to_path.value().c_str(), NULL, COPYFILE_DATA) == 0); + to_path.value().c_str(), nullptr, COPYFILE_DATA) == 0); } } // namespace internal diff --git a/src/butil/file_util_posix.cc b/src/butil/file_util_posix.cc index 322e48a0ab..a7bd5c57b3 100644 --- a/src/butil/file_util_posix.cc +++ b/src/butil/file_util_posix.cc @@ -171,7 +171,7 @@ bool DetermineDevShmExecutable() { CHECK_GE(sysconf_result, 0); size_t pagesize = static_cast(sysconf_result); CHECK_GE(sizeof(pagesize), sizeof(sysconf_result)); - void* mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd.get(), 0); + void* mapping = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, fd.get(), 0); if (mapping != MAP_FAILED) { if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) result = true; @@ -187,7 +187,7 @@ bool DetermineDevShmExecutable() { FilePath MakeAbsoluteFilePath(const FilePath& input) { ThreadRestrictions::AssertIOAllowed(); char full_path[PATH_MAX]; - if (realpath(input.value().c_str(), full_path) == NULL) + if (realpath(input.value().c_str(), full_path) == nullptr) return FilePath(); return FilePath(full_path); } @@ -501,7 +501,7 @@ bool CreateTemporaryFile(FilePath* path) { FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { int fd = CreateAndOpenFdForTemporaryFile(dir, path); if (fd < 0) - return NULL; + return nullptr; FILE* file = fdopen(fd, "a+"); if (!file) @@ -667,7 +667,7 @@ bool GetFileInfo(const FilePath& file_path, File::Info* results) { FILE* OpenFile(const FilePath& filename, const char* mode) { ThreadRestrictions::AssertIOAllowed(); - FILE* result = NULL; + FILE* result = nullptr; do { result = fopen(filename.value().c_str(), mode); } while (!result && errno == EINTR); diff --git a/src/butil/files/dir_reader_linux.h b/src/butil/files/dir_reader_linux.h index c7015464d4..72d486a609 100644 --- a/src/butil/files/dir_reader_linux.h +++ b/src/butil/files/dir_reader_linux.h @@ -70,7 +70,7 @@ class DirReaderLinux { const char* name() const { if (!size_) - return NULL; + return nullptr; const linux_dirent* dirent = reinterpret_cast(&buf_[offset_]); diff --git a/src/butil/files/dir_reader_unix.h b/src/butil/files/dir_reader_unix.h index 3c25f7929b..51c9eaa834 100644 --- a/src/butil/files/dir_reader_unix.h +++ b/src/butil/files/dir_reader_unix.h @@ -37,14 +37,14 @@ class DirReaderUnix { public: explicit DirReaderUnix(const char* directory_path) : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)), - dir_(NULL),current_(NULL) { + dir_(nullptr),current_(nullptr) { dir_ = fdopendir(fd_); } ~DirReaderUnix() { - if (NULL != dir_) { + if (nullptr != dir_) { if (IGNORE_EINTR(closedir(dir_)) == 0) { // this implicitly closes fd_ - dir_ = NULL; + dir_ = nullptr; } else { RAW_LOG(ERROR, "Failed to close directory."); } @@ -52,21 +52,21 @@ class DirReaderUnix { } bool IsValid() const { - return dir_ != NULL; + return dir_ != nullptr; } // Move to the next entry returning false if the iteration is complete. bool Next() { int err = readdir_r(dir_,&entry_, ¤t_); - if(0 != err || NULL == current_){ + if(0 != err || nullptr == current_){ return false; } return true; } const char* name() const { - if (NULL == current_) - return NULL; + if (nullptr == current_) + return nullptr; return current_->d_name; } diff --git a/src/butil/files/file_path.cc b/src/butil/files/file_path.cc index e6188546a7..c5176af7c3 100644 --- a/src/butil/files/file_path.cc +++ b/src/butil/files/file_path.cc @@ -253,7 +253,7 @@ void FilePath::GetComponents(std::vector* components) const { } bool FilePath::IsParent(const FilePath& child) const { - return AppendRelativePath(child, NULL); + return AppendRelativePath(child, nullptr); } bool FilePath::AppendRelativePath(const FilePath& child, @@ -292,7 +292,7 @@ bool FilePath::AppendRelativePath(const FilePath& child, ++child_comp; } - if (path != NULL) { + if (path != nullptr) { for (; child_comp != child_components.end(); ++child_comp) { *path = path->Append(*child_comp); } @@ -1159,7 +1159,7 @@ int FilePath::HFSFastUnicodeCompare(const StringType& string1, StringType FilePath::GetHFSDecomposedForm(const StringType& string) { ScopedCFTypeRef cfstring( CFStringCreateWithBytesNoCopy( - NULL, + nullptr, reinterpret_cast(string.c_str()), string.length(), kCFStringEncodingUTF8, @@ -1206,7 +1206,7 @@ int FilePath::CompareIgnoreCase(const StringType& string1, NOTREACHED(); ScopedCFTypeRef cfstring1( CFStringCreateWithBytesNoCopy( - NULL, + nullptr, reinterpret_cast(string1.c_str()), string1.length(), kCFStringEncodingUTF8, @@ -1214,7 +1214,7 @@ int FilePath::CompareIgnoreCase(const StringType& string1, kCFAllocatorNull)); ScopedCFTypeRef cfstring2( CFStringCreateWithBytesNoCopy( - NULL, + nullptr, reinterpret_cast(string2.c_str()), string2.length(), kCFStringEncodingUTF8, diff --git a/src/butil/files/file_path.h b/src/butil/files/file_path.h index c91f1f5afc..a8e9a55afb 100644 --- a/src/butil/files/file_path.h +++ b/src/butil/files/file_path.h @@ -202,7 +202,7 @@ class BUTIL_EXPORT FilePath { // parent. bool IsParent(const FilePath& child) const; - // If IsParent(child) holds, appends to path (if non-NULL) the + // If IsParent(child) holds, appends to path (if non-nullptr) the // relative path to child and returns true. For example, if parent // holds "/Users/johndoe/Library/Application Support", child holds // "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and diff --git a/src/butil/files/file_watcher.cpp b/src/butil/files/file_watcher.cpp index 5c697652f3..ad841569d9 100644 --- a/src/butil/files/file_watcher.cpp +++ b/src/butil/files/file_watcher.cpp @@ -33,12 +33,12 @@ int FileWatcher::init(const char* file_path) { if (init_from_not_exist(file_path) != 0) { return -1; } - check_and_consume(NULL); + check_and_consume(nullptr); return 0; } int FileWatcher::init_from_not_exist(const char* file_path) { - if (NULL == file_path) { + if (nullptr == file_path) { return -1; } if (!_file_path.empty()) { diff --git a/src/butil/files/file_watcher.h b/src/butil/files/file_watcher.h index 548e70b016..1b65282aa9 100644 --- a/src/butil/files/file_watcher.h +++ b/src/butil/files/file_watcher.h @@ -55,7 +55,7 @@ class FileWatcher { int init_from_not_exist(const char* file_path); // Check and consume change of the watched file. Write `last_timestamp' - // if it's not NULL. + // if it's not nullptr. // Returns: // CREATE the file is created since last call to this method. // UPDATED the file is modified since last call. @@ -64,7 +64,7 @@ class FileWatcher { // Note: If the file is updated too frequently, this method may return // UNCHANGED due to precision of stat(2) and the file system. If the file // is created and deleted too frequently, the event may not be detected. - Change check_and_consume(Timestamp* last_timestamp = NULL); + Change check_and_consume(Timestamp* last_timestamp = nullptr); // Set internal timestamp. User can use this method to make // check_and_consume() replay the change. diff --git a/src/butil/files/memory_mapped_file.cc b/src/butil/files/memory_mapped_file.cc index 95dae4f260..8f0e8f8d87 100644 --- a/src/butil/files/memory_mapped_file.cc +++ b/src/butil/files/memory_mapped_file.cc @@ -47,7 +47,7 @@ bool MemoryMappedFile::Initialize(File file) { } bool MemoryMappedFile::IsValid() const { - return data_ != NULL; + return data_ != nullptr; } } // namespace butil diff --git a/src/butil/files/memory_mapped_file_posix.cc b/src/butil/files/memory_mapped_file_posix.cc index 2901ac3d1d..0ce863c305 100644 --- a/src/butil/files/memory_mapped_file_posix.cc +++ b/src/butil/files/memory_mapped_file_posix.cc @@ -13,7 +13,7 @@ namespace butil { -MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) { +MemoryMappedFile::MemoryMappedFile() : data_(nullptr), length_(0) { } bool MemoryMappedFile::MapFileToMemory() { @@ -27,7 +27,7 @@ bool MemoryMappedFile::MapFileToMemory() { length_ = file_stat.st_size; data_ = static_cast( - mmap(NULL, length_, PROT_READ, MAP_SHARED, file_.GetPlatformFile(), 0)); + mmap(nullptr, length_, PROT_READ, MAP_SHARED, file_.GetPlatformFile(), 0)); if (data_ == MAP_FAILED) DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); @@ -37,11 +37,11 @@ bool MemoryMappedFile::MapFileToMemory() { void MemoryMappedFile::CloseHandles() { ThreadRestrictions::AssertIOAllowed(); - if (data_ != NULL) + if (data_ != nullptr) munmap(data_, length_); file_.Close(); - data_ = NULL; + data_ = nullptr; length_ = 0; } diff --git a/src/butil/files/scoped_file.h b/src/butil/files/scoped_file.h index 4d4d6ea1ad..1e6b93a729 100644 --- a/src/butil/files/scoped_file.h +++ b/src/butil/files/scoped_file.h @@ -49,10 +49,10 @@ typedef ScopedGeneric ScopedFD; class ScopedFILE { MOVE_ONLY_TYPE_FOR_CPP_03(ScopedFILE, RValue); public: - ScopedFILE() : _fp(NULL) {} + ScopedFILE() : _fp(nullptr) {} // Open file at |path| with |mode|. - // If fopen failed, operator FILE* returns NULL and errno is set. + // If fopen failed, operator FILE* returns nullptr and errno is set. ScopedFILE(const char *path, const char *mode) { _fp = fopen(path, mode); } @@ -63,13 +63,13 @@ class ScopedFILE { ScopedFILE(RValue rvalue) { _fp = rvalue.object->_fp; - rvalue.object->_fp = NULL; + rvalue.object->_fp = nullptr; } ~ScopedFILE() { - if (_fp != NULL) { + if (_fp != nullptr) { fclose(_fp); - _fp = NULL; + _fp = nullptr; } } @@ -78,20 +78,20 @@ class ScopedFILE { reset(fopen(path, mode)); } - void reset() { reset(NULL); } + void reset() { reset(nullptr); } void reset(FILE *fp) { - if (_fp != NULL) { + if (_fp != nullptr) { fclose(_fp); - _fp = NULL; + _fp = nullptr; } _fp = fp; } - // Set internal FILE* to NULL and return previous value. + // Set internal FILE* to nullptr and return previous value. FILE* release() { FILE* const prev_fp = _fp; - _fp = NULL; + _fp = nullptr; return prev_fp; } diff --git a/src/butil/files/temp_file.cpp b/src/butil/files/temp_file.cpp index d48499a0a4..234ec7f3e9 100644 --- a/src/butil/files/temp_file.cpp +++ b/src/butil/files/temp_file.cpp @@ -45,7 +45,7 @@ TempFile::TempFile() : _ever_opened(0) { } TempFile::TempFile(const char* ext) { - if (NULL == ext || '\0' == *ext) { + if (nullptr == ext || '\0' == *ext) { new (this) TempFile(); return; } diff --git a/src/butil/gperftools_profiler.h b/src/butil/gperftools_profiler.h index 893fd60d0b..75c8ecae2c 100644 --- a/src/butil/gperftools_profiler.h +++ b/src/butil/gperftools_profiler.h @@ -55,7 +55,7 @@ extern "C" { /* Start profiling and write profile info into fname, discarding any * existing profiling data in that file. * - * This is equivalent to calling ProfilerStartWithOptions(fname, NULL). + * This is equivalent to calling ProfilerStartWithOptions(fname, nullptr). */ BRPC_DLL_DECL int ProfilerStart(const char* fname); diff --git a/src/butil/iobuf.cpp b/src/butil/iobuf.cpp index be751d318c..685a7a4982 100644 --- a/src/butil/iobuf.cpp +++ b/src/butil/iobuf.cpp @@ -280,11 +280,11 @@ uint32_t block_size(IOBuf::Block const* b) { inline IOBuf::Block* create_block_aligned(size_t block_size, size_t alignment) { if (block_size > 0xFFFFFFFFULL) { LOG(FATAL) << "block_size=" << block_size << " is too large"; - return NULL; + return nullptr; } char* mem = (char*)iobuf::blockmem_allocate(block_size); - if (mem == NULL) { - return NULL; + if (mem == nullptr) { + return nullptr; } char* data = mem + sizeof(IOBuf::Block); // change data pointer & data size make align satisfied @@ -296,7 +296,7 @@ inline IOBuf::Block* create_block_aligned(size_t block_size, size_t alignment) { // === Share TLS blocks between appending operations === -static __thread TLSData g_tls_data = { NULL, 0, false }; +static __thread TLSData g_tls_data = { nullptr, 0, false }; // Used in release_tls_block() TLSData* get_g_tls_data() { return &g_tls_data; } @@ -324,7 +324,7 @@ void remove_tls_block_chain() { if (!b) { return; } - tls_data.block_head = NULL; + tls_data.block_head = nullptr; int n = 0; do { IOBuf::Block* const saved_next = b->u.portal_next; @@ -341,10 +341,10 @@ void remove_tls_block_chain() { IOBuf::Block* share_tls_block() { TLSData& tls_data = g_tls_data; IOBuf::Block* const b = tls_data.block_head; - if (b != NULL && !b->full()) { + if (b != nullptr && !b->full()) { return b; } - IOBuf::Block* new_block = NULL; + IOBuf::Block* new_block = nullptr; if (b) { new_block = b; while (new_block && new_block->full()) { @@ -359,7 +359,7 @@ IOBuf::Block* share_tls_block() { butil::thread_atexit(remove_tls_block_chain); } if (!new_block) { - new_block = create_block(); // may be NULL + new_block = create_block(); // may be nullptr if (new_block) { ++tls_data.num_blocks; } @@ -369,7 +369,7 @@ IOBuf::Block* share_tls_block() { } // Return chained blocks to TLS. -// NOTE: b MUST be non-NULL and all blocks linked SHOULD not be full. +// NOTE: b MUST be non-nullptr and all blocks linked SHOULD not be full. void release_tls_block_chain(IOBuf::Block* b) { TLSData& tls_data = g_tls_data; size_t n = 0; @@ -384,11 +384,11 @@ void release_tls_block_chain(IOBuf::Block* b) { return; } IOBuf::Block* first_b = b; - IOBuf::Block* last_b = NULL; + IOBuf::Block* last_b = nullptr; do { ++n; CHECK(!b->full()); - if (b->u.portal_next == NULL) { + if (b->u.portal_next == nullptr) { last_b = b; break; } @@ -422,7 +422,7 @@ IOBuf::Block* acquire_tls_block() { } tls_data.block_head = b->u.portal_next; --tls_data.num_blocks; - b->u.portal_next = NULL; + b->u.portal_next = nullptr; return b; } @@ -500,14 +500,14 @@ void IOBuf::operator=(const IOBuf& rhs) { template void IOBuf::_push_or_move_back_ref_to_smallview(const BlockRef& r) { BlockRef* const refs = _sv.refs; - if (NULL == refs[0].block) { + if (nullptr == refs[0].block) { refs[0] = r; if (!MOVE) { r.block->inc_ref(); } return; } - if (NULL == refs[1].block) { + if (nullptr == refs[1].block) { if (refs[0].block == r.block && refs[0].offset + refs[0].length == r.offset) { // Merge ref refs[0].length += r.length; @@ -596,7 +596,7 @@ template void IOBuf::_push_or_move_back_ref_to_bigview(const BlockRef&); template int IOBuf::_pop_or_moveout_front_ref() { if (_small()) { - if (_sv.refs[0].block != NULL) { + if (_sv.refs[0].block != nullptr) { if (!MOVEOUT) { _sv.refs[0].block->dec_ref(); } @@ -630,11 +630,11 @@ template int IOBuf::_pop_or_moveout_front_ref(); int IOBuf::_pop_back_ref() { if (_small()) { - if (_sv.refs[1].block != NULL) { + if (_sv.refs[1].block != nullptr) { _sv.refs[1].block->dec_ref(); reset_block_ref(_sv.refs[1]); return 0; - } else if (_sv.refs[0].block != NULL) { + } else if (_sv.refs[0].block != nullptr) { _sv.refs[0].block->dec_ref(); reset_block_ref(_sv.refs[0]); return 0; @@ -660,11 +660,11 @@ int IOBuf::_pop_back_ref() { void IOBuf::clear() { if (_small()) { - if (_sv.refs[0].block != NULL) { + if (_sv.refs[0].block != nullptr) { _sv.refs[0].block->dec_ref(); reset_block_ref(_sv.refs[0]); - if (_sv.refs[1].block != NULL) { + if (_sv.refs[1].block != nullptr) { _sv.refs[1].block->dec_ref(); reset_block_ref(_sv.refs[1]); } @@ -1108,7 +1108,7 @@ int IOBuf::push_back(char c) { } int IOBuf::append(char const* s) { - if (BAIDU_LIKELY(s != NULL)) { + if (BAIDU_LIKELY(s != nullptr)) { return append(s, strlen(s)); } return -1; @@ -1180,7 +1180,7 @@ int IOBuf::append_user_data_with_meta(void* data, return 0; } char* mem = (char*)malloc(sizeof(IOBuf::Block) + sizeof(UserDataExtension)); - if (mem == NULL) { + if (mem == nullptr) { return -1; } IOBuf::Block* b = new (mem) IOBuf::Block((char*)data, size, std::move(deleter)); @@ -1278,7 +1278,7 @@ IOBuf::Area IOBuf::reserve(size_t count) { } int IOBuf::unsafe_assign(Area area, const void* data) { - if (area == INVALID_AREA || data == NULL) { + if (area == INVALID_AREA || data == nullptr) { LOG(ERROR) << "Invalid parameters"; return -1; } @@ -1416,7 +1416,7 @@ void const* IOBuf::fetch(void* d, size_t n) const { total_nc += r.length; } } - return NULL; + return nullptr; } const void* IOBuf::fetch1() const { @@ -1424,7 +1424,7 @@ const void* IOBuf::fetch1() const { const IOBuf::BlockRef& r0 = _front_ref(); return r0.block->data + r0.offset; } - return NULL; + return nullptr; } std::ostream& operator<<(std::ostream& os, const IOBuf& buf) { @@ -1529,17 +1529,17 @@ ssize_t IOPortal::pappend_from_file_descriptor( iovec vec[MAX_APPEND_IOVEC]; int nvec = 0; size_t space = 0; - Block* prev_p = NULL; + Block* prev_p = nullptr; Block* p = _block; // Prepare at most MAX_APPEND_IOVEC blocks or space of blocks >= max_count do { - if (p == NULL) { + if (p == nullptr) { p = iobuf::acquire_tls_block(); if (BAIDU_UNLIKELY(!p)) { errno = ENOMEM; return -1; } - if (prev_p != NULL) { + if (prev_p != nullptr) { prev_p->u.portal_next = p; } else { _block = p; @@ -1590,17 +1590,17 @@ ssize_t IOPortal::append_from_reader(IReader* reader, size_t max_count) { iovec vec[MAX_APPEND_IOVEC]; int nvec = 0; size_t space = 0; - Block* prev_p = NULL; + Block* prev_p = nullptr; Block* p = _block; // Prepare at most MAX_APPEND_IOVEC blocks or space of blocks >= max_count do { - if (p == NULL) { + if (p == nullptr) { p = iobuf::acquire_tls_block(); if (BAIDU_UNLIKELY(!p)) { errno = ENOMEM; return -1; } - if (prev_p != NULL) { + if (prev_p != nullptr) { prev_p->u.portal_next = p; } else { _block = p; @@ -1736,9 +1736,9 @@ IOBuf::Area IOReserveAlignedBuf::reserve(size_t count) { //////////////// IOBufCutter //////////////// IOBufCutter::IOBufCutter(butil::IOBuf* buf) - : _data(NULL) - , _data_end(NULL) - , _block(NULL) + : _data(nullptr) + , _data_end(nullptr) + , _block(nullptr) , _buf(buf) { } @@ -1759,9 +1759,9 @@ bool IOBufCutter::load_next_ref() { _buf->_pop_front_ref(); } if (!_buf->_ref_num()) { - _data = NULL; - _data_end = NULL; - _block = NULL; + _data = nullptr; + _data_end = nullptr; + _block = nullptr; return false; } else { const IOBuf::BlockRef& r = _buf->_front_ref(); @@ -1820,15 +1820,15 @@ size_t IOBufCutter::cutn(butil::IOBuf* out, size_t n) { _block }; out->_push_back_ref(r); _buf->_pop_front_ref(); - _data = NULL; - _data_end = NULL; - _block = NULL; + _data = nullptr; + _data_end = nullptr; + _block = nullptr; return _buf->cutn(out, n - size) + size; } else { if (_block) { - _data = NULL; - _data_end = NULL; - _block = NULL; + _data = nullptr; + _data_end = nullptr; + _block = nullptr; _buf->_pop_front_ref(); } return _buf->cutn(out, n); @@ -1847,15 +1847,15 @@ size_t IOBufCutter::cutn(void* out, size_t n) { } else if (size != 0) { memcpy(out, _data, size); _buf->_pop_front_ref(); - _data = NULL; - _data_end = NULL; - _block = NULL; + _data = nullptr; + _data_end = nullptr; + _block = nullptr; return _buf->cutn((char*)out + size, n - size) + size; } else { if (_block) { - _data = NULL; - _data_end = NULL; - _block = NULL; + _data = nullptr; + _data_end = nullptr; + _block = nullptr; _buf->_pop_front_ref(); } return _buf->cutn(out, n); @@ -1871,7 +1871,7 @@ IOBufAsZeroCopyInputStream::IOBufAsZeroCopyInputStream(const IOBuf& buf) bool IOBufAsZeroCopyInputStream::Next(const void** data, int* size) { const IOBuf::BlockRef* cur_ref = _buf->_pref_at(_ref_index); - if (cur_ref == NULL) { + if (cur_ref == nullptr) { return false; } *data = cur_ref->block->data + cur_ref->offset + _add_offset; @@ -1925,14 +1925,14 @@ int64_t IOBufAsZeroCopyInputStream::ByteCount() const { } IOBufAsZeroCopyOutputStream::IOBufAsZeroCopyOutputStream(IOBuf* buf) - : _buf(buf), _block_size(0), _cur_block(NULL), _byte_count(0) { + : _buf(buf), _block_size(0), _cur_block(nullptr), _byte_count(0) { } IOBufAsZeroCopyOutputStream::IOBufAsZeroCopyOutputStream( IOBuf *buf, uint32_t block_size) : _buf(buf) , _block_size(block_size) - , _cur_block(NULL) + , _cur_block(nullptr) , _byte_count(0) { if (_block_size <= offsetof(IOBuf::Block, data)) { @@ -1945,14 +1945,14 @@ IOBufAsZeroCopyOutputStream::~IOBufAsZeroCopyOutputStream() { } bool IOBufAsZeroCopyOutputStream::Next(void** data, int* size) { - if (_cur_block == NULL || _cur_block->full()) { + if (_cur_block == nullptr || _cur_block->full()) { _release_block(); if (_block_size > 0) { _cur_block = iobuf::create_block(_block_size); } else { _cur_block = iobuf::acquire_tls_block(); } - if (_cur_block == NULL) { + if (_cur_block == nullptr) { return false; } } @@ -2025,7 +2025,7 @@ void IOBufAsZeroCopyOutputStream::BackUp(int count) { // buf.append("foobar"); // can reuse the TLS block. if (_block_size == 0) { iobuf::release_tls_block(_cur_block); - _cur_block = NULL; + _cur_block = nullptr; } return; } @@ -2053,7 +2053,7 @@ void IOBufAsZeroCopyOutputStream::_release_block() { } else { iobuf::release_tls_block(_cur_block); } - _cur_block = NULL; + _cur_block = nullptr; } std::streambuf::int_type IOBufAsInputStreamBuf::underflow() { @@ -2116,14 +2116,14 @@ std::streamsize IOBufAsInputStreamBuf::showmanyc() { IOBufAsOutputStreamBuf::~IOBufAsOutputStreamBuf() { shrink(); } void IOBufAsOutputStreamBuf::shrink() { - if (pbase() != NULL) { + if (pbase() != nullptr) { std::streamsize unused = epptr() - pptr(); // _zc.BackUp takes int. A single put area never exceeds one block // (Next() returns int size), so this fits in int by construction; // the cap is purely defensive. int kIntMax = std::numeric_limits::max(); _zc.BackUp(unused > kIntMax ? kIntMax : static_cast(unused)); - setp(NULL, NULL); + setp(nullptr, nullptr); } } @@ -2169,10 +2169,10 @@ int IOBufAsOutputStreamBuf::sync() { } bool IOBufAsOutputStreamBuf::refresh_put_area() { - void* block = NULL; + void* block = nullptr; int size = 0; if (!_zc.Next(&block, &size)) { - setp(NULL, NULL); + setp(nullptr, nullptr); return false; } char* p = static_cast(block); @@ -2181,7 +2181,7 @@ bool IOBufAsOutputStreamBuf::refresh_put_area() { } IOBufAsSnappySink::IOBufAsSnappySink(butil::IOBuf& buf) - : _cur_buf(NULL), _cur_len(0), _buf(&buf), _buf_stream(&buf) { + : _cur_buf(nullptr), _cur_len(0), _buf(&buf), _buf_stream(&buf) { } void IOBufAsSnappySink::Append(const char* bytes, size_t n) { @@ -2208,7 +2208,7 @@ char* IOBufAsSnappySink::GetAppendBuffer(size_t length, char* scratch) { LOG(FATAL) << "Fail to alloc buffer"; } } // else no need to try. - _cur_buf = NULL; + _cur_buf = nullptr; _cur_len = 0; return scratch; } @@ -2222,7 +2222,7 @@ void IOBufAsSnappySource::Skip(size_t n) { } const char* IOBufAsSnappySource::Peek(size_t* len) { - const char* buffer = NULL; + const char* buffer = nullptr; int res = 0; if (_stream.Next((const void**)&buffer, &res)) { *len = res; @@ -2231,13 +2231,13 @@ const char* IOBufAsSnappySource::Peek(size_t* len) { return buffer; } else { *len = 0; - return NULL; + return nullptr; } } IOBufAppender::IOBufAppender() - : _data(NULL) - , _data_end(NULL) + : _data(nullptr) + , _data_end(nullptr) , _zc_stream(&_buf) { } diff --git a/src/butil/iobuf.h b/src/butil/iobuf.h index b92a2e3da3..724ee02d2e 100644 --- a/src/butil/iobuf.h +++ b/src/butil/iobuf.h @@ -331,7 +331,7 @@ friend class SingleIOBuf; // Get `n' front-side bytes with minimum copying. Length of `aux_buffer' // must not be less than `n'. // Returns: - // NULL - n is greater than length() + // nullptr - n is greater than length() // aux_buffer - n bytes are copied into aux_buffer // internal buffer - the bytes are stored continuously in the internal // buffer, no copying is needed. This function does not @@ -341,7 +341,7 @@ friend class SingleIOBuf; // If n == 0 and buffer is empty, return value is undefined. const void* fetch(void* aux_buffer, size_t n) const; // Fetch one character from front side. - // Returns pointer to the character, NULL on empty. + // Returns pointer to the character, nullptr on empty. const void* fetch1() const; // Remove all data @@ -425,7 +425,7 @@ friend class SingleIOBuf; const BlockRef& _ref_at(size_t i) const; // Get pointer to n-th BlockRef(counting from front) - // If i is out-of-range, NULL is returned. + // If i is out-of-range, nullptr is returned. const BlockRef* _pref_at(size_t i) const; private: @@ -454,8 +454,8 @@ inline bool operator!=(const butil::IOBuf& b1, const butil::IOBuf& b2) // Typically used as the buffer to store bytes from sockets. class IOPortal : public IOBuf { public: - IOPortal() : _block(NULL) { } - IOPortal(const IOPortal& rhs) : IOBuf(rhs), _block(NULL) { } + IOPortal() : _block(nullptr) { } + IOPortal(const IOPortal& rhs) : IOBuf(rhs), _block(nullptr) { } ~IOPortal(); IOPortal& operator=(const IOPortal& rhs); @@ -531,7 +531,7 @@ class IOBufCutter { size_t copy_to(void* data, size_t n); // Fetch one character. - // Returns pointer to the character, NULL on empty + // Returns pointer to the character, nullptr on empty const void* fetch1(); // Pop n bytes from front side @@ -665,7 +665,7 @@ class IOBufInputStream : public std::istream { // `buf' must outlive this stream and must not be modified while the // stream is in use. explicit IOBufInputStream(const IOBuf& buf) - : std::istream(NULL), _sb(buf) { + : std::istream(nullptr), _sb(buf) { rdbuf(&_sb); } @@ -758,11 +758,11 @@ class IOBufOutputStream : public std::ostream { public: // `buf' must outlive this stream. explicit IOBufOutputStream(IOBuf& buf) - : std::ostream(NULL), _sb(buf) { + : std::ostream(nullptr), _sb(buf) { rdbuf(&_sb); } IOBufOutputStream(IOBuf& buf, uint32_t block_size) - : std::ostream(NULL), _sb(buf, block_size) { + : std::ostream(nullptr), _sb(buf, block_size) { rdbuf(&_sb); } diff --git a/src/butil/iobuf_inl.h b/src/butil/iobuf_inl.h index 756cf8bf63..71a449d282 100644 --- a/src/butil/iobuf_inl.h +++ b/src/butil/iobuf_inl.h @@ -64,14 +64,14 @@ inline ssize_t IOPortal::append_from_file_descriptor(int fd, size_t max_count) { inline void IOPortal::return_cached_blocks() { if (_block) { return_cached_blocks_impl(_block); - _block = NULL; + _block = nullptr; } } inline void reset_block_ref(IOBuf::BlockRef& ref) { ref.offset = 0; ref.length = 0; - ref.block = NULL; + ref.block = nullptr; } inline IOBuf::IOBuf() { @@ -181,9 +181,9 @@ inline const IOBuf::BlockRef& IOBuf::_ref_at(size_t i) const { inline const IOBuf::BlockRef* IOBuf::_pref_at(size_t i) const { if (_small()) { - return i < (size_t)(!!_sv.refs[0].block + !!_sv.refs[1].block) ? &_sv.refs[i] : NULL; + return i < (size_t)(!!_sv.refs[0].block + !!_sv.refs[1].block) ? &_sv.refs[i] : nullptr; } else { - return i < _bv.nref ? &_bv.ref_at(i) : NULL; + return i < _bv.nref ? &_bv.ref_at(i) : nullptr; } } @@ -235,7 +235,7 @@ inline bool IOBufCutter::cut1(void* c) { inline const void* IOBufCutter::fetch1() { if (_data == _data_end) { if (!load_next_ref()) { - return NULL; + return nullptr; } } return _data; @@ -339,8 +339,8 @@ inline int IOBufAppender::add_block() { _data_end = (char*)_data + size; return 0; } - _data = NULL; - _data_end = NULL; + _data = nullptr; + _data_end = nullptr; return -1; } @@ -348,13 +348,13 @@ inline void IOBufAppender::shrink() { const size_t size = (char*)_data_end - (char*)_data; if (size != 0) { _zc_stream.BackUp(size); - _data = NULL; - _data_end = NULL; + _data = nullptr; + _data_end = nullptr; } } inline IOBufBytesIterator::IOBufBytesIterator(const butil::IOBuf& buf) - : _block_begin(NULL), _block_end(NULL), _block_count(0), + : _block_begin(nullptr), _block_end(nullptr), _block_count(0), _bytes_left(buf.length()), _buf(&buf) { try_next_block(); } @@ -483,7 +483,7 @@ struct IOBuf::Block { , abi_check(0) , size(0) , cap(data_size) - , u({NULL}) + , u({nullptr}) , data(data_in) { iobuf::inc_g_nblock(); iobuf::inc_g_blockmem(); @@ -629,11 +629,11 @@ inline void release_tls_block(IOBuf::Block* b) { inline IOBuf::Block* create_block(const size_t block_size) { if (block_size > 0xFFFFFFFFULL) { LOG(FATAL) << "block_size=" << block_size << " is too large"; - return NULL; + return nullptr; } char* mem = (char*)iobuf::blockmem_allocate(block_size); - if (mem == NULL) { - return NULL; + if (mem == nullptr) { + return nullptr; } return new (mem) IOBuf::Block(mem + sizeof(IOBuf::Block), block_size - sizeof(IOBuf::Block)); diff --git a/src/butil/iobuf_profiler.cpp b/src/butil/iobuf_profiler.cpp index a88e7c559b..e7220ffe26 100644 --- a/src/butil/iobuf_profiler.cpp +++ b/src/butil/iobuf_profiler.cpp @@ -46,7 +46,7 @@ static uint g_iobuf_profiler_sample_rate = 100; // 2. IOBUF_PROFILER_SAMPLE_RATE: set value between (0, 100] to control sample rate. static void InitGlobalIOBufProfilerInfo() { const char* enabled = getenv("ENABLE_IOBUF_PROFILER"); - g_iobuf_profiler_enabled = enabled && strcmp("1", enabled) == 0 && ::GetStackTrace != NULL; + g_iobuf_profiler_enabled = enabled && strcmp("1", enabled) == 0 && ::GetStackTrace != nullptr; if (!g_iobuf_profiler_enabled) { return; } @@ -116,7 +116,7 @@ IOBufProfiler::~IOBufProfiler() { _stack_map.clear(); // Clear `_sample_queue'. - IOBufSample* sample = NULL; + IOBufSample* sample = nullptr; while (_sample_queue.Dequeue(sample)) { IOBufSample::Destroy(sample); } @@ -139,7 +139,7 @@ void IOBufProfiler::Dump(IOBufSample* s) { IOBufRefSampleSharedPtr* stack_ptr = _stack_map.seek(s); if (!stack_ptr) { stack_sample = IOBufSample::CopyAndSharedWithDestroyer(s); - stack_sample->block = NULL; + stack_sample->block = nullptr; stack_ptr = &_stack_map[stack_sample.get()]; *stack_ptr = stack_sample; } else { @@ -170,7 +170,7 @@ void IOBufProfiler::Dump(IOBufSample* s) { new_info.stack_count_map[*stack_ptr] = s->count; } } while (false); - s->block = NULL; + s->block = nullptr; } IOBufSample* IOBufSample::Copy(IOBufSample* ref) { @@ -280,7 +280,7 @@ void IOBufProfiler::Run() { } void IOBufProfiler::Consume() { - IOBufSample* sample = NULL; + IOBufSample* sample = nullptr; bool is_empty = true; while (_sample_queue.Dequeue(sample)) { Dump(sample); diff --git a/src/butil/iobuf_profiler.h b/src/butil/iobuf_profiler.h index 4686886f5a..2dfb8b59c7 100644 --- a/src/butil/iobuf_profiler.h +++ b/src/butil/iobuf_profiler.h @@ -57,8 +57,8 @@ struct IOBufSample { friend ObjectPool; IOBufSample() - : next(NULL) - , block(NULL) + : next(nullptr) + , block(nullptr) , count(0) , stack{} , nframes(0) diff --git a/src/butil/lazy_instance.h b/src/butil/lazy_instance.h index b300faf4d7..0a912b5b72 100644 --- a/src/butil/lazy_instance.h +++ b/src/butil/lazy_instance.h @@ -180,7 +180,7 @@ class LazyInstance { value = reinterpret_cast( Traits::New(private_buf_.void_data())); internal::CompleteLazyInstance(&private_instance_, value, this, - Traits::kRegisterOnExit ? OnExit : NULL); + Traits::kRegisterOnExit ? OnExit : nullptr); } // This annotation helps race detectors recognize correct lock-less @@ -195,7 +195,7 @@ class LazyInstance { bool operator==(Type* p) { switch (subtle::NoBarrier_Load(&private_instance_)) { case 0: - return p == NULL; + return p == nullptr; case internal::kLazyInstanceStateCreating: return static_cast(p) == private_buf_.void_data(); default: diff --git a/src/butil/location.cc b/src/butil/location.cc index cb7b5557b0..3c95f0b23f 100644 --- a/src/butil/location.cc +++ b/src/butil/location.cc @@ -31,7 +31,7 @@ Location::Location() : function_name_("Unknown"), file_name_("Unknown"), line_number_(-1), - program_counter_(NULL) { + program_counter_(nullptr) { } std::string Location::ToString() const { @@ -95,7 +95,7 @@ BUTIL_EXPORT const void* GetProgramCounter() { #elif defined(COMPILER_GCC) && !defined(OS_NACL) return __builtin_extract_return_addr(__builtin_return_address(0)); #else - return NULL; + return nullptr; #endif } diff --git a/src/butil/logging.cc b/src/butil/logging.cc index 29d4111eed..b389b18f13 100644 --- a/src/butil/logging.cc +++ b/src/butil/logging.cc @@ -184,17 +184,17 @@ typedef std::wstring PathString; #else typedef std::string PathString; #endif -PathString* log_file_name = NULL; +PathString* log_file_name = nullptr; -// this file is lazily opened and the handle may be NULL -FileHandle log_file = NULL; +// this file is lazily opened and the handle may be nullptr +FileHandle log_file = nullptr; // Should we pop up fatal debug messages in a dialog? bool show_error_dialogs = false; // An assert handler override specified by the client to be called instead of // the debug message dialog and process termination. -LogAssertHandler log_assert_handler = NULL; +LogAssertHandler log_assert_handler = nullptr; BAIDU_VOLATILE_THREAD_LOCAL(int32_t, tls_log_pid, 0); BAIDU_VOLATILE_THREAD_LOCAL(butil::PlatformThreadId, tls_log_tid, 0); @@ -241,7 +241,7 @@ PathString GetDefaultLogFile() { #if defined(OS_WIN) // On Windows we use the same path as the exe. wchar_t module_name[MAX_PATH]; - GetModuleFileName(NULL, module_name, MAX_PATH); + GetModuleFileName(nullptr, module_name, MAX_PATH); PathString log_file = module_name; PathString::size_type last_backslash = @@ -290,9 +290,9 @@ class LoggingLock { std::replace(safe_name.begin(), safe_name.end(), '\\', '/'); std::wstring t(L"Global\\"); t.append(safe_name); - log_mutex = ::CreateMutex(NULL, FALSE, t.c_str()); + log_mutex = ::CreateMutex(nullptr, FALSE, t.c_str()); - if (log_mutex == NULL) { + if (log_mutex == nullptr) { #if DEBUG // Keep the error code for debugging int error = GetLastError(); // NOLINT @@ -359,20 +359,20 @@ class LoggingLock { // static bool LoggingLock::initialized = false; // static -butil::Mutex* LoggingLock::log_lock = NULL; +butil::Mutex* LoggingLock::log_lock = nullptr; // static LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; #if defined(OS_WIN) // static -MutexHandle LoggingLock::log_mutex = NULL; +MutexHandle LoggingLock::log_mutex = nullptr; #elif defined(OS_POSIX) pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER; #endif // Called by logging functions to ensure that debug_file is initialized // and can be used for writing. Returns false if the file could not be -// initialized. debug_file will be NULL in this case. +// initialized. debug_file will be nullptr in this case. bool InitializeLogFileHandle() { if (log_file) return true; @@ -386,22 +386,22 @@ bool InitializeLogFileHandle() { if ((logging_destination & LOG_TO_FILE) != 0) { #if defined(OS_WIN) log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (log_file == INVALID_HANDLE_VALUE || log_file == nullptr) { // try the current directory log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { - log_file = NULL; + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (log_file == INVALID_HANDLE_VALUE || log_file == nullptr) { + log_file = nullptr; return false; } } SetFilePointer(log_file, 0, 0, FILE_END); #elif defined(OS_POSIX) log_file = fopen(log_file_name->c_str(), "a"); - if (log_file == NULL) { + if (log_file == nullptr) { fprintf(stderr, "Fail to fopen %s: %s", log_file_name->c_str(), berror()); return false; } @@ -424,7 +424,7 @@ void CloseLogFileUnlocked() { return; CloseFile(log_file); - log_file = NULL; + log_file = nullptr; } void Log2File(const std::string& log) { @@ -435,14 +435,14 @@ void Log2File(const std::string& log) { // to do this at the same time, there will be a race condition to create // the lock. This is why InitLogging should be called from the main // thread at the beginning of execution. - LoggingLock::Init(LOCK_LOG_FILE, NULL); + LoggingLock::Init(LOCK_LOG_FILE, nullptr); LoggingLock logging_lock; if (InitializeLogFileHandle()) { #if defined(OS_WIN) SetFilePointer(log_file, 0, 0, SEEK_END); DWORD num_written; WriteFile(log_file, static_cast(log.data()), - static_cast(log.size()), &num_written, NULL); + static_cast(log.size()), &num_written, nullptr); #else fwrite(log.data(), log.size(), 1, log_file); fflush(log_file); @@ -463,10 +463,10 @@ struct TimeVal { TimeVal GetTimestamp() { #if defined(OS_LINUX) || defined(OS_MACOSX) timeval tv; - gettimeofday(&tv, NULL); + gettimeofday(&tv, nullptr); return tv; #else - return { time(NULL) }; + return { time(nullptr) }; #endif } @@ -492,7 +492,7 @@ struct BAIDU_CACHELINE_ALIGNMENT LogInfo { struct BAIDU_CACHELINE_ALIGNMENT LogRequest { static LogRequest* const UNCONNECTED; - LogRequest* next{NULL}; + LogRequest* next{nullptr}; LogInfo log_info; }; @@ -547,9 +547,9 @@ AsyncLogger* AsyncLogger::GetInstance() { AsyncLogger::AsyncLogger() : butil::SimpleThread("async_log_thread") - , _log_head(NULL) + , _log_head(nullptr) , _cond(&_mutex) - , _current_log_request(NULL) + , _current_log_request(nullptr) , _stop(false) { Start(); // We need to stop async logger and @@ -633,7 +633,7 @@ void AsyncLogger::LogImpl(LogRequest* log_req) { // Release fence makes sure the thread getting request sees *req LogRequest* const prev_head = _log_head.exchange(log_req, butil::memory_order_release); - if (prev_head != NULL) { + if (prev_head != nullptr) { // Someone is logging. The async_log_thread thread may spin // until req->next to be non-UNCONNECTED. This process is not // lock-free, but the duration is so short(1~2 instructions, @@ -643,7 +643,7 @@ void AsyncLogger::LogImpl(LogRequest* log_req) { return; } // We've got the right to write. - log_req->next = NULL; + log_req->next = nullptr; if (!FLAGS_async_log_in_background_always) { // Use sync log for the LogRequest @@ -690,21 +690,21 @@ void AsyncLogger::Run() { } LogTask(_current_log_request); - _current_log_request = NULL; + _current_log_request = nullptr; } } void AsyncLogger::LogTask(LogRequest* req) { do { // req was logged, skip it. - if (req->next != NULL && req->log_info.content.empty()) { + if (req->next != nullptr && req->log_info.content.empty()) { LogRequest* const saved_req = req; req = req->next; butil::return_object(saved_req); } // Log all requests to file. - while (req->next != NULL) { + while (req->next != nullptr) { LogRequest* const saved_req = req; req = req->next; if (!saved_req->log_info.content.empty()) { @@ -730,7 +730,7 @@ bool AsyncLogger::IsLogComplete(LogRequest* old_head) { fprintf(stderr, "old_head->next should be NULL\n"); } LogRequest* new_head = old_head; - LogRequest* desired = NULL; + LogRequest* desired = nullptr; if (_log_head.compare_exchange_strong( new_head, desired, butil::memory_order_acquire)) { // No one added new requests. @@ -744,7 +744,7 @@ bool AsyncLogger::IsLogComplete(LogRequest* old_head) { // Someone added new requests. // Reverse the list until old_head. - LogRequest* tail = NULL; + LogRequest* tail = nullptr; LogRequest* p = new_head; do { while (p->next == LogRequest::UNCONNECTED) { @@ -780,7 +780,7 @@ void AsyncLogger::DoLog(const LogInfo& log_info) { LoggingSettings::LoggingSettings() : logging_dest(LOG_DEFAULT), - log_file(NULL), + log_file(nullptr), lock_log(LOCK_LOG_FILE), delete_old(APPEND_TO_OLD_LOG_FILE) {} @@ -851,7 +851,7 @@ void PrintLogPrefix(std::ostream& os, int severity, butil::StringPiece func, TimeVal tv) { PrintLogSeverity(os, severity); time_t t = tv.tv_sec; - struct tm local_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL}; + struct tm local_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; #if _MSC_VER >= 1400 localtime_s(&local_tm, &t); #else @@ -923,7 +923,7 @@ static void PrintLogPrefixAsJSON(std::ostream& os, int severity, // time os << "\",\"T\":\""; time_t t = tv.tv_sec; - struct tm local_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL}; + struct tm local_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr}; #if _MSC_VER >= 1400 localtime_s(&local_tm, &t); #else @@ -1046,7 +1046,7 @@ struct SetLogSinkFn { }; LogSink* SetLogSink(LogSink* sink) { - SetLogSinkFn fn = { sink, NULL }; + SetLogSinkFn fn = { sink, nullptr }; CHECK(DoublyBufferedLogSink::GetInstance()->Modify(fn)); return fn.old_sink; } @@ -1087,7 +1087,7 @@ void DisplayDebugMessageInDialog(const std::string& str) { // Message.exe" in the same directory as the application. If it // exists, we use it, otherwise, we use a regular message box. wchar_t prog_name[MAX_PATH]; - GetModuleFileNameW(NULL, prog_name, MAX_PATH); + GetModuleFileNameW(nullptr, prog_name, MAX_PATH); wchar_t* backslash = wcsrchr(prog_name, '\\'); if (backslash) backslash[1] = 0; @@ -1102,14 +1102,14 @@ void DisplayDebugMessageInDialog(const std::string& str) { startup_info.cb = sizeof(startup_info); PROCESS_INFORMATION process_info; - if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL, - NULL, &startup_info, &process_info)) { + if (CreateProcessW(prog_name, &cmdline[0], nullptr, nullptr, false, 0, nullptr, + nullptr, &startup_info, &process_info)) { WaitForSingleObject(process_info.hProcess, INFINITE); CloseHandle(process_info.hThread); CloseHandle(process_info.hProcess); } else { // debug process broken, let's just do a message box - MessageBoxW(NULL, &cmdline[0], L"Fatal error", + MessageBoxW(nullptr, &cmdline[0], L"Fatal error", MB_OK | MB_ICONHAND | MB_TOPMOST); } #else @@ -1148,8 +1148,8 @@ int CharArrayStreamBuf::overflow(int ch) { } size_t new_size = std::max(_size * 3 / 2, (size_t)64); char* new_data = (char*)malloc(new_size); - if (BAIDU_UNLIKELY(new_data == NULL)) { - setp(NULL, NULL); + if (BAIDU_UNLIKELY(new_data == nullptr)) { + setp(nullptr, nullptr); return std::streambuf::traits_type::eof(); } memcpy(new_data, _data, _size); @@ -1194,9 +1194,9 @@ LogStream& LogStream::SetPosition(const LogChar* file, int line, static bthread_key_t stream_bkey; static pthread_key_t stream_pkey; static pthread_once_t create_stream_key_once = PTHREAD_ONCE_INIT; -inline bool is_bthread_linked() { return bthread_key_create != NULL; } +inline bool is_bthread_linked() { return bthread_key_create != nullptr; } static void destroy_tls_streams(void* data) { - if (data == NULL) { + if (data == nullptr) { return; } LogStream** a = (LogStream**)data; @@ -1231,7 +1231,7 @@ static LogStream** get_tls_stream_array() { static LogStream** get_or_new_tls_stream_array() { LogStream** a = get_tls_stream_array(); - if (a == NULL) { + if (a == nullptr) { a = new LogStream*[LOG_NUM_SEVERITIES + 1]; memset(a, 0, sizeof(LogStream*) * (LOG_NUM_SEVERITIES + 1)); if (is_bthread_linked()) { @@ -1254,7 +1254,7 @@ inline LogStream* CreateLogStream(const LogChar* file, } // else vlog LogStream** stream_array = get_or_new_tls_stream_array(); LogStream* stream = stream_array[slot]; - if (stream == NULL) { + if (stream == nullptr) { stream = new LogStream; stream_array[slot] = stream; } @@ -1271,7 +1271,7 @@ inline LogStream* CreateLogStream(const LogChar* file, } inline void DestroyLogStream(LogStream* stream) { - if (stream != NULL) { + if (stream != nullptr) { stream->Flush(); } } @@ -1397,7 +1397,7 @@ void LogStream::FlushWithoutReset() { { DoublyBufferedLogSink::ScopedPtr ptr; if (DoublyBufferedLogSink::GetInstance()->Read(&ptr) == 0 && - (*ptr) != NULL) { + (*ptr) != nullptr) { bool result = (*ptr)->OnLogMessage( _severity, _file, _line, _func, content()); if (result) { @@ -1515,8 +1515,8 @@ BUTIL_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) { const int error_message_buffer_size = 256; char msgbuf[error_message_buffer_size]; DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; - DWORD len = FormatMessageA(flags, NULL, error_code, 0, msgbuf, - arraysize(msgbuf), NULL); + DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf, + arraysize(msgbuf), nullptr); if (len) { // Messages returned by system end with line breaks. return butil::CollapseWhitespaceASCII(msgbuf, true) + @@ -1633,14 +1633,14 @@ struct VModuleList; extern const int VLOG_UNINITIALIZED = std::numeric_limits::max(); static pthread_mutex_t vlog_site_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static VLogSite* vlog_site_list = NULL; -static VModuleList* vmodule_list = NULL; +static VLogSite* vlog_site_list = nullptr; +static VModuleList* vmodule_list = nullptr; static pthread_mutex_t reset_vmodule_and_v_mutex = PTHREAD_MUTEX_INITIALIZER; static const int64_t DELAY_DELETION_SEC = 10; static std::deque >* -deleting_vmodule_list = NULL; +deleting_vmodule_list = nullptr; struct VLogSite { VLogSite(const char* filename, int required_v, int line_no) @@ -1688,7 +1688,7 @@ struct VLogSite { const std::string& full_module() const { return _full_module; } private: - // Next site in the list. NULL means no next. + // Next site in the list. nullptr means no next. butil::subtle::AtomicWord _next; // --vmodule > --v @@ -1709,8 +1709,8 @@ struct VLogSite { // Written by Jack Handy // jakkhandy@hotmail.com bool wildcmp(const char* wild, const char* str) { - const char* cp = NULL; - const char* mp = NULL; + const char* cp = nullptr; + const char* mp = nullptr; while (*str && *wild != '*') { if (*wild != *str && *wild != '?') { @@ -1754,7 +1754,7 @@ struct VModuleList { size_t off = 0; for (; off < sp.length() && sp.field()[off] != '='; ++off) {} if (off + 1 < sp.length()) { - verbose_level = strtol(sp.field() + off + 1, NULL, 10); + verbose_level = strtol(sp.field() + off + 1, nullptr, 10); } const char* name_begin = sp.field(); @@ -1862,7 +1862,7 @@ static int vlog_site_list_add(VLogSite* site, bool add_vlog_site(const int** v, const char* filename, int line_no, int required_v) { VLogSite* site = new (std::nothrow) VLogSite(filename, required_v, line_no); - if (site == NULL) { + if (site == nullptr) { return false; } VModuleList* module_list = vmodule_list; @@ -1879,7 +1879,7 @@ bool add_vlog_site(const int** v, const char* filename, int line_no, } void print_vlog_sites(VLogSitePrinter* printer) { - VLogSite* head = NULL; + VLogSite* head = nullptr; { BAIDU_SCOPED_LOCK(vlog_site_list_mutex); head = vlog_site_list; @@ -1900,7 +1900,7 @@ static int on_reset_vmodule(const char* vmodule) { BAIDU_SCOPED_LOCK(reset_vmodule_and_v_mutex); VModuleList* module_list = new (std::nothrow) VModuleList; - if (NULL == module_list) { + if (nullptr == module_list) { LOG(FATAL) << "Fail to new VModuleList"; return -1; } @@ -1910,8 +1910,8 @@ static int on_reset_vmodule(const char* vmodule) { return -1; } - VModuleList* old_module_list = NULL; - VLogSite* old_vlog_site_list = NULL; + VModuleList* old_module_list = nullptr; + VLogSite* old_vlog_site_list = nullptr; { { BAIDU_SCOPED_LOCK(vlog_site_list_mutex); @@ -1928,7 +1928,7 @@ static int on_reset_vmodule(const char* vmodule) { if (old_module_list) { //delay the deletion. - if (NULL == deleting_vmodule_list) { + if (nullptr == deleting_vmodule_list) { deleting_vmodule_list = new std::deque >; } @@ -1953,8 +1953,8 @@ const bool ALLOW_UNUSED validate_vmodule_dummy = GFLAGS_NAMESPACE::RegisterFlagV // [Thread-safe] Reset FLAGS_v. static void on_reset_verbose(int default_v) { - VModuleList* cur_module_list = NULL; - VLogSite* cur_vlog_site_list = NULL; + VModuleList* cur_module_list = nullptr; + VLogSite* cur_vlog_site_list = nullptr; { // resetting must be serialized. BAIDU_SCOPED_LOCK(reset_vmodule_and_v_mutex); diff --git a/src/butil/logging.h b/src/butil/logging.h index d612e86874..a1b17631cb 100644 --- a/src/butil/logging.h +++ b/src/butil/logging.h @@ -118,7 +118,7 @@ // parsing. // // The code for DebugMessage.exe is only one line. In WinMain, do: -// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0); +// MessageBox(nullptr, GetCommandLineW(), L"Fatal Error", 0); // // If DebugMessage.exe is not found, the logging code will use a normal // MessageBox, potentially causing the problems discussed above. @@ -262,7 +262,7 @@ struct BUTIL_EXPORT LoggingSettings { // The defaults values are: // // logging_dest: LOG_DEFAULT - // log_file: NULL + // log_file: nullptr // lock_log: LOCK_LOG_FILE // delete_old: APPEND_TO_OLD_LOG_FILE LoggingSettings(); @@ -674,11 +674,11 @@ std::string* MakeCheckOpString( template \ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ const char* names) { \ - if (v1 op v2) return NULL; \ + if (v1 op v2) return nullptr; \ else return MakeCheckOpString(v1, v2, names); \ } \ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ - if (v1 op v2) return NULL; \ + if (v1 op v2) return nullptr; \ else return MakeCheckOpString(v1, v2, names); \ } BAIDU_DEFINE_CHECK_OP_IMPL(EQ, ==) @@ -905,7 +905,7 @@ BUTIL_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code); // creation of std::string which allocates memory internally. class CharArrayStreamBuf : public std::streambuf { public: - explicit CharArrayStreamBuf() : _data(NULL), _size(0) {} + explicit CharArrayStreamBuf() : _data(nullptr), _size(0) {} ~CharArrayStreamBuf() override; int overflow(int ch) override; diff --git a/src/butil/mac/foundation_util.h b/src/butil/mac/foundation_util.h index 12b8e66a63..5b588694f3 100644 --- a/src/butil/mac/foundation_util.h +++ b/src/butil/mac/foundation_util.h @@ -79,20 +79,20 @@ OSType CreatorCodeForCFBundleRef(CFBundleRef bundle); BUTIL_EXPORT OSType CreatorCodeForApplication(); // Searches for directories for the given key in only the given |domain_mask|. -// If found, fills result (which must always be non-NULL) with the +// If found, fills result (which must always be non-nullptr) with the // first found directory and returns true. Otherwise, returns false. BUTIL_EXPORT bool GetSearchPathDirectory(NSSearchPathDirectory directory, NSSearchPathDomainMask domain_mask, FilePath* result); // Searches for directories for the given key in only the local domain. -// If found, fills result (which must always be non-NULL) with the +// If found, fills result (which must always be non-nullptr) with the // first found directory and returns true. Otherwise, returns false. BUTIL_EXPORT bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result); // Searches for directories for the given key in only the user domain. -// If found, fills result (which must always be non-NULL) with the +// If found, fills result (which must always be non-nullptr) with the // first found directory and returns true. Otherwise, returns false. BUTIL_EXPORT bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result); @@ -154,7 +154,7 @@ BUTIL_EXPORT void NSObjectRelease(void* obj); BUTIL_EXPORT void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object); // Returns the base bundle ID, which can be set by SetBaseBundleID but -// defaults to a reasonable string. This never returns NULL. BaseBundleID +// defaults to a reasonable string. This never returns nullptr. BaseBundleID // returns a pointer to static storage that must not be freed. BUTIL_EXPORT const char* BaseBundleID(); @@ -244,8 +244,8 @@ namespace mac { // object is found by comparing its opaque type against the // requested type identifier. If the supplied object is not // compatible with the requested return type, CFCast<>() returns -// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer -// to either variant results in NULL being returned without +// nullptr and CFCastStrict<>() will DCHECK. Providing a nullptr pointer +// to either variant results in nullptr being returned without // triggering any DCHECK. // // Example usage: @@ -338,7 +338,7 @@ BUTIL_EXPORT std::string GetValueFromDictionaryErrorMessage( CFStringRef key, const std::string& expected_type, CFTypeRef value); // Utility function to pull out a value from a dictionary, check its type, and -// return it. Returns NULL if the key is not present or of the wrong type. +// return it. Returns nullptr if the key is not present or of the wrong type. template T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) { CFTypeRef value = CFDictionaryGetValue(dict, key); diff --git a/src/butil/mac/foundation_util.mm b/src/butil/mac/foundation_util.mm index 74d26aafa7..b180122e2b 100644 --- a/src/butil/mac/foundation_util.mm +++ b/src/butil/mac/foundation_util.mm @@ -83,7 +83,7 @@ FilePath PathForFrameworkBundleResource(CFStringRef resourceName) { OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) { OSType creator = kUnknownType; - CFBundleGetPackageInfo(bundle, NULL, &creator); + CFBundleGetPackageInfo(bundle, nullptr, &creator); return creator; } @@ -215,7 +215,7 @@ void NSObjectRelease(void* obj) { // In the traditional GC-less environment, NSMakeCollectable is a no-op, // and cf_object is autoreleased, balancing out the caller's ownership claim. // - // NSMakeCollectable returns nil when used on a NULL object. + // NSMakeCollectable returns nil when used on a nullptr object. return [NSMakeCollectable(cf_object) autorelease]; } @@ -236,7 +236,7 @@ void NSObjectRelease(void* obj) { void SetBaseBundleID(const char* new_base_bundle_id) { if (new_base_bundle_id != base_bundle_id) { free((void*)base_bundle_id); - base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL; + base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : nullptr; } } @@ -322,19 +322,19 @@ CTFontRef NSToCFCast(NSFont* ns_val) { #define CF_CAST_DEFN(TypeCF) \ template<> TypeCF##Ref \ CFCast(const CFTypeRef& cf_val) { \ - if (cf_val == NULL) { \ - return NULL; \ + if (cf_val == nullptr) { \ + return nullptr; \ } \ if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \ return (TypeCF##Ref)(cf_val); \ } \ - return NULL; \ + return nullptr; \ } \ \ template<> TypeCF##Ref \ CFCastStrict(const CFTypeRef& cf_val) { \ TypeCF##Ref rv = CFCast(cf_val); \ - DCHECK(cf_val == NULL || rv); \ + DCHECK(cf_val == nullptr || rv); \ return rv; \ } @@ -363,27 +363,27 @@ CTFontRef NSToCFCast(NSFont* ns_val) { // http://www.openradar.me/15341349 rdar://15341349 template<> CTFontRef CFCast(const CFTypeRef& cf_val) { - if (cf_val == NULL) { - return NULL; + if (cf_val == nullptr) { + return nullptr; } if (CFGetTypeID(cf_val) == CTFontGetTypeID()) { return (CTFontRef)(cf_val); } if (!_CFIsObjC(CTFontGetTypeID(), cf_val)) - return NULL; + return nullptr; id ns_val = reinterpret_cast(const_cast(cf_val)); if ([ns_val isKindOfClass:NSClassFromString(@"NSFont")]) { return (CTFontRef)(cf_val); } - return NULL; + return nullptr; } template<> CTFontRef CFCastStrict(const CFTypeRef& cf_val) { CTFontRef rv = CFCast(cf_val); - DCHECK(cf_val == NULL || rv); + DCHECK(cf_val == nullptr || rv); return rv; } #endif @@ -430,7 +430,7 @@ FilePath NSStringToFilePath(NSString* str) { std::ostream& operator<<(std::ostream& o, const CFErrorRef err) { butil::ScopedCFTypeRef desc(CFErrorCopyDescription(err)); butil::ScopedCFTypeRef user_info(CFErrorCopyUserInfo(err)); - CFStringRef errorDesc = NULL; + CFStringRef errorDesc = nullptr; if (user_info.get()) { errorDesc = reinterpret_cast( CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey)); diff --git a/src/butil/mac/scoped_cftyperef.h b/src/butil/mac/scoped_cftyperef.h index 626a431c18..977f910c3b 100644 --- a/src/butil/mac/scoped_cftyperef.h +++ b/src/butil/mac/scoped_cftyperef.h @@ -45,7 +45,7 @@ class ScopedCFTypeRef typedef CFT element_type; explicit ScopedCFTypeRef( - CFT object = NULL, + CFT object = nullptr, butil::scoped_policy::OwnershipPolicy policy = butil::scoped_policy::ASSUME) : ScopedTypeRef(object, policy) {} diff --git a/src/butil/mac/scoped_typeref.h b/src/butil/mac/scoped_typeref.h index 85efbf4913..22e9de4aed 100644 --- a/src/butil/mac/scoped_typeref.h +++ b/src/butil/mac/scoped_typeref.h @@ -51,7 +51,7 @@ class ScopedTypeRef { typedef T element_type; ScopedTypeRef( - T object = NULL, + T object = nullptr, scoped_policy::OwnershipPolicy policy = scoped_policy::ASSUME) : object_(object) { if (object_ && policy == scoped_policy::RETAIN) @@ -76,13 +76,13 @@ class ScopedTypeRef { // This is to be used only to take ownership of objects that are created // by pass-by-pointer create functions. To enforce this, require that the - // object be reset to NULL before this may be used. + // object be reset to nullptr before this may be used. T* InitializeInto() WARN_UNUSED_RESULT { DCHECK(!object_); return &object_; } - void reset(T object = NULL, + void reset(T object = nullptr, scoped_policy::OwnershipPolicy policy = scoped_policy::ASSUME) { if (object && policy == scoped_policy::RETAIN) Traits::Retain(object); @@ -118,7 +118,7 @@ class ScopedTypeRef { // Release(), use ScopedTypeRef<>::reset(). T release() WARN_UNUSED_RESULT { T temp = object_; - object_ = NULL; + object_ = nullptr; return temp; } diff --git a/src/butil/memory/aligned_memory.cc b/src/butil/memory/aligned_memory.cc index 186032fe48..678caf74f5 100644 --- a/src/butil/memory/aligned_memory.cc +++ b/src/butil/memory/aligned_memory.cc @@ -16,7 +16,7 @@ void* AlignedAlloc(size_t size, size_t alignment) { DCHECK_GT(size, 0U); DCHECK_EQ(alignment & (alignment - 1), 0U); DCHECK_EQ(alignment % sizeof(void*), 0U); - void* ptr = NULL; + void* ptr = nullptr; #if defined(COMPILER_MSVC) ptr = _aligned_malloc(size, alignment); // Android technically supports posix_memalign(), but does not expose it in @@ -28,7 +28,7 @@ void* AlignedAlloc(size_t size, size_t alignment) { ptr = memalign(alignment, size); #else if (posix_memalign(&ptr, alignment, size)) - ptr = NULL; + ptr = nullptr; #endif // Since aligned allocations may fail for non-memory related reasons, force a // crash if we encounter a failed allocation; maintaining consistent behavior diff --git a/src/butil/memory/linked_ptr.h b/src/butil/memory/linked_ptr.h index 5773b176f0..a70daf595a 100644 --- a/src/butil/memory/linked_ptr.h +++ b/src/butil/memory/linked_ptr.h @@ -80,7 +80,7 @@ class linked_ptr { // Take over ownership of a raw pointer. This should happen as soon as // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + explicit linked_ptr(T* ptr = nullptr) { capture(ptr); } ~linked_ptr() { depart(); } // Copy an existing linked_ptr<>, adding ourselves to the list of references. @@ -107,7 +107,7 @@ class linked_ptr { } // Smart pointer members. - void reset(T* ptr = NULL) { + void reset(T* ptr = nullptr) { depart(); capture(ptr); } @@ -120,7 +120,7 @@ class linked_ptr { bool last = link_.depart(); CHECK(last); T* v = value_; - value_ = NULL; + value_ = nullptr; return v; } diff --git a/src/butil/memory/ref_counted.h b/src/butil/memory/ref_counted.h index fb8bc72d0a..b0e03b87d2 100644 --- a/src/butil/memory/ref_counted.h +++ b/src/butil/memory/ref_counted.h @@ -232,7 +232,7 @@ class RefCountedData // void some_other_function() { // scoped_refptr foo = new MyFoo(); // ... -// foo = NULL; // explicitly releases |foo| +// foo = nullptr; // explicitly releases |foo| // ... // if (foo) // foo->Method(param); @@ -247,7 +247,7 @@ class RefCountedData // scoped_refptr b; // // b.swap(a); -// // now, |b| references the MyFoo object, and |a| references NULL. +// // now, |b| references the MyFoo object, and |a| references nullptr. // } // // To make both |a| and |b| in the above example reference the same MyFoo @@ -266,7 +266,7 @@ class scoped_refptr { public: typedef T element_type; - scoped_refptr() : ptr_(NULL) { + scoped_refptr() : ptr_(nullptr) { } scoped_refptr(T* p) : ptr_(p) { @@ -308,7 +308,7 @@ class scoped_refptr { operator T*() const { return ptr_; } T* operator->() const { - assert(ptr_ != NULL); + assert(ptr_ != nullptr); return ptr_; } @@ -344,7 +344,7 @@ class scoped_refptr { // Release ownership of ptr_, keeping its reference counter unchanged. T* release() WARN_UNUSED_RESULT { - T* saved_ptr = NULL; + T* saved_ptr = nullptr; swap(&saved_ptr); return saved_ptr; } diff --git a/src/butil/memory/ref_counted_memory.cc b/src/butil/memory/ref_counted_memory.cc index 0ffd04ff4e..c79e0ea1a2 100644 --- a/src/butil/memory/ref_counted_memory.cc +++ b/src/butil/memory/ref_counted_memory.cc @@ -49,8 +49,8 @@ RefCountedBytes* RefCountedBytes::TakeVector( const unsigned char* RefCountedBytes::front() const { // STL will assert if we do front() on an empty vector, but calling code - // expects a NULL. - return size() ? &data_.front() : NULL; + // expects a nullptr. + return size() ? &data_.front() : nullptr; } size_t RefCountedBytes::size() const { @@ -71,7 +71,7 @@ RefCountedString* RefCountedString::TakeString(std::string* to_destroy) { } const unsigned char* RefCountedString::front() const { - return data_.empty() ? NULL : + return data_.empty() ? nullptr : reinterpret_cast(data_.data()); } @@ -86,7 +86,7 @@ RefCountedMallocedMemory::RefCountedMallocedMemory( } const unsigned char* RefCountedMallocedMemory::front() const { - return length_ ? data_ : NULL; + return length_ ? data_ : nullptr; } size_t RefCountedMallocedMemory::size() const { diff --git a/src/butil/memory/ref_counted_memory.h b/src/butil/memory/ref_counted_memory.h index 1d7b928d21..d8a323d8a6 100644 --- a/src/butil/memory/ref_counted_memory.h +++ b/src/butil/memory/ref_counted_memory.h @@ -21,7 +21,7 @@ class BUTIL_EXPORT RefCountedMemory : public butil::RefCountedThreadSafe { public: // Retrieves a pointer to the beginning of the data we point to. If the data - // is empty, this will return NULL. + // is empty, this will return nullptr. virtual const unsigned char* front() const = 0; // Size of the memory pointed to. @@ -46,9 +46,9 @@ class BUTIL_EXPORT RefCountedMemory class BUTIL_EXPORT RefCountedStaticMemory : public RefCountedMemory { public: RefCountedStaticMemory() - : data_(NULL), length_(0) {} + : data_(nullptr), length_(0) {} RefCountedStaticMemory(const void* data, size_t length) - : data_(static_cast(length ? data : NULL)), + : data_(static_cast(length ? data : nullptr)), length_(length) {} // Overridden from RefCountedMemory: diff --git a/src/butil/memory/scoped_ptr.h b/src/butil/memory/scoped_ptr.h index 0f435cd683..f3356bf9d8 100644 --- a/src/butil/memory/scoped_ptr.h +++ b/src/butil/memory/scoped_ptr.h @@ -58,7 +58,7 @@ // TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay"). // scoped_ptr ptr2 = CreateFoo(); // ptr2 owns the return Foo. // scoped_ptr ptr3 = // ptr3 now owns what was in ptr2. -// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL. +// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr. // } // // Notice that if you do not call Pass() when returning from PassThru(), or @@ -214,7 +214,7 @@ class scoped_ptr_impl { } ~scoped_ptr_impl() { - if (data_.ptr != NULL) { + if (data_.ptr != nullptr) { // Not using get_deleter() saves one function call in non-optimized // builds. static_cast(data_)(data_.ptr); @@ -223,7 +223,7 @@ class scoped_ptr_impl { void reset(T* p) { // This is a self-reset, which is no longer allowed: http://crbug.com/162971 - RELEASE_ASSERT(p == NULL || p != data_.ptr); + RELEASE_ASSERT(p == nullptr || p != data_.ptr); // Note that running data_.ptr = p can lead to undefined behavior if // get_deleter()(get()) deletes this. In order to prevent this, reset() @@ -235,13 +235,13 @@ class scoped_ptr_impl { // then it will incorrectly dispatch calls to |p| rather than the original // value of |data_.ptr|. // - // During the transition period, set the stored pointer to NULL while + // During the transition period, set the stored pointer to nullptr while // deleting the object. Eventually, this safety check will be removed to // prevent the scenario initially described from occuring and // http://crbug.com/176091 can be closed. T* old = data_.ptr; - data_.ptr = NULL; - if (old != NULL) + data_.ptr = nullptr; + if (old != nullptr) static_cast(data_)(old); data_.ptr = p; } @@ -262,7 +262,7 @@ class scoped_ptr_impl { T* release() { T* old_ptr = data_.ptr; - data_.ptr = NULL; + data_.ptr = nullptr; return old_ptr; } @@ -292,7 +292,7 @@ class scoped_ptr_impl { // A scoped_ptr is like a T*, except that the destructor of scoped_ptr // automatically deletes the pointer it holds (if any). // That is, scoped_ptr owns the T object that it points to. -// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// Like a T*, a scoped_ptr may hold either nullptr or a pointer to a T object. // Also like T*, scoped_ptr is thread-compatible, and once you // dereference it, you get the thread safety guarantees of T. // @@ -317,8 +317,8 @@ class scoped_ptr { typedef T element_type; typedef D deleter_type; - // Constructor. Defaults to initializing with NULL. - scoped_ptr() : impl_(NULL) { } + // Constructor. Defaults to initializing with nullptr. + scoped_ptr() : impl_(nullptr) { } // Constructor. Takes ownership of p. explicit scoped_ptr(element_type* p) : impl_(p) { } @@ -363,16 +363,16 @@ class scoped_ptr { // Reset. Deletes the currently owned object, if any. // Then takes ownership of a new object, if given. - void reset(element_type* p = NULL) { impl_.reset(p); } + void reset(element_type* p = nullptr) { impl_.reset(p); } // Accessors to get the owned object. // operator* and operator-> will assert() if there is no current object. element_type& operator*() const { - assert(impl_.get() != NULL); + assert(impl_.get() != nullptr); return *impl_.get(); } element_type* operator->() const { - assert(impl_.get() != NULL); + assert(impl_.get() != nullptr); return impl_.get(); } element_type* get() const { return impl_.get(); } @@ -393,7 +393,7 @@ class scoped_ptr { scoped_ptr::*Testable; public: - operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : nullptr; } // Comparison operators. // These return whether two scoped_ptr refer to the same object, not just to @@ -408,8 +408,8 @@ class scoped_ptr { // Release a pointer. // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, + // If this object holds a nullptr pointer, the return value is nullptr. + // After this operation, this object will hold a nullptr pointer, // and will not own the object any more. element_type* release() WARN_UNUSED_RESULT { return impl_.release(); @@ -451,8 +451,8 @@ class scoped_ptr { typedef T element_type; typedef D deleter_type; - // Constructor. Defaults to initializing with NULL. - scoped_ptr() : impl_(NULL) { } + // Constructor. Defaults to initializing with nullptr. + scoped_ptr() : impl_(nullptr) { } // Constructor. Stores the given array. Note that the argument's type // must exactly match T*. In particular: @@ -483,11 +483,11 @@ class scoped_ptr { // Reset. Deletes the currently owned array, if any. // Then takes ownership of a new object, if given. - void reset(element_type* array = NULL) { impl_.reset(array); } + void reset(element_type* array = nullptr) { impl_.reset(array); } // Accessors to get the owned array. element_type& operator[](size_t i) const { - assert(impl_.get() != NULL); + assert(impl_.get() != nullptr); return impl_.get()[i]; } element_type* get() const { return impl_.get(); } @@ -503,7 +503,7 @@ class scoped_ptr { scoped_ptr::*Testable; public: - operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : nullptr; } // Comparison operators. // These return whether two scoped_ptr refer to the same object, not just to @@ -518,8 +518,8 @@ class scoped_ptr { // Release a pointer. // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, + // If this object holds a nullptr pointer, the return value is nullptr. + // After this operation, this object will hold a nullptr pointer, // and will not own the object any more. element_type* release() WARN_UNUSED_RESULT { return impl_.release(); diff --git a/src/butil/memory/singleton.cc b/src/butil/memory/singleton.cc index 1e3bdf2e1f..4b9e3f59bd 100644 --- a/src/butil/memory/singleton.cc +++ b/src/butil/memory/singleton.cc @@ -12,7 +12,7 @@ subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance) { // Handle the race. Another thread beat us and either: // - Has the object in BeingCreated state // - Already has the object created... - // We know value != NULL. It could be kBeingCreatedMarker, or a valid ptr. + // We know value != nullptr. It could be kBeingCreatedMarker, or a valid ptr. // Unless your constructor can be very time consuming, it is very unlikely // to hit this race. When it does, we just spin and yield the thread until // the object has been created. diff --git a/src/butil/memory/singleton.h b/src/butil/memory/singleton.h index ff132bc48e..0916b9dd2d 100644 --- a/src/butil/memory/singleton.h +++ b/src/butil/memory/singleton.h @@ -121,17 +121,17 @@ const bool LeakySingletonTraits::kAllowedToAccessOnNonjoinableThread = tru template struct StaticMemorySingletonTraits { // WARNING: User has to deal with get() in the singleton class - // this is traits for returning NULL. + // this is traits for returning nullptr. static Type* New() { - // Only constructs once and returns pointer; otherwise returns NULL. + // Only constructs once and returns pointer; otherwise returns nullptr. if (butil::subtle::NoBarrier_AtomicExchange(&dead_, 1)) - return NULL; + return nullptr; return new(buffer_.void_data()) Type(); } static void Delete(Type* p) { - if (p != NULL) + if (p != nullptr) p->Type::~Type(); } @@ -252,7 +252,7 @@ class Singleton { // Object isn't created yet, maybe we will get to create it, let's try... if (butil::subtle::Acquire_CompareAndSwap( &instance_, 0, butil::internal::kBeingCreatedMarker) == 0) { - // instance_ was NULL and is now kBeingCreatedMarker. Only one thread + // instance_ was nullptr and is now kBeingCreatedMarker. Only one thread // will ever get here. Threads might be spinning on us, and they will // stop right after we do this store. Type* newval = Traits::New(); @@ -265,8 +265,8 @@ class Singleton { butil::subtle::Release_Store( &instance_, reinterpret_cast(newval)); - if (newval != NULL && Traits::kRegisterAtExit) { - butil::AtExitManager::RegisterCallback(OnExit, NULL); + if (newval != nullptr && Traits::kRegisterAtExit) { + butil::AtExitManager::RegisterCallback(OnExit, nullptr); } return newval; diff --git a/src/butil/memory/singleton_on_pthread_once.h b/src/butil/memory/singleton_on_pthread_once.h index 9699bba7cb..bc0b609e0b 100644 --- a/src/butil/memory/singleton_on_pthread_once.h +++ b/src/butil/memory/singleton_on_pthread_once.h @@ -69,8 +69,8 @@ inline T* get_leaky_singleton() { GetLeakySingleton::g_leaky_singleton_untyped); } -// True(non-NULL) if the singleton is created. -// The returned object (if not NULL) can be used directly. +// True(non-nullptr) if the singleton is created. +// The returned object (if not nullptr) can be used directly. template inline T* has_leaky_singleton() { return reinterpret_cast( diff --git a/src/butil/memory/weak_ptr.cc b/src/butil/memory/weak_ptr.cc index 0954572a49..2887a8f570 100644 --- a/src/butil/memory/weak_ptr.cc +++ b/src/butil/memory/weak_ptr.cc @@ -50,7 +50,7 @@ WeakReference WeakReferenceOwner::GetRef() const { void WeakReferenceOwner::Invalidate() { if (flag_.get()) { flag_->Invalidate(); - flag_ = NULL; + flag_ = nullptr; } } diff --git a/src/butil/memory/weak_ptr.h b/src/butil/memory/weak_ptr.h index fd65bc92eb..7e4ae4c35c 100644 --- a/src/butil/memory/weak_ptr.h +++ b/src/butil/memory/weak_ptr.h @@ -3,7 +3,7 @@ // found in the LICENSE file. // Weak pointers are pointers to an object that do not affect its lifetime, -// and which may be invalidated (i.e. reset to NULL) by the object, or its +// and which may be invalidated (i.e. reset to nullptr) by the object, or its // owner, at any time, most commonly when the object is about to be deleted. // Weak pointers are useful when an object needs to be accessed safely by one @@ -189,7 +189,7 @@ template class WeakPtrFactory; template class WeakPtr : public internal::WeakPtrBase { public: - WeakPtr() : ptr_(NULL) { + WeakPtr() : ptr_(nullptr) { } // Allow conversion from U to T provided U "is a" T. Note that this @@ -198,14 +198,14 @@ class WeakPtr : public internal::WeakPtrBase { WeakPtr(const WeakPtr& other) : WeakPtrBase(other), ptr_(other.ptr_) { } - T* get() const { return ref_.is_valid() ? ptr_ : NULL; } + T* get() const { return ref_.is_valid() ? ptr_ : nullptr; } T& operator*() const { - DCHECK(get() != NULL); + DCHECK(get() != nullptr); return *get(); } T* operator->() const { - DCHECK(get() != NULL); + DCHECK(get() != nullptr); return get(); } @@ -220,11 +220,11 @@ class WeakPtr : public internal::WeakPtrBase { typedef T* WeakPtr::*Testable; public: - operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; } + operator Testable() const { return get() ? &WeakPtr::ptr_ : nullptr; } void reset() { ref_ = internal::WeakReference(); - ptr_ = NULL; + ptr_ = nullptr; } private: @@ -244,7 +244,7 @@ class WeakPtr : public internal::WeakPtrBase { } // This pointer is only valid when ref_.is_valid() is true. Otherwise, its - // value is undefined (as opposed to NULL). + // value is undefined (as opposed to nullptr). T* ptr_; }; @@ -260,7 +260,7 @@ class WeakPtrFactory { } ~WeakPtrFactory() { - ptr_ = NULL; + ptr_ = nullptr; } WeakPtr GetWeakPtr() { diff --git a/src/butil/object_pool.h b/src/butil/object_pool.h index 92bc4036c3..40bd28e7ae 100644 --- a/src/butil/object_pool.h +++ b/src/butil/object_pool.h @@ -58,7 +58,7 @@ template struct ObjectPoolFreeChunkMaxItem { // ObjectPool calls this function on newly constructed objects. If this // function returns false, the object is destructed immediately and -// get_object() shall return NULL. This is useful when the constructor +// get_object() shall return nullptr. This is useful when the constructor // failed internally(namely ENOMEM). template struct ObjectPoolValidator { static bool validate(const T*) { return true; } diff --git a/src/butil/object_pool_inl.h b/src/butil/object_pool_inl.h index c98ec16f9d..caabca9b06 100644 --- a/src/butil/object_pool_inl.h +++ b/src/butil/object_pool_inl.h @@ -90,14 +90,14 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { private: #ifdef BUTIL_USE_ASAN static void asan_poison_memory_region(T* ptr) { - if (!ObjectPoolWithASanPoison::value || NULL == ptr) { + if (!ObjectPoolWithASanPoison::value || nullptr == ptr) { return; } // Marks the object as addressable. BUTIL_ASAN_POISON_MEMORY_REGION(ptr, sizeof(T)); } static void asan_unpoison_memory_region(T* ptr) { - if (!ObjectPoolWithASanPoison::value || NULL == ptr) { + if (!ObjectPoolWithASanPoison::value || nullptr == ptr) { return; } // Marks the object as unaddressable. @@ -147,7 +147,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { BlockGroup() : nblock(0) { // We fetch_add nblock in add_block() before setting the entry, // thus address_resource() may sees the unset entry. Initialize - // all entries to NULL makes such address_resource() return NULL. + // all entries to nullptr makes such address_resource() return nullptr. memset(static_cast(blocks), 0, sizeof(butil::atomic) * OP_GROUP_NBLOCK); } }; @@ -157,7 +157,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { public: explicit LocalPool(ObjectPool* pool) : _pool(pool) - , _cur_block(NULL) + , _cur_block(nullptr) , _cur_block_index(0) { _cur_free.nfree = 0; } @@ -192,14 +192,14 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { BAIDU_OBJECT_POOL_FREE_ITEM_NUM_SUB1; \ return _cur_free.ptrs[--_cur_free.nfree]; \ } \ - T* obj = NULL; \ + T* obj = nullptr; \ /* Fetch memory from local block */ \ if (_cur_block && _cur_block->nitem < BLOCK_NITEM) { \ auto item = _cur_block->items + _cur_block->nitem; \ obj = new (item->void_data()) T CTOR_ARGS; \ if (!ObjectPoolValidator::validate(obj)) { \ obj->~T(); \ - return NULL; \ + return nullptr; \ } \ /* It's poisoned prior to use. */ \ OBJECT_POOL_ASAN_POISON_MEMORY_REGION(obj); \ @@ -208,19 +208,19 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { } \ /* Fetch a Block from global */ \ _cur_block = add_block(&_cur_block_index); \ - if (_cur_block != NULL) { \ + if (_cur_block != nullptr) { \ auto item = _cur_block->items + _cur_block->nitem; \ obj = new (item->void_data()) T CTOR_ARGS; \ if (!ObjectPoolValidator::validate(obj)) { \ obj->~T(); \ - return NULL; \ + return nullptr; \ } \ /* It's poisoned prior to use. */ \ OBJECT_POOL_ASAN_POISON_MEMORY_REGION(obj); \ ++_cur_block->nitem; \ return obj; \ } \ - return NULL; \ + return nullptr; \ inline T* get() { @@ -268,7 +268,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { inline bool local_free_empty() { LocalPool* lp = get_or_new_local_pool(); - if (BAIDU_LIKELY(lp != NULL)) { + if (BAIDU_LIKELY(lp != nullptr)) { return lp->free_empty(); } return true; @@ -277,8 +277,8 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { template inline T* get_object(Args&&... args) { LocalPool* lp = get_or_new_local_pool(); - T* ptr = NULL; - if (BAIDU_LIKELY(lp != NULL)) { + T* ptr = nullptr; + if (BAIDU_LIKELY(lp != nullptr)) { ptr = lp->get(std::forward(args)...); OBJECT_POOL_ASAN_UNPOISON_MEMORY_REGION(ptr); } @@ -287,7 +287,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { inline int return_object(T* ptr) { LocalPool* lp = get_or_new_local_pool(); - if (BAIDU_LIKELY(lp != NULL)) { + if (BAIDU_LIKELY(lp != nullptr)) { return lp->return_object(ptr); } return -1; @@ -296,7 +296,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { void clear_objects() { LocalPool* lp = _local_pool; if (lp) { - _local_pool = NULL; + _local_pool = nullptr; butil::thread_atexit_cancel(LocalPool::delete_local_pool, lp); delete lp; } @@ -322,7 +322,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { for (size_t i = 0; i < info.block_group_num; ++i) { BlockGroup* bg = _block_groups[i].load(butil::memory_order_consume); - if (NULL == bg) { + if (nullptr == bg) { break; } size_t nblock = std::min(bg->nblock.load(butil::memory_order_relaxed), @@ -330,7 +330,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { info.block_num += nblock; for (size_t j = 0; j < nblock; ++j) { Block* b = bg->blocks[j].load(butil::memory_order_consume); - if (NULL != b) { + if (nullptr != b) { info.item_num += b->nitem; } } @@ -357,7 +357,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { private: ObjectPool() { _free_chunks.reserve(OP_INITIAL_FREE_LIST_SIZE); - pthread_mutex_init(&_free_chunks_mutex, NULL); + pthread_mutex_init(&_free_chunks_mutex, nullptr); #if defined(BUTIL_USE_ASAN) && \ !defined(BAIDU_CLEAR_OBJECT_POOL_AFTER_ALL_THREADS_QUIT) // Objects returned to the pool stay ASan-poisoned (see return_object()). @@ -390,20 +390,20 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { // not destruct: the pool intentionally keeps objects alive for reuse, and // they remain reachable from the singleton, so they are not real leaks. static void unpoison_all_objects_before_leak_check() { - if (NULL == _singleton.load(butil::memory_order_consume)) { + if (nullptr == _singleton.load(butil::memory_order_consume)) { return; } const size_t ngroup = _ngroup.load(butil::memory_order_acquire); for (size_t i = 0; i < ngroup; ++i) { BlockGroup* bg = _block_groups[i].load(butil::memory_order_consume); - if (NULL == bg) { + if (nullptr == bg) { break; } const size_t nblock = std::min( bg->nblock.load(butil::memory_order_relaxed), OP_GROUP_NBLOCK); for (size_t j = 0; j < nblock; ++j) { Block* b = bg->blocks[j].load(butil::memory_order_consume); - if (NULL == b) { + if (nullptr == b) { continue; } for (size_t k = 0; k < b->nitem; ++k) { @@ -417,8 +417,8 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { // Create a Block and append it to right-most BlockGroup. static Block* add_block(size_t* index) { Block* const new_block = new(std::nothrow) Block; - if (NULL == new_block) { - return NULL; + if (nullptr == new_block) { + return nullptr; } size_t ngroup; do { @@ -440,13 +440,13 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { // Fail to add_block_group. delete new_block; - return NULL; + return nullptr; } // Create a BlockGroup and append it to _block_groups. // Shall be called infrequently because a BlockGroup is pretty big. static bool add_block_group(size_t old_ngroup) { - BlockGroup* bg = NULL; + BlockGroup* bg = nullptr; BAIDU_SCOPED_LOCK(_block_group_mutex); const size_t ngroup = _ngroup.load(butil::memory_order_acquire); if (ngroup != old_ngroup) { @@ -455,25 +455,22 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { } if (ngroup < OP_MAX_BLOCK_NGROUP) { bg = new(std::nothrow) BlockGroup; - if (NULL != bg) { + if (nullptr != bg) { // Release fence is paired with consume fence in add_block() // to avoid un-constructed bg to be seen by other threads. _block_groups[ngroup].store(bg, butil::memory_order_release); _ngroup.store(ngroup + 1, butil::memory_order_release); } } - return bg != NULL; + return bg != nullptr; } inline LocalPool* get_or_new_local_pool() { LocalPool* lp = BAIDU_GET_VOLATILE_THREAD_LOCAL(_local_pool); - if (BAIDU_LIKELY(lp != NULL)) { + if (BAIDU_LIKELY(lp != nullptr)) { return lp; } - lp = new(std::nothrow) LocalPool(this); - if (NULL == lp) { - return NULL; - } + lp = new LocalPool(this); BAIDU_SCOPED_LOCK(_change_thread_mutex); //avoid race with clear() BAIDU_SET_VOLATILE_THREAD_LOCAL(_local_pool, lp); butil::thread_atexit(LocalPool::delete_local_pool, lp); @@ -483,7 +480,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { void clear_from_destructor_of_local_pool() { // Remove tls - _local_pool = NULL; + _local_pool = nullptr; // Do nothing if there're active threads. if (_nlocal.fetch_sub(1, butil::memory_order_relaxed) != 1) { @@ -512,14 +509,14 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { const size_t ngroup = _ngroup.exchange(0, butil::memory_order_relaxed); for (size_t i = 0; i < ngroup; ++i) { BlockGroup* bg = _block_groups[i].load(butil::memory_order_relaxed); - if (NULL == bg) { + if (nullptr == bg) { break; } size_t nblock = std::min(bg->nblock.load(butil::memory_order_relaxed), OP_GROUP_NBLOCK); for (size_t j = 0; j < nblock; ++j) { Block* b = bg->blocks[j].load(butil::memory_order_relaxed); - if (NULL == b) { + if (nullptr == b) { continue; } for (size_t k = 0; k < b->nitem; ++k) { @@ -596,10 +593,10 @@ const size_t ObjectPool::FREE_CHUNK_NITEM; template BAIDU_THREAD_LOCAL typename ObjectPool::LocalPool* -ObjectPool::_local_pool = NULL; +ObjectPool::_local_pool = nullptr; template -butil::static_atomic*> ObjectPool::_singleton = BUTIL_STATIC_ATOMIC_INIT(NULL); +butil::static_atomic*> ObjectPool::_singleton = BUTIL_STATIC_ATOMIC_INIT(nullptr); template pthread_mutex_t ObjectPool::_singleton_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/src/butil/observer_list.h b/src/butil/observer_list.h index 8f0dd3b588..807f7921e3 100644 --- a/src/butil/observer_list.h +++ b/src/butil/observer_list.h @@ -95,13 +95,13 @@ class ObserverListBase ObserverType* GetNext() { if (!list_.get()) - return NULL; + return nullptr; ListType& observers = list_->observers_; // Advance if the current element is null size_t max_index = std::min(max_index_, observers.size()); while (index_ < max_index && !observers[index_]) ++index_; - return index_ < max_index ? observers[index_++] : NULL; + return index_ < max_index ? observers[index_++] : nullptr; } private: @@ -163,7 +163,7 @@ class ObserverListBase void Compact() { observers_.erase( std::remove(observers_.begin(), observers_.end(), - static_cast(NULL)), observers_.end()); + static_cast(nullptr)), observers_.end()); } private: @@ -209,7 +209,7 @@ class ObserverList : public ObserverListBase { ObserverListBase::Iterator \ it_inside_observer_macro(observer_list); \ ObserverType* obs; \ - while ((obs = it_inside_observer_macro.GetNext()) != NULL) \ + while ((obs = it_inside_observer_macro.GetNext()) != nullptr) \ obs->func; \ } \ } while (0) diff --git a/src/butil/popen.cpp b/src/butil/popen.cpp index 506a0d1bd8..9d959327f4 100644 --- a/src/butil/popen.cpp +++ b/src/butil/popen.cpp @@ -50,7 +50,7 @@ int launch_child_process(void* args) { dup2(cargs->pipe_fd1, STDOUT_FILENO); close(cargs->pipe_fd0); close(cargs->pipe_fd1); - execl("/bin/sh", "sh", "-c", cargs->cmd, NULL); + execl("/bin/sh", "sh", "-c", cargs->cmd, nullptr); _exit(1); } @@ -67,7 +67,7 @@ int read_command_output_through_clone(std::ostream& os, const char* cmd) { ChildArgs args = { cmd, pipe_fd[0], pipe_fd[1] }; char buffer[1024]; - char* child_stack = NULL; + char* child_stack = nullptr; char* child_stack_mem = (char*)malloc(CHILD_STACK_SIZE); if (!child_stack_mem) { LOG(ERROR) << "Fail to alloc stack for the child process"; @@ -108,7 +108,7 @@ int read_command_output_through_clone(std::ostream& os, const char* cmd) { break; } if (wpid == 0) { - if (bthread_usleep != NULL) { + if (bthread_usleep != nullptr) { bthread_usleep(1000); } else { usleep(1000); @@ -157,7 +157,7 @@ DEFINE_bool(run_command_through_clone, false, int read_command_output_through_popen(std::ostream& os, const char* cmd) { FILE* pipe = popen(cmd, "r"); - if (pipe == NULL) { + if (pipe == nullptr) { return -1; } char buffer[1024]; diff --git a/src/butil/ptr_container.h b/src/butil/ptr_container.h index 5732bbd570..24711c4e73 100644 --- a/src/butil/ptr_container.h +++ b/src/butil/ptr_container.h @@ -28,7 +28,7 @@ namespace butil { template class PtrContainer { public: - PtrContainer() : _ptr(NULL) {} + PtrContainer() : _ptr(nullptr) {} explicit PtrContainer(T* obj) : _ptr(obj) {} @@ -37,7 +37,7 @@ class PtrContainer { } PtrContainer(const PtrContainer& rhs) - : _ptr(rhs._ptr ? new T(*rhs._ptr) : NULL) {} + : _ptr(rhs._ptr ? new T(*rhs._ptr) : nullptr) {} void operator=(const PtrContainer& rhs) { if (this == &rhs) { @@ -52,7 +52,7 @@ class PtrContainer { } } else { delete _ptr; - _ptr = NULL; + _ptr = nullptr; } } @@ -65,7 +65,7 @@ class PtrContainer { operator void*() const { return _ptr; } - explicit operator bool() const { return get() != NULL; } + explicit operator bool() const { return get() != nullptr; } T& operator*() const { return *get(); } diff --git a/src/butil/recordio.cc b/src/butil/recordio.cc index dc51cf9167..884985607d 100644 --- a/src/butil/recordio.cc +++ b/src/butil/recordio.cc @@ -81,22 +81,22 @@ const butil::IOBuf* Record::Meta(const char* name) const { return _metas[i].data.get(); } } - return NULL; + return nullptr; } butil::IOBuf* Record::MutableMeta(const char* name_cstr, bool null_on_found) { const butil::StringPiece name = name_cstr; for (size_t i = 0; i < _metas.size(); ++i) { if (_metas[i].name == name) { - return null_on_found ? NULL : _metas[i].data.get(); + return null_on_found ? nullptr : _metas[i].data.get(); } } if (name.size() > MAX_NAME_SIZE) { LOG(ERROR) << "Too long name=" << name; - return NULL; + return nullptr; } else if (name.empty()) { LOG(ERROR) << "Empty name"; - return NULL; + return nullptr; } NamedMeta p; name.CopyToString(&p.name); @@ -108,15 +108,15 @@ butil::IOBuf* Record::MutableMeta(const char* name_cstr, bool null_on_found) { butil::IOBuf* Record::MutableMeta(const std::string& name, bool null_on_found) { for (size_t i = 0; i < _metas.size(); ++i) { if (_metas[i].name == name) { - return null_on_found ? NULL : _metas[i].data.get(); + return null_on_found ? nullptr : _metas[i].data.get(); } } if (name.size() > MAX_NAME_SIZE) { LOG(ERROR) << "Too long name" << name; - return NULL; + return nullptr; } else if (name.empty()) { LOG(ERROR) << "Empty name"; - return NULL; + return nullptr; } NamedMeta p; p.name = name; @@ -278,7 +278,7 @@ int RecordReader::CutRecord(Record* rec) { return -1; } butil::IOBuf* meta = rec->MutableMeta(name, true/*null_on_found*/); - if (meta == NULL) { + if (meta == nullptr) { LOG(ERROR) << "Fail to add meta=" << name << ", offset=" << offset(); return -1; diff --git a/src/butil/recordio.h b/src/butil/recordio.h index 8605f59e50..db34d7f3dd 100644 --- a/src/butil/recordio.h +++ b/src/butil/recordio.h @@ -41,12 +41,12 @@ class Record { // This method is mainly for iterating all metas. const NamedMeta& MetaAt(size_t i) const { return _metas[i]; } - // Get meta by |name|. NULL on not found. + // Get meta by |name|. nullptr on not found. const butil::IOBuf* Meta(const char* name) const; // Returns a mutable pointer to the meta with |name|. If the meta does // not exist, add it first. - // If |null_on_found| is true and meta with |name| is present, NULL is + // If |null_on_found| is true and meta with |name| is present, nullptr is // returned. This is useful for detecting uniqueness of meta names in some // scenarios. // NOTE: With the assumption that there won't be many metas, the impl. diff --git a/src/butil/resource_pool.h b/src/butil/resource_pool.h index e1c09faf86..6473997f61 100644 --- a/src/butil/resource_pool.h +++ b/src/butil/resource_pool.h @@ -78,7 +78,7 @@ template struct ResourcePoolFreeChunkMaxItem { // ResourcePool calls this function on newly constructed objects. If this // function returns false, the object is destructed immediately and -// get_resource() shall return NULL. This is useful when the constructor +// get_resource() shall return nullptr. This is useful when the constructor // failed internally(namely ENOMEM). template struct ResourcePoolValidator { static bool validate(const T*) { return true; } @@ -108,9 +108,9 @@ template inline int return_resource(ResourceId id) { } // Get the object associated with the identifier |id|. -// Returns NULL if |id| was not allocated by get_resource or +// Returns nullptr if |id| was not allocated by get_resource or // ResourcePool::get_resource() of a variant before. -// Addressing a free(returned to pool) identifier does not return NULL. +// Addressing a free(returned to pool) identifier does not return nullptr. // NOTE: Calling this function before any other get_resource/ // return_resource/address, even if the identifier is valid, // may race with another thread calling clear_resources. diff --git a/src/butil/resource_pool_inl.h b/src/butil/resource_pool_inl.h index 82649103a8..163b033443 100644 --- a/src/butil/resource_pool_inl.h +++ b/src/butil/resource_pool_inl.h @@ -131,7 +131,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { BlockGroup() : nblock(0) { // We fetch_add nblock in add_block() before setting the entry, // thus address_resource() may sees the unset entry. Initialize - // all entries to NULL makes such address_resource() return NULL. + // all entries to nullptr makes such address_resource() return nullptr. memset(static_cast(blocks), 0, sizeof(butil::atomic) * RP_GROUP_NBLOCK); } }; @@ -142,7 +142,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { public: explicit LocalPool(ResourcePool* pool) : _pool(pool) - , _cur_block(NULL) + , _cur_block(nullptr) , _cur_block_index(0) { _cur_free.nfree = 0; } @@ -182,7 +182,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { BAIDU_RESOURCE_POOL_FREE_ITEM_NUM_SUB1; \ return unsafe_address_resource(free_id); \ } \ - T* p = NULL; \ + T* p = nullptr; \ /* Fetch memory from local block */ \ if (_cur_block && _cur_block->nitem < BLOCK_NITEM) { \ id->value = _cur_block_index * BLOCK_NITEM + _cur_block->nitem; \ @@ -190,25 +190,25 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { p = new (item->void_data()) T CTOR_ARGS; \ if (!ResourcePoolValidator::validate(p)) { \ p->~T(); \ - return NULL; \ + return nullptr; \ } \ ++_cur_block->nitem; \ return p; \ } \ /* Fetch a Block from global */ \ _cur_block = add_block(&_cur_block_index); \ - if (_cur_block != NULL) { \ + if (_cur_block != nullptr) { \ id->value = _cur_block_index * BLOCK_NITEM + _cur_block->nitem; \ auto item = _cur_block->items + _cur_block->nitem; \ p = new (item->void_data()) T CTOR_ARGS; \ if (!ResourcePoolValidator::validate(p)) { \ p->~T(); \ - return NULL; \ + return nullptr; \ } \ ++_cur_block->nitem; \ return p; \ } \ - return NULL; \ + return nullptr; \ inline T* get(ResourceId* id) { @@ -262,10 +262,10 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { if (__builtin_expect(group_index < RP_MAX_BLOCK_NGROUP, 1)) { BlockGroup* bg = _block_groups[group_index].load(butil::memory_order_consume); - if (__builtin_expect(bg != NULL, 1)) { + if (__builtin_expect(bg != nullptr, 1)) { Block* b = bg->blocks[block_index & (RP_GROUP_NBLOCK - 1)] .load(butil::memory_order_consume); - if (__builtin_expect(b != NULL, 1)) { + if (__builtin_expect(b != nullptr, 1)) { const size_t offset = id.value - block_index * BLOCK_NITEM; if (__builtin_expect(offset < b->nitem, 1)) { return (T*)b->items + offset; @@ -274,21 +274,21 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { } } - return NULL; + return nullptr; } template inline T* get_resource(ResourceId* id, Args&&... args) { LocalPool* lp = get_or_new_local_pool(); - if (__builtin_expect(lp != NULL, 1)) { + if (__builtin_expect(lp != nullptr, 1)) { return lp->get(id, std::forward(args)...); } - return NULL; + return nullptr; } inline int return_resource(ResourceId id) { LocalPool* lp = get_or_new_local_pool(); - if (__builtin_expect(lp != NULL, 1)) { + if (__builtin_expect(lp != nullptr, 1)) { return lp->return_resource(id); } return -1; @@ -297,7 +297,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { void clear_resources() { LocalPool* lp = _local_pool; if (lp) { - _local_pool = NULL; + _local_pool = nullptr; butil::thread_atexit_cancel(LocalPool::delete_local_pool, lp); delete lp; } @@ -312,14 +312,14 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { void for_each_resource(F const& f) { for (size_t i = 0; i < _ngroup.load(butil::memory_order_acquire); ++i) { BlockGroup* bg = _block_groups[i].load(butil::memory_order_consume); - if (NULL == bg) { + if (nullptr == bg) { break; } size_t nblock = std::min(bg->nblock.load(butil::memory_order_relaxed), RP_GROUP_NBLOCK); for (size_t j = 0; j < nblock; ++j) { Block* b = bg->blocks[j].load(butil::memory_order_consume); - if (NULL != b) { + if (nullptr != b) { for (size_t k = 0; k < b->nitem; ++k) { auto item = b->items + k; T* obj = (T*)item->void_data(); @@ -345,7 +345,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { for (size_t i = 0; i < info.block_group_num; ++i) { BlockGroup* bg = _block_groups[i].load(butil::memory_order_consume); - if (NULL == bg) { + if (nullptr == bg) { break; } size_t nblock = std::min(bg->nblock.load(butil::memory_order_relaxed), @@ -353,7 +353,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { info.block_num += nblock; for (size_t j = 0; j < nblock; ++j) { Block* b = bg->blocks[j].load(butil::memory_order_consume); - if (NULL != b) { + if (nullptr != b) { info.item_num += b->nitem; } } @@ -380,7 +380,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { private: ResourcePool() { _free_chunks.reserve(RP_INITIAL_FREE_LIST_SIZE); - pthread_mutex_init(&_free_chunks_mutex, NULL); + pthread_mutex_init(&_free_chunks_mutex, nullptr); } ~ResourcePool() { @@ -390,8 +390,8 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { // Create a Block and append it to right-most BlockGroup. static Block* add_block(size_t* index) { Block* const new_block = new (std::nothrow) Block; - if (NULL == new_block) { - return NULL; + if (nullptr == new_block) { + return nullptr; } size_t ngroup; @@ -414,13 +414,13 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { // Fail to add_block_group. delete new_block; - return NULL; + return nullptr; } // Create a BlockGroup and append it to _block_groups. // Shall be called infrequently because a BlockGroup is pretty big. static bool add_block_group(size_t old_ngroup) { - BlockGroup* bg = NULL; + BlockGroup* bg = nullptr; BAIDU_SCOPED_LOCK(_block_group_mutex); const size_t ngroup = _ngroup.load(butil::memory_order_acquire); if (ngroup != old_ngroup) { @@ -429,7 +429,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { } if (ngroup < RP_MAX_BLOCK_NGROUP) { bg = new(std::nothrow) BlockGroup; - if (NULL != bg) { + if (nullptr != bg) { // Release fence is paired with consume fence in address() and // add_block() to avoid un-constructed bg to be seen by other // threads. @@ -437,17 +437,17 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { _ngroup.store(ngroup + 1, butil::memory_order_release); } } - return bg != NULL; + return bg != nullptr; } inline LocalPool* get_or_new_local_pool() { LocalPool* lp = BAIDU_GET_VOLATILE_THREAD_LOCAL(_local_pool); - if (lp != NULL) { + if (lp != nullptr) { return lp; } lp = new(std::nothrow) LocalPool(this); - if (NULL == lp) { - return NULL; + if (nullptr == lp) { + return nullptr; } BAIDU_SCOPED_LOCK(_change_thread_mutex); //avoid race with clear() BAIDU_SET_VOLATILE_THREAD_LOCAL(_local_pool, lp); @@ -458,7 +458,7 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { void clear_from_destructor_of_local_pool() { // Remove tls - _local_pool = NULL; + _local_pool = nullptr; if (_nlocal.fetch_sub(1, butil::memory_order_relaxed) != 1) { return; @@ -486,14 +486,14 @@ class BAIDU_CACHELINE_ALIGNMENT ResourcePool { const size_t ngroup = _ngroup.exchange(0, butil::memory_order_relaxed); for (size_t i = 0; i < ngroup; ++i) { BlockGroup* bg = _block_groups[i].load(butil::memory_order_relaxed); - if (NULL == bg) { + if (nullptr == bg) { break; } size_t nblock = std::min(bg->nblock.load(butil::memory_order_relaxed), RP_GROUP_NBLOCK); for (size_t j = 0; j < nblock; ++j) { Block* b = bg->blocks[j].load(butil::memory_order_relaxed); - if (NULL == b) { + if (nullptr == b) { continue; } for (size_t k = 0; k < b->nitem; ++k) { @@ -568,11 +568,11 @@ const size_t ResourcePool::FREE_CHUNK_NITEM; template BAIDU_THREAD_LOCAL typename ResourcePool::LocalPool* -ResourcePool::_local_pool = NULL; +ResourcePool::_local_pool = nullptr; template butil::static_atomic*> ResourcePool::_singleton = - BUTIL_STATIC_ATOMIC_INIT(NULL); + BUTIL_STATIC_ATOMIC_INIT(nullptr); template pthread_mutex_t ResourcePool::_singleton_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/src/butil/safe_strerror_posix.cc b/src/butil/safe_strerror_posix.cc index ece0c4af17..e12f7d508e 100644 --- a/src/butil/safe_strerror_posix.cc +++ b/src/butil/safe_strerror_posix.cc @@ -97,7 +97,7 @@ static void POSSIBLY_UNUSED wrap_posix_strerror_r( } void safe_strerror_r(int err, char *buf, size_t len) { - if (buf == NULL || len <= 0) { + if (buf == nullptr || len <= 0) { return; } // If using glibc (i.e., Linux), the compiler will automatically select the diff --git a/src/butil/scoped_lock.h b/src/butil/scoped_lock.h index 1111daab8c..604b054531 100644 --- a/src/butil/scoped_lock.h +++ b/src/butil/scoped_lock.h @@ -77,7 +77,7 @@ template class unique_lock { DISALLOW_COPY_AND_ASSIGN(unique_lock); public: typedef Mutex mutex_type; - unique_lock() : _mutex(NULL), _owns_lock(false) {} + unique_lock() : _mutex(nullptr), _owns_lock(false) {} explicit unique_lock(mutex_type& mutex) : _mutex(&mutex), _owns_lock(true) { mutex.lock(); @@ -132,7 +132,7 @@ template class unique_lock { mutex_type* release() { mutex_type* saved_mutex = _mutex; - _mutex = NULL; + _mutex = nullptr; _owns_lock = false; return saved_mutex; } @@ -157,7 +157,7 @@ template<> class lock_guard { const int rc = pthread_mutex_lock(_pmutex); if (rc) { LOG(FATAL) << "Fail to lock pthread_mutex_t=" << _pmutex << ", " << berror(rc); - _pmutex = NULL; + _pmutex = nullptr; } #else pthread_mutex_lock(_pmutex); @@ -186,7 +186,7 @@ template<> class lock_guard { const int rc = pthread_spin_lock(_pspin); if (rc) { LOG(FATAL) << "Fail to lock pthread_spinlock_t=" << _pspin << ", " << berror(rc); - _pspin = NULL; + _pspin = nullptr; } #else pthread_spin_lock(_pspin); @@ -212,7 +212,7 @@ template<> class unique_lock { DISALLOW_COPY_AND_ASSIGN(unique_lock); public: typedef pthread_mutex_t mutex_type; - unique_lock() : _mutex(NULL), _owns_lock(false) {} + unique_lock() : _mutex(nullptr), _owns_lock(false) {} explicit unique_lock(mutex_type& mutex) : _mutex(&mutex), _owns_lock(true) { pthread_mutex_lock(_mutex); @@ -276,7 +276,7 @@ template<> class unique_lock { mutex_type* release() { mutex_type* saved_mutex = _mutex; - _mutex = NULL; + _mutex = nullptr; _owns_lock = false; return saved_mutex; } @@ -294,7 +294,7 @@ template<> class unique_lock { DISALLOW_COPY_AND_ASSIGN(unique_lock); public: typedef pthread_spinlock_t mutex_type; - unique_lock() : _mutex(NULL), _owns_lock(false) {} + unique_lock() : _mutex(nullptr), _owns_lock(false) {} explicit unique_lock(mutex_type& mutex) : _mutex(&mutex), _owns_lock(true) { pthread_spin_lock(_mutex); @@ -358,7 +358,7 @@ template<> class unique_lock { mutex_type* release() { mutex_type* saved_mutex = _mutex; - _mutex = NULL; + _mutex = nullptr; _owns_lock = false; return saved_mutex; } diff --git a/src/butil/shared_object.h b/src/butil/shared_object.h index abcfd46c4b..aaed0efdd4 100644 --- a/src/butil/shared_object.h +++ b/src/butil/shared_object.h @@ -45,7 +45,7 @@ friend void intrusive_ptr_release(SharedObject*); { return _nref.fetch_add(1, butil::memory_order_relaxed); } // Remove one ref, if the ref_count hit zero, delete this object. - // Same as butil::intrusive_ptr(obj, false).reset(NULL) + // Same as butil::intrusive_ptr(obj, false).reset(nullptr) void RemoveRefManually() { if (_nref.fetch_sub(1, butil::memory_order_release) == 1) { butil::atomic_thread_fence(butil::memory_order_acquire); diff --git a/src/butil/single_iobuf.cpp b/src/butil/single_iobuf.cpp index 7fc9bbcd04..f47d07619f 100644 --- a/src/butil/single_iobuf.cpp +++ b/src/butil/single_iobuf.cpp @@ -25,15 +25,15 @@ namespace butil { SingleIOBuf::SingleIOBuf() - : _cur_block(NULL) + : _cur_block(nullptr) , _block_size(0) { _cur_ref.offset = 0; _cur_ref.length = 0; - _cur_ref.block = NULL; + _cur_ref.block = nullptr; } SingleIOBuf::SingleIOBuf(const IOBuf::BlockRef& ref) { - _cur_block = NULL; + _cur_block = nullptr; _block_size = 0; if (ref.block) { _cur_ref = ref; @@ -42,9 +42,9 @@ SingleIOBuf::SingleIOBuf(const IOBuf::BlockRef& ref) { } SingleIOBuf::SingleIOBuf(const SingleIOBuf& other) { - _cur_block = NULL; + _cur_block = nullptr; _block_size = 0; - if (other._cur_ref.block != NULL) { + if (other._cur_ref.block != nullptr) { _cur_ref = other._cur_ref; _cur_ref.block->inc_ref(); } @@ -57,7 +57,7 @@ SingleIOBuf::~SingleIOBuf() { SingleIOBuf& SingleIOBuf::operator=(const SingleIOBuf& rhs) { reset(); _block_size = 0; - if (rhs._cur_ref.block != NULL) { + if (rhs._cur_ref.block != nullptr) { _cur_ref = rhs._cur_ref; _cur_ref.block->inc_ref(); } @@ -83,7 +83,7 @@ void SingleIOBuf::swap(SingleIOBuf& other) { void* SingleIOBuf::allocate(uint32_t size) { IOBuf::Block* b = alloc_block_by_size(size); if (!b) { - return NULL; + return nullptr; } _cur_ref.offset = b->size; _cur_ref.length = size; @@ -102,23 +102,23 @@ void SingleIOBuf::deallocate(void* p) { } IOBuf::Block* SingleIOBuf::alloc_block_by_size(uint32_t data_size) { - if (_cur_block != NULL) { + if (_cur_block != nullptr) { if (_cur_block->left_space() >= data_size) { return _cur_block; } else { _cur_block->dec_ref(); - _cur_block = NULL; + _cur_block = nullptr; } } uint32_t total_size = data_size + sizeof(IOBuf::Block); if (total_size <= butil::GetDefaultBlockSize()) { _cur_block = iobuf::acquire_tls_block(); - if (_cur_block != NULL) { + if (_cur_block != nullptr) { if (_cur_block->left_space() >= data_size) { return _cur_block; } else { _cur_block->dec_ref(); - _cur_block = NULL; + _cur_block = nullptr; } } _cur_block = iobuf::create_block(); @@ -129,7 +129,7 @@ IOBuf::Block* SingleIOBuf::alloc_block_by_size(uint32_t data_size) { if (BAIDU_UNLIKELY(!_cur_block)) { errno = ENOMEM; _block_size = 0; - return NULL; + return nullptr; } return _cur_block; } @@ -148,18 +148,18 @@ void* SingleIOBuf::reallocate_downward(uint32_t new_size, uint32_t in_use_back, if (BAIDU_UNLIKELY(new_size <= ref.length)) { LOG(ERROR) << "invalid new size:" << new_size; errno = EINVAL; - return NULL; + return nullptr; } - if (BAIDU_UNLIKELY(ref.block == NULL)) { + if (BAIDU_UNLIKELY(ref.block == nullptr)) { LOG(ERROR) << "SingleIOBuf reallocate_downward failed. Block cannot be null!"; errno = EINVAL; - return NULL; + return nullptr; } char* old_p = ref.block->data + ref.offset; uint32_t old_size = ref.length; IOBuf::Block* b = alloc_block_by_size(new_size); if (!b) { - return NULL; + return nullptr; } char* new_p = b->data + b->size; memcpy_downward(old_p, old_size, @@ -178,7 +178,7 @@ const void* SingleIOBuf::get_begin() const { if (_cur_ref.block) { return _cur_ref.block->data + _cur_ref.offset; } - return NULL; + return nullptr; } uint32_t SingleIOBuf::get_length() const { @@ -193,14 +193,14 @@ void SingleIOBuf::reset() { _cur_block->dec_ref(); _block_size = 0; } - _cur_block = NULL; + _cur_block = nullptr; } - if (_cur_ref.block != NULL) { + if (_cur_ref.block != nullptr) { _cur_ref.block->dec_ref(); } _cur_ref.offset = 0; _cur_ref.length = 0; - _cur_ref.block = NULL; + _cur_ref.block = nullptr; } bool SingleIOBuf::assign(const IOBuf& buf, uint32_t msg_size) { @@ -229,9 +229,9 @@ bool SingleIOBuf::assign(const IOBuf& buf, uint32_t msg_size) { // Only drop the reference to the previously assigned data here. // reset() would also release _cur_block, which alloc_block_by_size() // has just set to `b', leaving `b' dangling. - if (_cur_ref.block != NULL) { + if (_cur_ref.block != nullptr) { _cur_ref.block->dec_ref(); - _cur_ref.block = NULL; + _cur_ref.block = nullptr; } char* out = b->data + b->size; const size_t nref = buf.backing_block_num(); @@ -264,10 +264,10 @@ int SingleIOBuf::assign_user_data(void* data, size_t size, std::functionspaces; _free_nodes = _free_nodes->next; return spaces; } - if (_blocks == NULL || _blocks->nalloc >= Block::NITEM) { + if (_blocks == nullptr || _blocks->nalloc >= Block::NITEM) { Block* new_block = (Block*)_allocator.Alloc(sizeof(Block)); - if (new_block == NULL) { - return NULL; + if (new_block == nullptr) { + return nullptr; } new_block->nalloc = 0; new_block->next = _blocks; @@ -94,9 +94,9 @@ class SingleThreadedPool { } // Return a space allocated by get() before. - // Do nothing for NULL. + // Do nothing for nullptr. void back(void* p) { - if (NULL != p) { + if (nullptr != p) { Node* node = (Node*)((char*)p - offsetof(Node, spaces)); node->next = _free_nodes; _free_nodes = node; @@ -106,7 +106,7 @@ class SingleThreadedPool { // Remove all allocated spaces. Spaces that are not back()-ed yet become // invalid as well. void reset() { - _free_nodes = NULL; + _free_nodes = nullptr; while (_blocks) { Block* next = _blocks->next; _allocator.Free(_blocks); diff --git a/src/butil/ssl_compat.h b/src/butil/ssl_compat.h index a42c0b4ee2..4015a7b6bc 100644 --- a/src/butil/ssl_compat.h +++ b/src/butil/ssl_compat.h @@ -37,29 +37,29 @@ BRPC_INLINE void *OPENSSL_zalloc(size_t num) { void *ret = OPENSSL_malloc(num); - if (ret != NULL) + if (ret != nullptr) memset(ret, 0, num); return ret; } BRPC_INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { - /* If the fields n and e in r are NULL, the corresponding input - * parameters MUST be non-NULL for n and e. d may be - * left NULL (in case only the public key is used). + /* If the fields n and e in r are nullptr, the corresponding input + * parameters MUST be non-nullptr for n and e. d may be + * left nullptr (in case only the public key is used). */ - if ((r->n == NULL && n == NULL) - || (r->e == NULL && e == NULL)) + if ((r->n == nullptr && n == nullptr) + || (r->e == nullptr && e == nullptr)) return 0; - if (n != NULL) { + if (n != nullptr) { BN_free(r->n); r->n = n; } - if (e != NULL) { + if (e != nullptr) { BN_free(r->e); r->e = e; } - if (d != NULL) { + if (d != nullptr) { BN_free(r->d); r->d = d; } @@ -68,18 +68,18 @@ BRPC_INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { } BRPC_INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) { - /* If the fields p and q in r are NULL, the corresponding input - * parameters MUST be non-NULL. + /* If the fields p and q in r are nullptr, the corresponding input + * parameters MUST be non-nullptr. */ - if ((r->p == NULL && p == NULL) - || (r->q == NULL && q == NULL)) + if ((r->p == nullptr && p == nullptr) + || (r->q == nullptr && q == nullptr)) return 0; - if (p != NULL) { + if (p != nullptr) { BN_free(r->p); r->p = p; } - if (q != NULL) { + if (q != nullptr) { BN_free(r->q); r->q = q; } @@ -88,23 +88,23 @@ BRPC_INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) { } BRPC_INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) { - /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input - * parameters MUST be non-NULL. + /* If the fields dmp1, dmq1 and iqmp in r are nullptr, the corresponding input + * parameters MUST be non-nullptr. */ - if ((r->dmp1 == NULL && dmp1 == NULL) - || (r->dmq1 == NULL && dmq1 == NULL) - || (r->iqmp == NULL && iqmp == NULL)) + if ((r->dmp1 == nullptr && dmp1 == nullptr) + || (r->dmq1 == nullptr && dmq1 == nullptr) + || (r->iqmp == nullptr && iqmp == nullptr)) return 0; - if (dmp1 != NULL) { + if (dmp1 != nullptr) { BN_free(r->dmp1); r->dmp1 = dmp1; } - if (dmq1 != NULL) { + if (dmq1 != nullptr) { BN_free(r->dmq1); r->dmq1 = dmq1; } - if (iqmp != NULL) { + if (iqmp != nullptr) { BN_free(r->iqmp); r->iqmp = iqmp; } @@ -114,60 +114,60 @@ BRPC_INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM * BRPC_INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { - if (n != NULL) + if (n != nullptr) *n = r->n; - if (e != NULL) + if (e != nullptr) *e = r->e; - if (d != NULL) + if (d != nullptr) *d = r->d; } BRPC_INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) { - if (p != NULL) + if (p != nullptr) *p = r->p; - if (q != NULL) + if (q != nullptr) *q = r->q; } BRPC_INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp) { - if (dmp1 != NULL) + if (dmp1 != nullptr) *dmp1 = r->dmp1; - if (dmq1 != NULL) + if (dmq1 != nullptr) *dmq1 = r->dmq1; - if (iqmp != NULL) + if (iqmp != nullptr) *iqmp = r->iqmp; } BRPC_INLINE void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { - if (p != NULL) + if (p != nullptr) *p = d->p; - if (q != NULL) + if (q != nullptr) *q = d->q; - if (g != NULL) + if (g != nullptr) *g = d->g; } BRPC_INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { - /* If the fields p, q and g in d are NULL, the corresponding input - * parameters MUST be non-NULL. + /* If the fields p, q and g in d are nullptr, the corresponding input + * parameters MUST be non-nullptr. */ - if ((d->p == NULL && p == NULL) - || (d->q == NULL && q == NULL) - || (d->g == NULL && g == NULL)) + if ((d->p == nullptr && p == nullptr) + || (d->q == nullptr && q == nullptr) + || (d->g == nullptr && g == nullptr)) return 0; - if (p != NULL) { + if (p != nullptr) { BN_free(d->p); d->p = p; } - if (q != NULL) { + if (q != nullptr) { BN_free(d->q); d->q = q; } - if (g != NULL) { + if (g != nullptr) { BN_free(d->g); d->g = g; } @@ -177,25 +177,25 @@ BRPC_INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { BRPC_INLINE void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) { - if (pub_key != NULL) + if (pub_key != nullptr) *pub_key = d->pub_key; - if (priv_key != NULL) + if (priv_key != nullptr) *priv_key = d->priv_key; } BRPC_INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { - /* If the field pub_key in d is NULL, the corresponding input - * parameters MUST be non-NULL. The priv_key field may - * be left NULL. + /* If the field pub_key in d is nullptr, the corresponding input + * parameters MUST be non-nullptr. The priv_key field may + * be left nullptr. */ - if (d->pub_key == NULL && pub_key == NULL) + if (d->pub_key == nullptr && pub_key == nullptr) return 0; - if (pub_key != NULL) { + if (pub_key != nullptr) { BN_free(d->pub_key); d->pub_key = pub_key; } - if (priv_key != NULL) { + if (priv_key != nullptr) { BN_free(d->priv_key); d->priv_key = priv_key; } @@ -204,14 +204,14 @@ BRPC_INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { } BRPC_INLINE void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) { - if (pr != NULL) + if (pr != nullptr) *pr = sig->r; - if (ps != NULL) + if (ps != nullptr) *ps = sig->s; } BRPC_INLINE int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) { - if (r == NULL || s == NULL) + if (r == nullptr || s == nullptr) return 0; BN_clear_free(sig->r); BN_clear_free(sig->s); @@ -222,36 +222,36 @@ BRPC_INLINE int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) { BRPC_INLINE void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { - if (p != NULL) + if (p != nullptr) *p = dh->p; - if (q != NULL) + if (q != nullptr) *q = dh->q; - if (g != NULL) + if (g != nullptr) *g = dh->g; } BRPC_INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { - /* If the fields p and g in d are NULL, the corresponding input - * parameters MUST be non-NULL. q may remain NULL. + /* If the fields p and g in d are nullptr, the corresponding input + * parameters MUST be non-nullptr. q may remain nullptr. */ - if ((dh->p == NULL && p == NULL) - || (dh->g == NULL && g == NULL)) + if ((dh->p == nullptr && p == nullptr) + || (dh->g == nullptr && g == nullptr)) return 0; - if (p != NULL) { + if (p != nullptr) { BN_free(dh->p); dh->p = p; } - if (q != NULL) { + if (q != nullptr) { BN_free(dh->q); dh->q = q; } - if (g != NULL) { + if (g != nullptr) { BN_free(dh->g); dh->g = g; } - if (q != NULL) { + if (q != nullptr) { dh->length = BN_num_bits(q); } @@ -259,25 +259,25 @@ BRPC_INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { } BRPC_INLINE void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) { - if (pub_key != NULL) + if (pub_key != nullptr) *pub_key = dh->pub_key; - if (priv_key != NULL) + if (priv_key != nullptr) *priv_key = dh->priv_key; } BRPC_INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) { - /* If the field pub_key in dh is NULL, the corresponding input - * parameters MUST be non-NULL. The priv_key field may - * be left NULL. + /* If the field pub_key in dh is nullptr, the corresponding input + * parameters MUST be non-nullptr. The priv_key field may + * be left nullptr. */ - if (dh->pub_key == NULL && pub_key == NULL) + if (dh->pub_key == nullptr && pub_key == nullptr) return 0; - if (pub_key != NULL) { + if (pub_key != nullptr) { BN_free(dh->pub_key); dh->pub_key = pub_key; } - if (priv_key != NULL) { + if (priv_key != nullptr) { BN_free(dh->priv_key); dh->priv_key = priv_key; } @@ -312,7 +312,7 @@ BRPC_INLINE int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) } BRPC_INLINE void RSA_meth_free(RSA_METHOD *meth) { - if (meth != NULL) { + if (meth != nullptr) { OPENSSL_free((char *)meth->name); OPENSSL_free(meth); } diff --git a/src/butil/status.cpp b/src/butil/status.cpp index bb2343ed9a..d459a149a2 100644 --- a/src/butil/status.cpp +++ b/src/butil/status.cpp @@ -32,18 +32,18 @@ inline size_t status_size(size_t message_size) { int Status::set_errorv(int c, const char* fmt, va_list args) { if (0 == c) { free(_state); - _state = NULL; + _state = nullptr; return 0; } - State* new_state = NULL; - State* state = NULL; - if (_state != NULL) { + State* new_state = nullptr; + State* state = nullptr; + if (_state != nullptr) { state = _state; } else { const size_t guess_size = std::max(strlen(fmt) * 2, 32UL); const size_t st_size = status_size(guess_size); new_state = reinterpret_cast(malloc(st_size)); - if (NULL == new_state) { + if (nullptr == new_state) { return -1; } new_state->state_size = st_size; @@ -69,7 +69,7 @@ int Status::set_errorv(int c, const char* fmt, va_list args) { free(new_state); const size_t st_size = status_size(bytes_used); new_state = reinterpret_cast(malloc(st_size)); - if (NULL == new_state) { + if (nullptr == new_state) { return -1; } new_state->code = c; @@ -90,13 +90,13 @@ int Status::set_errorv(int c, const char* fmt, va_list args) { int Status::set_error(int c, const butil::StringPiece& error_msg) { if (0 == c) { free(_state); - _state = NULL; + _state = nullptr; return 0; } const size_t st_size = status_size(error_msg.size()); - if (_state == NULL || _state->state_size < st_size) { + if (_state == nullptr || _state->state_size < st_size) { State* new_state = reinterpret_cast(malloc(st_size)); - if (NULL == new_state) { + if (nullptr == new_state) { return -1; } new_state->state_size = st_size; @@ -113,9 +113,9 @@ int Status::set_error(int c, const butil::StringPiece& error_msg) { Status::State* Status::copy_state(const State* s) { const size_t n = status_size(s->size); State* s2 = reinterpret_cast(malloc(n)); - if (NULL == s2) { + if (nullptr == s2) { // TODO: If we failed to allocate, the status will be OK. - return NULL; + return nullptr; } s2->code = s->code; s2->size = s->size; @@ -127,7 +127,7 @@ Status::State* Status::copy_state(const State* s) { }; std::string Status::error_str() const { - if (_state == NULL) { + if (_state == nullptr) { static std::string s_ok_str = "OK"; return s_ok_str; } diff --git a/src/butil/status.h b/src/butil/status.h index ce78169756..03a863a9fd 100644 --- a/src/butil/status.h +++ b/src/butil/status.h @@ -49,7 +49,7 @@ class Status { }; // Create a success status. - Status() : _state(NULL) { } + Status() : _state(nullptr) { } // Return a success status. static Status OK() { return Status(); } @@ -59,13 +59,13 @@ class Status { // error_text is formatted from `fmt' and following arguments. Status(int code, const char* fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))) - : _state(NULL) { + : _state(nullptr) { va_list ap; va_start(ap, fmt); set_errorv(code, fmt, ap); va_end(ap); } - Status(int code, const butil::StringPiece& error_msg) : _state(NULL) { + Status(int code, const butil::StringPiece& error_msg) : _state(nullptr) { set_error(code, error_msg); } @@ -84,11 +84,11 @@ class Status { int set_errorv(int code, const char* error_format, va_list args); // Returns true iff the status indicates success. - bool ok() const { return (_state == NULL); } + bool ok() const { return (_state == nullptr); } // Get the error code int error_code() const { - return (_state == NULL) ? 0 : _state->code; + return (_state == nullptr) ? 0 : _state->code; } // Return a string representation of the status. @@ -97,10 +97,10 @@ class Status { // * You can print a Status to std::ostream directly // * if message contains '\0', error_cstr() will not be shown fully. const char* error_cstr() const { - return (_state == NULL ? "OK" : _state->message); + return (_state == nullptr ? "OK" : _state->message); } butil::StringPiece error_data() const { - return (_state == NULL ? butil::StringPiece("OK", 2) + return (_state == nullptr ? butil::StringPiece("OK", 2) : butil::StringPiece(_state->message, _state->size)); } std::string error_str() const; @@ -108,7 +108,7 @@ class Status { void swap(butil::Status& other) { std::swap(_state, other._state); } private: - // OK status has a NULL _state. Otherwise, _state is a State object + // OK status has a nullptr _state. Otherwise, _state is a State object // converted from malloc(). State* _state; @@ -116,7 +116,7 @@ class Status { }; inline Status::Status(const Status& s) { - _state = (s._state == NULL) ? NULL : copy_state(s._state); + _state = (s._state == nullptr) ? nullptr : copy_state(s._state); } inline int Status::set_error(int code, const char* msg, ...) { @@ -129,7 +129,7 @@ inline int Status::set_error(int code, const char* msg, ...) { inline void Status::reset() { free(_state); - _state = NULL; + _state = nullptr; } inline void Status::operator=(const Status& s) { @@ -138,9 +138,9 @@ inline void Status::operator=(const Status& s) { if (_state == s._state) { return; } - if (s._state == NULL) { + if (s._state == nullptr) { free(_state); - _state = NULL; + _state = nullptr; } else { set_error(s._state->code, butil::StringPiece(s._state->message, s._state->size)); diff --git a/src/butil/stl_util.h b/src/butil/stl_util.h index 1cc15d9dea..0c49f69cd1 100644 --- a/src/butil/stl_util.h +++ b/src/butil/stl_util.h @@ -97,12 +97,12 @@ void STLDeleteContainerPairSecondPointers(ForwardIterator begin, // directly, but that is undefined behaviour if |v| is empty. template inline T* vector_as_array(std::vector* v) { - return v->empty() ? NULL : &*v->begin(); + return v->empty() ? nullptr : &*v->begin(); } template inline const T* vector_as_array(const std::vector* v) { - return v->empty() ? NULL : &*v->begin(); + return v->empty() ? nullptr : &*v->begin(); } // Return a mutable char* pointing to a string's internal buffer, @@ -119,7 +119,7 @@ inline const T* vector_as_array(const std::vector* v) { // already work on all current implementations. inline char* string_as_array(std::string* str) { // DO NOT USE const_cast(str->data()) - return str->empty() ? NULL : &*str->begin(); + return str->empty() ? nullptr : &*str->begin(); } // The following functions are useful for cleaning up STL containers whose @@ -130,7 +130,7 @@ inline char* string_as_array(std::string* str) { // hash_set, or any other STL container which defines sensible begin(), end(), // and clear() methods. // -// If container is NULL, this function is a no-op. +// If container is nullptr, this function is a no-op. // // As an alternative to calling STLDeleteElements() directly, consider // STLElementDeleter (defined below), which ensures that your container's @@ -145,7 +145,7 @@ void STLDeleteElements(T* container) { // Given an STL container consisting of (key, value) pairs, STLDeleteValues // deletes all the "value" components and clears the container. Does nothing -// in the case it's given a NULL pointer. +// in the case it's given a nullptr pointer. template void STLDeleteValues(T* container) { if (!container) diff --git a/src/butil/string_splitter.h b/src/butil/string_splitter.h index b485c2a3af..0651e68dce 100644 --- a/src/butil/string_splitter.h +++ b/src/butil/string_splitter.h @@ -65,7 +65,7 @@ class StringSplitter { inline StringSplitter(const char* input, char separator, EmptyFieldAction action = SKIP_EMPTY_FIELD); // Allows containing embedded '\0' characters and separator can be '\0', - // if str_end is not NULL. + // if str_end is not nullptr. inline StringSplitter(const char* str_begin, const char* str_end, char separator, EmptyFieldAction action = SKIP_EMPTY_FIELD); @@ -122,7 +122,7 @@ class StringMultiSplitter { // longer than this utility. inline StringMultiSplitter(const char* input, const char* separators, EmptyFieldAction action = SKIP_EMPTY_FIELD); - // Allows containing embedded '\0' characters if str_end is not NULL. + // Allows containing embedded '\0' characters if str_end is not nullptr. // NOTE: `separators` cannot contain embedded '\0' character. inline StringMultiSplitter(const char* str_begin, const char* str_end, const char* separators, @@ -191,7 +191,7 @@ class KeyValuePairsSplitter { inline KeyValuePairsSplitter(const char* str_begin, char pair_delimiter, char key_value_delimiter) - : KeyValuePairsSplitter(str_begin, NULL, + : KeyValuePairsSplitter(str_begin, nullptr, pair_delimiter, key_value_delimiter) {} inline KeyValuePairsSplitter(const StringPiece &sp, diff --git a/src/butil/string_splitter_inl.h b/src/butil/string_splitter_inl.h index ae035f1382..ed2981fcb6 100644 --- a/src/butil/string_splitter_inl.h +++ b/src/butil/string_splitter_inl.h @@ -37,7 +37,7 @@ StringSplitter::StringSplitter(const char* str_begin, StringSplitter::StringSplitter(const char* str, char sep, EmptyFieldAction action) - : StringSplitter(str, NULL, sep, action) {} + : StringSplitter(str, nullptr, sep, action) {} StringSplitter::StringSplitter(const StringPiece& input, char sep, EmptyFieldAction action) @@ -45,18 +45,18 @@ StringSplitter::StringSplitter(const StringPiece& input, char sep, void StringSplitter::init() { // Find the starting _head and _tail. - if (__builtin_expect(_head != NULL, 1)) { + if (__builtin_expect(_head != nullptr, 1)) { if (_empty_field_action == SKIP_EMPTY_FIELD) { for (; not_end(_head) && *_head == _sep; ++_head) {} } for (_tail = _head; not_end(_tail) && *_tail != _sep; ++_tail) {} } else { - _tail = NULL; + _tail = nullptr; } } StringSplitter& StringSplitter::operator++() { - if (__builtin_expect(_tail != NULL, 1)) { + if (__builtin_expect(_tail != nullptr, 1)) { if (not_end(_tail)) { ++_tail; if (_empty_field_action == SKIP_EMPTY_FIELD) { @@ -76,7 +76,7 @@ StringSplitter StringSplitter::operator++(int) { } StringSplitter::operator const void*() const { - return (_head != NULL && not_end(_head)) ? _head : NULL; + return (_head != nullptr && not_end(_head)) ? _head : nullptr; } const char* StringSplitter::field() const { @@ -92,7 +92,7 @@ StringPiece StringSplitter::field_sp() const { } bool StringSplitter::not_end(const char* p) const { - return (_str_tail == NULL) ? *p : (p != _str_tail); + return (_str_tail == nullptr) ? *p : (p != _str_tail); } int StringSplitter::to_int8(int8_t* pv) const { @@ -132,37 +132,37 @@ int StringSplitter::to_uint(unsigned int* pv) const { } int StringSplitter::to_long(long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtol(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringSplitter::to_ulong(unsigned long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtoul(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringSplitter::to_longlong(long long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtoll(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringSplitter::to_ulonglong(unsigned long long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtoull(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringSplitter::to_float(float* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtof(field(), &endptr); return (endptr == field() + length()) ? 0 : -1; } int StringSplitter::to_double(double* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtod(field(), &endptr); return (endptr == field() + length()) ? 0 : -1; } @@ -170,7 +170,7 @@ int StringSplitter::to_double(double* pv) const { StringMultiSplitter::StringMultiSplitter ( const char* str, const char* seps, EmptyFieldAction action) : _head(str) - , _str_tail(NULL) + , _str_tail(nullptr) , _seps(seps) , _empty_field_action(action) { init(); @@ -187,18 +187,18 @@ StringMultiSplitter::StringMultiSplitter ( } void StringMultiSplitter::init() { - if (__builtin_expect(_head != NULL, 1)) { + if (__builtin_expect(_head != nullptr, 1)) { if (_empty_field_action == SKIP_EMPTY_FIELD) { for (; not_end(_head) && is_sep(*_head); ++_head) {} } for (_tail = _head; not_end(_tail) && !is_sep(*_tail); ++_tail) {} } else { - _tail = NULL; + _tail = nullptr; } } StringMultiSplitter& StringMultiSplitter::operator++() { - if (__builtin_expect(_tail != NULL, 1)) { + if (__builtin_expect(_tail != nullptr, 1)) { if (not_end(_tail)) { ++_tail; if (_empty_field_action == SKIP_EMPTY_FIELD) { @@ -227,7 +227,7 @@ bool StringMultiSplitter::is_sep(char c) const { } StringMultiSplitter::operator const void*() const { - return (_head != NULL && not_end(_head)) ? _head : NULL; + return (_head != nullptr && not_end(_head)) ? _head : nullptr; } const char* StringMultiSplitter::field() const { @@ -243,7 +243,7 @@ StringPiece StringMultiSplitter::field_sp() const { } bool StringMultiSplitter::not_end(const char* p) const { - return (_str_tail == NULL) ? *p : (p != _str_tail); + return (_str_tail == nullptr) ? *p : (p != _str_tail); } int StringMultiSplitter::to_int8(int8_t* pv) const { @@ -283,37 +283,37 @@ int StringMultiSplitter::to_uint(unsigned int* pv) const { } int StringMultiSplitter::to_long(long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtol(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringMultiSplitter::to_ulong(unsigned long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtoul(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringMultiSplitter::to_longlong(long long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtoll(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringMultiSplitter::to_ulonglong(unsigned long long* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtoull(field(), &endptr, 10); return (endptr == field() + length()) ? 0 : -1; } int StringMultiSplitter::to_float(float* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtof(field(), &endptr); return (endptr == field() + length()) ? 0 : -1; } int StringMultiSplitter::to_double(double* pv) const { - char* endptr = NULL; + char* endptr = nullptr; *pv = strtod(field(), &endptr); return (endptr == field() + length()) ? 0 : -1; } diff --git a/src/butil/strings/safe_sprintf.cc b/src/butil/strings/safe_sprintf.cc index 09c5abd8b8..cb54f730be 100644 --- a/src/butil/strings/safe_sprintf.cc +++ b/src/butil/strings/safe_sprintf.cc @@ -315,7 +315,7 @@ bool Buffer::IToASCII(bool sign, bool upcase, int64_t i, int base, // We cannot choose the easier approach of just reversing the number, as that // fails in situations where we need to truncate numbers that have padding // and/or prefixes. - const char* reverse_prefix = NULL; + const char* reverse_prefix = nullptr; if (prefix && *prefix) { if (pad == '0') { while (*prefix) { @@ -324,13 +324,13 @@ bool Buffer::IToASCII(bool sign, bool upcase, int64_t i, int base, } Out(*prefix++); } - prefix = NULL; + prefix = nullptr; } else { for (reverse_prefix = prefix; *reverse_prefix; ++reverse_prefix) { } } } else - prefix = NULL; + prefix = nullptr; const size_t prefix_length = reverse_prefix - prefix; // Loop until we have converted the entire number. Output at least one @@ -527,7 +527,7 @@ ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args, const Arg& arg = args[cur_arg++]; int64_t i; - const char* prefix = NULL; + const char* prefix = nullptr; if (ch != 'p') { // Check that the argument has the expected type. if (arg.type != Arg::INT && arg.type != Arg::UINT) { diff --git a/src/butil/strings/string_number_conversions.cc b/src/butil/strings/string_number_conversions.cc index bcf3f49ce4..0b6cd4ea28 100644 --- a/src/butil/strings/string_number_conversions.cc +++ b/src/butil/strings/string_number_conversions.cc @@ -437,7 +437,7 @@ bool StringToDouble(const std::string& input, double* output) { // Thread-safe? It is on at least Mac, Linux, and Windows. ScopedClearErrno clear_errno; - char* endptr = NULL; + char* endptr = nullptr; *output = dmg_fp::strtod(input.c_str(), &endptr); // Cases to return false: diff --git a/src/butil/strings/string_piece.h b/src/butil/strings/string_piece.h index 808ccbb19f..d0e0173072 100644 --- a/src/butil/strings/string_piece.h +++ b/src/butil/strings/string_piece.h @@ -187,10 +187,10 @@ template class BasicStringPiece { // We provide non-explicit singleton constructors so users can pass // in a "const char*" or a "string" wherever a "StringPiece" is // expected (likewise for char16, string16, StringPiece16). - BasicStringPiece() : ptr_(NULL), length_(0) {} + BasicStringPiece() : ptr_(nullptr), length_(0) {} BasicStringPiece(const value_type* str) : ptr_(str), - length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {} + length_((str == nullptr) ? 0 : STRING_TYPE::traits_type::length(str)) {} #if __cplusplus >= 201703L BasicStringPiece( const std::basic_string_view& str) @@ -204,7 +204,7 @@ template class BasicStringPiece { : ptr_(str.data() + pos), length_(std::min(len, str.length() - pos)) {} BasicStringPiece(const typename STRING_TYPE::const_iterator& begin, const typename STRING_TYPE::const_iterator& end) - : ptr_((end > begin) ? &(*begin) : NULL), + : ptr_((end > begin) ? &(*begin) : nullptr), length_((end > begin) ? (size_type)(end - begin) : 0) {} // data() may return a pointer to a buffer with embedded NULs, and the @@ -217,7 +217,7 @@ template class BasicStringPiece { bool empty() const { return length_ == 0; } void clear() { - ptr_ = NULL; + ptr_ = nullptr; length_ = 0; } BasicStringPiece& assign(const BasicStringPiece& str, size_type pos, size_type len = npos) { @@ -266,7 +266,7 @@ template class BasicStringPiece { } STRING_TYPE as_string() const { - // std::string doesn't like to take a NULL pointer even with a 0 size. + // std::string doesn't like to take a nullptr pointer even with a 0 size. return empty() ? STRING_TYPE() : STRING_TYPE(data(), size()); } @@ -391,7 +391,7 @@ template class BasicStringPiece { // Converts to `std::basic_string`. explicit operator STRING_TYPE() const { - if (NULL == data()) { + if (nullptr == data()) { return {}; } return STRING_TYPE(data(), size()); diff --git a/src/butil/strings/string_util.cc b/src/butil/strings/string_util.cc index b7ec353d9a..ed0a632cac 100644 --- a/src/butil/strings/string_util.cc +++ b/src/butil/strings/string_util.cc @@ -733,7 +733,7 @@ template static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end, const CHAR** string, const CHAR* string_end, NEXT next) { - const CHAR* escape = NULL; + const CHAR* escape = nullptr; while (*pattern != pattern_end && *string != string_end) { if (!escape && IsWildcard(**pattern)) { // We don't want to match wildcard here, except if it's escaped. @@ -768,7 +768,7 @@ static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end, return; } - escape = NULL; + escape = nullptr; } } diff --git a/src/butil/strings/string_util.h b/src/butil/strings/string_util.h index bd3328a770..1c2c120d98 100644 --- a/src/butil/strings/string_util.h +++ b/src/butil/strings/string_util.h @@ -394,7 +394,7 @@ inline Char HexDigitToInt(Char c) { // Returns true if it's a whitespace character. inline bool IsWhitespace(wchar_t c) { - return wcschr(butil::kWhitespaceWide, c) != NULL; + return wcschr(butil::kWhitespaceWide, c) != nullptr; } inline bool IsBlankString(const butil::StringPiece &s) { @@ -497,7 +497,7 @@ BUTIL_EXPORT butil::string16 JoinString( // Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively. // Additionally, any number of consecutive '$' characters is replaced by that // number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be -// NULL. This only allows you to use up to nine replacements. +// nullptr. This only allows you to use up to nine replacements. BUTIL_EXPORT butil::string16 ReplaceStringPlaceholders( const butil::string16& format_string, const std::vector& subst, @@ -508,7 +508,7 @@ BUTIL_EXPORT std::string ReplaceStringPlaceholders( const std::vector& subst, std::vector* offsets); -// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL. +// Single-string shortcut for ReplaceStringHolders. |offset| may be nullptr. BUTIL_EXPORT butil::string16 ReplaceStringPlaceholders( const butil::string16& format_string, const butil::string16& a, diff --git a/src/butil/strings/stringprintf.cc b/src/butil/strings/stringprintf.cc index 0ca6366cc8..3c8dbba875 100644 --- a/src/butil/strings/stringprintf.cc +++ b/src/butil/strings/stringprintf.cc @@ -10,7 +10,7 @@ #include "butil/strings/string_util.h" #include "butil/strings/utf_string_conversions.h" -// gcc7 reports that the first arg to vsnprintfT in StringAppendVT is NULL, +// gcc7 reports that the first arg to vsnprintfT in StringAppendVT is nullptr, // which I can't figure out why, turn off the warning right now. #if defined(__GNUC__) && __GNUC__ >= 7 #pragma GCC diagnostic warning "-Wformat-truncation=0" diff --git a/src/butil/strings/sys_string_conversions.h b/src/butil/strings/sys_string_conversions.h index 7316c5e7ff..03be67eea9 100644 --- a/src/butil/strings/sys_string_conversions.h +++ b/src/butil/strings/sys_string_conversions.h @@ -59,7 +59,7 @@ BUTIL_EXPORT std::string SysWideToMultiByte(const std::wstring& wide, // Converts between STL strings and CFStringRefs/NSStrings. // Creates a string, and returns it with a refcount of 1. You are responsible -// for releasing it. Returns NULL on failure. +// for releasing it. Returns nullptr on failure. BUTIL_EXPORT CFStringRef SysUTF8ToCFStringRef(const std::string& utf8); BUTIL_EXPORT CFStringRef SysUTF16ToCFStringRef(const string16& utf16); diff --git a/src/butil/strings/sys_string_conversions_mac.mm b/src/butil/strings/sys_string_conversions_mac.mm index 804b614287..26151f99f8 100644 --- a/src/butil/strings/sys_string_conversions_mac.mm +++ b/src/butil/strings/sys_string_conversions_mac.mm @@ -34,7 +34,7 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring, encoding, 0, // lossByte false, // isExternalRepresentation - NULL, // buffer + nullptr, // buffer 0, // maxBufLen &out_size); if (converted == 0 || out_size == 0) @@ -56,7 +56,7 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring, false, // isExternalRepresentation reinterpret_cast(&out_buffer[0]), out_size, - NULL); // usedBufLen + nullptr); // usedBufLen if (converted == 0) return StringType(); @@ -79,7 +79,7 @@ static OutStringType STLStringToSTLStringWithEncodingsT( return OutStringType(); butil::ScopedCFTypeRef cfstring(CFStringCreateWithBytesNoCopy( - NULL, + nullptr, reinterpret_cast(in.data()), in_length * sizeof(typename InStringType::value_type), in_encoding, @@ -93,7 +93,7 @@ static OutStringType STLStringToSTLStringWithEncodingsT( } // Given an STL string |in| with an encoding specified by |in_encoding|, -// return it as a CFStringRef. Returns NULL on failure. +// return it as a CFStringRef. Returns nullptr on failure. template static CFStringRef STLStringToCFStringWithEncodingsT( const StringType& in, diff --git a/src/butil/strings/sys_string_conversions_posix.cc b/src/butil/strings/sys_string_conversions_posix.cc index 1255b4d6e5..b678a72c12 100644 --- a/src/butil/strings/sys_string_conversions_posix.cc +++ b/src/butil/strings/sys_string_conversions_posix.cc @@ -48,7 +48,7 @@ std::string SysWideToNativeMB(const std::wstring& wide) { memset(&ps, 0, sizeof(ps)); for (size_t i = 0; i < wide.size(); ++i) { const wchar_t src = wide[i]; - // Use a temp buffer since calling wcrtomb with an output of NULL does not + // Use a temp buffer since calling wcrtomb with an output of nullptr does not // calculate the output length. char buf[16]; // Skip NULLs to avoid wcrtomb's special handling of them. @@ -108,7 +108,7 @@ std::wstring SysNativeMBToWide(const StringPiece& native_mb) { memset(&ps, 0, sizeof(ps)); for (size_t i = 0; i < native_mb.size(); ) { const char* src = native_mb.data() + i; - size_t res = mbrtowc(NULL, src, native_mb.size() - i, &ps); + size_t res = mbrtowc(nullptr, src, native_mb.size() - i, &ps); switch (res) { // Handle any errors and return an empty string. case static_cast(-2): diff --git a/src/butil/strings/utf_offset_string_conversions.cc b/src/butil/strings/utf_offset_string_conversions.cc index 2981059b5a..75994208a6 100644 --- a/src/butil/strings/utf_offset_string_conversions.cc +++ b/src/butil/strings/utf_offset_string_conversions.cc @@ -176,7 +176,7 @@ void OffsetAdjuster::MergeSequentialAdjustments( // Converts the given source Unicode character type to the given destination // Unicode character type as a STL string. The given input buffer and size // determine the source, and the given output STL string will be replaced by -// the result. If non-NULL, |adjustments| is set to reflect the all the +// the result. If non-nullptr, |adjustments| is set to reflect the all the // alterations to the string that are not one-character-to-one-character. // It will always be sorted by increasing offset. template diff --git a/src/butil/strings/utf_offset_string_conversions.h b/src/butil/strings/utf_offset_string_conversions.h index 4984900fa0..80abb262e6 100644 --- a/src/butil/strings/utf_offset_string_conversions.h +++ b/src/butil/strings/utf_offset_string_conversions.h @@ -85,7 +85,7 @@ class BUTIL_EXPORT OffsetAdjuster { // Like the conversions in utf_string_conversions.h, but also fills in an // |adjustments| parameter that reflects the alterations done to the string. -// It may be NULL. +// It may be nullptr. BUTIL_EXPORT bool UTF8ToUTF16WithAdjustments( const char* src, size_t src_len, diff --git a/src/butil/synchronization/condition_variable_posix.cc b/src/butil/synchronization/condition_variable_posix.cc index 4a4b9f3e12..6ac2bf55cf 100644 --- a/src/butil/synchronization/condition_variable_posix.cc +++ b/src/butil/synchronization/condition_variable_posix.cc @@ -18,7 +18,7 @@ ConditionVariable::ConditionVariable(Mutex* user_lock) : user_mutex_(user_lock->native_handle()) { // NOTE(gejun): Disable monotonic clock always due to difficulty of adapting // all versions of gcc - int rv = pthread_cond_init(&condition_, NULL); + int rv = pthread_cond_init(&condition_, nullptr); DCHECK_EQ(0, rv); } @@ -46,7 +46,7 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) { &condition_, user_mutex_, &relative_time); #else struct timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); struct timespec absolute_time; absolute_time.tv_sec = now.tv_sec; absolute_time.tv_nsec = now.tv_usec * Time::kNanosecondsPerMicrosecond; diff --git a/src/butil/synchronization/lock.h b/src/butil/synchronization/lock.h index e62c76c438..eb5f982295 100644 --- a/src/butil/synchronization/lock.h +++ b/src/butil/synchronization/lock.h @@ -53,7 +53,7 @@ class BUTIL_EXPORT Mutex { // contending thread from going to sleep which helps performance greatly. ::InitializeCriticalSectionAndSpinCount(&_native_handle, 2000); #elif defined(OS_POSIX) - pthread_mutex_init(&_native_handle, NULL); + pthread_mutex_init(&_native_handle, nullptr); #endif } diff --git a/src/butil/synchronization/waitable_event_posix.cc b/src/butil/synchronization/waitable_event_posix.cc index adeb573085..dd3f9046db 100644 --- a/src/butil/synchronization/waitable_event_posix.cc +++ b/src/butil/synchronization/waitable_event_posix.cc @@ -87,7 +87,7 @@ class SyncWaiter : public WaitableEvent::Waiter { public: SyncWaiter() : fired_(false), - signaling_event_(NULL), + signaling_event_(nullptr), lock_(), cv_(&lock_) { } diff --git a/src/butil/synchronous_event.h b/src/butil/synchronous_event.h index b0839e5993..602c05ac3c 100644 --- a/src/butil/synchronous_event.h +++ b/src/butil/synchronous_event.h @@ -44,7 +44,7 @@ // FooEvent foo_event; // An instance of the event // FooObserver foo_observer; // An instance of the observer // foo_event.subscribe(&foo_observer); // register the observer to the event -// foo_event.notify(1, NULL); // foo_observer.on_event(1, NULL) is +// foo_event.notify(1, nullptr); // foo_observer.on_event(1, nullptr) is // // called *immediately* namespace butil { @@ -66,9 +66,9 @@ class SynchronousEvent { // Add an observer, callable inside on_event() and added observers // will be called with the same event in the same run. - // Returns 0 when successful, -1 when the obsever is NULL or already added. + // Returns 0 when successful, -1 when the obsever is nullptr or already added. int subscribe(Observer* ob) { - if (NULL == ob) { + if (nullptr == ob) { LOG(ERROR) << "Observer is NULL"; return -1; } @@ -82,9 +82,9 @@ class SynchronousEvent { // Remove an observer, callable inside on_event(). // Users are responsible for removing observers before destroying them. - // Returns 0 when successful, -1 when the observer is NULL or already removed. + // Returns 0 when successful, -1 when the observer is nullptr or already removed. int unsubscribe(Observer* ob) { - if (NULL == ob) { + if (nullptr == ob) { LOG(ERROR) << "Observer is NULL"; return -1; } @@ -93,7 +93,7 @@ class SynchronousEvent { if (it == _obs.end()) { return -1; } - *it = NULL; + *it = nullptr; --_n; return 0; } @@ -102,7 +102,7 @@ class SynchronousEvent { void clear() { for (typename ObserverSet::iterator it = _obs.begin(); it != _obs.end(); ++it) { - *it = NULL; + *it = nullptr; } _n = 0; } diff --git a/src/butil/thread_key.cpp b/src/butil/thread_key.cpp index 3bf4bb0f37..94c432a02b 100644 --- a/src/butil/thread_key.cpp +++ b/src/butil/thread_key.cpp @@ -36,9 +36,9 @@ namespace butil { static const uint32_t THREAD_KEY_RESERVE = 8096; pthread_mutex_t g_thread_key_mutex = PTHREAD_MUTEX_INITIALIZER; static size_t g_id = 0; -static std::deque* g_free_ids = NULL; -static std::vector* g_thread_keys = NULL; -static __thread std::vector* thread_key_tls_data = NULL; +static std::deque* g_free_ids = nullptr; +static std::vector* g_thread_keys = nullptr; +static __thread std::vector* thread_key_tls_data = nullptr; ThreadKey& ThreadKey::operator=(ThreadKey&& other) noexcept { if (this == &other) { @@ -72,7 +72,7 @@ static void DestroyTlsData() { } } delete thread_key_tls_data; - thread_key_tls_data = NULL; + thread_key_tls_data = nullptr; } int thread_key_create(ThreadKey& thread_key, DtorFunction dtor) { @@ -155,14 +155,14 @@ int thread_setspecific(ThreadKey& thread_key, void* data) { void* thread_getspecific(ThreadKey& thread_key) { if (BAIDU_UNLIKELY(!thread_key.Valid())) { - return NULL; + return nullptr; } size_t id = thread_key._id; size_t seq = thread_key._seq; if (BAIDU_UNLIKELY(!thread_key_tls_data || id >= thread_key_tls_data->size() || (*thread_key_tls_data)[id].seq != seq)){ - return NULL; + return nullptr; } return (*thread_key_tls_data)[id].data; diff --git a/src/butil/thread_key.h b/src/butil/thread_key.h index 77f346d608..47abcabee7 100644 --- a/src/butil/thread_key.h +++ b/src/butil/thread_key.h @@ -71,14 +71,14 @@ class ThreadKey { }; struct ThreadKeyInfo { - ThreadKeyInfo() : seq(0), dtor(NULL) {} + ThreadKeyInfo() : seq(0), dtor(nullptr) {} size_t seq; // Already allocated? DtorFunction dtor; // Destruction routine. }; struct ThreadKeyTLS { - ThreadKeyTLS() : seq(0), data(NULL) {} + ThreadKeyTLS() : seq(0), data(nullptr) {} // Sequence number form ThreadKey, // set in `thread_setspecific', @@ -130,7 +130,7 @@ class ThreadLocal { void reset(T* ptr); void reset() { - reset(NULL); + reset(nullptr); } private: @@ -152,7 +152,7 @@ template ThreadLocal::ThreadLocal(bool delete_on_thread_exit) : _mutex(PTHREAD_MUTEX_INITIALIZER) , _delete_on_thread_exit(delete_on_thread_exit) { - DtorFunction dtor = _delete_on_thread_exit ? DefaultDtor : NULL; + DtorFunction dtor = _delete_on_thread_exit ? DefaultDtor : nullptr; thread_key_create(_key, dtor); } @@ -175,12 +175,12 @@ T* ThreadLocal::get() { if (!ptr) { ptr = new (std::nothrow) T; if (!ptr) { - return NULL; + return nullptr; } int rc = thread_setspecific(_key, ptr); if (rc != 0) { DefaultDtor(ptr); - return NULL; + return nullptr; } { BAIDU_SCOPED_LOCK(_mutex); diff --git a/src/butil/thread_local.cpp b/src/butil/thread_local.cpp index f10c5b14d5..9607afebaf 100644 --- a/src/butil/thread_local.cpp +++ b/src/butil/thread_local.cpp @@ -81,7 +81,7 @@ static void helper_exit_global() { detail::ThreadExitHelper* h = (detail::ThreadExitHelper*)pthread_getspecific(detail::thread_atexit_key); if (h) { - pthread_setspecific(detail::thread_atexit_key, NULL); + pthread_setspecific(detail::thread_atexit_key, nullptr); delete h; } } @@ -101,9 +101,9 @@ detail::ThreadExitHelper* get_or_new_thread_exit_helper() { detail::ThreadExitHelper* h = (detail::ThreadExitHelper*)pthread_getspecific(detail::thread_atexit_key); - if (NULL == h) { + if (nullptr == h) { h = new (std::nothrow) detail::ThreadExitHelper; - if (NULL != h) { + if (nullptr != h) { pthread_setspecific(detail::thread_atexit_key, h); } } @@ -122,7 +122,7 @@ static void call_single_arg_fn(void* fn) { } // namespace detail int thread_atexit(void (*fn)(void*), void* arg) { - if (NULL == fn) { + if (nullptr == fn) { errno = EINVAL; return -1; } @@ -135,7 +135,7 @@ int thread_atexit(void (*fn)(void*), void* arg) { } int thread_atexit(void (*fn)()) { - if (NULL == fn) { + if (nullptr == fn) { errno = EINVAL; return -1; } @@ -143,7 +143,7 @@ int thread_atexit(void (*fn)()) { } void thread_atexit_cancel(void (*fn)(void*), void* arg) { - if (fn != NULL) { + if (fn != nullptr) { detail::ThreadExitHelper* h = detail::get_thread_exit_helper(); if (h) { h->remove(fn, arg); @@ -152,7 +152,7 @@ void thread_atexit_cancel(void (*fn)(void*), void* arg) { } void thread_atexit_cancel(void (*fn)()) { - if (NULL != fn) { + if (nullptr != fn) { thread_atexit_cancel(detail::call_single_arg_fn, (void*)fn); } } diff --git a/src/butil/thread_local.h b/src/butil/thread_local.h index 973ad14be7..71c65796d5 100644 --- a/src/butil/thread_local.h +++ b/src/butil/thread_local.h @@ -21,8 +21,7 @@ #define BUTIL_THREAD_LOCAL_H #include // std::nothrow -#include // NULL -#include "butil/macros.h" +#include "butil/macros.h" #ifdef _MSC_VER #define BAIDU_THREAD_LOCAL __declspec(thread) diff --git a/src/butil/thread_local_inl.h b/src/butil/thread_local_inl.h index 12f10e308f..89f4cad88b 100644 --- a/src/butil/thread_local_inl.h +++ b/src/butil/thread_local_inl.h @@ -28,11 +28,11 @@ template class ThreadLocalHelper { public: inline static T* get() { - if (__builtin_expect(value != NULL, 1)) { + if (__builtin_expect(value != nullptr, 1)) { return value; } value = new (std::nothrow) T; - if (value != NULL) { + if (value != nullptr) { butil::thread_atexit(delete_object, value); } return value; @@ -40,7 +40,7 @@ class ThreadLocalHelper { static BAIDU_THREAD_LOCAL T* value; }; -template BAIDU_THREAD_LOCAL T* ThreadLocalHelper::value = NULL; +template BAIDU_THREAD_LOCAL T* ThreadLocalHelper::value = nullptr; } // namespace detail diff --git a/src/butil/threading/platform_thread_posix.cc b/src/butil/threading/platform_thread_posix.cc index 5e1403da8e..32c34cf2be 100644 --- a/src/butil/threading/platform_thread_posix.cc +++ b/src/butil/threading/platform_thread_posix.cc @@ -39,10 +39,10 @@ namespace { struct ThreadParams { ThreadParams() - : delegate(NULL), + : delegate(nullptr), joinable(false), priority(kThreadPriority_Normal), - handle(NULL), + handle(nullptr), handle_set(false, false) { } @@ -83,7 +83,7 @@ void* ThreadFunc(void* params) { PlatformThread::CurrentId()); butil::TerminateOnThread(); - return NULL; + return nullptr; } bool CreateThread(size_t stack_size, bool joinable, @@ -231,7 +231,7 @@ void PlatformThread::Join(PlatformThreadHandle thread_handle) { // the thread referred to by |thread_handle| may still be running long-lived / // blocking tasks. butil::ThreadRestrictions::AssertIOAllowed(); - CHECK_EQ(0, pthread_join(thread_handle.handle_, NULL)); + CHECK_EQ(0, pthread_join(thread_handle.handle_, nullptr)); } } // namespace butil diff --git a/src/butil/threading/simple_thread.cc b/src/butil/threading/simple_thread.cc index 40559ba4ed..301117f0ec 100644 --- a/src/butil/threading/simple_thread.cc +++ b/src/butil/threading/simple_thread.cc @@ -79,7 +79,7 @@ DelegateSimpleThread::~DelegateSimpleThread() { void DelegateSimpleThread::Run() { DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)"; delegate_->Run(); - delegate_ = NULL; + delegate_ = nullptr; } DelegateSimpleThreadPool::DelegateSimpleThreadPool( @@ -109,7 +109,7 @@ void DelegateSimpleThreadPool::JoinAll() { DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads."; // Tell all our threads to quit their worker loop. - AddWork(NULL, num_threads_); + AddWork(nullptr, num_threads_); // Join and destroy all the worker threads. for (int i = 0; i < num_threads_; ++i) { @@ -130,7 +130,7 @@ void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) { } void DelegateSimpleThreadPool::Run() { - Delegate* work = NULL; + Delegate* work = nullptr; while (true) { dry_.Wait(); @@ -148,7 +148,7 @@ void DelegateSimpleThreadPool::Run() { dry_.Reset(); } - // A NULL delegate pointer signals us to quit. + // A nullptr delegate pointer signals us to quit. if (!work) break; diff --git a/src/butil/threading/simple_thread.h b/src/butil/threading/simple_thread.h index 7eb6790f68..904bda17de 100644 --- a/src/butil/threading/simple_thread.h +++ b/src/butil/threading/simple_thread.h @@ -167,7 +167,7 @@ class BUTIL_EXPORT DelegateSimpleThreadPool void JoinAll(); // It is safe to AddWork() any time, before or after Start(). - // Delegate* should always be a valid pointer, NULL is reserved internally. + // Delegate* should always be a valid pointer, nullptr is reserved internally. void AddWork(Delegate* work, int repeat_count); void AddWork(Delegate* work) { AddWork(work, 1); diff --git a/src/butil/threading/thread_id_name_manager.cc b/src/butil/threading/thread_id_name_manager.cc index cb0de0fab1..a12e75d9ed 100644 --- a/src/butil/threading/thread_id_name_manager.cc +++ b/src/butil/threading/thread_id_name_manager.cc @@ -20,7 +20,7 @@ static std::string* g_default_name; } ThreadIdNameManager::ThreadIdNameManager() - : main_process_name_(NULL), + : main_process_name_(nullptr), main_process_id_(kInvalidThreadId) { g_default_name = new std::string(kDefaultName); @@ -53,7 +53,7 @@ void ThreadIdNameManager::SetName(PlatformThreadId id, const char* name) { AutoLock locked(lock_); NameToInternedNameMap::iterator iter = name_to_interned_name_.find(str_name); - std::string* leaked_str = NULL; + std::string* leaked_str = nullptr; if (iter != name_to_interned_name_.end()) { leaked_str = iter->second; } else { diff --git a/src/butil/threading/thread_local.h b/src/butil/threading/thread_local.h index 4eda9378f0..3435deec52 100644 --- a/src/butil/threading/thread_local.h +++ b/src/butil/threading/thread_local.h @@ -15,7 +15,7 @@ // // ThreadLocalPointer wraps a Type*. It performs no creation or // destruction, so memory management must be handled elsewhere. The first call -// to Get() on a thread will return NULL. You can update the pointer with a +// to Get() on a thread will return nullptr. You can update the pointer with a // call to Set(). // // ThreadLocalBoolean wraps a bool. It will default to false if it has never @@ -33,17 +33,17 @@ // // My class is logically attached to a single thread. We cache a pointer // // on the thread it was created on, so we can implement current(). // MyClass::MyClass() { -// DCHECK(Singleton >::get()->Get() == NULL); +// DCHECK(Singleton >::get()->Get() == nullptr); // Singleton >::get()->Set(this); // } // // MyClass::~MyClass() { -// DCHECK(Singleton >::get()->Get() != NULL); -// Singleton >::get()->Set(NULL); +// DCHECK(Singleton >::get()->Get() != nullptr); +// Singleton >::get()->Set(nullptr); // } // // // Return the current MyClass associated with the calling thread, can be -// // NULL if there isn't a MyClass associated. +// // nullptr if there isn't a MyClass associated. // MyClass* MyClass::current() { // return Singleton >::get()->Get(); // } @@ -115,11 +115,11 @@ class ThreadLocalBoolean { ~ThreadLocalBoolean() {} bool Get() { - return tlp_.Get() != NULL; + return tlp_.Get() != nullptr; } void Set(bool val) { - tlp_.Set(val ? this : NULL); + tlp_.Set(val ? this : nullptr); } private: diff --git a/src/butil/threading/thread_local_posix.cc b/src/butil/threading/thread_local_posix.cc index 8af300da73..484bc88bf3 100644 --- a/src/butil/threading/thread_local_posix.cc +++ b/src/butil/threading/thread_local_posix.cc @@ -15,7 +15,7 @@ namespace internal { // static void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { - int error = pthread_key_create(slot, NULL); + int error = pthread_key_create(slot, nullptr); CHECK_EQ(error, 0); } diff --git a/src/butil/threading/thread_local_storage.cc b/src/butil/threading/thread_local_storage.cc index 6d6c42cfd8..32071d822e 100644 --- a/src/butil/threading/thread_local_storage.cc +++ b/src/butil/threading/thread_local_storage.cc @@ -141,17 +141,17 @@ void OnThreadExitInternal(void* value) { butil::subtle::NoBarrier_Load(&g_last_used_tls_key); for (int slot = last_used_tls_key; slot > 0; --slot) { void* value = stack_allocated_tls_data[slot]; - if (value == NULL) + if (value == nullptr) continue; butil::ThreadLocalStorage::TLSDestructorFunc destructor = g_tls_destructors[slot]; - if (destructor == NULL) + if (destructor == nullptr) continue; - stack_allocated_tls_data[slot] = NULL; // pre-clear the slot. + stack_allocated_tls_data[slot] = nullptr; // pre-clear the slot. destructor(value); // Any destructor might have called a different service, which then set - // a different slot to a non-NULL value. Hence we need to check + // a different slot to a non-nullptr value. Hence we need to check // the whole vector again. This is a pthread standard. need_to_scan_destructors = true; } @@ -162,7 +162,7 @@ void OnThreadExitInternal(void* value) { } // Remove our stack allocated vector. - PlatformThreadLocalStorage::SetTLSValue(key, NULL); + PlatformThreadLocalStorage::SetTLSValue(key, nullptr); } } // namespace @@ -220,7 +220,7 @@ void ThreadLocalStorage::StaticSlot::Free() { // So all we need to do is wipe the destructor. DCHECK_GT(slot_, 0); DCHECK_LT(slot_, kThreadLocalStorageSize); - g_tls_destructors[slot_] = NULL; + g_tls_destructors[slot_] = nullptr; slot_ = 0; initialized_ = false; } diff --git a/src/butil/threading/thread_local_storage.h b/src/butil/threading/thread_local_storage.h index d055bc531a..f9c06be850 100644 --- a/src/butil/threading/thread_local_storage.h +++ b/src/butil/threading/thread_local_storage.h @@ -97,7 +97,7 @@ class BUTIL_EXPORT ThreadLocalStorage { struct BUTIL_EXPORT StaticSlot { // Set up the TLS slot. Called by the constructor. // 'destructor' is a pointer to a function to perform per-thread cleanup of - // this object. If set to NULL, no cleanup is done for this TLS slot. + // this object. If set to nullptr, no cleanup is done for this TLS slot. // Returns false on error. bool Initialize(TLSDestructorFunc destructor); @@ -127,7 +127,7 @@ class BUTIL_EXPORT ThreadLocalStorage { class BUTIL_EXPORT Slot : public StaticSlot { public: // Calls StaticSlot::Initialize(). - explicit Slot(TLSDestructorFunc destructor = NULL); + explicit Slot(TLSDestructorFunc destructor = nullptr); private: using StaticSlot::initialized_; diff --git a/src/butil/time.cpp b/src/butil/time.cpp index ad91831fc3..a2d09821a1 100644 --- a/src/butil/time.cpp +++ b/src/butil/time.cpp @@ -46,7 +46,7 @@ static void InitClock() { exit(1); } timeval now; - if (gettimeofday(&now, NULL) != 0) { + if (gettimeofday(&now, nullptr) != 0) { exit(1); } s_init_time.tv_sec = now.tv_sec; @@ -103,7 +103,7 @@ int64_t read_cpu_frequency(bool* invariant_tsc) { if (n > 0) { char *mhz = static_cast(memmem(buf, n, "cpu MHz", 7)); - if (mhz != NULL) { + if (mhz != nullptr) { char *endp = buf + n; int seen_decpoint = 0; int ndigits = 0; diff --git a/src/butil/time.h b/src/butil/time.h index d0daaa5ff4..4c7f87934f 100644 --- a/src/butil/time.h +++ b/src/butil/time.h @@ -334,7 +334,7 @@ inline int64_t cpuwide_time_s() { // -------------------------------------------------------------------- inline int64_t gettimeofday_us() { timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); return now.tv_sec * 1000000L + now.tv_usec; } diff --git a/src/butil/time/time.h b/src/butil/time/time.h index cdc57b635a..d341271a49 100644 --- a/src/butil/time/time.h +++ b/src/butil/time/time.h @@ -268,7 +268,7 @@ class BUTIL_EXPORT Time { bool HasValidValues() const; }; - // Contains the NULL time. Use Time::Now() to get the current time. + // Contains the nullptr time. Use Time::Now() to get the current time. Time() : us_(0) { } diff --git a/src/butil/time/time_mac.cc b/src/butil/time/time_mac.cc index 98e818a9c6..733d7e249a 100644 --- a/src/butil/time/time_mac.cc +++ b/src/butil/time/time_mac.cc @@ -29,7 +29,7 @@ uint64_t ComputeCurrentTicks() { struct timeval boottime; int mib[2] = {CTL_KERN, KERN_BOOTTIME}; size_t size = sizeof(boottime); - int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0); + int kr = sysctl(mib, arraysize(mib), &boottime, &size, nullptr, 0); DCHECK_EQ(KERN_SUCCESS, kr); butil::TimeDelta time_difference = butil::Time::Now() - (butil::Time::FromTimeT(boottime.tv_sec) + @@ -171,7 +171,7 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) { date.year = exploded.year; butil::ScopedCFTypeRef time_zone( - is_local ? CFTimeZoneCopySystem() : NULL); + is_local ? CFTimeZoneCopySystem() : nullptr); CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) + kCFAbsoluteTimeIntervalSince1970; return Time(static_cast(seconds * kMicrosecondsPerSecond) + @@ -189,7 +189,7 @@ void Time::Explode(bool is_local, Exploded* exploded) const { kCFAbsoluteTimeIntervalSince1970; butil::ScopedCFTypeRef time_zone( - is_local ? CFTimeZoneCopySystem() : NULL); + is_local ? CFTimeZoneCopySystem() : nullptr); CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone); // 1 = Monday, ..., 7 = Sunday. int cf_day_of_week = CFAbsoluteTimeGetDayOfWeek(seconds, time_zone); diff --git a/src/butil/time/time_posix.cc b/src/butil/time/time_posix.cc index 2b363839d0..758909670c 100644 --- a/src/butil/time/time_posix.cc +++ b/src/butil/time/time_posix.cc @@ -211,7 +211,7 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) { timestruct.tm_isdst = -1; // attempt to figure it out #if !defined(OS_NACL) && !defined(OS_SOLARIS) timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore - timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore + timestruct.tm_zone = nullptr; // not a POSIX field, so mktime/timegm ignore #endif diff --git a/src/butil/zero_copy_stream_as_streambuf.cpp b/src/butil/zero_copy_stream_as_streambuf.cpp index 540a5bc546..1076b4038f 100644 --- a/src/butil/zero_copy_stream_as_streambuf.cpp +++ b/src/butil/zero_copy_stream_as_streambuf.cpp @@ -29,14 +29,14 @@ int ZeroCopyStreamAsStreamBuf::overflow(int ch) { if (ch == std::streambuf::traits_type::eof()) { return ch; } - void* block = NULL; + void* block = nullptr; int size = 0; if (_zero_copy_stream->Next(&block, &size)) { setp((char*)block, (char*)block + size); // if size == 0, this function will call overflow again. return sputc(ch); } else { - setp(NULL, NULL); + setp(nullptr, nullptr); return std::streambuf::traits_type::eof(); } } @@ -51,9 +51,9 @@ ZeroCopyStreamAsStreamBuf::~ZeroCopyStreamAsStreamBuf() { } void ZeroCopyStreamAsStreamBuf::shrink() { - if (pbase() != NULL) { + if (pbase() != nullptr) { _zero_copy_stream->BackUp(epptr() - pptr()); - setp(NULL, NULL); + setp(nullptr, nullptr); } } diff --git a/src/json2pb/json_to_pb.cpp b/src/json2pb/json_to_pb.cpp index 00e12d981e..63a965c6d2 100644 --- a/src/json2pb/json_to_pb.cpp +++ b/src/json2pb/json_to_pb.cpp @@ -218,7 +218,7 @@ inline bool convert_enum_type(const BUTIL_RAPIDJSON_NAMESPACE::Value&item, bool const google::protobuf::FieldDescriptor* field, const google::protobuf::Reflection* reflection, std::string* err) { - const google::protobuf::EnumValueDescriptor * enum_value_descriptor = NULL; + const google::protobuf::EnumValueDescriptor * enum_value_descriptor = nullptr; if (item.IsInt()) { enum_value_descriptor = field->enum_type()->FindValueByNumber(item.GetInt()); } else if (item.IsString()) { @@ -582,7 +582,7 @@ bool JsonValueToProtoMessage(const BUTIL_RAPIDJSON_NAMESPACE::Value& json_value, } std::string field_name_str_temp; - const BUTIL_RAPIDJSON_NAMESPACE::Value* value_ptr = NULL; + const BUTIL_RAPIDJSON_NAMESPACE::Value* value_ptr = nullptr; for (size_t i = 0; i < fields.size(); ++i) { const google::protobuf::FieldDescriptor* field = fields[i]; @@ -604,7 +604,7 @@ bool JsonValueToProtoMessage(const BUTIL_RAPIDJSON_NAMESPACE::Value& json_value, #else const BUTIL_RAPIDJSON_NAMESPACE::Value::Member* member = json_value.FindMember(field_name_str.data()); - if (member == NULL) { + if (member == nullptr) { if (field->is_required()) { J2PERROR(err, "Missing required field: %s", butil::EnsureString(field->full_name()).c_str()); return false; @@ -736,7 +736,7 @@ bool ProtoJsonToProtoMessage(google::protobuf::io::ZeroCopyInputStream* json, #if GOOGLE_PROTOBUF_VERSION >= 6031000 auto st = google::protobuf::json::JsonStreamToMessage(json, message, options); bool ok = st.ok(); - if (!ok && NULL != error) { + if (!ok && nullptr != error) { *error = st.ToString(); } return ok; @@ -748,7 +748,7 @@ bool ProtoJsonToProtoMessage(google::protobuf::io::ZeroCopyInputStream* json, auto st = google::protobuf::util::JsonToBinaryStream( type_resolver.get(), type_url, json, &output_stream, options); if (!st.ok()) { - if (NULL != error) { + if (nullptr != error) { *error = st.ToString(); } return false; @@ -757,7 +757,7 @@ bool ProtoJsonToProtoMessage(google::protobuf::io::ZeroCopyInputStream* json, butil::IOBufAsZeroCopyInputStream input_stream(buf); google::protobuf::io::CodedInputStream decoder(&input_stream); bool ok = message->ParseFromCodedStream(&decoder); - if (!ok && NULL != error) { + if (!ok && nullptr != error) { *error = "Fail to ParseFromCodedStream"; } return ok; diff --git a/src/json2pb/json_to_pb.h b/src/json2pb/json_to_pb.h index 3734ef313e..dae7aff270 100644 --- a/src/json2pb/json_to_pb.h +++ b/src/json2pb/json_to_pb.h @@ -45,7 +45,7 @@ struct Json2PbOptions { }; // Convert `json' to protobuf `message' according to `options'. -// Returns true on success. `error' (if not NULL) will be set with error +// Returns true on success. `error' (if not nullptr) will be set with error // message on failure. // // [When options.allow_remaining_bytes_after_parsing is true] @@ -93,10 +93,10 @@ using ProtoJson2PbOptions = google::protobuf::util::JsonParseOptions; bool ProtoJsonToProtoMessage(google::protobuf::io::ZeroCopyInputStream* json, google::protobuf::Message* message, const ProtoJson2PbOptions& options = ProtoJson2PbOptions(), - std::string* error = NULL); + std::string* error = nullptr); bool ProtoJsonToProtoMessage(const std::string& json, google::protobuf::Message* message, const ProtoJson2PbOptions& options = ProtoJson2PbOptions(), - std::string* error = NULL); + std::string* error = nullptr); } // namespace json2pb diff --git a/src/json2pb/pb_to_json.cpp b/src/json2pb/pb_to_json.cpp index c1fd528650..5ec3a90ec7 100644 --- a/src/json2pb/pb_to_json.cpp +++ b/src/json2pb/pb_to_json.cpp @@ -419,7 +419,7 @@ bool ProtoMessageToProtoJson(const google::protobuf::Message& message, #if GOOGLE_PROTOBUF_VERSION >= 6031000 auto st = google::protobuf::json::MessageToJsonStream(message, json, options); bool ok = st.ok(); - if (!ok && NULL != error) { + if (!ok && nullptr != error) { *error = st.ToString(); } return ok; @@ -436,7 +436,7 @@ bool ProtoMessageToProtoJson(const google::protobuf::Message& message, type_resolver.get(), GetTypeUrl(message), &input_stream, json, options); bool ok = st.ok(); - if (!ok && NULL != error) { + if (!ok && nullptr != error) { *error = st.ToString(); } return ok; diff --git a/src/json2pb/pb_to_json.h b/src/json2pb/pb_to_json.h index 4dda3a76a1..1cc3a71c11 100644 --- a/src/json2pb/pb_to_json.h +++ b/src/json2pb/pb_to_json.h @@ -72,25 +72,25 @@ struct Pb2JsonOptions { }; // Convert protobuf `messge' to `json' according to `options'. -// Returns true on success. `error' (if not NULL) will be set with error +// Returns true on success. `error' (if not nullptr) will be set with error // message on failure. bool ProtoMessageToJson(const google::protobuf::Message& message, std::string* json, const Pb2JsonOptions& options, - std::string* error = NULL); + std::string* error = nullptr); // send output to ZeroCopyOutputStream instead of std::string. bool ProtoMessageToJson(const google::protobuf::Message& message, google::protobuf::io::ZeroCopyOutputStream* json, const Pb2JsonOptions& options, - std::string* error = NULL); + std::string* error = nullptr); // Using default Pb2JsonOptions. bool ProtoMessageToJson(const google::protobuf::Message& message, std::string* json, - std::string* error = NULL); + std::string* error = nullptr); bool ProtoMessageToJson(const google::protobuf::Message& message, google::protobuf::io::ZeroCopyOutputStream* json, - std::string* error = NULL); + std::string* error = nullptr); // See for details. #if GOOGLE_PROTOBUF_VERSION >= 6030000 @@ -110,10 +110,10 @@ using Pb2ProtoJsonOptions = google::protobuf::util::JsonOptions; bool ProtoMessageToProtoJson(const google::protobuf::Message& message, google::protobuf::io::ZeroCopyOutputStream* json, const Pb2ProtoJsonOptions& options = Pb2ProtoJsonOptions(), - std::string* error = NULL); + std::string* error = nullptr); bool ProtoMessageToProtoJson(const google::protobuf::Message& message, std::string* json, const Pb2ProtoJsonOptions& options = Pb2ProtoJsonOptions(), - std::string* error = NULL); + std::string* error = nullptr); } // namespace json2pb #endif // BRPC_JSON2PB_PB_TO_JSON_H diff --git a/src/json2pb/protobuf_map.cpp b/src/json2pb/protobuf_map.cpp index 7553523482..0fcb0f3dab 100644 --- a/src/json2pb/protobuf_map.cpp +++ b/src/json2pb/protobuf_map.cpp @@ -28,21 +28,21 @@ bool IsProtobufMap(const FieldDescriptor* field) { return false; } const Descriptor* entry_desc = field->message_type(); - if (entry_desc == NULL) { + if (entry_desc == nullptr) { return false; } if (entry_desc->field_count() != 2) { return false; } const FieldDescriptor* key_desc = entry_desc->field(KEY_INDEX); - if (NULL == key_desc + if (nullptr == key_desc || key_desc->is_repeated() || key_desc->cpp_type() != FieldDescriptor::CPPTYPE_STRING || key_desc->name() != KEY_NAME) { return false; } const FieldDescriptor* value_desc = entry_desc->field(VALUE_INDEX); - if (NULL == value_desc + if (nullptr == value_desc || value_desc->name() != VALUE_NAME) { return false; } diff --git a/src/json2pb/zero_copy_stream_reader.h b/src/json2pb/zero_copy_stream_reader.h index 6c19d3306a..d1f515c24e 100644 --- a/src/json2pb/zero_copy_stream_reader.h +++ b/src/json2pb/zero_copy_stream_reader.h @@ -26,7 +26,7 @@ class ZeroCopyStreamReader { public: typedef char Ch; ZeroCopyStreamReader(google::protobuf::io::ZeroCopyInputStream *stream) - : _data(NULL), _data_size(0), _nread(0), _stream(stream) { + : _data(nullptr), _data_size(0), _nread(0), _stream(stream) { } //Take a charactor and return its address. const char* PeekAddr() { @@ -38,7 +38,7 @@ class ZeroCopyStreamReader { return _data; } } - return NULL; + return nullptr; } const char* TakeWithAddr() { const char* c = PeekAddr(); @@ -47,7 +47,7 @@ class ZeroCopyStreamReader { --_data_size; return _data++; } - return NULL; + return nullptr; } char Take() { const char* c = PeekAddr(); @@ -71,7 +71,7 @@ class ZeroCopyStreamReader { size_t Tell() { return _nread; } void Put(char) {} void Flush() {} - char *PutBegin() { return NULL; } + char *PutBegin() { return nullptr; } size_t PutEnd(char *) { return 0; } private: const char *_data; diff --git a/src/json2pb/zero_copy_stream_writer.h b/src/json2pb/zero_copy_stream_writer.h index 6404211958..43e9ac703e 100644 --- a/src/json2pb/zero_copy_stream_writer.h +++ b/src/json2pb/zero_copy_stream_writer.h @@ -42,14 +42,14 @@ class ZeroCopyStreamWriter { public: typedef char Ch; ZeroCopyStreamWriter(google::protobuf::io::ZeroCopyOutputStream *stream) - : _stream(stream), _data(NULL), - _cursor(NULL), _data_size(0) { + : _stream(stream), _data(nullptr), + _cursor(nullptr), _data_size(0) { } ~ZeroCopyStreamWriter() { if (_stream && _data) { _stream->BackUp(RemainSize()); } - _stream = NULL; + _stream = nullptr; } void Put(char c) { @@ -84,14 +84,14 @@ class ZeroCopyStreamWriter { char Peek() { return 0; } char Take() { return 0; } size_t Tell() { return 0; } - char *PutBegin() { return NULL; } + char *PutBegin() { return nullptr; } size_t PutEnd(char *) { return 0; } private: bool AcquireNextBuf() { if (__builtin_expect(!_stream, 0)) { return false; } - if (_data == NULL || _cursor == _data + _data_size) { + if (_data == nullptr || _cursor == _data + _data_size) { if (!_stream->Next((void **)&_data, &_data_size)) { return false; } diff --git a/src/mcpack2pb/parser-inl.h b/src/mcpack2pb/parser-inl.h index 76d03fea76..235bb5405e 100644 --- a/src/mcpack2pb/parser-inl.h +++ b/src/mcpack2pb/parser-inl.h @@ -158,12 +158,24 @@ inline void ArrayIterator::init(InputStream* stream, size_t size) { _stream = stream; _expected_popped_bytes = _stream->popped_bytes() + sizeof(ItemsHead); _expected_popped_end = _stream->popped_bytes() + size; + if (size < sizeof(ItemsHead)) { + CHECK(false) << "buffer(size=" << size << ") is not enough"; + return set_bad(); + } ItemsHead items_head; if (_stream->cut_packed_pod(&items_head) != sizeof(ItemsHead)) { CHECK(false) << "buffer(size=" << size << ") is not enough"; return set_bad(); } _item_count = items_head.item_count; + // The item count is read from the request and may be much larger than + // the actual payload. The generated code uses it to Reserve() memory for + // repeated protobuf fields, so cap it by the remaining bytes (each item + // occupies at least one byte) to avoid a huge preallocation. + const size_t remaining = size - sizeof(ItemsHead); + if (_item_count > remaining) { + _item_count = static_cast(remaining); + } operator++(); } @@ -175,6 +187,10 @@ inline void ISOArrayIterator::init(InputStream* stream, size_t size) { _item_size = 0; _item_count = 0; _left_item_count = 0; + if (size < sizeof(IsoItemsHead)) { + CHECK(false) << "Not enough data"; + return set_bad(); + } IsoItemsHead items_head; if (_stream->cut_packed_pod(&items_head) != sizeof(IsoItemsHead)) { CHECK(false) << "Not enough data"; diff --git a/src/mcpack2pb/parser.cpp b/src/mcpack2pb/parser.cpp index 5c785dc45f..92d7a22021 100644 --- a/src/mcpack2pb/parser.cpp +++ b/src/mcpack2pb/parser.cpp @@ -577,6 +577,15 @@ double UnparsedValue::as_double(const char* var) { } void UnparsedValue::as_string(std::string* out, const char* var) { + if (_size < 1) { + // A string field must contain at least the trailing '\0'. + // Reject _size == 0 here, otherwise `_size - 1' underflows and + // resize() throws an uncaught exception. Clear `out' so callers + // that reuse the string do not keep a stale value. + out->clear(); + _stream->set_bad(); + return; + } out->resize(_size - 1); if (_stream->cutn(&(*out)[0], _size - 1) != _size - 1) { CHECK(false) << "Not enough data for " << var; diff --git a/test/Makefile b/test/Makefile index 136b6f6803..f2348e7fa3 100644 --- a/test/Makefile +++ b/test/Makefile @@ -19,7 +19,7 @@ NEED_GPERFTOOLS=1 NEED_GTEST=1 include ../config.mk 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 -DUNIT_TEST -DBVAR_NOT_LINK_DEFAULT_VARIABLES -CXXFLAGS+=$(CPPFLAGS) -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-invalid-offsetof -Wno-unused-parameter -fno-omit-frame-pointer -fno-access-control -std=c++14 +CXXFLAGS+=$(CPPFLAGS) -pipe -Wall -W -fPIC -fstrict-aliasing -Wno-invalid-offsetof -Wno-unused-parameter -fno-omit-frame-pointer -fno-access-control # On Darwin, only gtest library is needed, other libraries have been linked in `brpc.dbg.dylib` ifeq ($(SYSTEM),Darwin) diff --git a/test/brpc_controller_unittest.cpp b/test/brpc_controller_unittest.cpp index 3f410a2599..d000d41add 100644 --- a/test/brpc_controller_unittest.cpp +++ b/test/brpc_controller_unittest.cpp @@ -28,6 +28,7 @@ #include "brpc/server.h" #include "brpc/channel.h" #include "brpc/controller.h" +#include "brpc/span.h" class ControllerTest : public ::testing::Test{ protected: @@ -41,6 +42,14 @@ void MyCancelCallback(bool* cancel_flag) { *cancel_flag = true; } +bool WaitForSpanToExpire(const std::weak_ptr& span) { + const int64_t deadline_us = butil::gettimeofday_us() + 5000000L; + while (!span.expired() && butil::gettimeofday_us() < deadline_us) { + usleep(1000); + } + return span.expired(); +} + TEST_F(ControllerTest, notify_on_failed) { brpc::SocketId id = 0; ASSERT_EQ(0, brpc::Socket::Create(brpc::SocketOptions(), &id)); @@ -74,6 +83,50 @@ TEST_F(ControllerTest, notify_on_destruction) { ASSERT_TRUE(cancel); } +TEST_F(ControllerTest, root_client_span_kept_alive_until_reset) { + brpc::ClearTlsParentSpan(); + + brpc::Controller cntl; + std::weak_ptr weak_span; + { + std::shared_ptr span = + brpc::Span::CreateClientSpan("test.RootClient/Call", 0); + ASSERT_TRUE(span); + ASSERT_TRUE(span->local_parent().expired()); + weak_span = span; + cntl._span = span; + } + + ASSERT_FALSE(weak_span.expired()); + ASSERT_TRUE(cntl._span); + + cntl.Reset(); + ASSERT_FALSE(cntl._span); + ASSERT_TRUE(WaitForSpanToExpire(weak_span)); +} + +TEST_F(ControllerTest, root_client_span_released_by_submit_span) { + brpc::ClearTlsParentSpan(); + + brpc::Controller cntl; + std::weak_ptr weak_span; + { + std::shared_ptr span = + brpc::Span::CreateClientSpan("test.RootClient/Call", 0); + ASSERT_TRUE(span); + ASSERT_TRUE(span->local_parent().expired()); + weak_span = span; + cntl._span = span; + } + + ASSERT_FALSE(weak_span.expired()); + ASSERT_TRUE(cntl._span); + + cntl.SubmitSpan(); + ASSERT_FALSE(cntl._span); + ASSERT_TRUE(WaitForSpanToExpire(weak_span)); +} + #if ! BRPC_WITH_GLOG static bool endsWith(const std::string& s1, const butil::StringPiece& s2) { diff --git a/test/brpc_grpc_protocol_unittest.cpp b/test/brpc_grpc_protocol_unittest.cpp index f170639d17..5a9752ea23 100644 --- a/test/brpc_grpc_protocol_unittest.cpp +++ b/test/brpc_grpc_protocol_unittest.cpp @@ -88,6 +88,17 @@ class MyGrpcService : public ::test::GrpcService { } }; +class WindowGrpcService : public ::test::GrpcService { +public: + void Method(::google::protobuf::RpcController*, + const ::test::GrpcRequest* req, + ::test::GrpcResponse* res, + ::google::protobuf::Closure* done) override { + brpc::ClosureGuard done_guard(done); + res->set_message(req->message()); + } +}; + class GrpcTest : public ::testing::Test { protected: GrpcTest() { @@ -272,4 +283,43 @@ TEST_F(GrpcTest, GrpcTimeOut) { } } +TEST(GrpcProtocol, client_sends_large_request_with_small_remote_window) { + WindowGrpcService service; + brpc::Server server; + ASSERT_EQ(0, server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE)); + brpc::ServerOptions server_options; + server_options.h2_settings.stream_window_size = 32; + ASSERT_EQ(0, server.Start("127.0.0.1:0", &server_options)); + + brpc::Channel channel; + brpc::ChannelOptions channel_options; + channel_options.protocol = g_protocol; + channel_options.timeout_ms = 10000; + ASSERT_EQ(0, channel.Init(server.listen_address(), &channel_options)); + test::GrpcService_Stub stub(&channel); + + // Establish the H2 connection and receive the server SETTINGS first. + { + test::GrpcRequest request; + test::GrpcResponse response; + brpc::Controller cntl; + request.set_message("warmup"); + request.set_gzip(false); + request.set_return_error(false); + stub.Method(&cntl, &request, &response, nullptr); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + ASSERT_EQ(request.message(), response.message()); + } + + test::GrpcRequest request; + test::GrpcResponse response; + brpc::Controller cntl; + request.set_message(std::string(128 * 1024, 'x')); + request.set_gzip(false); + request.set_return_error(false); + stub.Method(&cntl, &request, &response, nullptr); + EXPECT_FALSE(cntl.Failed()) << cntl.ErrorText(); + EXPECT_EQ(request.message(), response.message()); +} + } // namespace diff --git a/test/brpc_h2_unsent_message_unittest.cpp b/test/brpc_h2_unsent_message_unittest.cpp index 5e3b266dfe..1c7b985aed 100644 --- a/test/brpc_h2_unsent_message_unittest.cpp +++ b/test/brpc_h2_unsent_message_unittest.cpp @@ -27,11 +27,223 @@ #include "brpc/policy/http2_rpc_protocol.h" #include "gperftools_helper.h" +namespace brpc { +DECLARE_int64(socket_max_unwritten_bytes); +} + int main(int argc, char* argv[]) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } +namespace { + +brpc::policy::H2FrameHead PopFrame(butil::IOBuf* buf, std::string* payload) { + char head[brpc::policy::FRAME_HEAD_SIZE]; + CHECK_EQ(sizeof(head), buf->cutn(head, sizeof(head))); + brpc::policy::H2FrameHead frame; + frame.payload_size = + (static_cast(head[0]) << 16) | + (static_cast(head[1]) << 8) | + static_cast(head[2]); + frame.type = static_cast(head[3]); + frame.flags = head[4]; + frame.stream_id = + (static_cast(head[5]) << 24) | + (static_cast(head[6]) << 16) | + (static_cast(head[7]) << 8) | + static_cast(head[8]); + payload->resize(frame.payload_size); + if (frame.payload_size != 0) { + CHECK_EQ(frame.payload_size, + buf->cutn(&(*payload)[0], frame.payload_size)); + } + return frame; +} + +} // namespace + +TEST(H2UnsentMessage, split_request_data_by_remote_window) { + brpc::SocketId id; + brpc::SocketUniquePtr sock; + brpc::SocketOptions options; + options.user = brpc::get_client_side_messenger(); + ASSERT_EQ(0, brpc::Socket::Create(options, &id)); + ASSERT_EQ(0, brpc::Socket::Address(id, &sock)); + + brpc::policy::H2Context* ctx = + new brpc::policy::H2Context(sock.get(), nullptr); + ASSERT_EQ(0, ctx->Init()); + sock->initialize_parsing_context(&ctx); + ctx->_remote_settings.max_frame_size = 4; + ctx->_remote_settings.stream_window_size = 5; + ctx->_remote_window_left = 6; + + brpc::policy::H2StreamContext* sctx = + new brpc::policy::H2StreamContext(false); + sctx->Init(ctx, 1); + + butil::IOBuf body; + body.append("abcdefghij"); + butil::IOBuf out; + ASSERT_TRUE(ctx->TryToInsertClientStream(1, sctx, body, &out).ok()); + + std::string payload; + brpc::policy::H2FrameHead frame = PopFrame(&out, &payload); + EXPECT_EQ(4u, frame.payload_size); + EXPECT_EQ(brpc::policy::H2_FRAME_DATA, frame.type); + EXPECT_EQ(0, frame.flags & 0x1); + EXPECT_EQ("abcd", payload); + frame = PopFrame(&out, &payload); + EXPECT_EQ(1u, frame.payload_size); + EXPECT_EQ(0, frame.flags & 0x1); + EXPECT_EQ("e", payload); + EXPECT_TRUE(out.empty()); + EXPECT_EQ(5u, sctx->_pending_data.size()); + EXPECT_EQ(5u, ctx->_pending_data_size); + EXPECT_EQ(1, ctx->_remote_window_left); + EXPECT_EQ(0, sctx->_remote_window_left); + + ctx->_remote_window_left.fetch_add(3, butil::memory_order_relaxed); + sctx->_remote_window_left.fetch_add(3, butil::memory_order_relaxed); + { + std::unique_lock mu(ctx->_stream_mutex); + ctx->AppendPendingDataLocked(sctx, &out); + } + frame = PopFrame(&out, &payload); + EXPECT_EQ(3u, frame.payload_size); + EXPECT_EQ(0, frame.flags & 0x1); + EXPECT_EQ("fgh", payload); + EXPECT_TRUE(out.empty()); + EXPECT_EQ(2u, ctx->_pending_data_size); + + ctx->_remote_window_left.fetch_add(2, butil::memory_order_relaxed); + sctx->_remote_window_left.fetch_add(2, butil::memory_order_relaxed); + { + std::unique_lock mu(ctx->_stream_mutex); + ctx->AppendPendingDataLocked(sctx, &out); + } + frame = PopFrame(&out, &payload); + EXPECT_EQ(2u, frame.payload_size); + EXPECT_NE(0, frame.flags & 0x1); + EXPECT_EQ("ij", payload); + EXPECT_TRUE(out.empty()); + EXPECT_TRUE(sctx->_pending_data.empty()); + EXPECT_EQ(0u, ctx->_pending_data_size); +} + +TEST(H2UnsentMessage, request_does_not_fail_when_body_exceeds_window) { + brpc::SocketId id; + brpc::SocketUniquePtr sock; + brpc::SocketOptions options; + options.user = brpc::get_client_side_messenger(); + ASSERT_EQ(0, brpc::Socket::Create(options, &id)); + ASSERT_EQ(0, brpc::Socket::Address(id, &sock)); + + brpc::policy::H2Context* ctx = + new brpc::policy::H2Context(sock.get(), nullptr); + ASSERT_EQ(0, ctx->Init()); + sock->initialize_parsing_context(&ctx); + ctx->_last_sent_stream_id = 1; + ctx->_remote_settings.max_frame_size = 4; + ctx->_remote_settings.stream_window_size = 3; + ctx->_remote_window_left = 3; + + brpc::Controller cntl; + cntl.http_request().uri() = "http://example.com/echo"; + cntl.request_attachment().append("abcdefghij"); + brpc::policy::H2UnsentRequest* request = + brpc::policy::H2UnsentRequest::New(&cntl); + ASSERT_TRUE(request != nullptr); + + butil::IOBuf out; + const butil::Status status = + request->AppendAndDestroySelf(&out, sock.get()); + EXPECT_TRUE(status.ok()) << status; + brpc::policy::H2StreamContext* sctx = ctx->FindStream(1); + ASSERT_TRUE(sctx != nullptr); + EXPECT_EQ(7u, sctx->_pending_data.size()); + EXPECT_EQ(7u, ctx->_pending_data_size); + EXPECT_EQ(0, ctx->_remote_window_left); + EXPECT_EQ(0, sctx->_remote_window_left); +} + +TEST(H2UnsentMessage, invalid_window_update_does_not_change_window) { + brpc::SocketId id; + brpc::SocketUniquePtr sock; + brpc::SocketOptions options; + options.user = brpc::get_client_side_messenger(); + ASSERT_EQ(0, brpc::Socket::Create(options, &id)); + ASSERT_EQ(0, brpc::Socket::Address(id, &sock)); + + brpc::policy::H2Context* ctx = + new brpc::policy::H2Context(sock.get(), nullptr); + ASSERT_EQ(0, ctx->Init()); + sock->initialize_parsing_context(&ctx); + const int64_t max_window_size = std::numeric_limits::max(); + ctx->_remote_window_left = max_window_size; + + const char increment[] = {0, 0, 0, 1}; + butil::IOBuf payload; + payload.append(increment, sizeof(increment)); + butil::IOBufBytesIterator it(payload); + const brpc::policy::H2FrameHead frame = { + 4, brpc::policy::H2_FRAME_WINDOW_UPDATE, 0, 0}; + const brpc::policy::H2ParseResult result = ctx->OnWindowUpdate(it, frame); + + EXPECT_EQ(brpc::H2_FLOW_CONTROL_ERROR, result.error()); + EXPECT_EQ(max_window_size, + ctx->_remote_window_left.load(butil::memory_order_relaxed)); +} + +TEST(H2UnsentMessage, clear_pending_data_releases_overcrowded_buffer) { + brpc::SocketId id; + brpc::SocketUniquePtr sock; + brpc::SocketOptions options; + options.user = brpc::get_client_side_messenger(); + ASSERT_EQ(0, brpc::Socket::Create(options, &id)); + ASSERT_EQ(0, brpc::Socket::Address(id, &sock)); + + brpc::policy::H2Context* ctx = + new brpc::policy::H2Context(sock.get(), nullptr); + ASSERT_EQ(0, ctx->Init()); + sock->initialize_parsing_context(&ctx); + ctx->_remote_window_left = 0; + + butil::IOBuf body; + body.append("pending"); + butil::IOBuf out; + GFLAGS_NAMESPACE::FlagSaver flag_saver; + brpc::FLAGS_socket_max_unwritten_bytes = body.size(); + + std::unique_ptr sctx( + new brpc::policy::H2StreamContext(false)); + sctx->Init(ctx, 1); + ASSERT_TRUE( + ctx->TryToInsertClientStream(1, sctx.get(), body, &out).ok()); + brpc::policy::H2StreamContext* inserted_sctx = sctx.release(); + ASSERT_TRUE(out.empty()); + ASSERT_EQ(body.size(), ctx->_pending_data_size); + EXPECT_TRUE(ctx->PendingDataOvercrowded()); + + std::unique_ptr rejected_sctx( + new brpc::policy::H2StreamContext(false)); + rejected_sctx->Init(ctx, 3); + butil::IOBuf rejected_body; + rejected_body.append("x"); + const butil::Status rejected = ctx->TryToInsertClientStream( + 3, rejected_sctx.get(), rejected_body, &out); + EXPECT_EQ(brpc::EOVERCROWDED, rejected.error_code()); + EXPECT_EQ(nullptr, ctx->FindStream(3)); + EXPECT_EQ(body.size(), ctx->_pending_data_size); + + ctx->ClearPendingData(1); + EXPECT_FALSE(ctx->PendingDataOvercrowded()); + + EXPECT_TRUE(inserted_sctx->_pending_data.empty()); + EXPECT_EQ(0u, ctx->_pending_data_size); +} + TEST(H2UnsentMessage, request_throughput) { brpc::Controller cntl; butil::IOBuf request_buf; diff --git a/test/brpc_http_rpc_protocol_unittest.cpp b/test/brpc_http_rpc_protocol_unittest.cpp index 87837abf1a..97de699547 100644 --- a/test/brpc_http_rpc_protocol_unittest.cpp +++ b/test/brpc_http_rpc_protocol_unittest.cpp @@ -1408,12 +1408,12 @@ TEST_F(HttpTest, http2_sanity) { options.protocol = "h2"; ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - // Check that the first request with size larger than the default window can - // be sent out, when remote settings are not received. + // Check that the first request larger than the default window completes + // after SETTINGS and WINDOW_UPDATE make more capacity available. brpc::Controller cntl; test::EchoRequest big_req; test::EchoResponse res; - std::string message(2 * 1024 * 1024 /* 2M */, 'x'); + std::string message(128 * 1024, 'x'); big_req.set_message(message); cntl.http_request().set_method(brpc::HTTP_METHOD_POST); cntl.http_request().uri() = "/EchoService/Echo"; @@ -1527,7 +1527,7 @@ TEST_F(HttpTest, http2_rst_after_header_and_data) { ASSERT_TRUE(cntl.http_response().status_code() == brpc::HTTP_STATUS_OK); } -TEST_F(HttpTest, http2_window_used_up) { +TEST_F(HttpTest, http2_window_used_up_buffers_request) { brpc::Controller cntl; butil::IOBuf request_buf; test::EchoRequest req; @@ -1545,6 +1545,8 @@ TEST_F(HttpTest, http2_window_used_up) { buf.append(settingsbuf, brpc::policy::FRAME_HEAD_SIZE + nb); brpc::policy::ParseH2Message(&buf, _h2_client_sock.get(), false, NULL); + brpc::policy::H2Context* ctx = static_cast( + _h2_client_sock->parsing_context()); int nsuc = brpc::H2Settings::DEFAULT_INITIAL_WINDOW_SIZE / cntl.request_attachment().size(); for (int i = 0; i <= nsuc; i++) { brpc::policy::H2UnsentRequest* h2_req = brpc::policy::H2UnsentRequest::New(&cntl); @@ -1554,15 +1556,15 @@ TEST_F(HttpTest, http2_window_used_up) { NULL, &cntl, request_buf, NULL); butil::IOBuf dummy; butil::Status st = socket_message->AppendAndDestroySelf(&dummy, _h2_client_sock.get()); + ASSERT_TRUE(st.ok()); if (i == nsuc) { - // the last message should fail according to flow control policy. - ASSERT_FALSE(st.ok()); - ASSERT_TRUE(st.error_code() == brpc::ELIMIT); - ASSERT_TRUE(butil::StringPiece(st.error_str()).starts_with("remote_window_left is not enough")); + ASSERT_GT(ctx->_pending_data_size, 0u); + h2_req->DestroyStreamUserData( + _h2_client_sock, &cntl, ECANCELED, false); + ASSERT_EQ(0u, ctx->_pending_data_size); } else { - ASSERT_TRUE(st.ok()); + h2_req->DestroyStreamUserData(_h2_client_sock, &cntl, 0, false); } - h2_req->DestroyStreamUserData(_h2_client_sock, &cntl, 0, false); } } diff --git a/test/brpc_load_balancer_unittest.cpp b/test/brpc_load_balancer_unittest.cpp index 0f0eccccd3..1b326a8ff0 100644 --- a/test/brpc_load_balancer_unittest.cpp +++ b/test/brpc_load_balancer_unittest.cpp @@ -1026,6 +1026,56 @@ TEST_F(LoadBalancerTest, weighted_randomized) { } } +TEST_F(LoadBalancerTest, weighted_randomized_equal_weight) { + // With equal weights every server must get the same share of the traffic. + // The tolerance of `weighted_randomized` above is +/-2x, which is too loose + // to catch a single misplaced slot, so check the distribution tightly here. + const char* servers[] = { + "10.92.115.19:8831", + "10.42.108.25:8832", + "10.36.150.31:8833", + "10.36.150.32:8899" + }; + brpc::policy::WeightedRandomizedLoadBalancer wrlb; + for (size_t i = 0; i < ARRAY_SIZE(servers); ++i) { + butil::EndPoint dummy; + ASSERT_EQ(0, str2endpoint(servers[i], &dummy)); + brpc::ServerId id(8888); + brpc::SocketOptions options; + options.remote_side = dummy; + options.user = new SaveRecycle; + ASSERT_EQ(0, brpc::Socket::Create(options, &id.id)); + id.tag = "1"; + ASSERT_TRUE(wrlb.AddServer(id)); + } + + std::map select_result; + brpc::SocketUniquePtr ptr; + brpc::LoadBalancer::SelectIn in = { 0, false, false, 0u, NULL }; + brpc::LoadBalancer::SelectOut out(&ptr); + const int run_times = 40000; + for (int i = 0; i < run_times; ++i) { + ASSERT_EQ(0, wrlb.SelectServer(in, &out)); + ++select_result[ptr->remote_side()]; + } + + // Every server must be selected at least once, in particular the one added + // last, which owns the largest prefix sum. + ASSERT_EQ(ARRAY_SIZE(servers), select_result.size()); + const double expect_rate = 1.0 / ARRAY_SIZE(servers); + for (const auto& result : select_result) { + const double actual_rate = result.second * 1.0 / run_times; + std::cout << result.first << " select_times=" << result.second + << " actual_rate=" << actual_rate + << " expect_rate=" << expect_rate << std::endl; + // 0.9x ~ 1.1x of the expected rate. With n=40000 and p=0.25 the count has + // sigma = sqrt(n*p*(1-p)) ~= 86.6, so the +-10% band is about 11 sigma + // wide and a passing run is not luck. + ASSERT_GE(actual_rate, expect_rate * 0.9); + ASSERT_LE(actual_rate, expect_rate * 1.1); + } +} + TEST_F(LoadBalancerTest, health_check_no_valid_server) { const char* servers[] = { "10.92.115.19:8832", diff --git a/test/brpc_mcpack2pb_unittest.cpp b/test/brpc_mcpack2pb_unittest.cpp new file mode 100644 index 0000000000..6718cae93b --- /dev/null +++ b/test/brpc_mcpack2pb_unittest.cpp @@ -0,0 +1,159 @@ +// 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. + +// Unit tests for the mcpack2pb parser. + +#include +#include "butil/iobuf.h" +#include "mcpack2pb/parser.h" + +namespace { + +TEST(Mcpack2pbParserTest, StringFieldWithZeroValueSize) { + // A 51-byte mcpack2 frame whose `service_name' string field has + // value_size == 0. This used to underflow in UnparsedValue::as_string() + // (resize(_size - 1) with _size == 0) and throw std::length_error, which + // is not caught on the request path and therefore crashes the server. + const unsigned char data[] = { + 0x10, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xa0, 0x08, 0x1e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xd0, 0x0d, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x00, + }; + butil::IOBuf body; + body.append(data, sizeof(data)); + + butil::IOBufAsZeroCopyInputStream zc_stream(body); + mcpack2pb::InputStream stream(&zc_stream); + ASSERT_NE(0u, mcpack2pb::unbox(&stream)); + + mcpack2pb::ObjectIterator it1(&stream, body.size() - stream.popped_bytes()); + bool found_content = false; + for (; it1 != NULL; ++it1) { + if (it1->name == "content") { + found_content = true; + break; + } + } + ASSERT_TRUE(found_content); + ASSERT_EQ(mcpack2pb::FIELD_ARRAY, it1->value.type()); + + mcpack2pb::ArrayIterator it2(it1->value); + ASSERT_TRUE(it2 != NULL); + bool found_service_name = false; + for (mcpack2pb::ObjectIterator it3(*it2); it3 != NULL; ++it3) { + if (it3->name == "service_name") { + found_service_name = true; + ASSERT_EQ(mcpack2pb::FIELD_STRING, it3->value.type()); + std::string service_name = "stale"; + it3->value.as_string(&service_name, "service_name"); + // A zero-sized string field must be rejected gracefully instead of + // throwing (resize(SIZE_MAX)) and crashing the process. + EXPECT_FALSE(it3->value.stream()->good()); + // The output string must be cleared so callers that reuse the + // string do not keep a stale value. + EXPECT_TRUE(service_name.empty()); + break; + } + } + ASSERT_TRUE(found_service_name); +} + +TEST(Mcpack2pbParserTest, ParseStringField) { + // A valid object {"msg":"abc"}. + const unsigned char data[] = { + 0x10, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xd0, 0x04, 0x04, + 0x6d, 0x73, 0x67, 0x00, + 0x61, 0x62, 0x63, 0x00, + }; + butil::IOBuf body; + body.append(data, sizeof(data)); + + butil::IOBufAsZeroCopyInputStream zc_stream(body); + mcpack2pb::InputStream stream(&zc_stream); + ASSERT_NE(0u, mcpack2pb::unbox(&stream)); + + mcpack2pb::ObjectIterator it(&stream, body.size() - stream.popped_bytes()); + ASSERT_TRUE(it != NULL); + EXPECT_EQ("msg", it->name.as_string()); + ASSERT_EQ(mcpack2pb::FIELD_STRING, it->value.type()); + std::string value; + it->value.as_string(&value, "msg"); + EXPECT_EQ("abc", value); + EXPECT_TRUE(stream.good()); +} + +TEST(Mcpack2pbParserTest, ArrayItemCountIsCappedToRemainingBytes) { + // An mcpack array whose header claims item_count = 0x7fffffff (INT32_MAX) + // but contains no actual items. The raw item_count is fed by the + // generated code into Reserve() of a repeated protobuf field, which used + // to preallocate ~16GB from a tiny request. The item count must be capped + // by the bytes actually available in the array. + const unsigned char data[] = { + 0xff, 0xff, 0xff, 0x7f, // item_count = 0x7fffffff, no items + }; + butil::IOBuf body; + body.append(data, sizeof(data)); + + butil::IOBufAsZeroCopyInputStream zc_stream(body); + mcpack2pb::InputStream stream(&zc_stream); + mcpack2pb::ArrayIterator it(&stream, sizeof(data)); + // No item can fit in an empty payload. + EXPECT_EQ(0u, it.item_count()); +} + +TEST(Mcpack2pbParserTest, ArrayItemCountIsCappedToAvailableBytes) { + // item_count = 1000 but the payload only holds one int32 item (6 bytes). + // Each item occupies at least one byte, so the count must not exceed the + // remaining bytes (6). + const unsigned char data[] = { + 0xe8, 0x03, 0x00, 0x00, // item_count = 1000 + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, // one int32 item + }; + butil::IOBuf body; + body.append(data, sizeof(data)); + + butil::IOBufAsZeroCopyInputStream zc_stream(body); + mcpack2pb::InputStream stream(&zc_stream); + mcpack2pb::ArrayIterator it(&stream, sizeof(data)); + EXPECT_LE(it.item_count(), sizeof(data) - sizeof(uint32_t)); +} + +TEST(Mcpack2pbParserTest, ArrayItemCountIsZeroWhenPayloadSmallerThanHeader) { + // The declared array payload (3 bytes) is smaller than the 4-byte + // ItemsHead, but the stream still contains data. The parser must not read + // past the declared boundary and trust the extra bytes as item_count + // (which would feed a huge value into Reserve() again). + const unsigned char data[] = { + 0xff, 0xff, 0xff, 0x7f, // would be read as item_count = 0x7fffffff + }; + butil::IOBuf body; + body.append(data, sizeof(data)); + + butil::IOBufAsZeroCopyInputStream zc_stream(body); + mcpack2pb::InputStream stream(&zc_stream); + mcpack2pb::ArrayIterator it(&stream, 3); // size = 3 < sizeof(ItemsHead) + EXPECT_EQ(0u, it.item_count()); +} + +} // namespace diff --git a/test/brpc_rdma_unittest.cpp b/test/brpc_rdma_unittest.cpp index e30ae09f35..2ecd1f3cac 100644 --- a/test/brpc_rdma_unittest.cpp +++ b/test/brpc_rdma_unittest.cpp @@ -72,6 +72,7 @@ extern int (*IbvQueryQp)(ibv_qp*, ibv_qp_attr*, ibv_qp_attr_mask, ibv_qp_init_at extern int (*IbvDestroyQp)(ibv_qp*); extern butil::atomic g_rdma_available; extern bool g_skip_rdma_init; +extern bool g_fail_resource_alloc_for_test; } // namespace rdma } // namespace brpc @@ -1919,6 +1920,112 @@ TEST_F(RdmaTest, v3_server_reply_has_no_ece_without_hw_negotiation) { StopServer(); } +class ResourceAllocFailGuard { +public: + explicit ResourceAllocFailGuard(bool v) + : _saved(rdma::g_fail_resource_alloc_for_test) { + rdma::g_fail_resource_alloc_for_test = v; + } + ~ResourceAllocFailGuard() { + rdma::g_fail_resource_alloc_for_test = _saved; + } +private: + bool _saved; +}; + +TEST_F(RdmaTest, client_alloc_resource_fail_fallback_tcp) { + StartServer(); + ResourceAllocFailGuard alloc_fail_guard(true); + + Channel channel; + ChannelOptions chan_options; + chan_options.socket_mode = SOCKET_MODE_RDMA; + chan_options.connect_timeout_ms = 500; + chan_options.timeout_ms = 500; + chan_options.max_retry = 0; + ASSERT_EQ(0, channel.Init(g_ep, &chan_options)); + + Controller cntl; + test::EchoRequest req; + test::EchoResponse res; + req.set_message(__FUNCTION__); + req.set_sleep_us(200000); + google::protobuf::Closure* done = DoNothing(); + ::test::EchoService::Stub(&channel).Echo(&cntl, &req, &res, done); + usleep(100000); + + SocketUniquePtr s; + ASSERT_EQ(0, Socket::Address(cntl._single_server_id, &s)); + ASSERT_EQ(rdma::RdmaEndpoint::FALLBACK_TCP, + static_cast(s->_transport.get())->_rdma_ep->_state); + ASSERT_EQ(RdmaTransport::RDMA_OFF, + static_cast(s->_transport.get())->_rdma_state); + // The socket must not be failed, otherwise it can no longer carry TCP. + ASSERT_FALSE(s->Failed()); + + // The RPC still completes over TCP. + bthread_id_join(cntl.call_id()); + ASSERT_EQ(0, cntl.ErrorCode()) << cntl.ErrorText(); + + StopServer(); +} + +TEST_F(RdmaTest, server_alloc_resource_fail_fallback_tcp) { + StartServer(); + ResourceAllocFailGuard alloc_fail_guard(true); + + sockaddr_in addr; + bzero((char*)&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + butil::fd_guard sockfd(socket(AF_INET, SOCK_STREAM, 0)); + ASSERT_TRUE(sockfd >= 0); + ASSERT_EQ(0, connect(sockfd, (sockaddr*)&addr, sizeof(sockaddr))); + usleep(100000); // wait for server to handle the msg + Socket* s = GetSocketFromServer(0); + ASSERT_TRUE(s != NULL); + ASSERT_EQ(rdma::RdmaEndpoint::UNINIT, + static_cast(s->_transport.get())->_rdma_ep->_state); + + // Send a well-formed v2 hello: the negotiation succeeds + // but the resource allocation does not. + rdma::v2_wire::HelloMessage msg{}; + msg.msg_len = rdma::HELLO_V2_MSG_LEN_MIN; + msg.hello_ver = rdma::HELLO_V2_VERSION; + msg.impl_ver = rdma::IMPL_V2_VERSION; + msg.sq_size = 16; + msg.rq_size = 16; + msg.block_size = 8192; + msg.qp_num = 0; + msg.gid = rdma::GetRdmaGid(); + + uint8_t data[rdma::HELLO_V2_MSG_LEN_MIN]; + memcpy(data, "RDMA", 4); + msg.Serialize(data + 4); + ASSERT_EQ(rdma::HELLO_V2_MSG_LEN_MIN, + write(sockfd, data, rdma::HELLO_V2_MSG_LEN_MIN)); + usleep(100000); + ASSERT_EQ(rdma::RdmaEndpoint::S_ACK_WAIT, + static_cast(s->_transport.get())->_rdma_ep->_state); + ASSERT_EQ(RdmaTransport::RDMA_OFF, + static_cast(s->_transport.get())->_rdma_state); + ASSERT_FALSE(s->Failed()); + + // Ack without RDMA so that the server finishes the handshake in TCP mode. + uint32_t flags = butil::HostToNet32(0); + ASSERT_EQ(sizeof(flags), write(sockfd, &flags, sizeof(flags))); + usleep(100000); + ASSERT_EQ(rdma::RdmaEndpoint::FALLBACK_TCP, + static_cast(s->_transport.get())->_rdma_ep->_state); + ASSERT_FALSE(s->Failed()); + + sockfd.reset(-1); + usleep(100000); + ASSERT_EQ(NULL, GetSocketFromServer(0)); + + StopServer(); +} + TEST_F(RdmaTest, try_global_disable_rdma) { StartServer(); rdma::g_rdma_available.store(false, butil::memory_order_relaxed); diff --git a/test/brpc_redis_unittest.cpp b/test/brpc_redis_unittest.cpp index 9095c82961..dc0f9d5595 100644 --- a/test/brpc_redis_unittest.cpp +++ b/test/brpc_redis_unittest.cpp @@ -1499,6 +1499,67 @@ TEST_F(RedisTest, memory_allocation_limits) { ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, err); } + { + // Simple string exceeding limit. Unlike bulk strings and arrays this + // branch had no cap, so a length >= 2^31 truncated the signed _length + // field to a negative value and later reads went out of bounds. + butil::IOBuf buf; + std::string large_status = "+"; + large_status.append(2000, 'a'); + large_status.append("\r\n"); + buf.append(large_status); + + brpc::RedisReply reply(&arena); + brpc::ParseError err = reply.ConsumePartialIOBuf(buf); + ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, err); + } + + { + // Error string exceeding limit (same branch as simple string). + butil::IOBuf buf; + std::string large_error = "-"; + large_error.append(2000, 'a'); + large_error.append("\r\n"); + buf.append(large_error); + + brpc::RedisReply reply(&arena); + brpc::ParseError err = reply.ConsumePartialIOBuf(buf); + ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, err); + } + + { + // Simple string exceeding limit before CRLF arrives. Without a cap on + // the waiting-for-CRLF path a peer that never sends the terminator + // could grow buf without bound. + butil::IOBuf buf; + std::string large_status = "+"; + large_status.append(brpc::FLAGS_redis_max_allocation_size + 100, 'a'); + buf.append(large_status); + + brpc::RedisReply reply(&arena); + brpc::ParseError err = reply.ConsumePartialIOBuf(buf); + ASSERT_EQ(brpc::PARSE_ERROR_ABSOLUTELY_WRONG, err); + } + + { + // A simple string exactly at the limit may have its CRLF split across + // reads; a lone trailing '\r' must not trip the cap early. + butil::IOBuf buf; + std::string boundary_status = "+"; + boundary_status.append(brpc::FLAGS_redis_max_allocation_size, 'a'); + boundary_status.push_back('\r'); + buf.append(boundary_status); + + brpc::RedisReply reply(&arena); + brpc::ParseError err = reply.ConsumePartialIOBuf(buf); + ASSERT_EQ(brpc::PARSE_ERROR_NOT_ENOUGH_DATA, err); + + buf.push_back('\n'); + err = reply.ConsumePartialIOBuf(buf); + ASSERT_EQ(brpc::PARSE_OK, err); + ASSERT_EQ(brpc::FLAGS_redis_max_allocation_size, (int)reply.size()); + } + // Test redis_command.cpp limits { // Test command string exceeding limit diff --git a/test/brpc_rtmp_unittest.cpp b/test/brpc_rtmp_unittest.cpp index 61a63744fc..286f8a87de 100644 --- a/test/brpc_rtmp_unittest.cpp +++ b/test/brpc_rtmp_unittest.cpp @@ -28,6 +28,8 @@ #include #include "butil/time.h" #include "butil/macros.h" +#include "butil/fd_guard.h" +#include "brpc/policy/rtmp_protocol.h" #include "brpc/socket.h" #include "brpc/acceptor.h" #include "brpc/server.h" @@ -805,6 +807,63 @@ TEST(RtmpTest, flv_reader_rejects_zero_datasize_audio_tag) { ASSERT_EQ(before, buf.size()); } +// A crafted Abort message that names the chunk stream currently being parsed +// (itself) used to make ClearChunkStream delete the RtmpChunkStream while its +// Feed() is still running, which caused a heap-use-after-free right after +// OnMessage() returned. +TEST(RtmpTest, abort_message_naming_own_chunk_stream) { + int pipe_fds[2]; + ASSERT_EQ(0, pipe(pipe_fds)); + butil::fd_guard guard0(pipe_fds[0]); // read end, closed by this guard + butil::fd_guard guard1(pipe_fds[1]); // write end, handed over to Socket + + brpc::SocketId id; + brpc::SocketOptions options; + options.fd = guard1.release(); // Socket takes ownership of the fd + ASSERT_EQ(0, brpc::Socket::Create(options, &id)); + brpc::SocketUniquePtr sock; + ASSERT_EQ(0, brpc::Socket::Address(id, &sock)); + + brpc::policy::RtmpContext ctx(NULL, NULL); + ctx.SetState(sock->remote_side(), + brpc::policy::RtmpContext::STATE_RECEIVED_C2); + + // fmt0 chunk on chunk stream 2 carrying an Abort message (type 2) whose + // payload is the same chunk stream id (2). + std::string chunk; + chunk.push_back((char)0x02); // basic header: fmt=0, cs_id=2 + chunk.append(3, '\0'); // timestamp = 0 + chunk.push_back('\0'); // message_length (3 bytes) = 4 + chunk.push_back('\0'); + chunk.push_back((char)0x04); + chunk.push_back((char)0x02); // message_type = Abort + chunk.append(4, '\0'); // stream_id = 0 (little endian) + chunk.push_back('\0'); // payload: cs_id = 2 (big endian) + chunk.push_back('\0'); + chunk.push_back('\0'); + chunk.push_back((char)0x02); + + butil::IOBuf buf; + buf.append(chunk); + ASSERT_EQ(brpc::PARSE_OK, ctx.Feed(&buf, sock.get()).error()); + + // A following type-1 chunk inherits the message header from the previous + // message on the same stream. If the abort had wrongly deleted the chunk + // stream, the freshly recreated stream would have no last header and this + // chunk would be rejected; instead it must be parsed successfully. + std::string cont; + cont.push_back((char)0x42); // basic header: fmt=1, cs_id=2 + cont.append(3, '\0'); // timestamp delta = 0 + cont.push_back('\0'); // message_length (3 bytes) = 4 + cont.push_back('\0'); + cont.push_back((char)0x04); + cont.push_back((char)0x03); // message_type = Ack + cont.append(4, '\0'); // payload: bytes_received = 0 + butil::IOBuf buf2; + buf2.append(cont); + ASSERT_EQ(brpc::PARSE_OK, ctx.Feed(&buf2, sock.get()).error()); +} + TEST(RtmpTest, successfully_play_streams) { PlayingDummyService rtmp_service; brpc::Server server; diff --git a/test/brpc_sofa_pbrpc_protocol_unittest.cpp b/test/brpc_sofa_pbrpc_protocol_unittest.cpp index 4cf91b4fd4..3996de0e7c 100644 --- a/test/brpc_sofa_pbrpc_protocol_unittest.cpp +++ b/test/brpc_sofa_pbrpc_protocol_unittest.cpp @@ -214,6 +214,26 @@ class SofaTest : public ::testing::Test{ MyAuthenticator _auth; }; +// Build a SOFA header without a real SocketMessage. Fields are stored in host +// byte order (see PackSofaHeader), each 64-bit field is stored as low 32-bit +// word followed by high 32-bit word. +static void AppendSofaTestHeader(butil::IOBuf* buf, uint32_t meta_size, + uint64_t body_size, uint64_t msg_size) { + char header[24]; + memcpy(header, "SOFA", 4); + const uint32_t meta = meta_size; + const uint32_t body_words[2] = { + static_cast(body_size & 0xFFFFFFFFULL), + static_cast(body_size >> 32)}; + const uint32_t msg_words[2] = { + static_cast(msg_size & 0xFFFFFFFFULL), + static_cast(msg_size >> 32)}; + memcpy(header + 4, &meta, sizeof(meta)); + memcpy(header + 8, body_words, sizeof(body_words)); + memcpy(header + 16, msg_words, sizeof(msg_words)); + buf->append(header, sizeof(header)); +} + TEST_F(SofaTest, process_request_failed_socket) { brpc::policy::SofaRpcMeta meta; meta.set_type(brpc::policy::SofaRpcMeta::REQUEST); @@ -344,4 +364,26 @@ TEST_F(SofaTest, sofa_compress) { TestSofaCompress(brpc::COMPRESS_TYPE_GZIP); TestSofaCompress(brpc::COMPRESS_TYPE_ZLIB); } + +TEST_F(SofaTest, reject_oversized_body) { + GFLAGS_NAMESPACE::FlagSaver flag_saver; + brpc::FLAGS_max_body_size = 1024; + const uint64_t body_size = 8 * 1024 * 1024; + butil::IOBuf buf; + AppendSofaTestHeader(&buf, 0, body_size, body_size); + brpc::ParseResult pr = + brpc::policy::ParseSofaMessage(&buf, _socket.get(), false, NULL); + ASSERT_EQ(brpc::PARSE_ERROR_TOO_BIG_DATA, pr.error()); +} + +TEST_F(SofaTest, reject_oversized_meta) { + GFLAGS_NAMESPACE::FlagSaver flag_saver; + brpc::FLAGS_max_body_size = 1024; + const uint32_t meta_size = 8 * 1024 * 1024; + butil::IOBuf buf; + AppendSofaTestHeader(&buf, meta_size, 0, meta_size); + brpc::ParseResult pr = + brpc::policy::ParseSofaMessage(&buf, _socket.get(), false, NULL); + ASSERT_EQ(brpc::PARSE_ERROR_TOO_BIG_DATA, pr.error()); +} } //namespace diff --git a/test/brpc_streaming_rpc_unittest.cpp b/test/brpc_streaming_rpc_unittest.cpp index d6ad16949d..a759bae560 100644 --- a/test/brpc_streaming_rpc_unittest.cpp +++ b/test/brpc_streaming_rpc_unittest.cpp @@ -143,10 +143,14 @@ static void* SendTwoMessagesOnServerExtraStream(void* arg) { const int64_t connect_deadline_us = butil::gettimeofday_us() + 2 * 1000 * 1000L; bool connected = false; while (butil::gettimeofday_us() < connect_deadline_us) { - brpc::SocketUniquePtr ptr; - if (brpc::Socket::Address(sid, &ptr) == 0) { - brpc::Stream* s = static_cast(ptr->conn()); - if (s->_host_socket != NULL && s->_connected) { + brpc::StreamUniquePtr ptr; + if (brpc::Stream::Address(sid, &ptr) == 0) { + brpc::Stream* s = ptr.get(); + // SetConnected() publishes _connected only after _host_socket and + // the remote settings are ready. Check the acquire flag first + // before reading the non-atomic host pointer. + if (s->_connected.load(butil::memory_order_acquire) && + s->_host_socket != NULL) { connected = true; break; } @@ -286,20 +290,6 @@ TEST_F(StreamingRpcTest, batch_create_stream_feedback_race) { ASSERT_EQ(2u, request_streams.size()); state.client_extra_stream_id = request_streams[1]; - // Block SetConnected() on the extra stream to enlarge the race window. - brpc::SocketUniquePtr client_extra_ptr; - ASSERT_EQ(0, brpc::Socket::Address(state.client_extra_stream_id, &client_extra_ptr)); - brpc::Stream* client_extra_stream = static_cast(client_extra_ptr->conn()); - bthread_mutex_lock(&client_extra_stream->_connect_mutex); - struct UnlockGuard { - bthread_mutex_t* m; - ~UnlockGuard() { - if (m) { - bthread_mutex_unlock(m); - } - } - } unlock_guard{&client_extra_stream->_connect_mutex}; - BRPC_SCOPE_EXIT { if (state.server_extra_stream_id != brpc::INVALID_STREAM_ID) { brpc::StreamClose(state.server_extra_stream_id); @@ -317,13 +307,6 @@ TEST_F(StreamingRpcTest, batch_create_stream_feedback_race) { server.Stop(0); server.Join(); - // Release the SocketUniquePtr held above so the fake socket can be - // recycled. Otherwise BeforeRecycle / on_closed for the extra stream - // is deferred until `client_extra_ptr` destructs at scope exit, which - // happens *after* `client_handler` and `state` are destroyed -> UAF - // inside Stream::Consume on Linux. - client_extra_ptr.reset(); - // on_closed() runs asynchronously on each client stream's consumer // bthread. Wait for both before letting handler/state go out of // scope, otherwise Stream::Consume will dereference freed memory. @@ -338,13 +321,11 @@ TEST_F(StreamingRpcTest, batch_create_stream_feedback_race) { stub.Echo(&cntl, &request, &response, brpc::NewCallback(SetAtomicTrue, &state.rpc_done)); // Wait until client consumes the first 64B payload on extra stream. + // This increases the chance that Consume() runs before SetConnected() + // finishes on the extra stream, exercising the SetConnected()/Consume() + // ordering relevant to FEEDBACK sending via the atomic _local_consumed. ASSERT_TRUE(WaitForTrue(state.client_got_first_msg, 2000)); - // Unblock SetConnected(); the fix in PR 3215 should send the first FEEDBACK - // with consumed_size=64 here, making server-side stream writable again. - bthread_mutex_unlock(&client_extra_stream->_connect_mutex); - unlock_guard.m = NULL; - ASSERT_TRUE(WaitForTrue(state.rpc_done, 2000)); ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); @@ -587,11 +568,13 @@ TEST_F(StreamingRpcTest, auto_close_if_host_socket_closed) { ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText() << " request_stream=" << request_stream; { - brpc::SocketUniquePtr ptr; - ASSERT_EQ(0, brpc::Socket::Address(request_stream, &ptr)); - brpc::Stream* s = (brpc::Stream*)ptr->conn(); - ASSERT_TRUE(s->_host_socket != NULL); - s->_host_socket->SetFailed(); + brpc::StreamUniquePtr ptr; + ASSERT_EQ(0, brpc::Stream::Address(request_stream, &ptr)); + brpc::Stream* s = ptr.get(); + ASSERT_TRUE(s->_connected.load(butil::memory_order_acquire)); + brpc::Socket* host_socket = s->_host_socket; + ASSERT_TRUE(host_socket != NULL); + host_socket->SetFailed(); } usleep(100); @@ -638,9 +621,10 @@ TEST_F(StreamingRpcTest, failed_when_rst) { usleep(100); } { - brpc::SocketUniquePtr ptr; - ASSERT_EQ(0, brpc::Socket::Address(request_stream, &ptr)); - brpc::Stream* s = (brpc::Stream*)ptr->conn(); + brpc::StreamUniquePtr ptr; + ASSERT_EQ(0, brpc::Stream::Address(request_stream, &ptr)); + brpc::Stream* s = ptr.get(); + ASSERT_TRUE(s->_connected.load(butil::memory_order_acquire)); ASSERT_TRUE(s->_host_socket != NULL); brpc::policy::SendStreamRst(s->_host_socket, s->_remote_settings.stream_id()); @@ -866,11 +850,12 @@ TEST_F(StreamingRpcTest, segment_stream_data_automatically) { brpc::SocketUniquePtr host_socket_ptr; { - brpc::SocketUniquePtr ptr; - ASSERT_EQ(0, brpc::Socket::Address(request_stream, &ptr)); - brpc::Stream *s = (brpc::Stream *)ptr->conn(); - ASSERT_TRUE(s->_host_socket != NULL); - s->_host_socket->ReAddress(&host_socket_ptr); + brpc::StreamUniquePtr ptr; + ASSERT_EQ(0, brpc::Stream::Address(request_stream, &ptr)); + ASSERT_TRUE(ptr->_connected.load(butil::memory_order_acquire)); + brpc::Socket* host_socket = ptr->_host_socket; + ASSERT_TRUE(host_socket != NULL); + host_socket->ReAddress(&host_socket_ptr); } ASSERT_EQ(0, brpc::StreamClose(request_stream)); @@ -883,7 +868,12 @@ TEST_F(StreamingRpcTest, segment_stream_data_automatically) { host_socket_ptr->UpdateStatsEverySecond(now_ms); brpc::SocketStat stat; host_socket_ptr->GetStat(&stat); - ASSERT_LT(N * sizeof(N), stat.out_num_messages_m); + // A whole message (with all its segments) is now written to the host socket + // in a single wait-free Socket::Write, so the number of host-socket messages + // no longer reflects the number of stream frames. Heavy segmentation still + // shows up as extra on-wire bytes: each 1-byte segment carries a full STRM + // frame header + meta, so out_size_m is far larger than the raw payload. + ASSERT_LT(N * sizeof(N), stat.out_size_m); ASSERT_FALSE(handler.failed()); ASSERT_EQ(0, handler.idle_times()); ASSERT_EQ(N, handler._expected_next_value); @@ -1051,11 +1041,11 @@ TEST_F(StreamingRpcTest, batch_create_extra_stream) { for (size_t i = 0; i < request_streams.size(); ++i) { const brpc::StreamId sid = request_streams[i]; ASSERT_TRUE(WaitForTrue([sid]() { - brpc::SocketUniquePtr ptr; - if (brpc::Socket::Address(sid, &ptr) != 0) { + brpc::StreamUniquePtr ptr; + if (brpc::Stream::Address(sid, &ptr) != 0) { return false; } - brpc::Stream* s = static_cast(ptr->conn()); + brpc::Stream* s = ptr.get(); return s->_host_socket != NULL && s->_connected.load(butil::memory_order_acquire); }, 5000)) << "stream_index=" << i; @@ -1136,11 +1126,11 @@ TEST_F(StreamingRpcTest, batch_create_extra_stream_upstream_only) { for (size_t i = 0; i < request_streams.size(); ++i) { const brpc::StreamId sid = request_streams[i]; ASSERT_TRUE(WaitForTrue([sid]() { - brpc::SocketUniquePtr ptr; - if (brpc::Socket::Address(sid, &ptr) != 0) { + brpc::StreamUniquePtr ptr; + if (brpc::Stream::Address(sid, &ptr) != 0) { return false; } - brpc::Stream* s = static_cast(ptr->conn()); + brpc::Stream* s = ptr.get(); return s->_host_socket != NULL && s->_connected.load(butil::memory_order_acquire); }, 5000)) << "stream_index=" << i; @@ -1175,3 +1165,82 @@ TEST_F(StreamingRpcTest, batch_create_extra_stream_upstream_only) { server.Stop(0); server.Join(); } + +TEST_F(StreamingRpcTest, unconsumed_bytes_reclaimed_on_stream_close) { + GFLAGS_NAMESPACE::SetCommandLineOption( + "socket_max_streams_unconsumed_bytes", "10485760"); + BRPC_SCOPE_EXIT { + GFLAGS_NAMESPACE::SetCommandLineOption( + "socket_max_streams_unconsumed_bytes", "0"); + }; + + class BlockingHandler : public brpc::StreamInputHandler { + public: + BlockingHandler() : blocked(true) {} + + int on_received_messages(brpc::StreamId, + butil::IOBuf* const[], size_t) override { + while (blocked.load(std::memory_order_acquire)) { + usleep(100); + } + return 0; + } + void on_idle_timeout(brpc::StreamId) override {} + void on_closed(brpc::StreamId) override {} + + std::atomic blocked; + } handler; + + brpc::StreamOptions opt; + opt.handler = &handler; + opt.max_buf_size = 1024 * 1024; + + brpc::Server server; + MyServiceWithStream service(opt); + ASSERT_EQ(0, server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(9007, NULL)); + + brpc::Channel channel; + ASSERT_EQ(0, channel.Init("127.0.0.1:9007", NULL)); + + brpc::Controller cntl; + brpc::StreamId request_stream; + brpc::StreamOptions request_stream_options; + request_stream_options.max_buf_size = 1024 * 1024; + ASSERT_EQ(0, StreamCreate(&request_stream, cntl, &request_stream_options)); + brpc::ScopedStream stream_guard(request_stream); + + test::EchoService_Stub stub(&channel); + stub.Echo(&cntl, &request, &response, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + + brpc::SocketUniquePtr host_socket; + { + brpc::StreamUniquePtr ptr; + ASSERT_EQ(0, brpc::Stream::Address(request_stream, &ptr)); + ASSERT_TRUE(ptr->_connected.load(butil::memory_order_acquire)); + ASSERT_TRUE(ptr->_host_socket != NULL); + ptr->_host_socket->ReAddress(&host_socket); + } + int64_t baseline = host_socket->_total_streams_unconsumed_size.load( + butil::memory_order_relaxed); + + size_t write_size = 100 * 1024; + butil::IOBuf out; + out.append(std::string(write_size, 'x')); + ASSERT_EQ(0, brpc::StreamWrite(request_stream, out)); + ASSERT_TRUE(WaitForTrue([&]() { + return host_socket->_total_streams_unconsumed_size.load( + butil::memory_order_relaxed) >= baseline + static_cast(write_size); + }, 2000)); + + ASSERT_EQ(0, brpc::StreamClose(request_stream)); + ASSERT_TRUE(WaitForTrue([&]() { + return host_socket->_total_streams_unconsumed_size.load( + butil::memory_order_relaxed) == baseline; + }, 2000)); + + handler.blocked.store(false, std::memory_order_release); + server.Stop(0); + server.Join(); +} diff --git a/test/brpc_urma_unittest.cpp b/test/brpc_urma_unittest.cpp new file mode 100644 index 0000000000..d05784d009 --- /dev/null +++ b/test/brpc_urma_unittest.cpp @@ -0,0 +1,609 @@ +// 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. + +#include +#include +#include + +#if BRPC_WITH_URMA +#include "butil/atomicops.h" +#include "butil/sys_byteorder.h" +#include "urma_api.h" +#include "brpc/urma/urma_handshake.h" +#include "brpc/urma/urma_handshake.pb.h" +#include "brpc/urma/urma_helper.h" +#include "urma_types.h" + +using namespace brpc; + +namespace brpc { +namespace urma { + +DECLARE_int32(urma_client_handshake_version); +extern bool g_skip_urma_init; +extern butil::atomic g_urma_available; + +} // namespace urma +} // namespace brpc + +// --------------------------------------------------------------------------- +// v2 binary HelloMessage: serialize + deserialize round-trips. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, v2_serialize_deserialize_roundtrip) { + urma::v2_wire::HelloMessage m; + m.msg_len = urma::v2_wire::HELLO_PACKET_LEN; + m.hello_ver = urma::v2_wire::HELLO_V2_VERSION; + m.impl_ver = urma::v2_wire::IMPL_V2_VERSION; + m.buffer_size = 8192; + m.recv_buffer_cnt = 127; + m.jetty_id = 0x12345678; + for (int i = 0; i < 16; ++i) { + m.eid[i] = static_cast(i + 1); + } + m.uasid = 0xdeadbeef; + m.tp_type = 1; // URMA_CTP + for (int i = 0; i < 16; ++i) { + m.seg_eid[i] = static_cast(16 - i); + } + m.seg_uasid = 0xcafebabe; + m.seg_va = 0x1122334455667788ULL; + m.seg_len = 1ULL << 20; + m.seg_token_id = 0x42424242; + + uint8_t buf[urma::v2_wire::HELLO_BODY_LEN]; + m.Serialize(buf); + + urma::v2_wire::HelloMessage m2; + m2.Deserialize(buf); + EXPECT_EQ(m.msg_len, m2.msg_len); + EXPECT_EQ(m.hello_ver, m2.hello_ver); + EXPECT_EQ(m.impl_ver, m2.impl_ver); + EXPECT_EQ(m.buffer_size, m2.buffer_size); + EXPECT_EQ(m.recv_buffer_cnt, m2.recv_buffer_cnt); + EXPECT_EQ(m.jetty_id, m2.jetty_id); + EXPECT_EQ(0, memcmp(m.eid, m2.eid, 16)); + EXPECT_EQ(m.uasid, m2.uasid); + EXPECT_EQ(m.tp_type, m2.tp_type); + EXPECT_EQ(0, memcmp(m.seg_eid, m2.seg_eid, 16)); + EXPECT_EQ(m.seg_uasid, m2.seg_uasid); + EXPECT_EQ(m.seg_va, m2.seg_va); + EXPECT_EQ(m.seg_len, m2.seg_len); + EXPECT_EQ(m.seg_token_id, m2.seg_token_id); +} + +// --------------------------------------------------------------------------- +// v2 packet on the wire: "URMA" magic + body. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, v2_packet_magic_is_urma) { + EXPECT_EQ(4u, urma::v2_wire::MAGIC_STR_LEN); + char magic[4] = {'U', 'R', 'M', 'A'}; + EXPECT_EQ(0, memcmp(magic, "URMA", 4)); + EXPECT_EQ(4u + 82u, urma::v2_wire::HELLO_PACKET_LEN); +} + +// --------------------------------------------------------------------------- +// v3 protobuf UrmaHello: serialize + parse round-trips. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, v3_protobuf_roundtrip) { + urma::UrmaHello msg; + msg.set_buffer_size(8192); + msg.set_recv_buffer_cnt(127); + msg.set_jetty_id(0x12345678); + uint8_t eid[16]; + for (int i = 0; i < 16; ++i) { + eid[i] = static_cast(i + 1); + } + msg.set_eid(eid, 16); + msg.set_uasid(0xdeadbeef); + msg.set_tp_type(1); + uint8_t seg_eid[16]; + for (int i = 0; i < 16; ++i) { + seg_eid[i] = static_cast(16 - i); + } + msg.set_seg_eid(seg_eid, 16); + msg.set_seg_uasid(0xcafebabe); + msg.set_seg_va(0x1122334455667788ULL); + msg.set_seg_len(1ULL << 20); + msg.set_seg_token_id(0x42424242); + + std::string body; + ASSERT_TRUE(msg.SerializeToString(&body)); + urma::UrmaHello msg2; + ASSERT_TRUE(msg2.ParseFromString(body)); + EXPECT_EQ(msg.buffer_size(), msg2.buffer_size()); + EXPECT_EQ(msg.recv_buffer_cnt(), msg2.recv_buffer_cnt()); + EXPECT_EQ(msg.jetty_id(), msg2.jetty_id()); + EXPECT_EQ(16, msg2.eid().size()); + EXPECT_EQ(0, memcmp(msg.eid().data(), msg2.eid().data(), 16)); + EXPECT_EQ(msg.uasid(), msg2.uasid()); + EXPECT_EQ(msg.tp_type(), msg2.tp_type()); + EXPECT_EQ(16, msg2.seg_eid().size()); + EXPECT_EQ(msg.seg_uasid(), msg2.seg_uasid()); + EXPECT_EQ(msg.seg_va(), msg2.seg_va()); + EXPECT_EQ(msg.seg_len(), msg2.seg_len()); + EXPECT_EQ(msg.seg_token_id(), msg2.seg_token_id()); +} + +// --------------------------------------------------------------------------- +// CreateServerHandshakeByMagic dispatches on the magic bytes. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, server_handshake_factory_dispatches_on_magic) { + // We cannot fully exercise the server handshake without a real socket + + // endpoint, but we can verify the factory returns the right protocol + // version for each magic, and nullptr for an unknown magic. + uint8_t magic_v2[4] = {'U', 'R', 'M', 'A'}; + uint8_t magic_v3[4] = {'U', 'R', 'M', '3'}; + uint8_t magic_bad[4] = {'P', 'R', 'P', 'C'}; + + // v2 magic -> protocol version 2 + urma::UrmaHandshake* hs2 = + urma::CreateServerHandshakeByMagic(nullptr, magic_v2); + // Note: the factory dereferences the endpoint only inside SendLocalHello / + // ReceiveAndParseRemoteHello; passing nullptr is safe for the version query. + // (We delete immediately to avoid touching the endpoint.) + if (hs2) { + EXPECT_EQ(2, hs2->ProtocolVersion()); + delete hs2; + } + // v3 magic -> protocol version 3 + urma::UrmaHandshake* hs3 = + urma::CreateServerHandshakeByMagic(nullptr, magic_v3); + if (hs3) { + EXPECT_EQ(3, hs3->ProtocolVersion()); + delete hs3; + } + // unknown magic -> nullptr (caller falls back to TCP) + urma::UrmaHandshake* hsb = + urma::CreateServerHandshakeByMagic(nullptr, magic_bad); + EXPECT_EQ(nullptr, hsb); +} + +// --------------------------------------------------------------------------- +// CreateClientHandshake picks the version from the gflag. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, client_handshake_factory_respects_flag) { + const int saved = urma::FLAGS_urma_client_handshake_version; + + urma::FLAGS_urma_client_handshake_version = 2; + urma::UrmaHandshake* hs2 = urma::CreateClientHandshake(nullptr); + if (hs2) { + EXPECT_EQ(2, hs2->ProtocolVersion()); + delete hs2; + } + + urma::FLAGS_urma_client_handshake_version = 3; + urma::UrmaHandshake* hs3 = urma::CreateClientHandshake(nullptr); + if (hs3) { + EXPECT_EQ(3, hs3->ProtocolVersion()); + delete hs3; + } + + urma::FLAGS_urma_client_handshake_version = saved; +} + +// --------------------------------------------------------------------------- +// 4-byte ACK: HELLO_ACK_URMA_OK bit. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, ack_bit_is_urma_ok) { + // The ACK is a 4-byte big-endian flags word; bit 0 means "I want URMA". + // Verify the round-trip: host -> net -> host preserves the bit. + uint32_t flags = 0x1; // HELLO_ACK_URMA_OK + uint32_t flags_be = butil::HostToNet32(flags); + uint32_t flags_back = butil::NetToHost32(flags_be); + EXPECT_EQ(flags, flags_back); + EXPECT_NE(0u, flags_back & 0x1); +} + +// --------------------------------------------------------------------------- +// ParsedHello field layout: covers the flattened segment (seg_* fields). +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, parsed_hello_segment_fields) { + urma::ParsedHello p; + std::memset(&p, 0, sizeof(p)); + p.buffer_size = 8192; + p.recv_buffer_cnt = 127; + p.jetty_id = 42; + p.tp_type = 1; + p.seg_va = 0x1000; + p.seg_len = 0x100000; + p.seg_token_id = 7; + EXPECT_EQ(8192u, p.buffer_size); + EXPECT_EQ(127u, p.recv_buffer_cnt); + EXPECT_EQ(42u, p.jetty_id); + EXPECT_EQ(1u, p.tp_type); + EXPECT_EQ(0x1000u, p.seg_va); + EXPECT_EQ(0x100000u, p.seg_len); + EXPECT_EQ(7u, p.seg_token_id); +} + +TEST(UrmaHandshakeTest, rejects_invalid_resource_and_window_values) { + urma::ParsedHello hello; + hello.buffer_size = 8192; + hello.recv_buffer_cnt = 127; + hello.jetty_id = 1; + hello.tp_type = URMA_CTP; + hello.seg_va = 0x1000; + hello.seg_len = 8192; + EXPECT_TRUE(urma::ValidHello(hello)); + + hello.recv_buffer_cnt = 2; + EXPECT_FALSE(urma::ValidHello(hello)); + hello.recv_buffer_cnt = 127; + hello.seg_len = 0; + EXPECT_FALSE(urma::ValidHello(hello)); + hello.seg_len = 8192; + hello.jetty_id = 0; + EXPECT_FALSE(urma::ValidHello(hello)); +} + +TEST(UrmaHelperTest, selects_priority_matching_transport_path_type) { + urma_device_attr_t attr{}; + attr.dev_cap.priority_info[3].tp_type.bs.rtp = 1; + attr.dev_cap.priority_info[6].tp_type.bs.ctp = 1; + + EXPECT_EQ(3, urma::FindUrmaPriorityForTpType(attr, URMA_RTP)); + EXPECT_EQ(6, urma::FindUrmaPriorityForTpType(attr, URMA_CTP)); + EXPECT_EQ(-1, urma::FindUrmaPriorityForTpType(attr, URMA_UTP)); +} + +// --------------------------------------------------------------------------- +// SupportedByUrma: only baidu_std. +// --------------------------------------------------------------------------- +TEST(UrmaHandshakeTest, supported_by_urma_protocol_allowlist) { + EXPECT_TRUE(urma::SupportedByUrma("baidu_std")); + EXPECT_FALSE(urma::SupportedByUrma("http")); + EXPECT_FALSE(urma::SupportedByUrma("hulu_pbrpc")); + EXPECT_FALSE(urma::SupportedByUrma("nshead")); +} + +// --------------------------------------------------------------------------- +// URMA mock smoke test: drives urma_init / device enumeration / context / +// jetty / post / poll. These tests rely on mock semantics and are skipped +// when the test binary links a real liburma provider. +// --------------------------------------------------------------------------- +class UrmaMockTest : public ::testing::Test { +protected: + void SetUp() override { + urma::g_skip_urma_init = false; + + urma_init_attr_t init_attr{}; + const urma_status_t status = urma_init(&init_attr); + ASSERT_TRUE(status == URMA_SUCCESS || status == URMA_EEXIST); + _owns_urma_init = status == URMA_SUCCESS; + + int num_devices = 0; + urma_device_t** devices = urma_get_device_list(&num_devices); + ASSERT_NE(nullptr, devices); + ASSERT_GT(num_devices, 0); + const bool using_mock = + strcmp(devices[0]->name, "mock_urma_device") == 0; + urma_free_device_list(devices); + if (!using_mock) { + if (_owns_urma_init) { + EXPECT_EQ(URMA_SUCCESS, urma_uninit()); + _owns_urma_init = false; + } + GTEST_SKIP() << "UrmaMockTest requires the URMA link-time mock"; + } + } + + void TearDown() override { + if (_owns_urma_init) { + EXPECT_EQ(URMA_SUCCESS, urma_uninit()); + } + urma::g_skip_urma_init = true; + urma::g_urma_available.store(true, butil::memory_order_relaxed); + } + +private: + bool _owns_urma_init{false}; +}; + +TEST_F(UrmaMockTest, init_and_enumerate_device) { + urma_init_attr_t init_attr{}; + EXPECT_EQ(URMA_EEXIST, urma_init(&init_attr)); + + int num_devices = 0; + urma_device_t** devices = urma_get_device_list(&num_devices); + ASSERT_NE(nullptr, devices); + ASSERT_GE(num_devices, 1); + EXPECT_STREQ("mock_urma_device", devices[0]->name); + urma_free_device_list(devices); +} + +TEST_F(UrmaMockTest, create_context_and_query_device) { + int num_devices = 0; + urma_device_t** devices = urma_get_device_list(&num_devices); + ASSERT_NE(nullptr, devices); + ASSERT_GE(num_devices, 1); + + uint32_t eid_cnt = 0; + urma_eid_info_t* eids = urma_get_eid_list(devices[0], &eid_cnt); + ASSERT_NE(nullptr, eids); + ASSERT_GE(eid_cnt, 1u); + urma_free_eid_list(eids); + + urma_context_t* ctx = urma_create_context(devices[0], 0); + ASSERT_NE(nullptr, ctx); + + urma_device_attr_t attr{}; + ASSERT_EQ(URMA_SUCCESS, urma_query_device(devices[0], &attr)); + EXPECT_GE(attr.dev_cap.max_jfc, 1u); + EXPECT_GE(attr.dev_cap.max_jetty, 1u); + + EXPECT_EQ(URMA_SUCCESS, urma_delete_context(ctx)); + urma_free_device_list(devices); +} + +TEST_F(UrmaMockTest, rejects_send_without_target_jetty) { + // A SEND without a target jetty is invalid. Keeping the mock strict here + // prevents tests from relying on input that a real provider cannot post. + int num_devices = 0; + urma_device_t** devices = urma_get_device_list(&num_devices); + ASSERT_NE(nullptr, devices); + ASSERT_GE(num_devices, 1); + uint32_t eid_cnt = 0; + urma_eid_info_t* eids = urma_get_eid_list(devices[0], &eid_cnt); + urma_free_eid_list(eids); + urma_context_t* ctx = urma_create_context(devices[0], 0); + ASSERT_NE(nullptr, ctx); + + urma_jfce_t* jfce = urma_create_jfce(ctx); + ASSERT_NE(nullptr, jfce); + urma_jfc_cfg_t jfc_cfg{}; + jfc_cfg.depth = 16; + jfc_cfg.jfce = jfce; + urma_jfc_t* jfc = urma_create_jfc(ctx, &jfc_cfg); + ASSERT_NE(nullptr, jfc); + + urma_jfr_cfg_t jfr_cfg{}; + jfr_cfg.depth = 16; + jfr_cfg.trans_mode = URMA_TM_RM; + jfr_cfg.max_sge = 1; + jfr_cfg.min_rnr_timer = URMA_TYPICAL_MIN_RNR_TIMER; + jfr_cfg.jfc = jfc; + urma_jfr_t* jfr = urma_create_jfr(ctx, &jfr_cfg); + ASSERT_NE(nullptr, jfr); + + urma_jetty_cfg_t jetty_cfg{}; + jetty_cfg.flag.bs.share_jfr = 1; + jetty_cfg.jfs_cfg.depth = 16; + jetty_cfg.jfs_cfg.trans_mode = URMA_TM_RM; + jetty_cfg.jfs_cfg.priority = URMA_MAX_PRIORITY; + jetty_cfg.jfs_cfg.max_sge = 1; + jetty_cfg.jfs_cfg.rnr_retry = URMA_TYPICAL_RNR_RETRY; + jetty_cfg.jfs_cfg.err_timeout = URMA_TYPICAL_ERR_TIMEOUT; + jetty_cfg.jfs_cfg.jfc = jfc; + jetty_cfg.shared.jfr = jfr; + jetty_cfg.shared.jfc = jfc; + urma_jetty_t* jetty = urma_create_jetty(ctx, &jetty_cfg); + ASSERT_NE(nullptr, jetty); + + urma_jfs_wr_t wr{}; + memset(&wr, 0, sizeof(wr)); + wr.opcode = URMA_OPC_SEND; + wr.flag.bs.complete_enable = 1; + wr.user_ctx = 0xABCD; + wr.next = nullptr; + urma_jfs_wr_t* bad = nullptr; + EXPECT_EQ(URMA_EINVAL, urma_post_jetty_send_wr(jetty, &wr, &bad)); + EXPECT_EQ(&wr, bad); + + urma_cr_t crs[4]; + EXPECT_EQ(0, urma_poll_jfc(jfc, 4, crs)); + + urma_delete_jetty(jetty); + urma_delete_jfr(jfr); + urma_delete_jfc(jfc); + urma_delete_jfce(jfce); + urma_delete_context(ctx); + urma_free_device_list(devices); +} + +TEST_F(UrmaMockTest, + paired_send_is_bidirectional_and_separates_immediate_credit) { + int num_devices = 0; + urma_device_t** devices = urma_get_device_list(&num_devices); + ASSERT_NE(nullptr, devices); + ASSERT_GT(num_devices, 0); + urma_context_t* ctx = urma_create_context(devices[0], 0); + ASSERT_NE(nullptr, ctx); + + urma_jfce_t* sender_jfce = urma_create_jfce(ctx); + urma_jfce_t* receiver_jfce = urma_create_jfce(ctx); + ASSERT_NE(nullptr, sender_jfce); + ASSERT_NE(nullptr, receiver_jfce); + urma_jfc_cfg_t sender_jfc_cfg{}; + sender_jfc_cfg.depth = 8; + sender_jfc_cfg.jfce = sender_jfce; + urma_jfc_t* sender_jfc = urma_create_jfc(ctx, &sender_jfc_cfg); + ASSERT_NE(nullptr, sender_jfc); + urma_jfc_cfg_t receiver_jfc_cfg{}; + receiver_jfc_cfg.depth = 8; + receiver_jfc_cfg.jfce = receiver_jfce; + urma_jfc_t* receiver_jfc = urma_create_jfc(ctx, &receiver_jfc_cfg); + ASSERT_NE(nullptr, receiver_jfc); + + urma_jfr_cfg_t sender_jfr_cfg{}; + sender_jfr_cfg.depth = 4; + sender_jfr_cfg.trans_mode = URMA_TM_RM; + sender_jfr_cfg.max_sge = 1; + sender_jfr_cfg.jfc = sender_jfc; + urma_jfr_t* sender_jfr = urma_create_jfr(ctx, &sender_jfr_cfg); + ASSERT_NE(nullptr, sender_jfr); + urma_jfr_cfg_t receiver_jfr_cfg = sender_jfr_cfg; + receiver_jfr_cfg.jfc = receiver_jfc; + urma_jfr_t* receiver_jfr = urma_create_jfr(ctx, &receiver_jfr_cfg); + ASSERT_NE(nullptr, receiver_jfr); + + auto create_jetty = [&](urma_jfc_t* jfc, urma_jfr_t* jfr) { + urma_jetty_cfg_t cfg{}; + cfg.flag.bs.share_jfr = 1; + cfg.jfs_cfg.depth = 4; + cfg.jfs_cfg.trans_mode = URMA_TM_RM; + cfg.jfs_cfg.max_sge = 1; + cfg.jfs_cfg.jfc = jfc; + cfg.shared.jfr = jfr; + cfg.shared.jfc = jfc; + return urma_create_jetty(ctx, &cfg); + }; + urma_jetty_t* sender = create_jetty(sender_jfc, sender_jfr); + urma_jetty_t* receiver = create_jetty(receiver_jfc, receiver_jfr); + ASSERT_NE(nullptr, sender); + ASSERT_NE(nullptr, receiver); + + urma_rjetty_t remote{}; + remote.jetty_id = receiver->jetty_id; + remote.trans_mode = URMA_TM_RM; + remote.type = URMA_JETTY; + remote.tp_type = URMA_CTP; + urma_token_t token{}; + urma_target_jetty_t* target = + urma_import_jetty(ctx, &remote, &token); + ASSERT_NE(nullptr, target); + + char recv_buf[64]{}; + urma_sge_t recv_sge{ + reinterpret_cast(recv_buf), sizeof(recv_buf), nullptr, + nullptr}; + urma_sg_t recv_sg{&recv_sge, 1}; + urma_jfr_wr_t recv_wr{recv_sg, 99, nullptr}; + char credit_recv_buf[1]{}; + urma_sge_t credit_recv_sge{ + reinterpret_cast(credit_recv_buf), + sizeof(credit_recv_buf), nullptr, nullptr}; + urma_sg_t credit_recv_sg{&credit_recv_sge, 1}; + urma_jfr_wr_t credit_recv_wr{credit_recv_sg, 100, nullptr}; + recv_wr.next = &credit_recv_wr; + urma_jfr_wr_t* bad_recv = nullptr; + ASSERT_EQ(URMA_SUCCESS, + urma_post_jfr_wr(receiver_jfr, &recv_wr, &bad_recv)); + + const char payload[] = "urma-payload"; + urma_sge_t send_sge{ + reinterpret_cast(payload), sizeof(payload), nullptr, + nullptr}; + urma_sg_t send_sg{&send_sge, 1}; + urma_jfs_wr_t send_wr{}; + send_wr.opcode = URMA_OPC_SEND; + send_wr.flag.bs.complete_enable = 1; + send_wr.tjetty = target; + send_wr.user_ctx = 7; + send_wr.send.src = send_sg; + urma_jfs_wr_t credit_wr{}; + credit_wr.opcode = URMA_OPC_SEND_IMM; + credit_wr.flag.bs.complete_enable = 1; + credit_wr.tjetty = target; + credit_wr.user_ctx = 8; + credit_wr.send.imm_data = 13; + send_wr.next = &credit_wr; + urma_jfs_wr_t* bad_send = nullptr; + ASSERT_EQ(URMA_SUCCESS, + urma_post_jetty_send_wr(sender, &send_wr, &bad_send)); + + urma_cr_t sender_cr[2]{}; + ASSERT_EQ(2, urma_poll_jfc(sender_jfc, 2, sender_cr)); + EXPECT_EQ(0, sender_cr[0].flag.bs.s_r); + EXPECT_EQ(7u, sender_cr[0].user_ctx); + EXPECT_EQ(0, sender_cr[1].flag.bs.s_r); + EXPECT_EQ(8u, sender_cr[1].user_ctx); + + urma_cr_t receiver_cr[2]{}; + ASSERT_EQ(2, urma_poll_jfc(receiver_jfc, 2, receiver_cr)); + EXPECT_EQ(1, receiver_cr[0].flag.bs.s_r); + EXPECT_EQ(URMA_CR_OPC_SEND, receiver_cr[0].opcode); + EXPECT_EQ(0u, receiver_cr[0].imm_data); + EXPECT_EQ(sizeof(payload), receiver_cr[0].completion_len); + EXPECT_EQ(0, memcmp(payload, recv_buf, sizeof(payload))); + EXPECT_EQ(1, receiver_cr[1].flag.bs.s_r); + EXPECT_EQ(URMA_CR_OPC_SEND_WITH_IMM, receiver_cr[1].opcode); + EXPECT_EQ(13u, receiver_cr[1].imm_data); + EXPECT_EQ(0u, receiver_cr[1].completion_len); + + // Exercise the response direction as well. Production posts all receive + // WRs through the shared JFR. + urma_rjetty_t sender_remote = remote; + sender_remote.jetty_id = sender->jetty_id; + urma_target_jetty_t* sender_target = + urma_import_jetty(ctx, &sender_remote, &token); + ASSERT_NE(nullptr, sender_target); + char response_buf[64]{}; + urma_sge_t response_recv_sge{ + reinterpret_cast(response_buf), sizeof(response_buf), + nullptr, nullptr}; + urma_sg_t response_recv_sg{&response_recv_sge, 1}; + urma_jfr_wr_t response_recv_wr{response_recv_sg, 101, nullptr}; + ASSERT_EQ(URMA_SUCCESS, + urma_post_jfr_wr(sender_jfr, &response_recv_wr, &bad_recv)); + + const char response[] = "urma-response"; + urma_sge_t response_send_sge{ + reinterpret_cast(response), sizeof(response), nullptr, + nullptr}; + urma_sg_t response_send_sg{&response_send_sge, 1}; + urma_jfs_wr_t response_send_wr{}; + response_send_wr.opcode = URMA_OPC_SEND; + response_send_wr.flag.bs.complete_enable = 1; + response_send_wr.tjetty = sender_target; + response_send_wr.user_ctx = 9; + response_send_wr.send.src = response_send_sg; + ASSERT_EQ(URMA_SUCCESS, + urma_post_jetty_send_wr(receiver, &response_send_wr, &bad_send)); + + urma_cr_t response_send_cr{}; + ASSERT_EQ(1, urma_poll_jfc(receiver_jfc, 1, &response_send_cr)); + EXPECT_EQ(0, response_send_cr.flag.bs.s_r); + EXPECT_EQ(9u, response_send_cr.user_ctx); + + urma_cr_t response_recv_cr{}; + ASSERT_EQ(1, urma_poll_jfc(sender_jfc, 1, &response_recv_cr)); + EXPECT_EQ(1, response_recv_cr.flag.bs.s_r); + EXPECT_EQ(URMA_CR_OPC_SEND, response_recv_cr.opcode); + EXPECT_EQ(sizeof(response), response_recv_cr.completion_len); + EXPECT_EQ(0, memcmp(response, response_buf, sizeof(response))); + + urma_unimport_jetty(sender_target); + urma_unimport_jetty(target); + urma_delete_jetty(receiver); + urma_delete_jetty(sender); + urma_delete_jfr(receiver_jfr); + urma_delete_jfr(sender_jfr); + urma_delete_jfc(receiver_jfc); + urma_delete_jfc(sender_jfc); + urma_delete_jfce(receiver_jfce); + urma_delete_jfce(sender_jfce); + urma_delete_context(ctx); + urma_free_device_list(devices); +} + +#else // BRPC_WITH_URMA + +// When URMA is not compiled in, the test file is a no-op so the build stays +// clean. The brpc_urma_unittest target still links (against brpc-shared which +// provides the empty stubs). + +#endif // BRPC_WITH_URMA + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + gflags::ParseCommandLineFlags(&argc, &argv, true); +#if BRPC_WITH_URMA + urma::g_skip_urma_init = true; + urma::g_urma_available.store(true, butil::memory_order_relaxed); +#endif + return RUN_ALL_TESTS(); +} diff --git a/test/bthread_priority_queue_unittest.cpp b/test/bthread_priority_queue_unittest.cpp index d6c9e43a98..42f6dd85db 100644 --- a/test/bthread_priority_queue_unittest.cpp +++ b/test/bthread_priority_queue_unittest.cpp @@ -138,8 +138,9 @@ TEST_F(PriorityQueueTest, start_foreground_priority_to_run) { struct EDSimArg { int n_tasks; + int error_code; }; - EDSimArg ed_arg{N}; + EDSimArg ed_arg{N, 0}; auto ed_fn = [](void* arg) -> void* { EDSimArg* ea = static_cast(arg); @@ -147,10 +148,21 @@ TEST_F(PriorityQueueTest, start_foreground_priority_to_run) { bthread::TaskGroup::address_meta(bthread_self()); meta->priority_index = 0; + std::vector children; + children.reserve(ea->n_tasks); for (int i = 0; i < ea->n_tasks; ++i) { TaskArg* ta = new TaskArg{i}; bthread_t child; - bthread_start_urgent(&child, NULL, priority_task_fn, ta); + int rc = bthread_start_urgent(&child, NULL, priority_task_fn, ta); + if (rc != 0) { + delete ta; + ea->error_code = rc; + break; + } + children.push_back(child); + } + for (auto child : children) { + bthread_join(child, NULL); } return NULL; }; @@ -161,7 +173,8 @@ TEST_F(PriorityQueueTest, start_foreground_priority_to_run) { bthread_t ed_tid; ASSERT_EQ(0, bthread_start_background(&ed_tid, &priority_attr, ed_fn, &ed_arg)); - bthread_join(ed_tid, NULL); + ASSERT_EQ(0, bthread_join(ed_tid, NULL)); + ASSERT_EQ(0, ed_arg.error_code); ASSERT_EQ(N, g_priority_count.load()); std::lock_guard lk(g_tid_mutex); @@ -180,6 +193,7 @@ TEST_F(PriorityQueueTest, multiple_eds_concurrent_preempt) { int ed_index; int n_children; std::atomic* resume_count; + int error_code; }; auto ed_fn = [](void* arg) -> void* { @@ -194,7 +208,13 @@ TEST_F(PriorityQueueTest, multiple_eds_concurrent_preempt) { int id = ea->ed_index * ea->n_children + i; TaskArg* ta = new TaskArg{id}; bthread_t child; - bthread_start_urgent(&child, NULL, priority_task_fn, ta); + const int rc = bthread_start_urgent( + &child, NULL, priority_task_fn, ta); + if (rc != 0) { + delete ta; + ea->error_code = rc; + break; + } children.push_back(child); ea->resume_count->fetch_add(1, std::memory_order_relaxed); } @@ -210,13 +230,14 @@ TEST_F(PriorityQueueTest, multiple_eds_concurrent_preempt) { std::vector ed_args(NUM_EDS); std::vector ed_tids(NUM_EDS); for (int i = 0; i < NUM_EDS; ++i) { - ed_args[i] = {i, TASKS_PER_ED, &resume_count}; + ed_args[i] = {i, TASKS_PER_ED, &resume_count, 0}; ASSERT_EQ(0, bthread_start_background(&ed_tids[i], &priority_attr, ed_fn, &ed_args[i])); } for (int i = 0; i < NUM_EDS; ++i) { - bthread_join(ed_tids[i], NULL); + ASSERT_EQ(0, bthread_join(ed_tids[i], NULL)); + ASSERT_EQ(0, ed_args[i].error_code); } ASSERT_EQ(TOTAL, g_priority_count.load());