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/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index e15d81db4f..b3462d227e 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -129,7 +129,23 @@ jobs: 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_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 \ @@ -140,7 +156,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 @@ -188,7 +204,24 @@ jobs: 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_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 \ @@ -200,7 +233,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 @@ -246,9 +279,9 @@ jobs: 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. + # 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 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/MODULE.bazel b/MODULE.bazel index 6f7b01a86e..1e71bfcb9d 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 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/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/src/butil/object_pool_inl.h b/src/butil/object_pool_inl.h index c98ec16f9d..d561d3fd3e 100644 --- a/src/butil/object_pool_inl.h +++ b/src/butil/object_pool_inl.h @@ -470,10 +470,7 @@ class BAIDU_CACHELINE_ALIGNMENT ObjectPool { if (BAIDU_LIKELY(lp != NULL)) { 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);