diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index e15d81db4f..2112ce31e7 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -85,6 +85,49 @@ jobs: -DWITH_ASAN=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. make -j ${{env.proc_num}} && make clean + compile-and-test-with-urma: + # WITH_URMA=ON is not covered by the jobs above: none of them set the flag, + # so src/brpc/urma/*.cpp and brpc_urma_unittest.cpp are never compiled. + # liburma is absent on the runner, so CMake falls back to the link-time + # mock (src/brpc/urma/mock_urma.cpp) and no URMA hardware is needed. + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + - uses: ./.github/actions/install-essential-dependencies + + # test/CMakeLists.txt does find_package(Gperftools) and links + # ${GPERFTOOLS_LIBRARIES} into every unittest target. The make-based + # unittest jobs never hit this, but the CMake generate step fails with + # NOTFOUND without it. + - name: install gperftools + run: sudo apt-get install -y libgoogle-perftools-dev + + # DOWNLOAD_URMA_HEADERS fetches from atomgit.com, which is slow and often + # unreachable from CI. openEuler mirrors the same repo (identical tags and + # layout) on GitHub, so clone that and hand it to CMake via URMA_ROOT. + - name: fetch UMDK headers + run: | + git clone --depth 1 --branch v26.06.0_CAM \ + https://github.com/openeuler-mirror/umdk.git $GITHUB_WORKSPACE/umdk + test -f $GITHUB_WORKSPACE/umdk/src/urma/lib/urma/core/include/urma_api.h + + - name: gcc with URMA + env: + URMA_ROOT: ${{ github.workspace }}/umdk + run: | + export CC=gcc && export CXX=g++ + mkdir urma_build && cd urma_build + cmake -DWITH_URMA=ON \ + -DBUILD_UNIT_TESTS=ON -DBUILD_BRPC_TOOLS=OFF \ + -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. + # brpc_urma_unittest links brpc-shared-debug, built from + # SOURCES_DEBUG_LIB, which contains every urma_*.cpp plus + # mock_urma.cpp -- so this target compiles all the URMA code. + make -j ${{env.proc_num}} brpc_urma_unittest + + - name: run brpc_urma_unittest + run: cd urma_build/test && ./brpc_urma_unittest + gcc-compile-with-make-protobuf: runs-on: ubuntu-22.04 steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index 10e9052dcb..a2838bceaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,9 @@ 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) @@ -371,10 +374,17 @@ if(WITH_URMA) if(URMA_LIB) message(STATUS "Found URMA library: ${URMA_LIB}") set(URMA_USE_MOCK 0) - else() + elseif(WITH_URMA_MOCK) message(STATUS - "liburma not found; building with the URMA link-time mock") + "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() diff --git a/MODULE.bazel b/MODULE.bazel index 391b8c2784..21a0684422 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -62,4 +62,12 @@ git_repository( 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/WORKSPACE b/WORKSPACE index 22fc411b32..fcb1e97533 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -284,6 +284,14 @@ git_repository( 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 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/config_brpc.sh b/config_brpc.sh index 2c1394e840..edfa989c49 100755 --- a/config_brpc.sh +++ b/config_brpc.sh @@ -54,11 +54,12 @@ else LDD=ldd fi -TEMP=`getopt -o v: --long headers:,libs:,cc:,cxx:,with-glog,with-thrift,with-rdma,with-urma,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 @@ -92,6 +93,7 @@ while true; do --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 ;; @@ -554,9 +556,12 @@ if [ $WITH_URMA != 0 ]; then append_to_output_libs "$URMA_LIB" append_to_output "DYNAMIC_LINKINGS+=-lurma" append_to_output "URMA_USE_MOCK=0" - else + elif [ $WITH_URMA_MOCK != 0 ]; then append_to_output "URMA_USE_MOCK=1" - print_info "liburma not found; using URMA link-time mock" + 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 diff --git a/docs/cn/bazel_support.md b/docs/cn/bazel_support.md index 0ff86119cb..190168a901 100644 --- a/docs/cn/bazel_support.md +++ b/docs/cn/bazel_support.md @@ -1,20 +1,99 @@ -## bRPC 作为Bazel第三方依赖 -1. bRPC 依赖于一些开源库, 但这些库并没有提供bazel支持, 所以需要你手动将一部分依赖加入到你的构建项目中. -2. 将 /example/build_with_bazel/*.BUILD 和 brpc_workspace.bzl 该文件移动到你的项目根目录下, 将 -```c++ - load("@//:brpc_workspace.bzl", "brpc_workspace") - brpc_workspace(); +## bRPC 作为 Bazel 第三方依赖 + +推荐在 Bazel 项目中使用 bzlmod(`MODULE.bazel`)依赖本地 bRPC 源码。 +`example/build_with_bazel_module` 中有一个包含 server 和 client 的可运行示例: + +```shell +$ cd example/build_with_bazel_module +$ bazel run //:echo_c++_server & +$ bazel run //:echo_c++_client +``` + +先在你的 `.bazelrc` 中添加 bRPC 使用的 registry: + +```shell +common --registry=https://bcr.bazel.build +common --registry=https://baidu.github.io/babylon/registry +common --registry=https://raw.githubusercontent.com/apache/brpc/master/registry ``` -内容添加到你的WORKSPACE中. -3. 链接请使用 - ```c++ - ... - deps = [ +然后在 `MODULE.bazel` 中添加 bRPC,并指向本地 bRPC 源码: + +```python +module( + name = "my_brpc_app", + version = "0.1.0", +) + +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 = "/path/to/brpc", +) + +single_version_override( + module_name = "leveldb", + registry = "https://raw.githubusercontent.com/secretflow/bazel-registry/main", +) + +single_version_override( + module_name = "openssl", + version = "3.3.2.bcr.1", + registry = "https://raw.githubusercontent.com/secretflow/bazel-registry/main", +) +``` + +`bazel_dep` 用来声明模块名和仓库映射,`local_path_override` 让 Bazel 使用本地源码,而不是从 registry 解析 bRPC。 + +bzlmod 不会传递依赖模块中的 override。把 bRPC 当依赖时,需要在自己项目的根 +`MODULE.bazel` 里重复上面的 `single_version_override`;它们在 aarch64 上是必需的,否则 leveldb toolchain 解析会失败。 + +之后在目标中链接 bRPC: + +```python +cc_binary( + name = "server", + srcs = ["server.cpp"], + deps = [ + "@apache_brpc//:brpc", + ], +) +``` + +如果服务使用 protobuf,可以从 bRPC 加载 `brpc_proto_library`: + +```python +load("@apache_brpc//bazel/tools:brpc_proto_library.bzl", "brpc_proto_library") + +brpc_proto_library( + name = "cc_echo_proto", + srcs = ["echo.proto"], +) +``` + +## 旧版 WORKSPACE 用法 + +仍在使用 `WORKSPACE` 的项目可以参考 `example/build_with_bazel`。 + +1. 将 `example/build_with_bazel/*.BUILD` 和 + `example/build_with_bazel/brpc_workspace.bzl` 移动到你的项目根目录下。 +2. 在 `WORKSPACE` 中添加: + +```python +load("@//:brpc_workspace.bzl", "brpc_workspace") + +brpc_workspace() +``` + +3. 在目标中链接 `apache_brpc`: + +```python +deps = [ "@apache_brpc//:bthread", "@apache_brpc//:brpc", "@apache_brpc//:butil", "@apache_brpc//:bvar", - ] - ... - ``` +] +``` diff --git a/docs/cn/urma.md b/docs/cn/urma.md index a9be634ec7..b1c048fae1 100644 --- a/docs/cn/urma.md +++ b/docs/cn/urma.md @@ -20,7 +20,7 @@ WR。完成事件既可由 JFC 忙轮询获取,也可通过 JFCE 事件 fd 获 ### CMake 编译 ```bash -# 带 URMA 支持编译 brpc +# 带 URMA 支持编译 brpc(需要 liburma;无硬件/CI 场景见下方 mock 说明) cmake -B build -DWITH_URMA=ON make -C build -j$(nproc) @@ -30,11 +30,37 @@ 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` 时使用 -真实硬件数据通路,否则链接 brpc 的 mock,使 URMA 代码和测试仍可在无硬件 -环境编译。 +真实硬件数据通路;否则默认直接报错终止构建,避免静默回退到 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。 ## 使用 diff --git a/docs/en/bazel_support.md b/docs/en/bazel_support.md index 607cf9c462..3dba89e51e 100644 --- a/docs/en/bazel_support.md +++ b/docs/en/bazel_support.md @@ -1,20 +1,104 @@ ## bRPC as a Bazel third-party dependency -1. bRPC relies on a number of open source libraries that do not provide bazel support, so you will need to manually add some of these dependencies to your build project. -2. Move the BUILD file /example/build_with_bazel/*.BUILD and brpc_workspace.bzl to the root of your project, and add the contents of -```c++ - load("@//:brpc_workspace.bzl", "brpc_workspace") - brpc_workspace(); + +The recommended way to depend on a local bRPC checkout from a Bazel project is +to use bzlmod (`MODULE.bazel`). See `example/build_with_bazel_module` for a +runnable example with both a server and a client: + +```shell +$ cd example/build_with_bazel_module +$ bazel run //:echo_c++_server & +$ bazel run //:echo_c++_client +``` + +Add the registries used by bRPC to your `.bazelrc`: + +```shell +common --registry=https://bcr.bazel.build +common --registry=https://baidu.github.io/babylon/registry +common --registry=https://raw.githubusercontent.com/apache/brpc/master/registry ``` -to your WORKSPACE -3. link apache_brpc like: - ```c++ - ... - deps = [ +Add bRPC to your `MODULE.bazel`, and point it to your local bRPC checkout: + +```python +module( + name = "my_brpc_app", + version = "0.1.0", +) + +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 = "/path/to/brpc", +) + +single_version_override( + module_name = "leveldb", + registry = "https://raw.githubusercontent.com/secretflow/bazel-registry/main", +) + +single_version_override( + module_name = "openssl", + version = "3.3.2.bcr.1", + registry = "https://raw.githubusercontent.com/secretflow/bazel-registry/main", +) +``` + +The `bazel_dep` keeps the module name and repository mapping, while +`local_path_override` makes Bazel use the local checkout instead of resolving +bRPC from a registry. + +bzlmod does not propagate overrides from dependency modules. When using bRPC as +a dependency, repeat the `single_version_override` entries above in your root +`MODULE.bazel`; they are required on aarch64 because leveldb toolchain +resolution otherwise fails. + +Then link bRPC from your targets: + +```python +cc_binary( + name = "server", + srcs = ["server.cpp"], + deps = [ + "@apache_brpc//:brpc", + ], +) +``` + +If your service uses protobuf, load `brpc_proto_library` from bRPC: + +```python +load("@apache_brpc//bazel/tools:brpc_proto_library.bzl", "brpc_proto_library") + +brpc_proto_library( + name = "cc_echo_proto", + srcs = ["echo.proto"], +) +``` + +## Legacy WORKSPACE usage + +For projects that still use `WORKSPACE`, see `example/build_with_bazel`. + +1. Move `example/build_with_bazel/*.BUILD` and + `example/build_with_bazel/brpc_workspace.bzl` to the root of your project. +2. Add the following to your `WORKSPACE`: + +```python +load("@//:brpc_workspace.bzl", "brpc_workspace") + +brpc_workspace() +``` + +3. Link `apache_brpc` from your targets: + +```python +deps = [ "@apache_brpc//:bthread", "@apache_brpc//:brpc", "@apache_brpc//:butil", "@apache_brpc//:bvar", - ] - ... - ``` +] +``` diff --git a/docs/en/urma.md b/docs/en/urma.md index 964f648bd2..8556fbdf93 100644 --- a/docs/en/urma.md +++ b/docs/en/urma.md @@ -20,7 +20,7 @@ from a JFC either by busy polling or through a JFCE event fd. ### Build with CMake ```bash -# Build brpc with URMA support +# Build brpc with URMA support (requires liburma; see below for CI/mock builds) cmake -B build -DWITH_URMA=ON make -C build -j$(nproc) @@ -30,13 +30,42 @@ 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, -brpc uses its link-time mock so URMA code and tests can still be built without -hardware. +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 diff --git a/example/build_with_bazel_module/.bazelrc b/example/build_with_bazel_module/.bazelrc new file mode 100644 index 0000000000..f31156f431 --- /dev/null +++ b/example/build_with_bazel_module/.bazelrc @@ -0,0 +1,60 @@ +# 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..340a1ba014 --- /dev/null +++ b/example/build_with_bazel_module/BUILD.bazel @@ -0,0 +1,43 @@ +# 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", + ], +) + +cc_binary( + name = "echo_c++_client", + srcs = [ + "client.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..44e6f30c17 --- /dev/null +++ b/example/build_with_bazel_module/MODULE.bazel @@ -0,0 +1,41 @@ +# 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 = "../..", +) + +single_version_override( + module_name = "leveldb", + registry = "https://raw.githubusercontent.com/secretflow/bazel-registry/main", +) + +single_version_override( + module_name = "openssl", + version = "3.3.2.bcr.1", + registry = "https://raw.githubusercontent.com/secretflow/bazel-registry/main", +) diff --git a/example/build_with_bazel_module/client.cpp b/example/build_with_bazel_module/client.cpp new file mode 100644 index 0000000000..2ce335073b --- /dev/null +++ b/example/build_with_bazel_module/client.cpp @@ -0,0 +1,89 @@ +// 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 client sending requests to server every 1 second. + +#include +#include +#include +#include "echo.pb.h" + +DEFINE_string(attachment, "", "Carry this along with requests"); +DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto"); +DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short"); +DEFINE_string(server, "0.0.0.0:8002", "IP Address of server"); +DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds"); +DEFINE_int32(max_retry, 3, "Max retries(not including the first RPC)"); +DEFINE_int32(interval_ms, 1000, "Milliseconds between consecutive requests"); + +int main(int argc, char* argv[]) { + // Parse gflags. We recommend you to use gflags as well. + GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true); + + // A Channel represents a communication line to a Server. Notice that + // Channel is thread-safe and can be shared by all threads in your program. + brpc::Channel channel; + + // Initialize the channel, NULL means using default options. + brpc::ChannelOptions options; + options.protocol = FLAGS_protocol; + options.connection_type = FLAGS_connection_type; + options.timeout_ms = FLAGS_timeout_ms/*milliseconds*/; + options.max_retry = FLAGS_max_retry; + if (channel.Init(FLAGS_server.c_str(), &options) != 0) { + LOG(ERROR) << "Fail to initialize channel"; + return -1; + } + + // Normally, you should not call a Channel directly, but instead construct + // a stub Service wrapping it. stub can be shared by all threads as well. + example::EchoService_Stub stub(&channel); + + // Send a request and wait for the response every 1 second. + int log_id = 0; + while (!brpc::IsAskedToQuit()) { + // We will receive response synchronously, safe to put variables + // on stack. + example::EchoRequest request; + example::EchoResponse response; + brpc::Controller cntl; + + request.set_message("hello world"); + + cntl.set_log_id(log_id ++); // set by user + // Set attachment which is wired to network directly instead of + // being serialized into protobuf messages. + cntl.request_attachment().append(FLAGS_attachment); + + // Because `done'(last parameter) is NULL, this function waits until + // the response comes back or error occurs(including timedout). + stub.Echo(&cntl, &request, &response, NULL); + if (!cntl.Failed()) { + LOG(INFO) << "Received response from " << cntl.remote_side() + << " to " << cntl.local_side() + << ": " << response.message() << " (attached=" + << cntl.response_attachment() << ")" + << " latency=" << cntl.latency_us() << "us"; + } else { + LOG(WARNING) << cntl.ErrorText(); + } + usleep(FLAGS_interval_ms * 1000L); + } + + LOG(INFO) << "EchoClient is going to quit"; + return 0; +} 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..6de9c033e0 --- /dev/null +++ b/example/build_with_bazel_module/server.cpp @@ -0,0 +1,97 @@ +// 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.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 6b2c7850ff..e57cda196a 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -86,11 +86,12 @@ macro(brpc_example_find_common_deps out_libs) ) 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) @@ -123,6 +124,11 @@ 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} @@ -132,6 +138,7 @@ macro(brpc_example_find_common_deps out_libs) ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${THRIFT_LIB} + ${_brpc_example_urma_lib} dl ) diff --git a/example/urma_performance/CMakeLists.txt b/example/urma_performance/CMakeLists.txt index 154970fbd3..eae472fe90 100644 --- a/example/urma_performance/CMakeLists.txt +++ b/example/urma_performance/CMakeLists.txt @@ -26,13 +26,7 @@ brpc_example_find_common_deps(DYNAMIC_LIB) protobuf_generate_cpp(PROTO_SRC PROTO_HEADER test.proto) set(BRPC_EXAMPLE_WITH_URMA ON) -find_library(URMA_LIB NAMES urma) -if(URMA_LIB) - list(APPEND DYNAMIC_LIB ${URMA_LIB}) -else() - message(STATUS - "liburma not found; using the URMA implementation linked into brpc") -endif() + add_executable(urma_performance_client client.cpp ${PROTO_SRC} ${PROTO_HEADER}) brpc_example_configure_target(urma_performance_client) diff --git a/src/brpc/urma/mock_urma.cpp b/src/brpc/urma/mock_urma.cpp index 266c08b19a..b6b7e29733 100644 --- a/src/brpc/urma/mock_urma.cpp +++ b/src/brpc/urma/mock_urma.cpp @@ -62,7 +62,13 @@ struct PendingRecv { uint64_t user_ctx; }; -std::shared_mutex g_rw_mutex; +// brpc is built with -std=c++14 whenever protobuf < 4.21 (see BRPC_CXX_STANDARD +// in CMakeLists.txt and CXXFLAGS in config_brpc.sh), which is the case on the +// CI runners. std::shared_mutex is C++17-only; std::shared_timed_mutex is the +// C++14 equivalent and has the same locking semantics here. +typedef std::shared_timed_mutex MockSharedMutex; + +MockSharedMutex g_rw_mutex; bool initialized = false; std::vector device_list; std::map context_map; @@ -119,7 +125,7 @@ urma_eid_info_t mock_eid_info = { extern "C" { urma_status_t urma_init(urma_init_attr_t *init_attr) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (initialized) { return URMA_EEXIST; } @@ -128,7 +134,7 @@ urma_status_t urma_init(urma_init_attr_t *init_attr) { } urma_status_t urma_uninit(void) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); initialized = false; for (auto device : device_list) { delete device; @@ -153,7 +159,7 @@ urma_status_t urma_uninit(void) { urma_device_t **urma_get_device_list(int *num_devices) { { - std::shared_lock lock(g_rw_mutex); + std::shared_lock lock(g_rw_mutex); if (!initialized) { *num_devices = 0; return nullptr; @@ -168,7 +174,7 @@ urma_device_t **urma_get_device_list(int *num_devices) { } } { - std::unique_lock write_lock(g_rw_mutex); + std::unique_lock write_lock(g_rw_mutex); if (!initialized) { *num_devices = 0; return nullptr; @@ -193,7 +199,7 @@ urma_device_t **urma_get_device_list(int *num_devices) { urma_device_t *urma_get_device_by_name(char *dev_name) { { - std::shared_lock lock(g_rw_mutex); + std::shared_lock lock(g_rw_mutex); if (!initialized) { return nullptr; } @@ -207,7 +213,7 @@ urma_device_t *urma_get_device_by_name(char *dev_name) { } } { - std::unique_lock write_lock(g_rw_mutex); + std::unique_lock write_lock(g_rw_mutex); if (!initialized) { return nullptr; } @@ -265,7 +271,7 @@ void urma_free_eid_list(urma_eid_info_t *eid_list) { } urma_context_t *urma_create_context(urma_device_t *device, uint32_t eid_index) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!device) { return nullptr; } @@ -277,7 +283,7 @@ urma_context_t *urma_create_context(urma_device_t *device, uint32_t eid_index) { } urma_status_t urma_delete_context(urma_context_t *ctx) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!ctx || context_map.find(ctx) == context_map.end()) { return URMA_EINVAL; } @@ -287,7 +293,7 @@ urma_status_t urma_delete_context(urma_context_t *ctx) { } urma_jfce_t *urma_create_jfce(urma_context_t *ctx) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!ctx || context_map.find(ctx) == context_map.end()) { return nullptr; } @@ -305,7 +311,7 @@ urma_jfce_t *urma_create_jfce(urma_context_t *ctx) { } urma_status_t urma_delete_jfce(urma_jfce_t *jfce) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!jfce || jfce_map.find(jfce) == jfce_map.end()) { return URMA_EINVAL; } @@ -316,7 +322,7 @@ urma_status_t urma_delete_jfce(urma_jfce_t *jfce) { } urma_jfc_t *urma_create_jfc(urma_context_t *ctx, urma_jfc_cfg_t *cfg) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { return nullptr; } @@ -334,7 +340,7 @@ urma_jfc_t *urma_create_jfc(urma_context_t *ctx, urma_jfc_cfg_t *cfg) { } urma_status_t urma_delete_jfc(urma_jfc_t *jfc) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!jfc || jfc_state_map.find(jfc) == jfc_state_map.end()) { return URMA_EINVAL; } @@ -345,7 +351,7 @@ urma_status_t urma_delete_jfc(urma_jfc_t *jfc) { } urma_jfr_t *urma_create_jfr(urma_context_t *ctx, urma_jfr_cfg_t *cfg) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { return nullptr; } @@ -361,7 +367,7 @@ urma_jfr_t *urma_create_jfr(urma_context_t *ctx, urma_jfr_cfg_t *cfg) { } urma_status_t urma_delete_jfr(urma_jfr_t *jfr) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!jfr || jfr_map.find(jfr) == jfr_map.end()) { return URMA_EINVAL; } @@ -373,7 +379,7 @@ urma_status_t urma_delete_jfr(urma_jfr_t *jfr) { } urma_target_seg_t *urma_register_seg(urma_context_t *ctx, urma_seg_cfg_t *cfg) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { return nullptr; } @@ -389,7 +395,7 @@ urma_target_seg_t *urma_register_seg(urma_context_t *ctx, urma_seg_cfg_t *cfg) { } urma_status_t urma_unregister_seg(urma_target_seg_t *seg) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!seg || seg_map.find(seg) == seg_map.end()) { return URMA_EINVAL; } @@ -401,7 +407,7 @@ urma_status_t urma_unregister_seg(urma_target_seg_t *seg) { 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); + std::unique_lock lock(g_rw_mutex); if (!ctx || !seg || !token_value || context_map.find(ctx) == context_map.end()) { return nullptr; @@ -414,7 +420,7 @@ urma_target_seg_t *urma_import_seg(urma_context_t *ctx, urma_seg_t *seg, } urma_status_t urma_unimport_seg(urma_target_seg_t *tseg) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!tseg || seg_map.find(tseg) == seg_map.end()) { return URMA_EINVAL; } @@ -428,7 +434,7 @@ urma_status_t urma_get_async_event(urma_context_t *ctx, if (!ctx || !event) { return URMA_EINVAL; } - std::shared_lock lock(g_rw_mutex); + std::shared_lock lock(g_rw_mutex); if (context_map.find(ctx) == context_map.end()) { return URMA_EINVAL; } @@ -438,7 +444,7 @@ urma_status_t urma_get_async_event(urma_context_t *ctx, 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); + std::unique_lock lock(g_rw_mutex); if (!ctx || !cfg || context_map.find(ctx) == context_map.end()) { return nullptr; } @@ -455,7 +461,7 @@ urma_jetty_t *urma_create_jetty(urma_context_t *ctx, urma_jetty_cfg_t *cfg) { } urma_status_t urma_delete_jetty(urma_jetty_t *jetty) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!jetty || jetty_map.find(jetty) == jetty_map.end()) { return URMA_EINVAL; } @@ -466,7 +472,7 @@ urma_status_t urma_delete_jetty(urma_jetty_t *jetty) { } urma_status_t urma_unbind_jetty(urma_jetty_t *jetty) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!jetty || jetty_map.find(jetty) == jetty_map.end()) { return URMA_EINVAL; } @@ -477,7 +483,7 @@ urma_status_t urma_unbind_jetty(urma_jetty_t *jetty) { 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); + std::unique_lock lock(g_rw_mutex); if (!ctx || !rjetty || !token_value || context_map.find(ctx) == context_map.end()) { return nullptr; @@ -490,7 +496,7 @@ urma_target_jetty_t *urma_import_jetty(urma_context_t *ctx, } urma_status_t urma_unimport_jetty(urma_target_jetty_t *tjetty) { - std::unique_lock lock(g_rw_mutex); + std::unique_lock lock(g_rw_mutex); if (!tjetty || target_jetty_map.find(tjetty) == target_jetty_map.end()) { return URMA_EINVAL; } @@ -501,7 +507,7 @@ urma_status_t urma_unimport_jetty(urma_target_jetty_t *tjetty) { urma_status_t urma_bind_jetty(urma_jetty_t *jetty, urma_target_jetty_t *tjetty) { - std::unique_lock lock(g_rw_mutex); + 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; @@ -511,7 +517,7 @@ urma_status_t urma_bind_jetty(urma_jetty_t *jetty, } urma_status_t urma_modify_jetty(urma_jetty_t *jetty, urma_jetty_attr_t *attr) { - std::shared_lock lock(g_rw_mutex); + std::shared_lock lock(g_rw_mutex); if (!jetty || !attr || jetty_map.find(jetty) == jetty_map.end()) { return URMA_EINVAL; } @@ -520,7 +526,7 @@ urma_status_t urma_modify_jetty(urma_jetty_t *jetty, urma_jetty_attr_t *attr) { 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); + 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) @@ -555,7 +561,7 @@ urma_status_t urma_post_jetty_send_wr(urma_jetty_t *jetty, urma_jfs_wr_t *wr, PendingRecv recv{}; urma_jfc_t* remote_jfc = nullptr; { - std::unique_lock lock(g_rw_mutex); + 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; @@ -585,7 +591,7 @@ urma_status_t urma_post_jetty_send_wr(urma_jetty_t *jetty, urma_jfs_wr_t *wr, JfcState* remote_state = nullptr; { - std::shared_lock lock(g_rw_mutex); + 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; @@ -613,7 +619,7 @@ urma_status_t urma_post_jetty_send_wr(urma_jetty_t *jetty, urma_jfs_wr_t *wr, 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); + 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) { @@ -644,7 +650,7 @@ urma_status_t urma_post_jetty_recv_wr(urma_jetty_t *jetty, urma_jfr_wr_t **bad_wr) { urma_jfr_t* shared_jfr = nullptr; { - std::shared_lock lock(g_rw_mutex); + std::shared_lock lock(g_rw_mutex); if (!jetty || jetty_map.find(jetty) == jetty_map.end()) { if (bad_wr) { *bad_wr = wr; @@ -659,7 +665,7 @@ urma_status_t urma_post_jetty_recv_wr(urma_jetty_t *jetty, 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); + std::shared_lock lock(g_rw_mutex); auto it = jfc_state_map.find(jfc); if (it == jfc_state_map.end()) { return -1; @@ -690,7 +696,7 @@ int urma_wait_jfc(urma_jfce_t* jfce, uint32_t jfc_cnt, int, } uint64_t value = 0; (void)read(jfce->fd, &value, sizeof(value)); - std::shared_lock lock(g_rw_mutex); + 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) { @@ -708,6 +714,27 @@ int urma_wait_jfc(urma_jfce_t* jfce, uint32_t jfc_cnt, int, void urma_ack_jfc(urma_jfc_t*[], uint32_t[], uint32_t) { } +// Referenced by SetBondingMode() in urma_helper.cpp whenever the provider +// header urma_ubagg.h is available (BRPC_URMA_HAS_BONDING_EXT). Without a +// definition here, WITH_URMA=ON fails to link against the mock. The mock +// advertises no bonding device, so this is never reached at runtime, but the +// symbol must exist. +urma_status_t urma_user_ctl(urma_context_t *ctx, urma_user_ctl_in_t *in, + urma_user_ctl_out_t *out) { + if (ctx == nullptr || in == nullptr || out == nullptr) { + return URMA_EINVAL; + } + std::shared_lock lock(g_rw_mutex); + if (context_map.find(ctx) == context_map.end()) { + return URMA_EINVAL; + } + // No provider state to configure; accept the command and report an empty + // output buffer. + out->addr = 0; + out->len = 0; + return URMA_SUCCESS; +} + } // extern "C" #endif // BRPC_WITH_URMA