From 159c85505c84d78c030838d402536260805f4a26 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Fri, 7 Aug 2026 17:38:00 +0800 Subject: [PATCH 01/48] Fix RDMA PollCq missing recv CQEs after re-arming the CQs (#3425) PollCq only re-polled send_cq after arming both CQs, so a recv CQE arriving in the one-shot notification race window of recv_cq was left in the CQ and the RPC timed out. Restart the re-poll from recv_cq so that both CQs are covered. --- src/brpc/rdma/rdma_endpoint.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/brpc/rdma/rdma_endpoint.cpp b/src/brpc/rdma/rdma_endpoint.cpp index 6c20ea3994..8660d8d963 100644 --- a/src/brpc/rdma/rdma_endpoint.cpp +++ b/src/brpc/rdma/rdma_endpoint.cpp @@ -1492,6 +1492,17 @@ void RdmaEndpoint::PollCq(Socket* m) { 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)) { From 0c8aede17187363a0b03584388fb26d57f438db0 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Fri, 7 Aug 2026 17:38:10 +0800 Subject: [PATCH 02/48] Fix rdma handshake failing the socket instead of falling back to TCP (#3424) --- src/brpc/rdma/rdma_endpoint.cpp | 75 +++++++++++++++++----- src/brpc/rdma/rdma_endpoint.h | 10 ++- test/brpc_rdma_unittest.cpp | 107 ++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 19 deletions(-) diff --git a/src/brpc/rdma/rdma_endpoint.cpp b/src/brpc/rdma/rdma_endpoint.cpp index 8660d8d963..e2ce2e0c1b 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"); @@ -430,7 +434,9 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { // 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; @@ -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); @@ -1072,8 +1078,26 @@ 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; } @@ -1097,10 +1121,10 @@ int RdmaEndpoint::AllocateResources() { } 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; } @@ -1364,10 +1388,20 @@ 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 = NULL; } + + // 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; @@ -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,10 +1523,13 @@ 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; diff --git a/src/brpc/rdma/rdma_endpoint.h b/src/brpc/rdma/rdma_endpoint.h index 36e22ad28d..03bec81408 100644 --- a/src/brpc/rdma/rdma_endpoint.h +++ b/src/brpc/rdma/rdma_endpoint.h @@ -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/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); From 0ec3a9ddaa45f79639ebdaa018970de8d897dc53 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sun, 9 Aug 2026 14:35:44 +0800 Subject: [PATCH 03/48] Refactor streaming rpc (#3422) --- src/brpc/controller.cpp | 8 +- src/brpc/policy/baidu_rpc_protocol.cpp | 20 +- src/brpc/policy/streaming_rpc_protocol.cpp | 25 +- src/brpc/socket.h | 2 +- src/brpc/stream.cpp | 660 ++++++++++++--------- src/brpc/stream.h | 9 +- src/brpc/stream_impl.h | 105 ++-- src/brpc/versioned_ref_with_id.h | 144 +++-- src/bthread/execution_queue_inl.h | 25 +- test/brpc_streaming_rpc_unittest.cpp | 169 ++++-- 10 files changed, 698 insertions(+), 469 deletions(-) diff --git a/src/brpc/controller.cpp b/src/brpc/controller.cpp index 244d5d237f..5583231cb1 100644 --- a/src/brpc/controller.cpp +++ b/src/brpc/controller.cpp @@ -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); diff --git a/src/brpc/policy/baidu_rpc_protocol.cpp b/src/brpc/policy/baidu_rpc_protocol.cpp index 49863b2c06..41ff97ee22 100644 --- a/src/brpc/policy/baidu_rpc_protocol.cpp +++ b/src/brpc/policy/baidu_rpc_protocol.cpp @@ -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 { @@ -1129,12 +1129,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/streaming_rpc_protocol.cpp b/src/brpc/policy/streaming_rpc_protocol.cpp index b741acff5c..429d2bc282 100644 --- a/src/brpc/policy/streaming_rpc_protocol.cpp +++ b/src/brpc/policy/streaming_rpc_protocol.cpp @@ -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,16 +116,7 @@ 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 @@ -136,7 +127,7 @@ void ProcessStreamingMessage(InputMessageBase* /*msg*/) { CHECK(false) << "Should never be called"; } -void SendStreamRst(Socket *sock, int64_t remote_stream_id) { +void SendStreamRst(Socket* sock, int64_t remote_stream_id) { CHECK(sock != NULL); StreamFrameMeta fm; fm.set_stream_id(remote_stream_id); @@ -148,7 +139,7 @@ void SendStreamRst(Socket *sock, int64_t remote_stream_id) { 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); StreamFrameMeta fm; diff --git a/src/brpc/socket.h b/src/brpc/socket.h index 7c53058941..3bc90918d9 100644 --- a/src/brpc/socket.h +++ b/src/brpc/socket.h @@ -353,7 +353,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/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/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/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(); +} From 7a3e034e20dcfba04f30ffc95a03d934ff59ac4e Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sun, 9 Aug 2026 14:47:53 +0800 Subject: [PATCH 04/48] Fix brpc_proto_library failure when brpc is used as an external Bazel dependency (#3427) --- .bazelignore | 2 + .github/workflows/ci-linux.yml | 47 +++++++-- .licenserc.yaml | 1 + MODULE.bazel | 20 +++- bazel/tools/brpc_proto_library.bzl | 20 ++-- bazel/tools/proto_gen.bzl | 69 ++++++++----- example/build_with_bazel/BUILD.bazel | 6 -- example/build_with_bazel_module/.bazelrc | 61 ++++++++++++ example/build_with_bazel_module/.bazelversion | 1 + example/build_with_bazel_module/BUILD.bazel | 32 ++++++ example/build_with_bazel_module/MODULE.bazel | 30 ++++++ example/build_with_bazel_module/echo.proto | 33 +++++++ example/build_with_bazel_module/server.cpp | 99 +++++++++++++++++++ src/butil/object_pool_inl.h | 5 +- 14 files changed, 369 insertions(+), 57 deletions(-) create mode 100644 example/build_with_bazel_module/.bazelrc create mode 100644 example/build_with_bazel_module/.bazelversion create mode 100644 example/build_with_bazel_module/BUILD.bazel create mode 100644 example/build_with_bazel_module/MODULE.bazel create mode 100644 example/build_with_bazel_module/echo.proto create mode 100644 example/build_with_bazel_module/server.cpp 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); From cb84e83c59cf41a11b5e426116d663f2800de64b Mon Sep 17 00:00:00 2001 From: lh2debug-2 Date: Sun, 9 Aug 2026 15:03:54 +0800 Subject: [PATCH 05/48] fix rpcz root client span lifetime (#3420) (#3421) Keep the current RPC span alive from Controller until the RPC finishes, SubmitSpan runs, or the Controller is reset. This lets root client spans without a local parent be submitted to rpcz instead of being destroyed after the caller-side temporary shared_ptr goes out of scope. Child client spans remain linked to their parent through weak local-parent references and parent-owned client lists, so they are still serialized under their parent without introducing shared_ptr cycles. Co-authored-by: lh2debug --- src/brpc/controller.cpp | 66 +++++++++++++++---------------- src/brpc/controller.h | 2 +- src/brpc/span.cpp | 20 ++++++---- src/brpc/span.h | 8 ++++ test/brpc_controller_unittest.cpp | 43 ++++++++++++++++++++ 5 files changed, 97 insertions(+), 42 deletions(-) diff --git a/src/brpc/controller.cpp b/src/brpc/controller.cpp index 5583231cb1..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; } @@ -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/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/test/brpc_controller_unittest.cpp b/test/brpc_controller_unittest.cpp index 3f410a2599..77de20990a 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: @@ -74,6 +75,48 @@ 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); +} + +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); +} + #if ! BRPC_WITH_GLOG static bool endsWith(const std::string& s1, const butil::StringPiece& s2) { From ce0eaec3918c828ea8e1f46e2023f32deab4ec04 Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang Date: Sun, 9 Aug 2026 19:42:20 +0800 Subject: [PATCH 06/48] Merge pull request #3429 from wasphin/feature/protobuf-35 Support Protobuf v35 --- .github/workflows/ci-linux.yml | 2 +- src/brpc/nonreflectable_message.h | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index b3462d227e..1bc4a5729d 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -278,7 +278,7 @@ jobs: clang-unittest-bazel-with-babylon-and-new-pb: runs-on: ubuntu-22.04 env: - TEST_PROTOBUF_VERSION: "34.1" + 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. 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 } }; From febb014aaa3e7cfab7229d4db7c9c21c26e4bcfa Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Mon, 10 Aug 2026 10:20:11 +0800 Subject: [PATCH 07/48] Signal workers for priority tasks (#3423) --- src/bthread/task_group.cpp | 5 +++- test/bthread_priority_queue_unittest.cpp | 33 +++++++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) 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/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()); From 117531111d74d1afe44f37e49161fdd2c966b72e Mon Sep 17 00:00:00 2001 From: Regal <141622927+ZhengweiZhu@users.noreply.github.com> Date: Sat, 15 Aug 2026 09:42:04 +0800 Subject: [PATCH 08/48] test: wait for submitted spans to be collected (#3448) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wait for the asynchronous span collector to release root client spans after Controller reset or submission. This prevents LeakSanitizer from reporting pending test spans when the short-lived test binary exits before the collector’s first polling interval. Signed-off-by: Zhengwei Zhu <141622927+ZhengweiZhu@users.noreply.github.com> --- test/brpc_controller_unittest.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/brpc_controller_unittest.cpp b/test/brpc_controller_unittest.cpp index 77de20990a..d000d41add 100644 --- a/test/brpc_controller_unittest.cpp +++ b/test/brpc_controller_unittest.cpp @@ -42,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)); @@ -94,6 +102,7 @@ TEST_F(ControllerTest, root_client_span_kept_alive_until_reset) { cntl.Reset(); ASSERT_FALSE(cntl._span); + ASSERT_TRUE(WaitForSpanToExpire(weak_span)); } TEST_F(ControllerTest, root_client_span_released_by_submit_span) { @@ -115,6 +124,7 @@ TEST_F(ControllerTest, root_client_span_released_by_submit_span) { cntl.SubmitSpan(); ASSERT_FALSE(cntl._span); + ASSERT_TRUE(WaitForSpanToExpire(weak_span)); } #if ! BRPC_WITH_GLOG From 58ad9048b945e25dba7008ea89156dfb66113b66 Mon Sep 17 00:00:00 2001 From: Regal <141622927+ZhengweiZhu@users.noreply.github.com> Date: Sat, 15 Aug 2026 09:54:19 +0800 Subject: [PATCH 09/48] build: complete UBRING Bazel and CI support (#3445) Add the missing BRPC_WITH_UBRING Bazel configuration, wire it through the library and example targets, and document the supported build commands. Enable RDMA and UBRING in CI jobs whose all-options configurations did not exercise those features. Run both feature suites in the existing Bazel unit-test jobs and enable RDMA in the Make unit-test job. Use unsigned literals for UBRING atomic counter operations to match the counter type and avoid template deduction failures on stricter compilers. Signed-off-by: Zhengwei Zhu <141622927+ZhengweiZhu@users.noreply.github.com> --- .bazelrc | 2 ++ .github/workflows/ci-linux.yml | 18 +++++++++--- BUILD.bazel | 3 ++ bazel/config/BUILD.bazel | 6 ++++ docs/cn/ubring.md | 7 +++-- docs/en/ubring.md | 7 +++-- example/BUILD.bazel | 40 +++++++++++++++++++++++++++ example/ubring_performance/client.cpp | 21 ++++++++------ src/brpc/ubshm/timer/timer_mgr.cpp | 8 +++--- 9 files changed, 91 insertions(+), 21 deletions(-) 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 1bc4a5729d..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,7 +123,7 @@ 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 @@ -135,6 +135,8 @@ jobs: 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 \ @@ -149,6 +151,8 @@ jobs: 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 \ @@ -198,6 +202,8 @@ jobs: - run: | bazel test --test_output=streamed \ --action_env=CC=clang \ + --config=rdma \ + --config=ubring \ //test/... clang-compile-with-bazel-all-options: @@ -211,6 +217,8 @@ jobs: --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 \ @@ -226,6 +234,8 @@ jobs: --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 \ @@ -242,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 @@ -296,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/BUILD.bazel b/BUILD.bazel index b1676c4a62..727af8574a 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -51,6 +51,9 @@ 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_debug_bthread_sche_safety": ["BRPC_DEBUG_BTHREAD_SCHE_SAFETY=1"], "//conditions:default": ["BRPC_DEBUG_BTHREAD_SCHE_SAFETY=0"], diff --git a/bazel/config/BUILD.bazel b/bazel/config/BUILD.bazel index fabc4be061..e9d07eb73a 100644 --- a/bazel/config/BUILD.bazel +++ b/bazel/config/BUILD.bazel @@ -155,4 +155,10 @@ config_setting( name = "with_babylon_counter", define_values = {"with_babylon_counter": "true"}, visibility = ["//visibility:public"], +) + +config_setting( + name = "brpc_with_ubring", + define_values = {"BRPC_WITH_UBRING": "true"}, + visibility = ["//visibility:public"], ) \ No newline at end of file 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/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/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/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/src/brpc/ubshm/timer/timer_mgr.cpp b/src/brpc/ubshm/timer/timer_mgr.cpp index e57be93185..b563e7f6ab 100644 --- a/src/brpc/ubshm/timer/timer_mgr.cpp +++ b/src/brpc/ubshm/timer/timer_mgr.cpp @@ -77,7 +77,7 @@ static RETURN_CODE DeleteTimerInner(uint32_t fd) { 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; } @@ -305,7 +305,7 @@ void DeleteTimerSafe(uint32_t fd) { 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) { @@ -365,7 +365,7 @@ 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); @@ -384,7 +384,7 @@ int32_t TimerStart(const itimerspec *time, void *(*cb)(void *), void *args) { 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; } From 04d0bf0f80d1406b0e45c89b04b6ecf936ff08bb Mon Sep 17 00:00:00 2001 From: Chuang Zhang Date: Sat, 15 Aug 2026 11:08:02 +0800 Subject: [PATCH 10/48] fix(test): avoid overriding the configured C++ standard (#3446) --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 5a80007eb128426a0eb0de4e78607ddb8a078651 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:55:23 +0800 Subject: [PATCH 11/48] Replace NULL with nullptr in butil/debug (#3438) --- src/butil/debug/crash_logging.cc | 18 +++++++-------- src/butil/debug/crash_logging.h | 2 +- src/butil/debug/debugger_posix.cc | 4 ++-- src/butil/debug/dump_without_crashing.cc | 2 +- src/butil/debug/stack_trace.cc | 2 +- src/butil/debug/stack_trace.h | 2 +- src/butil/debug/stack_trace_posix.cc | 28 ++++++++++++------------ 7 files changed, 29 insertions(+), 29 deletions(-) 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. From bd6fa80ba6f72f004bbd3bda928d894c48057640 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:55:40 +0800 Subject: [PATCH 12/48] Replace NULL with nullptr in butil/details, butil/mac, butil/synchronization and butil/time (#3439) --- src/butil/details/extended_endpoint.hpp | 30 +++++++++---------- src/butil/mac/foundation_util.h | 14 ++++----- src/butil/mac/foundation_util.mm | 26 ++++++++-------- src/butil/mac/scoped_cftyperef.h | 2 +- src/butil/mac/scoped_typeref.h | 8 ++--- .../condition_variable_posix.cc | 4 +-- src/butil/synchronization/lock.h | 2 +- .../synchronization/waitable_event_posix.cc | 2 +- src/butil/time/time.h | 2 +- src/butil/time/time_mac.cc | 6 ++-- src/butil/time/time_posix.cc | 2 +- 11 files changed, 49 insertions(+), 49 deletions(-) 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/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/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/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 From 950cf26f9b262b443c466cfe39cc86ffb8eb68bb Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:55:57 +0800 Subject: [PATCH 13/48] Refactor NULL with nullptr in butil/files (#3440) --- src/butil/files/dir_reader_linux.h | 2 +- src/butil/files/dir_reader_unix.h | 14 +++++++------- src/butil/files/file_path.cc | 10 +++++----- src/butil/files/file_path.h | 2 +- src/butil/files/file_watcher.cpp | 4 ++-- src/butil/files/file_watcher.h | 4 ++-- src/butil/files/memory_mapped_file.cc | 2 +- src/butil/files/memory_mapped_file_posix.cc | 8 ++++---- src/butil/files/scoped_file.h | 20 ++++++++++---------- src/butil/files/temp_file.cpp | 2 +- 10 files changed, 34 insertions(+), 34 deletions(-) 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; } From a22d3052c8964e90c51ed7f6bf9455bd611669b4 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:56:15 +0800 Subject: [PATCH 14/48] Refactor NULL with nullptr in butil/memory (#3441) --- src/butil/memory/aligned_memory.cc | 4 +- src/butil/memory/linked_ptr.h | 6 +-- src/butil/memory/ref_counted.h | 10 ++--- src/butil/memory/ref_counted_memory.cc | 8 ++-- src/butil/memory/ref_counted_memory.h | 6 +-- src/butil/memory/scoped_ptr.h | 46 ++++++++++---------- src/butil/memory/singleton.cc | 2 +- src/butil/memory/singleton.h | 14 +++--- src/butil/memory/singleton_on_pthread_once.h | 4 +- src/butil/memory/weak_ptr.cc | 2 +- src/butil/memory/weak_ptr.h | 18 ++++---- 11 files changed, 60 insertions(+), 60 deletions(-) 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() { From 9f9b62f68369326d970d484493b5165deec75516 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:56:33 +0800 Subject: [PATCH 15/48] Refactor NULL with nullptr in butil/strings (#3442) --- src/butil/strings/safe_sprintf.cc | 8 ++++---- src/butil/strings/string_number_conversions.cc | 2 +- src/butil/strings/string_piece.h | 12 ++++++------ src/butil/strings/string_util.cc | 4 ++-- src/butil/strings/string_util.h | 6 +++--- src/butil/strings/stringprintf.cc | 2 +- src/butil/strings/sys_string_conversions.h | 2 +- src/butil/strings/sys_string_conversions_mac.mm | 8 ++++---- src/butil/strings/sys_string_conversions_posix.cc | 4 ++-- src/butil/strings/utf_offset_string_conversions.cc | 2 +- src/butil/strings/utf_offset_string_conversions.h | 2 +- 11 files changed, 26 insertions(+), 26 deletions(-) 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, From a2a43d951a778d5346d3def3b0655e8a95c16c97 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:56:50 +0800 Subject: [PATCH 16/48] Refactor NULL with nullptr in butil/threading (#3443) --- src/butil/threading/platform_thread_posix.cc | 8 ++++---- src/butil/threading/simple_thread.cc | 8 ++++---- src/butil/threading/simple_thread.h | 2 +- src/butil/threading/thread_id_name_manager.cc | 4 ++-- src/butil/threading/thread_local.h | 14 +++++++------- src/butil/threading/thread_local_posix.cc | 2 +- src/butil/threading/thread_local_storage.cc | 12 ++++++------ src/butil/threading/thread_local_storage.h | 4 ++-- 8 files changed, 27 insertions(+), 27 deletions(-) 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_; From 3124cf035de919bbe37e386029ebe21f3816ddb3 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sat, 15 Aug 2026 13:57:09 +0800 Subject: [PATCH 17/48] Replace NULL with nullptr in butil/containers (#3437) --- src/butil/containers/bounded_queue.h | 40 ++++++++-------- src/butil/containers/doubly_buffered_data.h | 48 +++++++++---------- src/butil/containers/flat_map.h | 20 ++++---- src/butil/containers/flat_map_inl.h | 52 ++++++++++----------- src/butil/containers/linked_list.h | 2 +- src/butil/containers/mpsc_queue.h | 20 ++++---- src/butil/containers/scoped_ptr_hash_map.h | 6 +-- src/butil/containers/small_map.h | 32 ++++++------- src/butil/containers/stack_container.h | 8 ++-- 9 files changed, 114 insertions(+), 114 deletions(-) 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); From 24146ca5565e07a29cfbda23595e1796bf00d355 Mon Sep 17 00:00:00 2001 From: UB Date: Sat, 15 Aug 2026 11:42:00 +0530 Subject: [PATCH 18/48] cap simple string length in RedisReply::ConsumePartialIOBuf (#3404) * cap simple string length in RedisReply::ConsumePartialIOBuf Signed-off-by: ubeddulla khan * reject negative redis_max_allocation_size in simple string branch Signed-off-by: ubeddulla khan * enforce redis simple string cap while waiting for CRLF Signed-off-by: ubeddulla khan --------- Signed-off-by: ubeddulla khan --- src/brpc/redis_reply.cpp | 18 +++++++++++ test/brpc_redis_unittest.cpp | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) 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/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 From e0abb1001ef76d400dddc2b2c3a1ff42f5d3afac Mon Sep 17 00:00:00 2001 From: Chuang Zhang Date: Sat, 15 Aug 2026 16:56:56 +0800 Subject: [PATCH 19/48] Progressive timeout dev (#3409) * add the progressive timeout reader * optimize the code format * WIP: progressive read timeout review * test: strengthen progressive read timeout coverage --- example/http_c++/http_client.cpp | 35 +++ example/http_c++/http_server.cpp | 7 + src/brpc/controller.cpp | 259 ++++++++++++++++++++++- src/brpc/controller.h | 8 +- src/brpc/errno.proto | 1 + src/brpc/policy/http_rpc_protocol.cpp | 1 + src/brpc/policy/http_rpc_protocol.h | 12 +- src/brpc/progressive_reader.h | 2 + test/brpc_http_rpc_protocol_unittest.cpp | 237 ++++++++++++++++++++- 9 files changed, 557 insertions(+), 5 deletions(-) diff --git a/example/http_c++/http_client.cpp b/example/http_c++/http_client.cpp index 23222dee9b..3a09186f84 100644 --- a/example/http_c++/http_client.cpp +++ b/example/http_c++/http_client.cpp @@ -22,11 +22,15 @@ // - Access www.foo.com // ./http_client www.foo.com +#include #include #include #include +#include "bthread/countdown_event.h" DEFINE_string(d, "", "POST this data to the http server"); +DEFINE_bool(progressive, false, "whether or not progressive read data from server"); +DEFINE_int32(progressive_read_timeout_ms, 5000, "progressive read data idle timeout in milliseconds"); DEFINE_string(load_balancer, "", "The algorithm for load balancing"); DEFINE_int32(timeout_ms, 2000, "RPC timeout in milliseconds"); DEFINE_int32(max_retry, 3, "Max retries(not including the first RPC)"); @@ -36,6 +40,25 @@ namespace brpc { DECLARE_bool(http_verbose); } +class PartDataReader: public brpc::ProgressiveReader { +public: + explicit PartDataReader(bthread::CountdownEvent* done): _done(done){} + + butil::Status OnReadOnePart(const void* data, size_t length) { + const std::string part(static_cast(data), length); + LOG(INFO) << "data: " << part << " size: " << length; + return butil::Status::OK(); + } + + void OnEndOfMessage(const butil::Status& status) { + LOG(INFO) << "progressive read data final status : " << status; + _done->signal(); + delete this; + } +private: + bthread::CountdownEvent* _done; +}; + int main(int argc, char* argv[]) { // Parse gflags. We recommend you to use gflags as well. GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true); @@ -71,6 +94,11 @@ int main(int argc, char* argv[]) { cntl.request_attachment().append(FLAGS_d); } + if (FLAGS_progressive) { + cntl.set_progressive_read_timeout_ms(FLAGS_progressive_read_timeout_ms); + cntl.response_will_be_read_progressively(); + } + // Because `done'(last parameter) is NULL, this function waits until // the response comes back or error occurs(including timedout). channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); @@ -78,6 +106,13 @@ int main(int argc, char* argv[]) { std::cerr << cntl.ErrorText() << std::endl; return -1; } + + if (FLAGS_progressive) { + bthread::CountdownEvent done(1); + cntl.ReadProgressiveAttachmentBy(new PartDataReader(&done)); + done.wait(); + LOG(INFO) << "wait client progressive read done safely"; + } // If -http_verbose is on, brpc already prints the response to stderr. if (!brpc::FLAGS_http_verbose) { std::cout << cntl.response_attachment() << std::endl; diff --git a/example/http_c++/http_server.cpp b/example/http_c++/http_server.cpp index 05c9a0ee4c..4c3c8722fd 100644 --- a/example/http_c++/http_server.cpp +++ b/example/http_c++/http_server.cpp @@ -31,6 +31,7 @@ DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no " DEFINE_string(certificate, "cert.pem", "Certificate file path to enable SSL"); DEFINE_string(private_key, "key.pem", "Private key file path to enable SSL"); DEFINE_string(ciphers, "", "Cipher suite used for SSL connections"); +DEFINE_bool(enable_progressive_timeout, false, "whether or not trigger progressive write attachment data timeout"); namespace example { @@ -104,6 +105,9 @@ class FileServiceImpl : public FileService { // sleep a while to send another part. bthread_usleep(10000); + if (FLAGS_enable_progressive_timeout && i > 50) { + bthread_usleep(100000000UL); + } } return NULL; } @@ -194,6 +198,9 @@ class HttpSSEServiceImpl : public HttpSSEService { // sleep a while to send another part. bthread_usleep(10000 * 10); + if (FLAGS_enable_progressive_timeout && i > 50) { + bthread_usleep(100000000UL); + } } return NULL; } diff --git a/src/brpc/controller.cpp b/src/brpc/controller.cpp index 8a8410beb9..66a9a3a504 100644 --- a/src/brpc/controller.cpp +++ b/src/brpc/controller.cpp @@ -73,6 +73,7 @@ BAIDU_REGISTER_ERRNO(brpc::EEOF, "Got EOF"); BAIDU_REGISTER_ERRNO(brpc::EUNUSED, "The socket was not needed"); BAIDU_REGISTER_ERRNO(brpc::ESSL, "SSL related operation failed"); BAIDU_REGISTER_ERRNO(brpc::EH2RUNOUTSTREAMS, "The H2 socket was run out of streams"); +BAIDU_REGISTER_ERRNO(brpc::EPROGREADTIMEOUT, "Progressive read timed out"); BAIDU_REGISTER_ERRNO(brpc::EINTERNAL, "General internal error"); BAIDU_REGISTER_ERRNO(brpc::ERESPONSE, "Bad response"); @@ -94,8 +95,9 @@ namespace brpc { DEFINE_bool(graceful_quit_on_sigterm, false, "Register SIGTERM handle func to quit graceful"); DEFINE_bool(graceful_quit_on_sighup, false, - "Register SIGHUP handle func to quit graceful"); - + "Register SIGHUP handle func to quit graceful"); +DEFINE_bool(log_idle_progressive_read_close, false, + "Print log when an idle progressive read is closed"); const IdlNames idl_single_req_single_res = { "req", "res" }; const IdlNames idl_single_req_multi_res = { "req", "" }; const IdlNames idl_multi_req_single_res = { "", "res" }; @@ -174,6 +176,226 @@ class IgnoreAllRead : public ProgressiveReader { void OnEndOfMessage(const butil::Status&) {} }; +struct ProgressiveReadTimeoutTask; + +struct ProgressiveReadTimeoutState { + ProgressiveReadTimeoutState(SocketId id, int32_t timeout_ms) + : socket_id(id) + , read_timeout_ms(timeout_ms) + , deadline_us(butil::cpuwide_time_us() + timeout_ms * 1000L) + , timer_id(0) + , timer_task(NULL) + , user_callback_running(false) + , reader_failed(false) + , timeout_triggered(false) + , end_delivered(false) {} + + butil::Mutex mutex; + const SocketId socket_id; + const int32_t read_timeout_ms; + int64_t deadline_us; + bthread_timer_t timer_id; + ProgressiveReadTimeoutTask* timer_task; + bool user_callback_running; + bool reader_failed; + bool timeout_triggered; + bool end_delivered; + butil::Status timer_error; +}; + +struct ProgressiveReadTimeoutTask { + explicit ProgressiveReadTimeoutTask( + const std::shared_ptr& state_in) + : state(state_in) {} + + std::shared_ptr state; +}; + +class ProgressiveTimeoutReader : public ProgressiveReader { +public: + ProgressiveTimeoutReader(SocketId id, int32_t read_timeout_ms, + ProgressiveReader* reader) + : _reader(reader) + , _state(new ProgressiveReadTimeoutState(id, read_timeout_ms)) {} + + int Start() { + std::unique_lock mu(_state->mutex); + return AddWatchdogLocked(_state, _state->read_timeout_ms * 1000L); + } + + butil::Status OnReadOnePart(const void* data, size_t length) override { + { + std::unique_lock mu(_state->mutex); + if (_state->timeout_triggered) { + return MakeTimeoutStatus(_state->read_timeout_ms); + } + if (!_state->timer_error.ok()) { + return _state->timer_error; + } + _state->user_callback_running = true; + } + + butil::Status status = _reader->OnReadOnePart(data, length); + { + std::unique_lock mu(_state->mutex); + _state->user_callback_running = false; + if (_state->timeout_triggered) { + status = MakeTimeoutStatus(_state->read_timeout_ms); + } else if (!_state->timer_error.ok()) { + status = _state->timer_error; + } else if (status.ok() && !_state->end_delivered) { + _state->deadline_us = butil::cpuwide_time_us() + + _state->read_timeout_ms * 1000L; + } else if (!status.ok()) { + _state->reader_failed = true; + } + } + return status; + } + + void OnEndOfMessage(const butil::Status& status) override { + bthread_timer_t timer_id = 0; + ProgressiveReadTimeoutTask* timer_task = NULL; + butil::Status final_status = status; + ProgressiveReader* reader = NULL; + { + std::unique_lock mu(_state->mutex); + if (_state->end_delivered) { + LOG(ERROR) << "ProgressiveReader::OnEndOfMessage was called more than once"; + return; + } + _state->end_delivered = true; + timer_id = _state->timer_id; + timer_task = _state->timer_task; + _state->timer_id = 0; + _state->timer_task = NULL; + if (_state->timeout_triggered) { + final_status = MakeTimeoutStatus(_state->read_timeout_ms); + } else if (!_state->timer_error.ok()) { + final_status = _state->timer_error; + } + reader = _reader; + _reader = NULL; + } + + CancelWatchdog(timer_id, timer_task); + reader->OnEndOfMessage(final_status); + delete this; + } + +private: + ~ProgressiveTimeoutReader() override {} + + static butil::Status MakeTimeoutStatus(int32_t timeout_ms) { + return butil::Status( + EPROGREADTIMEOUT, + "Progressive read timed out after %d ms", timeout_ms); + } + + static butil::Status MakeTimerErrorStatus(int error_code) { + return butil::Status( + error_code, "Fail to add progressive read timeout timer: %s", + berror(error_code)); + } + + static void CancelWatchdog( + bthread_timer_t timer_id, ProgressiveReadTimeoutTask* timer_task) { + if (timer_id == 0) { + return; + } + const int rc = bthread_timer_del(timer_id); + if (rc == 0) { + delete timer_task; + } else if (rc == 1 || rc == EINVAL) { + // The callback owns timer_task once it starts running. EINVAL means + // that the callback has already finished and released the task. + } else { + LOG(ERROR) << "Unexpected bthread_timer_del error=" << rc; + } + } + + static int AddWatchdogLocked( + const std::shared_ptr& state, + int64_t delay_us) { + if (state->end_delivered || state->reader_failed) { + return ECANCELED; + } + if (delay_us <= 0) { + delay_us = 1; + } + ProgressiveReadTimeoutTask* task = + new (std::nothrow) ProgressiveReadTimeoutTask(state); + if (task == NULL) { + return ENOMEM; + } + bthread_timer_t timer_id = 0; + const int rc = bthread_timer_add( + &timer_id, butil::microseconds_from_now(delay_us), + HandleIdleProgressiveReader, task); + if (rc != 0) { + delete task; + return rc; + } + state->timer_id = timer_id; + state->timer_task = task; + return 0; + } + + static void HandleIdleProgressiveReader(void* arg) { + std::unique_ptr task( + static_cast(arg)); + const std::shared_ptr state = task->state; + bool fail_socket = false; + int error_code = 0; + std::string error_text; + { + std::unique_lock mu(state->mutex); + if (state->timer_task == task.get()) { + state->timer_id = 0; + state->timer_task = NULL; + } + if (state->end_delivered || state->reader_failed) { + return; + } + + const int64_t now_us = butil::cpuwide_time_us(); + if (state->user_callback_running || now_us < state->deadline_us) { + const int64_t delay_us = state->user_callback_running + ? state->read_timeout_ms * 1000L + : state->deadline_us - now_us; + const int rc = AddWatchdogLocked(state, delay_us); + if (rc != 0) { + state->timer_error = MakeTimerErrorStatus(rc); + fail_socket = true; + error_code = rc; + error_text = state->timer_error.error_str(); + } + } else { + state->timeout_triggered = true; + fail_socket = true; + error_code = EPROGREADTIMEOUT; + error_text = MakeTimeoutStatus(state->read_timeout_ms).error_str(); + } + } + + if (!fail_socket) { + return; + } + SocketUniquePtr socket; + if (Socket::Address(state->socket_id, &socket) != 0) { + LOG(ERROR) << "Fail to address socket_id=" << state->socket_id + << " after progressive read timeout"; + } else { + LOG_IF(INFO, FLAGS_log_idle_progressive_read_close) + << error_text << ", socket_id=" << state->socket_id; + socket->SetFailed(error_code, "%s", error_text.c_str()); + } + } + + ProgressiveReader* _reader; + const std::shared_ptr _state; +}; + static IgnoreAllRead* s_ignore_all_read = NULL; static pthread_once_t s_ignore_all_read_once = PTHREAD_ONCE_INIT; static void CreateIgnoreAllRead() { s_ignore_all_read = new IgnoreAllRead; } @@ -261,6 +483,7 @@ void Controller::ResetPods() { _backup_request_ms = UNSET_MAGIC_NUM; _backup_request_policy = NULL; _connect_timeout_ms = UNSET_MAGIC_NUM; + _progressive_read_timeout_ms = UNSET_MAGIC_NUM; _real_timeout_ms = UNSET_MAGIC_NUM; _deadline_us = -1; _timeout_id = 0; @@ -336,6 +559,11 @@ void Controller::Call::Reset() { stream_user_data = NULL; } +void Controller::set_progressive_read_timeout_ms( + int32_t progressive_read_timeout_ms) { + _progressive_read_timeout_ms = progressive_read_timeout_ms; +} + void Controller::set_timeout_ms(int64_t timeout_ms) { if (timeout_ms <= 0x7fffffff) { _timeout_ms = timeout_ms; @@ -1613,6 +1841,33 @@ void Controller::ReadProgressiveAttachmentBy(ProgressiveReader* r) { __FUNCTION__)); } add_flag(FLAGS_PROGRESSIVE_READER); + if (progressive_read_timeout_ms() > 0) { + const SocketId socket_id = _rpa->GetSocketId(); + if (socket_id == INVALID_SOCKET_ID) { + pthread_once(&s_ignore_all_read_once, CreateIgnoreAllRead); + _rpa->ReadProgressiveAttachmentBy(s_ignore_all_read); + return r->OnEndOfMessage(butil::Status( + ENOTSUP, + "Progressive read timeout is only supported for HTTP/1.x")); + } + ProgressiveTimeoutReader* reader = new (std::nothrow) + ProgressiveTimeoutReader( + socket_id, _progressive_read_timeout_ms, r); + if (reader == NULL) { + pthread_once(&s_ignore_all_read_once, CreateIgnoreAllRead); + _rpa->ReadProgressiveAttachmentBy(s_ignore_all_read); + return r->OnEndOfMessage( + butil::Status(ENOMEM, "Fail to create progressive timeout reader")); + } + const int rc = reader->Start(); + if (rc != 0) { + pthread_once(&s_ignore_all_read_once, CreateIgnoreAllRead); + _rpa->ReadProgressiveAttachmentBy(s_ignore_all_read); + return reader->OnEndOfMessage(butil::Status( + rc, "Fail to add progressive read timeout timer: %s", berror(rc))); + } + return _rpa->ReadProgressiveAttachmentBy(reader); + } return _rpa->ReadProgressiveAttachmentBy(r); } diff --git a/src/brpc/controller.h b/src/brpc/controller.h index 564c0875e1..41d42ae712 100644 --- a/src/brpc/controller.h +++ b/src/brpc/controller.h @@ -199,6 +199,9 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); // Set/get timeout in milliseconds for the RPC call. Use // ChannelOptions.timeout_ms on unset. + void set_progressive_read_timeout_ms(int32_t progressive_read_timeout_ms); + int32_t progressive_read_timeout_ms() const { return _progressive_read_timeout_ms; } + void set_timeout_ms(int64_t timeout_ms); int64_t timeout_ms() const { return _timeout_ms; } @@ -361,7 +364,9 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); // Make the RPC end when the HTTP response has complete headers and let // user read the remaining body by using ReadProgressiveAttachmentBy(). - void response_will_be_read_progressively() { add_flag(FLAGS_READ_PROGRESSIVELY); } + void response_will_be_read_progressively() { + add_flag(FLAGS_READ_PROGRESSIVELY); + } // Make the RPC end when the HTTP request has complete headers and let // user read the remaining body by using ReadProgressiveAttachmentBy(). void request_will_be_read_progressively() { add_flag(FLAGS_READ_PROGRESSIVELY); } @@ -911,6 +916,7 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); int32_t _timeout_ms; int32_t _connect_timeout_ms; int32_t _backup_request_ms; + int32_t _progressive_read_timeout_ms; // Priority: `_backup_request_policy' > `_backup_request_ms'. BackupRequestPolicy* _backup_request_policy; // If this rpc call has retry/backup request,this var save the real timeout for current call diff --git a/src/brpc/errno.proto b/src/brpc/errno.proto index 26ffadc201..166d82dc4a 100644 --- a/src/brpc/errno.proto +++ b/src/brpc/errno.proto @@ -41,6 +41,7 @@ enum Errno { ESSL = 1016; // SSL related error EH2RUNOUTSTREAMS = 1017; // The H2 socket was run out of streams EREJECT = 1018; // The Request is rejected + EPROGREADTIMEOUT = 1019; // The Progressive read timeout // Errno caused by server EINTERNAL = 2001; // Internal Server Error diff --git a/src/brpc/policy/http_rpc_protocol.cpp b/src/brpc/policy/http_rpc_protocol.cpp index 8cbe06980f..3fb9408850 100644 --- a/src/brpc/policy/http_rpc_protocol.cpp +++ b/src/brpc/policy/http_rpc_protocol.cpp @@ -1201,6 +1201,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, LOG(FATAL) << "Fail to new HttpContext"; return MakeParseError(PARSE_ERROR_NO_RESOURCE); } + http_imsg->SetSocketId(socket->id()); // 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 diff --git a/src/brpc/policy/http_rpc_protocol.h b/src/brpc/policy/http_rpc_protocol.h index bc8bd06593..cd41798e9f 100644 --- a/src/brpc/policy/http_rpc_protocol.h +++ b/src/brpc/policy/http_rpc_protocol.h @@ -87,11 +87,20 @@ class HttpContext : public ReadableProgressiveAttachment , public InputMessageBase , public HttpMessage { public: + SocketId GetSocketId() override { + return _socket_id; + } + + void SetSocketId(SocketId id) { + _socket_id = id; + } + explicit HttpContext(bool read_body_progressively, HttpMethod request_method = HTTP_METHOD_GET) : InputMessageBase() , HttpMessage(read_body_progressively, request_method) - , _is_stage2(false) { + , _is_stage2(false) + , _socket_id(INVALID_SOCKET_ID) { // add one ref for Destroy butil::intrusive_ptr(this).detach(); } @@ -122,6 +131,7 @@ class HttpContext : public ReadableProgressiveAttachment private: bool _is_stage2; + SocketId _socket_id; }; // Implement functions required in protocol.h diff --git a/src/brpc/progressive_reader.h b/src/brpc/progressive_reader.h index 6f54ae68a7..c84be8b7e7 100644 --- a/src/brpc/progressive_reader.h +++ b/src/brpc/progressive_reader.h @@ -20,6 +20,7 @@ #define BRPC_PROGRESSIVE_READER_H #include "brpc/shared_object.h" +#include "brpc/socket_id.h" namespace brpc { @@ -84,6 +85,7 @@ class ReadableProgressiveAttachment : public SharedObject { // Any error occurred should destroy the reader by calling r->Destroy(). // r->Destroy() should be guaranteed to be called once and only once. virtual void ReadProgressiveAttachmentBy(ProgressiveReader* r) = 0; + virtual SocketId GetSocketId() = 0; }; } // namespace brpc diff --git a/test/brpc_http_rpc_protocol_unittest.cpp b/test/brpc_http_rpc_protocol_unittest.cpp index 87837abf1a..6735a171b1 100644 --- a/test/brpc_http_rpc_protocol_unittest.cpp +++ b/test/brpc_http_rpc_protocol_unittest.cpp @@ -19,6 +19,7 @@ // Date: Sun Jul 13 15:04:18 CST 2014 +#include #include #include #include @@ -736,9 +737,13 @@ static void CopyPAPrefixedWithSeqNo(char* buf, uint64_t seq_no) { class DownloadServiceImpl : public ::test::DownloadService { public: DownloadServiceImpl(DonePlace done_place = DONE_BEFORE_CREATE_PA, - size_t num_repeat = 1) + size_t num_repeat = 1, + int write_interval_us = 0, + int initial_write_delay_us = 0) : _done_place(done_place) , _nrep(num_repeat) + , _write_interval_us(write_interval_us) + , _initial_write_delay_us(initial_write_delay_us) , _nwritten(0) , _ever_full(false) , _last_errno(0) {} @@ -762,6 +767,9 @@ class DownloadServiceImpl : public ::test::DownloadService { if (_done_place == DONE_BEFORE_CREATE_PA) { done_guard.reset(NULL); } + if (_initial_write_delay_us > 0) { + bthread_usleep(_initial_write_delay_us); + } ASSERT_GT(PA_DATA_LEN, 8u); // long enough to hold a 64-bit decimal. char buf[PA_DATA_LEN]; for (size_t c = 0; c < _nrep;) { @@ -778,6 +786,9 @@ class DownloadServiceImpl : public ::test::DownloadService { } } else { _nwritten += PA_DATA_LEN; + if (_write_interval_us > 0) { + bthread_usleep(_write_interval_us); + } } ++c; } @@ -840,6 +851,8 @@ class DownloadServiceImpl : public ::test::DownloadService { private: DonePlace _done_place; size_t _nrep; + int _write_interval_us; + int _initial_write_delay_us; size_t _nwritten; bool _ever_full; int _last_errno; @@ -941,6 +954,47 @@ class ReadBody : public brpc::ProgressiveReader, butil::Status _destroying_st; }; +class TimeoutReadBody : public brpc::ProgressiveReader, + public brpc::SharedObject { +public: + explicit TimeoutReadBody(int read_delay_us = 0, int read_error = 0) + : _read_delay_us(read_delay_us) + , _read_error(read_error) + , _nread(0) + , _nend(0) + , _end_error(0) { + butil::intrusive_ptr(this).detach(); + } + + butil::Status OnReadOnePart(const void*, size_t length) override { + if (_read_delay_us > 0) { + bthread_usleep(_read_delay_us); + } + _nread.fetch_add(length); + if (_read_error != 0) { + return butil::Status(_read_error, "intended progressive read failure"); + } + return butil::Status::OK(); + } + + void OnEndOfMessage(const butil::Status& status) override { + _end_error.store(status.error_code()); + _nend.fetch_add(1); + butil::intrusive_ptr(this, false); + } + + size_t read_bytes() const { return _nread.load(); } + int end_count() const { return _nend.load(); } + int end_error() const { return _end_error.load(); } + +private: + const int _read_delay_us; + const int _read_error; + std::atomic _nread; + std::atomic _nend; + std::atomic _end_error; +}; + #ifdef BUTIL_USE_ASAN static const int GENERAL_DELAY_US = 1000000; // 1s #else @@ -1034,6 +1088,187 @@ TEST_F(HttpTest, read_short_body_progressively) { } } +TEST_F(HttpTest, progressive_read_timeout_keeps_active_reader_alive) { + const int port = 8923; + brpc::Server server; + DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 8, 100000); + ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(port, NULL)); + + brpc::Channel channel; + brpc::ChannelOptions options; + options.protocol = brpc::PROTOCOL_HTTP; + ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); + + brpc::Controller cntl; + cntl.response_will_be_read_progressively(); + cntl.set_progressive_read_timeout_ms(500); + cntl.http_request().uri() = "/DownloadService/Download"; + channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + + butil::intrusive_ptr reader(new TimeoutReadBody); + cntl.ReadProgressiveAttachmentBy(reader.get()); + for (int i = 0; i < 200 && reader->end_count() == 0; ++i) { + bthread_usleep(10000); + } + ASSERT_EQ(1, reader->end_count()); + EXPECT_EQ(0, reader->end_error()); + EXPECT_EQ(8 * PA_DATA_LEN, reader->read_bytes()); +} + +TEST_F(HttpTest, progressive_read_timeout_closes_idle_http1_reader_once) { + const int port = 8923; + brpc::Server server; + DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 2, 300000); + ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(port, NULL)); + + butil::intrusive_ptr reader(new TimeoutReadBody); + { + brpc::Channel channel; + brpc::ChannelOptions options; + options.protocol = brpc::PROTOCOL_HTTP; + ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); + { + brpc::Controller cntl; + cntl.response_will_be_read_progressively(); + cntl.set_progressive_read_timeout_ms(50); + cntl.http_request().uri() = "/DownloadService/Download"; + channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + cntl.ReadProgressiveAttachmentBy(reader.get()); + bthread_usleep(400000); + ASSERT_NE(0, svc.last_errno()); + EXPECT_EQ(0, reader->end_count()); + } + } + for (int i = 0; i < 100 && reader->end_count() == 0; ++i) { + bthread_usleep(10000); + } + ASSERT_EQ(1, reader->end_count()); + EXPECT_EQ(brpc::EPROGREADTIMEOUT, reader->end_error()); + bthread_usleep(400000); + EXPECT_EQ(1, reader->end_count()); +} + +TEST_F(HttpTest, progressive_read_timeout_before_first_body_part) { + const int port = 8923; + brpc::Server server; + DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 1, 0, 300000); + ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(port, NULL)); + + butil::intrusive_ptr reader(new TimeoutReadBody); + { + brpc::Channel channel; + brpc::ChannelOptions options; + options.protocol = brpc::PROTOCOL_HTTP; + ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); + { + brpc::Controller cntl; + cntl.response_will_be_read_progressively(); + cntl.set_progressive_read_timeout_ms(50); + cntl.http_request().uri() = "/DownloadService/Download"; + channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + cntl.ReadProgressiveAttachmentBy(reader.get()); + bthread_usleep(400000); + ASSERT_NE(0, svc.last_errno()); + EXPECT_EQ(size_t(0), reader->read_bytes()); + EXPECT_EQ(0, reader->end_count()); + } + } + for (int i = 0; i < 100 && reader->end_count() == 0; ++i) { + bthread_usleep(10000); + } + ASSERT_EQ(1, reader->end_count()); + EXPECT_EQ(brpc::EPROGREADTIMEOUT, reader->end_error()); +} + +TEST_F(HttpTest, progressive_read_timeout_ignores_slow_user_callback) { + const int port = 8923; + brpc::Server server; + DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 3, 50000); + ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(port, NULL)); + + brpc::Channel channel; + brpc::ChannelOptions options; + options.protocol = brpc::PROTOCOL_HTTP; + ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); + + brpc::Controller cntl; + cntl.response_will_be_read_progressively(); + cntl.set_progressive_read_timeout_ms(50); + cntl.http_request().uri() = "/DownloadService/Download"; + channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + + butil::intrusive_ptr reader( + new TimeoutReadBody(200000)); + cntl.ReadProgressiveAttachmentBy(reader.get()); + for (int i = 0; i < 100 && reader->end_count() == 0; ++i) { + bthread_usleep(10000); + } + ASSERT_EQ(1, reader->end_count()); + EXPECT_EQ(0, reader->end_error()); + EXPECT_EQ(3 * PA_DATA_LEN, reader->read_bytes()); +} + +TEST_F(HttpTest, progressive_read_timeout_preserves_reader_error) { + const int port = 8923; + brpc::Server server; + DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 10); + ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(port, NULL)); + + brpc::Channel channel; + brpc::ChannelOptions options; + options.protocol = brpc::PROTOCOL_HTTP; + ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); + + brpc::Controller cntl; + cntl.response_will_be_read_progressively(); + cntl.set_progressive_read_timeout_ms(1000); + cntl.http_request().uri() = "/DownloadService/Download"; + channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + + butil::intrusive_ptr reader( + new TimeoutReadBody(0, EIO)); + cntl.ReadProgressiveAttachmentBy(reader.get()); + ASSERT_EQ(1, reader->end_count()); + EXPECT_EQ(EIO, reader->end_error()); +} + +TEST_F(HttpTest, progressive_read_timeout_rejects_http2) { + const int port = 8923; + brpc::Server server; + ASSERT_EQ(0, server.AddService(&_svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + ASSERT_EQ(0, server.Start(port, NULL)); + + brpc::Channel channel; + brpc::ChannelOptions options; + options.protocol = brpc::PROTOCOL_H2; + ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); + + brpc::Controller cntl; + cntl.response_will_be_read_progressively(); + cntl.set_progressive_read_timeout_ms(1000); + cntl.http_request().uri() = "/EchoService/Echo"; + test::EchoRequest req; + req.set_message(EXP_REQUEST); + channel.CallMethod(NULL, &cntl, &req, NULL, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + + butil::intrusive_ptr reader(new TimeoutReadBody); + cntl.ReadProgressiveAttachmentBy(reader.get()); + ASSERT_EQ(1, reader->end_count()); + EXPECT_EQ(ENOTSUP, reader->end_error()); + EXPECT_EQ(size_t(0), reader->read_bytes()); +} + TEST_F(HttpTest, read_progressively_after_cntl_destroys) { DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, std::numeric_limits::max()); From 437a7b705ccab4a5c7d8be64acc7cefdb150ad79 Mon Sep 17 00:00:00 2001 From: Weibing Wang Date: Sun, 16 Aug 2026 01:06:46 +0800 Subject: [PATCH 20/48] Limit mcpack2pb array item count to the actual payload size (#3451) * Limit mcpack2pb array item count to the actual payload size The item count in an mcpack array header is read directly from the request and was used as-is by the generated parsing code to Reserve() memory for repeated protobuf fields. A malformed request could claim an item count up to INT32_MAX and force the server to preallocate ~16GB of virtual memory, which may abort the process on memory-constrained hosts. Cap the item count by the remaining bytes of the array (each item occupies at least one byte) so that the preallocation is bounded by the request size. * Fix underflow in mcpack2pb array item count clamping --- src/mcpack2pb/parser-inl.h | 16 +++++++ test/brpc_mcpack2pb_unittest.cpp | 79 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 test/brpc_mcpack2pb_unittest.cpp 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/test/brpc_mcpack2pb_unittest.cpp b/test/brpc_mcpack2pb_unittest.cpp new file mode 100644 index 0000000000..68de0522fe --- /dev/null +++ b/test/brpc_mcpack2pb_unittest.cpp @@ -0,0 +1,79 @@ +// 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, 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 From ca370c28a905a387e482ee6deae446ac82a6464a Mon Sep 17 00:00:00 2001 From: Weibing Wang Date: Sun, 16 Aug 2026 01:08:30 +0800 Subject: [PATCH 21/48] Fix RTMP abort message deleting the chunk stream being parsed (#3452) * Fix RTMP abort message deleting the chunk stream being parsed * Address review comments on RTMP abort regression test --- src/brpc/policy/rtmp_protocol.cpp | 7 +++- test/brpc_rtmp_unittest.cpp | 59 +++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/brpc/policy/rtmp_protocol.cpp b/src/brpc/policy/rtmp_protocol.cpp index 62322018d1..c5ece81ae1 100644 --- a/src/brpc/policy/rtmp_protocol.cpp +++ b/src/brpc/policy/rtmp_protocol.cpp @@ -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; } 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; From 552bfd6e25b373f16fd0775d9de1ffcd8272b250 Mon Sep 17 00:00:00 2001 From: Weibing Wang Date: Sun, 16 Aug 2026 01:08:59 +0800 Subject: [PATCH 22/48] Fix SOFA PBRPC parser not limiting metadata size (#3449) ParseSofaMessage only checked body_size against max_body_size, while meta_size and the total frame size were left unbounded. A frame with a large meta_size and zero body_size passed the body_size check and made the connection keep buffering far beyond the configured limit before the invalid metadata was rejected. Bound meta_size by max_body_size as well, consistent with other protocols such as baidu_std and hulu_pbrpc. Add unit tests covering oversized body and oversized metadata. --- src/brpc/policy/sofa_pbrpc_protocol.cpp | 9 ++--- test/brpc_sofa_pbrpc_protocol_unittest.cpp | 42 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/brpc/policy/sofa_pbrpc_protocol.cpp b/src/brpc/policy/sofa_pbrpc_protocol.cpp index 01b21851d5..328ae4aa38 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); 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 From 48db968fa02a325e7cbee0b81e6f129e9d2d104e Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Sun, 16 Aug 2026 10:29:58 +0800 Subject: [PATCH 23/48] Refactor NULL with nullptr in butil (#3444) --- src/butil/arena.cpp | 16 +-- src/butil/arena.h | 2 +- src/butil/at_exit.cc | 2 +- src/butil/binary_printer.h | 4 +- src/butil/bit_array.h | 2 +- src/butil/class_name.cpp | 6 +- src/butil/comlog_sink.cc | 12 +- src/butil/comlog_sink.h | 2 +- src/butil/endpoint.cpp | 36 ++--- src/butil/endpoint.h | 10 +- src/butil/environment.cc | 6 +- src/butil/environment.h | 2 +- src/butil/file_util.cc | 10 +- src/butil/file_util.h | 12 +- src/butil/file_util_mac.mm | 2 +- src/butil/file_util_posix.cc | 8 +- src/butil/gperftools_profiler.h | 2 +- src/butil/iobuf.cpp | 130 ++++++++--------- src/butil/iobuf.h | 18 +-- src/butil/iobuf_inl.h | 28 ++-- src/butil/iobuf_profiler.cpp | 10 +- src/butil/iobuf_profiler.h | 4 +- src/butil/lazy_instance.h | 4 +- src/butil/location.cc | 4 +- src/butil/logging.cc | 132 +++++++++--------- src/butil/logging.h | 10 +- src/butil/object_pool.h | 2 +- src/butil/object_pool_inl.h | 64 ++++----- src/butil/observer_list.h | 8 +- src/butil/popen.cpp | 8 +- src/butil/ptr_container.h | 8 +- src/butil/recordio.cc | 16 +-- src/butil/recordio.h | 4 +- src/butil/resource_pool.h | 6 +- src/butil/resource_pool_inl.h | 66 ++++----- src/butil/safe_strerror_posix.cc | 2 +- src/butil/scoped_lock.h | 16 +-- src/butil/shared_object.h | 2 +- src/butil/single_iobuf.cpp | 48 +++---- src/butil/single_iobuf.h | 2 +- src/butil/single_threaded_pool.h | 16 +-- src/butil/ssl_compat.h | 146 ++++++++++---------- src/butil/status.cpp | 24 ++-- src/butil/status.h | 24 ++-- src/butil/stl_util.h | 10 +- src/butil/string_splitter.h | 6 +- src/butil/string_splitter_inl.h | 48 +++---- src/butil/synchronous_event.h | 14 +- src/butil/thread_key.cpp | 12 +- src/butil/thread_key.h | 12 +- src/butil/thread_local.cpp | 14 +- src/butil/thread_local.h | 3 +- src/butil/thread_local_inl.h | 6 +- src/butil/time.cpp | 4 +- src/butil/time.h | 2 +- src/butil/zero_copy_stream_as_streambuf.cpp | 8 +- 56 files changed, 537 insertions(+), 538 deletions(-) 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/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/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/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 d561d3fd3e..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,19 +455,19 @@ 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 LocalPool(this); @@ -480,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) { @@ -509,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) { @@ -593,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/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/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/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); } } From 9aa41f79f2bc39ad081e8e2ab80fe3b4dead328b Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang Date: Sun, 16 Aug 2026 15:22:43 +0800 Subject: [PATCH 24/48] Support flow-controlled gRPC client requests (#3430) * Support flow-controlled gRPC client requests - Split client request DATA frames according to the peer's connection and stream flow-control windows. - Buffer unsent DATA and resume transmission when WINDOW_UPDATE restores capacity. - Track pending request bytes per H2 connection and apply socket_max_unwritten_bytes as an upper bound. - Reject or reroute new requests once the pending DATA limit is reached. - Release buffered DATA when an RPC fails, times out, or its stream is removed. - Add tests for fragmented transmission, deferred DATA flushing, pending-byte accounting, and buffer cleanup. * Fix pending HTTP/2 data limit race - Check pending DATA capacity atomically with client stream insertion. - Leave stream and window state unchanged when the limit is exceeded. - Use an ephemeral port in the gRPC flow-control test. - Avoid accessing an empty payload buffer in H2 frame tests. --- src/brpc/policy/http2_rpc_protocol.cpp | 395 ++++++++++++++++------- src/brpc/policy/http2_rpc_protocol.h | 26 +- test/brpc_grpc_protocol_unittest.cpp | 50 +++ test/brpc_h2_unsent_message_unittest.cpp | 212 ++++++++++++ test/brpc_http_rpc_protocol_unittest.cpp | 22 +- 5 files changed, 566 insertions(+), 139 deletions(-) diff --git a/src/brpc/policy/http2_rpc_protocol.cpp b/src/brpc/policy/http2_rpc_protocol.cpp index d527a055c2..eb0e35317d 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; @@ -323,20 +325,19 @@ inline H2Context::FrameHandler FindFrameHandler(H2FrameType 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,6 +371,16 @@ 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; { @@ -377,6 +388,8 @@ H2StreamContext* H2Context::RemoveStreamAndDeferWU(int stream_id) { if (!_pending_streams.erase(stream_id, &sctx)) { return NULL; } + 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()); } } @@ -429,6 +446,9 @@ int H2Context::TryToInsertStream(int stream_id, H2StreamContext* ctx) { } H2StreamContext*& sctx = _pending_streams[stream_id]; if (sctx == NULL) { + // 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; } @@ -872,43 +892,27 @@ H2ParseResult H2Context::OnSettings( _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 { + 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,6 +923,9 @@ H2ParseResult H2Context::OnSettings( LOG(WARNING) << "Fail to respond settings with ack to " << *_socket; return MakeH2Error(H2_PROTOCOL_ERROR); } + if (window_diff > 0 && !FlushPendingData(0)) { + return MakeH2Error(H2_PROTOCOL_ERROR); + } return MakeH2Message(NULL); } @@ -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); } 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); } } 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'; } @@ -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(); @@ -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; if (_stream_id != 0) { H2Context* ctx = static_cast(sending_sock->parsing_context()); + ctx->ClearPendingData(_stream_id); ctx->AddAbandonedStream(_stream_id); } } @@ -1534,11 +1684,6 @@ 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); @@ -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(); } @@ -1821,7 +1967,8 @@ 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( diff --git a/src/brpc/policy/http2_rpc_protocol.h b/src/brpc/policy/http2_rpc_protocol.h index b4422ee057..27055ae9a5 100644 --- a/src/brpc/policy/http2_rpc_protocol.h +++ b/src/brpc/policy/http2_rpc_protocol.h @@ -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(); @@ -319,7 +320,7 @@ class H2Context : public Destroyable, public Describable { // main_socket: the socket owns this object as parsing_context // server: NULL 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/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 6735a171b1..706913140f 100644 --- a/test/brpc_http_rpc_protocol_unittest.cpp +++ b/test/brpc_http_rpc_protocol_unittest.cpp @@ -1643,12 +1643,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"; @@ -1762,7 +1762,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; @@ -1780,6 +1780,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); @@ -1789,15 +1791,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); } } From 137c1ca30487811149a5d36da4c096c69a6d5c73 Mon Sep 17 00:00:00 2001 From: Weibing Wang Date: Sun, 16 Aug 2026 17:31:23 +0800 Subject: [PATCH 25/48] Revert "Progressive timeout dev (#3409)" (#3453) This reverts commit e0abb1001ef76d400dddc2b2c3a1ff42f5d3afac. --- example/http_c++/http_client.cpp | 35 --- example/http_c++/http_server.cpp | 7 - src/brpc/controller.cpp | 259 +---------------------- src/brpc/controller.h | 8 +- src/brpc/errno.proto | 1 - src/brpc/policy/http_rpc_protocol.cpp | 1 - src/brpc/policy/http_rpc_protocol.h | 12 +- src/brpc/progressive_reader.h | 2 - test/brpc_http_rpc_protocol_unittest.cpp | 237 +-------------------- 9 files changed, 5 insertions(+), 557 deletions(-) diff --git a/example/http_c++/http_client.cpp b/example/http_c++/http_client.cpp index 3a09186f84..23222dee9b 100644 --- a/example/http_c++/http_client.cpp +++ b/example/http_c++/http_client.cpp @@ -22,15 +22,11 @@ // - Access www.foo.com // ./http_client www.foo.com -#include #include #include #include -#include "bthread/countdown_event.h" DEFINE_string(d, "", "POST this data to the http server"); -DEFINE_bool(progressive, false, "whether or not progressive read data from server"); -DEFINE_int32(progressive_read_timeout_ms, 5000, "progressive read data idle timeout in milliseconds"); DEFINE_string(load_balancer, "", "The algorithm for load balancing"); DEFINE_int32(timeout_ms, 2000, "RPC timeout in milliseconds"); DEFINE_int32(max_retry, 3, "Max retries(not including the first RPC)"); @@ -40,25 +36,6 @@ namespace brpc { DECLARE_bool(http_verbose); } -class PartDataReader: public brpc::ProgressiveReader { -public: - explicit PartDataReader(bthread::CountdownEvent* done): _done(done){} - - butil::Status OnReadOnePart(const void* data, size_t length) { - const std::string part(static_cast(data), length); - LOG(INFO) << "data: " << part << " size: " << length; - return butil::Status::OK(); - } - - void OnEndOfMessage(const butil::Status& status) { - LOG(INFO) << "progressive read data final status : " << status; - _done->signal(); - delete this; - } -private: - bthread::CountdownEvent* _done; -}; - int main(int argc, char* argv[]) { // Parse gflags. We recommend you to use gflags as well. GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true); @@ -94,11 +71,6 @@ int main(int argc, char* argv[]) { cntl.request_attachment().append(FLAGS_d); } - if (FLAGS_progressive) { - cntl.set_progressive_read_timeout_ms(FLAGS_progressive_read_timeout_ms); - cntl.response_will_be_read_progressively(); - } - // Because `done'(last parameter) is NULL, this function waits until // the response comes back or error occurs(including timedout). channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); @@ -106,13 +78,6 @@ int main(int argc, char* argv[]) { std::cerr << cntl.ErrorText() << std::endl; return -1; } - - if (FLAGS_progressive) { - bthread::CountdownEvent done(1); - cntl.ReadProgressiveAttachmentBy(new PartDataReader(&done)); - done.wait(); - LOG(INFO) << "wait client progressive read done safely"; - } // If -http_verbose is on, brpc already prints the response to stderr. if (!brpc::FLAGS_http_verbose) { std::cout << cntl.response_attachment() << std::endl; diff --git a/example/http_c++/http_server.cpp b/example/http_c++/http_server.cpp index 4c3c8722fd..05c9a0ee4c 100644 --- a/example/http_c++/http_server.cpp +++ b/example/http_c++/http_server.cpp @@ -31,7 +31,6 @@ DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no " DEFINE_string(certificate, "cert.pem", "Certificate file path to enable SSL"); DEFINE_string(private_key, "key.pem", "Private key file path to enable SSL"); DEFINE_string(ciphers, "", "Cipher suite used for SSL connections"); -DEFINE_bool(enable_progressive_timeout, false, "whether or not trigger progressive write attachment data timeout"); namespace example { @@ -105,9 +104,6 @@ class FileServiceImpl : public FileService { // sleep a while to send another part. bthread_usleep(10000); - if (FLAGS_enable_progressive_timeout && i > 50) { - bthread_usleep(100000000UL); - } } return NULL; } @@ -198,9 +194,6 @@ class HttpSSEServiceImpl : public HttpSSEService { // sleep a while to send another part. bthread_usleep(10000 * 10); - if (FLAGS_enable_progressive_timeout && i > 50) { - bthread_usleep(100000000UL); - } } return NULL; } diff --git a/src/brpc/controller.cpp b/src/brpc/controller.cpp index 66a9a3a504..8a8410beb9 100644 --- a/src/brpc/controller.cpp +++ b/src/brpc/controller.cpp @@ -73,7 +73,6 @@ BAIDU_REGISTER_ERRNO(brpc::EEOF, "Got EOF"); BAIDU_REGISTER_ERRNO(brpc::EUNUSED, "The socket was not needed"); BAIDU_REGISTER_ERRNO(brpc::ESSL, "SSL related operation failed"); BAIDU_REGISTER_ERRNO(brpc::EH2RUNOUTSTREAMS, "The H2 socket was run out of streams"); -BAIDU_REGISTER_ERRNO(brpc::EPROGREADTIMEOUT, "Progressive read timed out"); BAIDU_REGISTER_ERRNO(brpc::EINTERNAL, "General internal error"); BAIDU_REGISTER_ERRNO(brpc::ERESPONSE, "Bad response"); @@ -95,9 +94,8 @@ namespace brpc { DEFINE_bool(graceful_quit_on_sigterm, false, "Register SIGTERM handle func to quit graceful"); DEFINE_bool(graceful_quit_on_sighup, false, - "Register SIGHUP handle func to quit graceful"); -DEFINE_bool(log_idle_progressive_read_close, false, - "Print log when an idle progressive read is closed"); + "Register SIGHUP handle func to quit graceful"); + const IdlNames idl_single_req_single_res = { "req", "res" }; const IdlNames idl_single_req_multi_res = { "req", "" }; const IdlNames idl_multi_req_single_res = { "", "res" }; @@ -176,226 +174,6 @@ class IgnoreAllRead : public ProgressiveReader { void OnEndOfMessage(const butil::Status&) {} }; -struct ProgressiveReadTimeoutTask; - -struct ProgressiveReadTimeoutState { - ProgressiveReadTimeoutState(SocketId id, int32_t timeout_ms) - : socket_id(id) - , read_timeout_ms(timeout_ms) - , deadline_us(butil::cpuwide_time_us() + timeout_ms * 1000L) - , timer_id(0) - , timer_task(NULL) - , user_callback_running(false) - , reader_failed(false) - , timeout_triggered(false) - , end_delivered(false) {} - - butil::Mutex mutex; - const SocketId socket_id; - const int32_t read_timeout_ms; - int64_t deadline_us; - bthread_timer_t timer_id; - ProgressiveReadTimeoutTask* timer_task; - bool user_callback_running; - bool reader_failed; - bool timeout_triggered; - bool end_delivered; - butil::Status timer_error; -}; - -struct ProgressiveReadTimeoutTask { - explicit ProgressiveReadTimeoutTask( - const std::shared_ptr& state_in) - : state(state_in) {} - - std::shared_ptr state; -}; - -class ProgressiveTimeoutReader : public ProgressiveReader { -public: - ProgressiveTimeoutReader(SocketId id, int32_t read_timeout_ms, - ProgressiveReader* reader) - : _reader(reader) - , _state(new ProgressiveReadTimeoutState(id, read_timeout_ms)) {} - - int Start() { - std::unique_lock mu(_state->mutex); - return AddWatchdogLocked(_state, _state->read_timeout_ms * 1000L); - } - - butil::Status OnReadOnePart(const void* data, size_t length) override { - { - std::unique_lock mu(_state->mutex); - if (_state->timeout_triggered) { - return MakeTimeoutStatus(_state->read_timeout_ms); - } - if (!_state->timer_error.ok()) { - return _state->timer_error; - } - _state->user_callback_running = true; - } - - butil::Status status = _reader->OnReadOnePart(data, length); - { - std::unique_lock mu(_state->mutex); - _state->user_callback_running = false; - if (_state->timeout_triggered) { - status = MakeTimeoutStatus(_state->read_timeout_ms); - } else if (!_state->timer_error.ok()) { - status = _state->timer_error; - } else if (status.ok() && !_state->end_delivered) { - _state->deadline_us = butil::cpuwide_time_us() + - _state->read_timeout_ms * 1000L; - } else if (!status.ok()) { - _state->reader_failed = true; - } - } - return status; - } - - void OnEndOfMessage(const butil::Status& status) override { - bthread_timer_t timer_id = 0; - ProgressiveReadTimeoutTask* timer_task = NULL; - butil::Status final_status = status; - ProgressiveReader* reader = NULL; - { - std::unique_lock mu(_state->mutex); - if (_state->end_delivered) { - LOG(ERROR) << "ProgressiveReader::OnEndOfMessage was called more than once"; - return; - } - _state->end_delivered = true; - timer_id = _state->timer_id; - timer_task = _state->timer_task; - _state->timer_id = 0; - _state->timer_task = NULL; - if (_state->timeout_triggered) { - final_status = MakeTimeoutStatus(_state->read_timeout_ms); - } else if (!_state->timer_error.ok()) { - final_status = _state->timer_error; - } - reader = _reader; - _reader = NULL; - } - - CancelWatchdog(timer_id, timer_task); - reader->OnEndOfMessage(final_status); - delete this; - } - -private: - ~ProgressiveTimeoutReader() override {} - - static butil::Status MakeTimeoutStatus(int32_t timeout_ms) { - return butil::Status( - EPROGREADTIMEOUT, - "Progressive read timed out after %d ms", timeout_ms); - } - - static butil::Status MakeTimerErrorStatus(int error_code) { - return butil::Status( - error_code, "Fail to add progressive read timeout timer: %s", - berror(error_code)); - } - - static void CancelWatchdog( - bthread_timer_t timer_id, ProgressiveReadTimeoutTask* timer_task) { - if (timer_id == 0) { - return; - } - const int rc = bthread_timer_del(timer_id); - if (rc == 0) { - delete timer_task; - } else if (rc == 1 || rc == EINVAL) { - // The callback owns timer_task once it starts running. EINVAL means - // that the callback has already finished and released the task. - } else { - LOG(ERROR) << "Unexpected bthread_timer_del error=" << rc; - } - } - - static int AddWatchdogLocked( - const std::shared_ptr& state, - int64_t delay_us) { - if (state->end_delivered || state->reader_failed) { - return ECANCELED; - } - if (delay_us <= 0) { - delay_us = 1; - } - ProgressiveReadTimeoutTask* task = - new (std::nothrow) ProgressiveReadTimeoutTask(state); - if (task == NULL) { - return ENOMEM; - } - bthread_timer_t timer_id = 0; - const int rc = bthread_timer_add( - &timer_id, butil::microseconds_from_now(delay_us), - HandleIdleProgressiveReader, task); - if (rc != 0) { - delete task; - return rc; - } - state->timer_id = timer_id; - state->timer_task = task; - return 0; - } - - static void HandleIdleProgressiveReader(void* arg) { - std::unique_ptr task( - static_cast(arg)); - const std::shared_ptr state = task->state; - bool fail_socket = false; - int error_code = 0; - std::string error_text; - { - std::unique_lock mu(state->mutex); - if (state->timer_task == task.get()) { - state->timer_id = 0; - state->timer_task = NULL; - } - if (state->end_delivered || state->reader_failed) { - return; - } - - const int64_t now_us = butil::cpuwide_time_us(); - if (state->user_callback_running || now_us < state->deadline_us) { - const int64_t delay_us = state->user_callback_running - ? state->read_timeout_ms * 1000L - : state->deadline_us - now_us; - const int rc = AddWatchdogLocked(state, delay_us); - if (rc != 0) { - state->timer_error = MakeTimerErrorStatus(rc); - fail_socket = true; - error_code = rc; - error_text = state->timer_error.error_str(); - } - } else { - state->timeout_triggered = true; - fail_socket = true; - error_code = EPROGREADTIMEOUT; - error_text = MakeTimeoutStatus(state->read_timeout_ms).error_str(); - } - } - - if (!fail_socket) { - return; - } - SocketUniquePtr socket; - if (Socket::Address(state->socket_id, &socket) != 0) { - LOG(ERROR) << "Fail to address socket_id=" << state->socket_id - << " after progressive read timeout"; - } else { - LOG_IF(INFO, FLAGS_log_idle_progressive_read_close) - << error_text << ", socket_id=" << state->socket_id; - socket->SetFailed(error_code, "%s", error_text.c_str()); - } - } - - ProgressiveReader* _reader; - const std::shared_ptr _state; -}; - static IgnoreAllRead* s_ignore_all_read = NULL; static pthread_once_t s_ignore_all_read_once = PTHREAD_ONCE_INIT; static void CreateIgnoreAllRead() { s_ignore_all_read = new IgnoreAllRead; } @@ -483,7 +261,6 @@ void Controller::ResetPods() { _backup_request_ms = UNSET_MAGIC_NUM; _backup_request_policy = NULL; _connect_timeout_ms = UNSET_MAGIC_NUM; - _progressive_read_timeout_ms = UNSET_MAGIC_NUM; _real_timeout_ms = UNSET_MAGIC_NUM; _deadline_us = -1; _timeout_id = 0; @@ -559,11 +336,6 @@ void Controller::Call::Reset() { stream_user_data = NULL; } -void Controller::set_progressive_read_timeout_ms( - int32_t progressive_read_timeout_ms) { - _progressive_read_timeout_ms = progressive_read_timeout_ms; -} - void Controller::set_timeout_ms(int64_t timeout_ms) { if (timeout_ms <= 0x7fffffff) { _timeout_ms = timeout_ms; @@ -1841,33 +1613,6 @@ void Controller::ReadProgressiveAttachmentBy(ProgressiveReader* r) { __FUNCTION__)); } add_flag(FLAGS_PROGRESSIVE_READER); - if (progressive_read_timeout_ms() > 0) { - const SocketId socket_id = _rpa->GetSocketId(); - if (socket_id == INVALID_SOCKET_ID) { - pthread_once(&s_ignore_all_read_once, CreateIgnoreAllRead); - _rpa->ReadProgressiveAttachmentBy(s_ignore_all_read); - return r->OnEndOfMessage(butil::Status( - ENOTSUP, - "Progressive read timeout is only supported for HTTP/1.x")); - } - ProgressiveTimeoutReader* reader = new (std::nothrow) - ProgressiveTimeoutReader( - socket_id, _progressive_read_timeout_ms, r); - if (reader == NULL) { - pthread_once(&s_ignore_all_read_once, CreateIgnoreAllRead); - _rpa->ReadProgressiveAttachmentBy(s_ignore_all_read); - return r->OnEndOfMessage( - butil::Status(ENOMEM, "Fail to create progressive timeout reader")); - } - const int rc = reader->Start(); - if (rc != 0) { - pthread_once(&s_ignore_all_read_once, CreateIgnoreAllRead); - _rpa->ReadProgressiveAttachmentBy(s_ignore_all_read); - return reader->OnEndOfMessage(butil::Status( - rc, "Fail to add progressive read timeout timer: %s", berror(rc))); - } - return _rpa->ReadProgressiveAttachmentBy(reader); - } return _rpa->ReadProgressiveAttachmentBy(r); } diff --git a/src/brpc/controller.h b/src/brpc/controller.h index 41d42ae712..564c0875e1 100644 --- a/src/brpc/controller.h +++ b/src/brpc/controller.h @@ -199,9 +199,6 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); // Set/get timeout in milliseconds for the RPC call. Use // ChannelOptions.timeout_ms on unset. - void set_progressive_read_timeout_ms(int32_t progressive_read_timeout_ms); - int32_t progressive_read_timeout_ms() const { return _progressive_read_timeout_ms; } - void set_timeout_ms(int64_t timeout_ms); int64_t timeout_ms() const { return _timeout_ms; } @@ -364,9 +361,7 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); // Make the RPC end when the HTTP response has complete headers and let // user read the remaining body by using ReadProgressiveAttachmentBy(). - void response_will_be_read_progressively() { - add_flag(FLAGS_READ_PROGRESSIVELY); - } + void response_will_be_read_progressively() { add_flag(FLAGS_READ_PROGRESSIVELY); } // Make the RPC end when the HTTP request has complete headers and let // user read the remaining body by using ReadProgressiveAttachmentBy(). void request_will_be_read_progressively() { add_flag(FLAGS_READ_PROGRESSIVELY); } @@ -916,7 +911,6 @@ friend void policy::ProcessThriftRequest(InputMessageBase*); int32_t _timeout_ms; int32_t _connect_timeout_ms; int32_t _backup_request_ms; - int32_t _progressive_read_timeout_ms; // Priority: `_backup_request_policy' > `_backup_request_ms'. BackupRequestPolicy* _backup_request_policy; // If this rpc call has retry/backup request,this var save the real timeout for current call diff --git a/src/brpc/errno.proto b/src/brpc/errno.proto index 166d82dc4a..26ffadc201 100644 --- a/src/brpc/errno.proto +++ b/src/brpc/errno.proto @@ -41,7 +41,6 @@ enum Errno { ESSL = 1016; // SSL related error EH2RUNOUTSTREAMS = 1017; // The H2 socket was run out of streams EREJECT = 1018; // The Request is rejected - EPROGREADTIMEOUT = 1019; // The Progressive read timeout // Errno caused by server EINTERNAL = 2001; // Internal Server Error diff --git a/src/brpc/policy/http_rpc_protocol.cpp b/src/brpc/policy/http_rpc_protocol.cpp index 3fb9408850..8cbe06980f 100644 --- a/src/brpc/policy/http_rpc_protocol.cpp +++ b/src/brpc/policy/http_rpc_protocol.cpp @@ -1201,7 +1201,6 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket, LOG(FATAL) << "Fail to new HttpContext"; return MakeParseError(PARSE_ERROR_NO_RESOURCE); } - http_imsg->SetSocketId(socket->id()); // 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 diff --git a/src/brpc/policy/http_rpc_protocol.h b/src/brpc/policy/http_rpc_protocol.h index cd41798e9f..bc8bd06593 100644 --- a/src/brpc/policy/http_rpc_protocol.h +++ b/src/brpc/policy/http_rpc_protocol.h @@ -87,20 +87,11 @@ class HttpContext : public ReadableProgressiveAttachment , public InputMessageBase , public HttpMessage { public: - SocketId GetSocketId() override { - return _socket_id; - } - - void SetSocketId(SocketId id) { - _socket_id = id; - } - explicit HttpContext(bool read_body_progressively, HttpMethod request_method = HTTP_METHOD_GET) : InputMessageBase() , HttpMessage(read_body_progressively, request_method) - , _is_stage2(false) - , _socket_id(INVALID_SOCKET_ID) { + , _is_stage2(false) { // add one ref for Destroy butil::intrusive_ptr(this).detach(); } @@ -131,7 +122,6 @@ class HttpContext : public ReadableProgressiveAttachment private: bool _is_stage2; - SocketId _socket_id; }; // Implement functions required in protocol.h diff --git a/src/brpc/progressive_reader.h b/src/brpc/progressive_reader.h index c84be8b7e7..6f54ae68a7 100644 --- a/src/brpc/progressive_reader.h +++ b/src/brpc/progressive_reader.h @@ -20,7 +20,6 @@ #define BRPC_PROGRESSIVE_READER_H #include "brpc/shared_object.h" -#include "brpc/socket_id.h" namespace brpc { @@ -85,7 +84,6 @@ class ReadableProgressiveAttachment : public SharedObject { // Any error occurred should destroy the reader by calling r->Destroy(). // r->Destroy() should be guaranteed to be called once and only once. virtual void ReadProgressiveAttachmentBy(ProgressiveReader* r) = 0; - virtual SocketId GetSocketId() = 0; }; } // namespace brpc diff --git a/test/brpc_http_rpc_protocol_unittest.cpp b/test/brpc_http_rpc_protocol_unittest.cpp index 706913140f..97de699547 100644 --- a/test/brpc_http_rpc_protocol_unittest.cpp +++ b/test/brpc_http_rpc_protocol_unittest.cpp @@ -19,7 +19,6 @@ // Date: Sun Jul 13 15:04:18 CST 2014 -#include #include #include #include @@ -737,13 +736,9 @@ static void CopyPAPrefixedWithSeqNo(char* buf, uint64_t seq_no) { class DownloadServiceImpl : public ::test::DownloadService { public: DownloadServiceImpl(DonePlace done_place = DONE_BEFORE_CREATE_PA, - size_t num_repeat = 1, - int write_interval_us = 0, - int initial_write_delay_us = 0) + size_t num_repeat = 1) : _done_place(done_place) , _nrep(num_repeat) - , _write_interval_us(write_interval_us) - , _initial_write_delay_us(initial_write_delay_us) , _nwritten(0) , _ever_full(false) , _last_errno(0) {} @@ -767,9 +762,6 @@ class DownloadServiceImpl : public ::test::DownloadService { if (_done_place == DONE_BEFORE_CREATE_PA) { done_guard.reset(NULL); } - if (_initial_write_delay_us > 0) { - bthread_usleep(_initial_write_delay_us); - } ASSERT_GT(PA_DATA_LEN, 8u); // long enough to hold a 64-bit decimal. char buf[PA_DATA_LEN]; for (size_t c = 0; c < _nrep;) { @@ -786,9 +778,6 @@ class DownloadServiceImpl : public ::test::DownloadService { } } else { _nwritten += PA_DATA_LEN; - if (_write_interval_us > 0) { - bthread_usleep(_write_interval_us); - } } ++c; } @@ -851,8 +840,6 @@ class DownloadServiceImpl : public ::test::DownloadService { private: DonePlace _done_place; size_t _nrep; - int _write_interval_us; - int _initial_write_delay_us; size_t _nwritten; bool _ever_full; int _last_errno; @@ -954,47 +941,6 @@ class ReadBody : public brpc::ProgressiveReader, butil::Status _destroying_st; }; -class TimeoutReadBody : public brpc::ProgressiveReader, - public brpc::SharedObject { -public: - explicit TimeoutReadBody(int read_delay_us = 0, int read_error = 0) - : _read_delay_us(read_delay_us) - , _read_error(read_error) - , _nread(0) - , _nend(0) - , _end_error(0) { - butil::intrusive_ptr(this).detach(); - } - - butil::Status OnReadOnePart(const void*, size_t length) override { - if (_read_delay_us > 0) { - bthread_usleep(_read_delay_us); - } - _nread.fetch_add(length); - if (_read_error != 0) { - return butil::Status(_read_error, "intended progressive read failure"); - } - return butil::Status::OK(); - } - - void OnEndOfMessage(const butil::Status& status) override { - _end_error.store(status.error_code()); - _nend.fetch_add(1); - butil::intrusive_ptr(this, false); - } - - size_t read_bytes() const { return _nread.load(); } - int end_count() const { return _nend.load(); } - int end_error() const { return _end_error.load(); } - -private: - const int _read_delay_us; - const int _read_error; - std::atomic _nread; - std::atomic _nend; - std::atomic _end_error; -}; - #ifdef BUTIL_USE_ASAN static const int GENERAL_DELAY_US = 1000000; // 1s #else @@ -1088,187 +1034,6 @@ TEST_F(HttpTest, read_short_body_progressively) { } } -TEST_F(HttpTest, progressive_read_timeout_keeps_active_reader_alive) { - const int port = 8923; - brpc::Server server; - DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 8, 100000); - ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(port, NULL)); - - brpc::Channel channel; - brpc::ChannelOptions options; - options.protocol = brpc::PROTOCOL_HTTP; - ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - - brpc::Controller cntl; - cntl.response_will_be_read_progressively(); - cntl.set_progressive_read_timeout_ms(500); - cntl.http_request().uri() = "/DownloadService/Download"; - channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - - butil::intrusive_ptr reader(new TimeoutReadBody); - cntl.ReadProgressiveAttachmentBy(reader.get()); - for (int i = 0; i < 200 && reader->end_count() == 0; ++i) { - bthread_usleep(10000); - } - ASSERT_EQ(1, reader->end_count()); - EXPECT_EQ(0, reader->end_error()); - EXPECT_EQ(8 * PA_DATA_LEN, reader->read_bytes()); -} - -TEST_F(HttpTest, progressive_read_timeout_closes_idle_http1_reader_once) { - const int port = 8923; - brpc::Server server; - DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 2, 300000); - ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(port, NULL)); - - butil::intrusive_ptr reader(new TimeoutReadBody); - { - brpc::Channel channel; - brpc::ChannelOptions options; - options.protocol = brpc::PROTOCOL_HTTP; - ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - { - brpc::Controller cntl; - cntl.response_will_be_read_progressively(); - cntl.set_progressive_read_timeout_ms(50); - cntl.http_request().uri() = "/DownloadService/Download"; - channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - cntl.ReadProgressiveAttachmentBy(reader.get()); - bthread_usleep(400000); - ASSERT_NE(0, svc.last_errno()); - EXPECT_EQ(0, reader->end_count()); - } - } - for (int i = 0; i < 100 && reader->end_count() == 0; ++i) { - bthread_usleep(10000); - } - ASSERT_EQ(1, reader->end_count()); - EXPECT_EQ(brpc::EPROGREADTIMEOUT, reader->end_error()); - bthread_usleep(400000); - EXPECT_EQ(1, reader->end_count()); -} - -TEST_F(HttpTest, progressive_read_timeout_before_first_body_part) { - const int port = 8923; - brpc::Server server; - DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 1, 0, 300000); - ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(port, NULL)); - - butil::intrusive_ptr reader(new TimeoutReadBody); - { - brpc::Channel channel; - brpc::ChannelOptions options; - options.protocol = brpc::PROTOCOL_HTTP; - ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - { - brpc::Controller cntl; - cntl.response_will_be_read_progressively(); - cntl.set_progressive_read_timeout_ms(50); - cntl.http_request().uri() = "/DownloadService/Download"; - channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - cntl.ReadProgressiveAttachmentBy(reader.get()); - bthread_usleep(400000); - ASSERT_NE(0, svc.last_errno()); - EXPECT_EQ(size_t(0), reader->read_bytes()); - EXPECT_EQ(0, reader->end_count()); - } - } - for (int i = 0; i < 100 && reader->end_count() == 0; ++i) { - bthread_usleep(10000); - } - ASSERT_EQ(1, reader->end_count()); - EXPECT_EQ(brpc::EPROGREADTIMEOUT, reader->end_error()); -} - -TEST_F(HttpTest, progressive_read_timeout_ignores_slow_user_callback) { - const int port = 8923; - brpc::Server server; - DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 3, 50000); - ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(port, NULL)); - - brpc::Channel channel; - brpc::ChannelOptions options; - options.protocol = brpc::PROTOCOL_HTTP; - ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - - brpc::Controller cntl; - cntl.response_will_be_read_progressively(); - cntl.set_progressive_read_timeout_ms(50); - cntl.http_request().uri() = "/DownloadService/Download"; - channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - - butil::intrusive_ptr reader( - new TimeoutReadBody(200000)); - cntl.ReadProgressiveAttachmentBy(reader.get()); - for (int i = 0; i < 100 && reader->end_count() == 0; ++i) { - bthread_usleep(10000); - } - ASSERT_EQ(1, reader->end_count()); - EXPECT_EQ(0, reader->end_error()); - EXPECT_EQ(3 * PA_DATA_LEN, reader->read_bytes()); -} - -TEST_F(HttpTest, progressive_read_timeout_preserves_reader_error) { - const int port = 8923; - brpc::Server server; - DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, 10); - ASSERT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(port, NULL)); - - brpc::Channel channel; - brpc::ChannelOptions options; - options.protocol = brpc::PROTOCOL_HTTP; - ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - - brpc::Controller cntl; - cntl.response_will_be_read_progressively(); - cntl.set_progressive_read_timeout_ms(1000); - cntl.http_request().uri() = "/DownloadService/Download"; - channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - - butil::intrusive_ptr reader( - new TimeoutReadBody(0, EIO)); - cntl.ReadProgressiveAttachmentBy(reader.get()); - ASSERT_EQ(1, reader->end_count()); - EXPECT_EQ(EIO, reader->end_error()); -} - -TEST_F(HttpTest, progressive_read_timeout_rejects_http2) { - const int port = 8923; - brpc::Server server; - ASSERT_EQ(0, server.AddService(&_svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(port, NULL)); - - brpc::Channel channel; - brpc::ChannelOptions options; - options.protocol = brpc::PROTOCOL_H2; - ASSERT_EQ(0, channel.Init(butil::EndPoint(butil::my_ip(), port), &options)); - - brpc::Controller cntl; - cntl.response_will_be_read_progressively(); - cntl.set_progressive_read_timeout_ms(1000); - cntl.http_request().uri() = "/EchoService/Echo"; - test::EchoRequest req; - req.set_message(EXP_REQUEST); - channel.CallMethod(NULL, &cntl, &req, NULL, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - - butil::intrusive_ptr reader(new TimeoutReadBody); - cntl.ReadProgressiveAttachmentBy(reader.get()); - ASSERT_EQ(1, reader->end_count()); - EXPECT_EQ(ENOTSUP, reader->end_error()); - EXPECT_EQ(size_t(0), reader->read_bytes()); -} - TEST_F(HttpTest, read_progressively_after_cntl_destroys) { DownloadServiceImpl svc(DONE_BEFORE_CREATE_PA, std::numeric_limits::max()); From 7f6466313574b7e9159f3a81fddc1d1288400003 Mon Sep 17 00:00:00 2001 From: nas <156536069+Nas01010101@users.noreply.github.com> Date: Sun, 16 Aug 2026 05:39:37 -0400 Subject: [PATCH 26/48] Fix WeightedRandomizedLoadBalancer skipping the last server (#3426) * fix WeightedRandomizedLoadBalancer skipping the last server SelectServer() draws random_weight from fast_rand_less_than(weight_sum), i.e. from [0, weight_sum - 1], and then lower_bound()s it against Server::current_weight_sum, which Add() fills with an inclusive prefix sum. lower_bound() returns the first server whose prefix sum is >= random_weight, but a server owns the half-open range [prefix(i-1), prefix(i)), so the predicate has to be > random_weight. Because of that the first server in the list also serves random_weight == prefix(0) and the last server never serves anything at all, since random_weight can never reach weight_sum. With four servers of equal weight the measured distribution is 49.8/25.1/25.1/0.0 percent instead of 25 percent each. Search for random_weight + 1 so that lower_bound() lands on the first prefix sum strictly greater than random_weight. The existing weighted_randomized test does not catch this: its servers have weights 3/2/5/10 and it only asserts that each rate is within 0.5x~2x of the expected one. The weight-10 server measures 0.448 before this change and 0.494 after it, both inside that band. Add weighted_randomized_equal_weight, which uses equal weights so that a single misplaced slot is visible, and check the rates within 0.9x~1.1x. Signed-off-by: Anas <156536069+Nas01010101@users.noreply.github.com> * use upper_bound for the weighted prefix-sum search upper_bound(random_weight) states the intent directly: the first server whose inclusive prefix sum is strictly greater than random_weight. It is the same search as lower_bound(random_weight + 1) without the increment. Also correct the tolerance comment in the unit test: with run_times=40000 and p=0.25 the count has sigma ~= 86.6, so the 0.9x~1.1x band is about 11 sigma, not more than 20. --------- Signed-off-by: Anas <156536069+Nas01010101@users.noreply.github.com> --- .../weighted_randomized_load_balancer.cpp | 4 +- test/brpc_load_balancer_unittest.cpp | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/brpc/policy/weighted_randomized_load_balancer.cpp b/src/brpc/policy/weighted_randomized_load_balancer.cpp index 46923acb86..d2786ed8bf 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)) { 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", From 96ce9f11eef0a9d05f9ed8e910ffac7df8afa5bd Mon Sep 17 00:00:00 2001 From: Weibing Wang Date: Sun, 16 Aug 2026 18:01:01 +0800 Subject: [PATCH 27/48] Fix bug when parsing zero-length string field in mcpack2pb (#3450) * Fix bug when parsing zero-length string field in mcpack2pb UnparsedValue::as_string() resizes the output string to without checking , where is the value_size of a string field read from the input. When value_size is 0, underflows to SIZE_MAX and resize() throws std::length_error, which is not caught on the request path and therefore crashes the server. Reject such malformed fields by marking the stream bad so the caller can fail the request gracefully instead. * Clear output string when size error --- src/mcpack2pb/parser.cpp | 9 ++++ test/brpc_mcpack2pb_unittest.cpp | 80 ++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) 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/brpc_mcpack2pb_unittest.cpp b/test/brpc_mcpack2pb_unittest.cpp index 68de0522fe..6718cae93b 100644 --- a/test/brpc_mcpack2pb_unittest.cpp +++ b/test/brpc_mcpack2pb_unittest.cpp @@ -23,6 +23,86 @@ 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 From 7f8120a5835359823d8c384fd1d534a054bac4e2 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Tue, 18 Aug 2026 13:47:41 +0800 Subject: [PATCH 28/48] Refactor NULL with nullptr in brpc/details (#3457) --- .../details/controller_private_accessor.h | 2 +- src/brpc/details/has_epollrdhup.cpp | 3 +- src/brpc/details/health_check.cpp | 8 +- src/brpc/details/hpack.cpp | 34 ++-- src/brpc/details/http_message.cpp | 38 ++--- src/brpc/details/http_message.h | 12 +- src/brpc/details/http_parser.cpp | 4 +- src/brpc/details/jemalloc_profiler.cpp | 2 +- src/brpc/details/mesalink_ssl_helper.cpp | 46 +++--- src/brpc/details/method_status.cpp | 2 +- src/brpc/details/method_status.h | 8 +- src/brpc/details/naming_service_thread.cpp | 64 +++---- src/brpc/details/naming_service_thread.h | 2 +- src/brpc/details/server_private_accessor.h | 4 +- src/brpc/details/sparse_minute_counter.h | 4 +- src/brpc/details/ssl_helper.cpp | 156 +++++++++--------- src/brpc/details/ssl_helper.h | 2 +- src/brpc/details/tcmalloc_extension.cpp | 8 +- src/brpc/details/tcmalloc_extension.h | 10 +- src/brpc/details/usercode_backup_pool.cpp | 14 +- 20 files changed, 206 insertions(+), 217 deletions(-) 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()) { From f0f72fdaa56a81dd4f3505b22395e3bc36df784a Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Tue, 18 Aug 2026 13:50:38 +0800 Subject: [PATCH 29/48] Refactor NULL with nullptr in json2pb (#3455) --- src/json2pb/json_to_pb.cpp | 12 ++++++------ src/json2pb/json_to_pb.h | 6 +++--- src/json2pb/pb_to_json.cpp | 4 ++-- src/json2pb/pb_to_json.h | 14 +++++++------- src/json2pb/protobuf_map.cpp | 6 +++--- src/json2pb/zero_copy_stream_reader.h | 8 ++++---- src/json2pb/zero_copy_stream_writer.h | 10 +++++----- 7 files changed, 30 insertions(+), 30 deletions(-) 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; } From 3188cb587cef475f135b8159b7f67693c79b4633 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Tue, 18 Aug 2026 13:51:47 +0800 Subject: [PATCH 30/48] Refactor NULL with nullptr in brpc/builtin (#3456) --- src/brpc/builtin/bad_method_service.cpp | 4 +- src/brpc/builtin/bthreads_service.cpp | 4 +- src/brpc/builtin/common.cpp | 10 +-- src/brpc/builtin/common.h | 2 +- src/brpc/builtin/connections_service.cpp | 4 +- src/brpc/builtin/dir_service.cpp | 8 +-- src/brpc/builtin/flags_service.cpp | 4 +- src/brpc/builtin/flot_min_js.cpp | 6 +- src/brpc/builtin/get_favicon_service.cpp | 2 +- src/brpc/builtin/get_js_service.cpp | 6 +- src/brpc/builtin/hotspots_service.cpp | 72 +++++++++---------- src/brpc/builtin/ids_service.cpp | 2 +- src/brpc/builtin/index_service.cpp | 6 +- src/brpc/builtin/jquery_min_js.cpp | 6 +- src/brpc/builtin/pprof_service.cpp | 34 ++++----- .../builtin/prometheus_metrics_service.cpp | 10 +-- src/brpc/builtin/rpcz_service.cpp | 14 ++-- src/brpc/builtin/sockets_service.cpp | 2 +- src/brpc/builtin/sorttable_js.cpp | 2 +- src/brpc/builtin/vars_service.cpp | 4 +- src/brpc/builtin/viz_min_js.cpp | 6 +- 21 files changed, 104 insertions(+), 104 deletions(-) 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); From 64120a372756a540235738d92b4dd3dbef1175c2 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Tue, 18 Aug 2026 13:53:58 +0800 Subject: [PATCH 31/48] Refactor NULL with nullptr in brpc/ubshm (#3460) --- src/brpc/ubshm/common/common.h | 4 +- src/brpc/ubshm/common/thread_lock.h | 2 +- src/brpc/ubshm/shm/shm_ipc.cpp | 30 +++++------ src/brpc/ubshm/shm/shm_mgr.cpp | 4 +- src/brpc/ubshm/shm/shm_ubs.cpp | 78 ++++++++++++++--------------- src/brpc/ubshm/timer/timer_mgr.cpp | 72 +++++++++++++------------- src/brpc/ubshm/ub_endpoint.cpp | 58 ++++++++++----------- src/brpc/ubshm/ub_endpoint.h | 4 +- src/brpc/ubshm/ub_helper.cpp | 2 +- src/brpc/ubshm/ub_ring.cpp | 68 ++++++++++++------------- src/brpc/ubshm/ub_ring.h | 18 +++---- src/brpc/ubshm/ub_ring_manager.cpp | 44 ++++++++-------- src/brpc/ubshm/ubs_mem/ubs_mem.h | 2 +- 13 files changed, 193 insertions(+), 193 deletions(-) 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 b563e7f6ab..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,19 +58,19 @@ 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; @@ -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,19 +286,19 @@ 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; @@ -309,7 +309,7 @@ void DeleteTimerSafe(uint32_t fd) { } 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)) { @@ -368,18 +368,18 @@ int32_t TimerStart(const itimerspec *time, void *(*cb)(void *), void *args) { 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; } @@ -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 From 11f8192bdf3fdde9acb182e09dca0a457664af95 Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Tue, 18 Aug 2026 13:55:37 +0800 Subject: [PATCH 32/48] Refactor NULL with nullptr in brpc/rdma (#3459) --- src/brpc/rdma/block_pool.cpp | 92 +++++++-------- src/brpc/rdma/block_pool.h | 6 +- src/brpc/rdma/rdma_endpoint.cpp | 142 ++++++++++++------------ src/brpc/rdma/rdma_endpoint.h | 16 +-- src/brpc/rdma/rdma_handshake.cpp | 4 +- src/brpc/rdma/rdma_handshake.h | 2 +- src/brpc/rdma/rdma_handshake_server.cpp | 4 +- src/brpc/rdma/rdma_helper.cpp | 113 ++++++++----------- 8 files changed, 179 insertions(+), 200 deletions(-) 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 e2ce2e0c1b..fd70fb5c2b 100644 --- a/src/brpc/rdma/rdma_endpoint.cpp +++ b/src/brpc/rdma/rdma_endpoint.cpp @@ -88,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); } } @@ -113,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) @@ -160,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; @@ -187,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; @@ -223,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) { @@ -313,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) { @@ -322,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) { @@ -366,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, @@ -379,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(), @@ -428,7 +428,7 @@ 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. @@ -439,7 +439,7 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { 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 @@ -451,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. @@ -465,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) { @@ -496,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) { @@ -512,7 +512,7 @@ void* RdmaEndpoint::ProcessHandshakeAtClient(void* arg) { errno = 0; - return NULL; + return nullptr; } // Server-side handshake entry: the state machine. @@ -533,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); @@ -547,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(); @@ -611,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); } @@ -624,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); } @@ -632,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); } @@ -641,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); } @@ -718,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; @@ -817,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. @@ -867,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; @@ -970,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); @@ -1025,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; } } @@ -1101,7 +1101,7 @@ int RdmaEndpoint::DoAllocateResources() { return 0; } - CHECK(_resource == NULL); + CHECK(_resource == nullptr); if (_sq_size <= FLAGS_rdma_prepared_qp_size && _rq_size <= FLAGS_rdma_prepared_qp_size) { @@ -1114,7 +1114,7 @@ int RdmaEndpoint::DoAllocateResources() { if (!_resource) { _resource = AllocateQpCq(_sq_size, _rq_size); } else { - _resource->next = NULL; + _resource->next = nullptr; } if (!_resource) { return -1; @@ -1156,7 +1156,7 @@ int RdmaEndpoint::DoAllocateResources() { 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; } @@ -1196,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) { @@ -1262,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) { @@ -1277,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; } @@ -1286,7 +1286,7 @@ static void DeallocateCq(ibv_cq* cq) { } static int DrainCq(ibv_cq* cq) { - if (NULL == cq) { + if (nullptr == cq) { return 0; } @@ -1318,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; @@ -1349,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) { @@ -1363,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(); } @@ -1393,7 +1393,7 @@ void RdmaEndpoint::DeallocateResources() { _resource->next = g_rdma_resource_list; g_rdma_resource_list = _resource; } - _resource = NULL; + _resource = nullptr; } // Detach everything from this endpoint so that the function is @@ -1407,8 +1407,8 @@ void RdmaEndpoint::DeallocateResources() { 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) { @@ -1773,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 03bec81408..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); 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); From 3366074fa57866be96f8299f400166983aec526f Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Tue, 18 Aug 2026 22:20:53 +0800 Subject: [PATCH 33/48] Refactor NULL with nullptr in brpc/policy (#3458) * Refactor NULL with nullptr in brpc/policy * Fix NULL in mysql comments --- src/brpc/policy/auto_concurrency_limiter.cpp | 2 +- src/brpc/policy/baidu_rpc_protocol.cpp | 60 +++--- .../consistent_hashing_load_balancer.cpp | 9 +- src/brpc/policy/consul_naming_service.cpp | 2 +- src/brpc/policy/couchbase_protocol.cpp | 12 +- src/brpc/policy/crc32c_checksum.cpp | 4 +- src/brpc/policy/dh.cpp | 20 +- src/brpc/policy/dh.h | 2 +- src/brpc/policy/discovery_naming_service.cpp | 26 +-- src/brpc/policy/domain_naming_service.cpp | 16 +- src/brpc/policy/dynpart_load_balancer.cpp | 2 +- src/brpc/policy/esp_protocol.cpp | 10 +- src/brpc/policy/file_naming_service.cpp | 4 +- src/brpc/policy/giano_authenticator.cpp | 20 +- src/brpc/policy/giano_authenticator.h | 2 +- src/brpc/policy/gzip_compress.cpp | 12 +- src/brpc/policy/http2_rpc_protocol.cpp | 106 +++++------ src/brpc/policy/http2_rpc_protocol.h | 6 +- src/brpc/policy/http_rpc_protocol.cpp | 159 ++++++++-------- src/brpc/policy/hulu_pbrpc_protocol.cpp | 24 +-- src/brpc/policy/list_naming_service.cpp | 2 +- .../policy/locality_aware_load_balancer.cpp | 14 +- src/brpc/policy/memcache_binary_protocol.cpp | 12 +- src/brpc/policy/mongo_protocol.cpp | 18 +- src/brpc/policy/mysql/mysql.cpp | 42 ++--- src/brpc/policy/mysql/mysql.h | 2 +- src/brpc/policy/mysql/mysql_auth_packet.h | 10 +- src/brpc/policy/mysql/mysql_command.cpp | 4 +- src/brpc/policy/mysql/mysql_protocol.cpp | 34 ++-- src/brpc/policy/mysql/mysql_reply.cpp | 78 ++++---- src/brpc/policy/mysql/mysql_reply.h | 8 +- src/brpc/policy/mysql/mysql_statement.cpp | 2 +- src/brpc/policy/mysql/mysql_statement_inl.h | 2 +- src/brpc/policy/mysql/mysql_transaction.cpp | 14 +- src/brpc/policy/nacos_naming_service.cpp | 4 +- src/brpc/policy/nova_pbrpc_protocol.cpp | 4 +- src/brpc/policy/nshead_mcpack_protocol.cpp | 6 +- src/brpc/policy/nshead_protocol.cpp | 14 +- src/brpc/policy/p2c_ewma_load_balancer.cpp | 26 +-- src/brpc/policy/public_pbrpc_protocol.cpp | 6 +- src/brpc/policy/randomized_load_balancer.cpp | 6 +- src/brpc/policy/redis_protocol.cpp | 14 +- .../policy/remote_file_naming_service.cpp | 4 +- src/brpc/policy/round_robin_load_balancer.cpp | 6 +- src/brpc/policy/rtmp_protocol.cpp | 172 +++++++++--------- src/brpc/policy/rtmp_protocol.h | 12 +- src/brpc/policy/sofa_pbrpc_protocol.cpp | 16 +- src/brpc/policy/streaming_rpc_protocol.cpp | 14 +- src/brpc/policy/thrift_protocol.cpp | 10 +- .../policy/timeout_concurrency_limiter.cpp | 4 +- src/brpc/policy/ubrpc2pb_protocol.cpp | 40 ++-- .../weighted_randomized_load_balancer.cpp | 6 +- .../weighted_round_robin_load_balancer.cpp | 2 +- 53 files changed, 537 insertions(+), 569 deletions(-) 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 41ff97ee22..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); } @@ -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()); 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 eb0e35317d..af9ed0b151 100644 --- a/src/brpc/policy/http2_rpc_protocol.cpp +++ b/src/brpc/policy/http2_rpc_protocol.cpp @@ -318,7 +318,7 @@ 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]; } @@ -382,11 +382,11 @@ size_t H2Context::VolatilePendingStreamSize() const { } 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(); @@ -436,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) { @@ -445,7 +445,7 @@ 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); @@ -481,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( @@ -509,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); @@ -517,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); } @@ -538,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); @@ -555,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); @@ -594,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) { @@ -616,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); @@ -662,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); @@ -713,7 +713,7 @@ H2ParseResult H2StreamContext::OnContinuation( return OnEndStream(); } } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } H2ParseResult H2Context::OnData( @@ -734,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. @@ -802,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( @@ -813,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); } @@ -835,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); } @@ -845,7 +845,7 @@ H2ParseResult H2StreamContext::OnResetStream( } else { // No need to process the request. delete sctx; - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } } @@ -862,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); @@ -890,7 +890,7 @@ H2ParseResult H2Context::OnSettings( return MakeH2Error(H2_PROTOCOL_ERROR); } _local_settings = _unack_local_settings; - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } int64_t window_diff = 0; { @@ -926,7 +926,7 @@ H2ParseResult H2Context::OnSettings( if (window_diff > 0 && !FlushPendingData(0)) { return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } H2ParseResult H2Context::OnPriority( @@ -952,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]; @@ -962,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( @@ -999,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]; @@ -1017,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); } } @@ -1043,7 +1043,7 @@ H2ParseResult H2Context::OnWindowUpdate( if (!FlushPendingData(0)) { return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } else { { std::unique_lock mu(_stream_mutex); @@ -1062,7 +1062,7 @@ H2ParseResult H2Context::OnWindowUpdate( if (!FlushPendingData(frame_head.stream_id)) { return MakeH2Error(H2_PROTOCOL_ERROR); } - return MakeH2Message(NULL); + return MakeH2Message(nullptr); } } @@ -1147,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); } @@ -1167,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; } @@ -1190,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(); @@ -1199,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 @@ -1283,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; @@ -1308,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()) { @@ -1637,7 +1637,7 @@ void H2UnsentRequest::DestroyStreamUserData(SocketUniquePtr& sending_sock, 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); @@ -1658,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"); @@ -1687,7 +1687,7 @@ H2UnsentRequest::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) { // 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"); } @@ -1754,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()) { @@ -1774,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()) { @@ -1846,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()); @@ -1946,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"); @@ -1975,13 +1975,13 @@ 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 27055ae9a5..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: @@ -318,7 +318,7 @@ 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() override; // Must be called before usage. 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 c5ece81ae1..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; } @@ -1967,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; } @@ -1984,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; } @@ -2001,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; } @@ -2018,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; } @@ -2035,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; } @@ -2066,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; } @@ -2093,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; } @@ -2287,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; } @@ -2356,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]; @@ -2465,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); } } @@ -2507,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; @@ -2537,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; @@ -2582,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; } @@ -2600,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); } } @@ -2619,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 { @@ -3419,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 @@ -3454,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. } @@ -3491,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; } @@ -3500,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) @@ -3517,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) { @@ -3565,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()); } @@ -3611,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", @@ -3631,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*) { @@ -3639,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; @@ -3675,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 328ae4aa38..6b663c19f9 100644 --- a/src/brpc/policy/sofa_pbrpc_protocol.cpp +++ b/src/brpc/policy/sofa_pbrpc_protocol.cpp @@ -237,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", @@ -345,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; @@ -388,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"); @@ -409,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; @@ -509,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 429d2bc282..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); } } @@ -120,7 +120,7 @@ ParseResult ParseStreamingMessage(butil::IOBuf* source, } while (0); // Hack input messenger - return MakeMessage(NULL); + return MakeMessage(nullptr); } void ProcessStreamingMessage(InputMessageBase* /*msg*/) { @@ -128,12 +128,12 @@ void ProcessStreamingMessage(InputMessageBase* /*msg*/) { } void SendStreamRst(Socket* sock, int64_t remote_stream_id) { - CHECK(sock != NULL); + 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); @@ -141,13 +141,13 @@ void SendStreamRst(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); @@ -156,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 d2786ed8bf..0f9a339a05 100644 --- a/src/brpc/policy/weighted_randomized_load_balancer.cpp +++ b/src/brpc/policy/weighted_randomized_load_balancer.cpp @@ -155,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)) { @@ -170,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() { From 5205a9ed97eef0a702955c41030dc386494984b6 Mon Sep 17 00:00:00 2001 From: zchuango Date: Wed, 5 Aug 2026 14:56:06 +0800 Subject: [PATCH 34/48] Add URMA transport support --- .gitignore | 4 + BUILD.bazel | 13 +- CMakeLists.txt | 84 +- MODULE.bazel | 11 + Makefile | 6 + WORKSPACE | 9 +- bazel/config/BUILD.bazel | 8 +- bazel/third_party/umdk/umdk.BUILD | 28 + config_brpc.sh | 25 +- docs/cn/urma.md | 149 ++ docs/en/urma.md | 161 ++ example/cmake/BrpcExample.cmake | 59 +- example/urma_performance/CMakeLists.txt | 43 + example/urma_performance/client.cpp | 156 ++ example/urma_performance/server.cpp | 96 ++ example/urma_performance/test.proto | 34 + src/brpc/channel.cpp | 2 + src/brpc/channel.h | 3 +- src/brpc/input_messenger.cpp | 10 +- src/brpc/input_messenger.h | 6 + src/brpc/server.h | 2 +- src/brpc/socket.h | 18 + src/brpc/socket_mode.h | 8 +- src/brpc/transport_factory.cpp | 44 +- src/brpc/transport_factory.h | 11 +- src/brpc/urma/mock_urma.cpp | 713 +++++++++ src/brpc/urma/urma_bonding.h | 35 + src/brpc/urma/urma_endpoint.cpp | 1846 +++++++++++++++++++++++ src/brpc/urma/urma_endpoint.h | 355 +++++ src/brpc/urma/urma_handshake.cpp | 356 +++++ src/brpc/urma/urma_handshake.h | 180 +++ src/brpc/urma/urma_handshake.proto | 47 + src/brpc/urma/urma_helper.cpp | 788 ++++++++++ src/brpc/urma/urma_helper.h | 119 ++ src/brpc/urma_transport.cpp | 248 +++ src/brpc/urma_transport.h | 84 ++ test/brpc_urma_unittest.cpp | 609 ++++++++ 37 files changed, 6331 insertions(+), 39 deletions(-) create mode 100644 bazel/third_party/umdk/umdk.BUILD create mode 100644 docs/cn/urma.md create mode 100644 docs/en/urma.md create mode 100644 example/urma_performance/CMakeLists.txt create mode 100644 example/urma_performance/client.cpp create mode 100644 example/urma_performance/server.cpp create mode 100644 example/urma_performance/test.proto create mode 100644 src/brpc/urma/mock_urma.cpp create mode 100644 src/brpc/urma/urma_bonding.h create mode 100644 src/brpc/urma/urma_endpoint.cpp create mode 100644 src/brpc/urma/urma_endpoint.h create mode 100644 src/brpc/urma/urma_handshake.cpp create mode 100644 src/brpc/urma/urma_handshake.h create mode 100644 src/brpc/urma/urma_handshake.proto create mode 100644 src/brpc/urma/urma_helper.cpp create mode 100644 src/brpc/urma/urma_helper.h create mode 100644 src/brpc/urma_transport.cpp create mode 100644 src/brpc/urma_transport.h create mode 100644 test/brpc_urma_unittest.cpp 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/BUILD.bazel b/BUILD.bazel index 727af8574a..3ea069351f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -54,6 +54,9 @@ DEFINES = [ }) + 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"], @@ -523,6 +526,7 @@ filegroup( "src/brpc/*.proto", "src/brpc/policy/*.proto", "src/brpc/rdma/*.proto", + "src/brpc/urma/*.proto", ]), visibility = ["//visibility:public"], ) @@ -561,9 +565,7 @@ cc_library( "src/brpc/event_dispatcher_kqueue.cpp", ]), copts = COPTS, - includes = [ - "src/", - ], + includes = ["src/"], linkopts = LINKOPTS, visibility = ["//visibility:public"], deps = [ @@ -575,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..10e9052dcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,10 @@ 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_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 +125,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 +169,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 +328,56 @@ 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) + else() + message(STATUS + "liburma not found; building with the URMA link-time mock") + set(URMA_USE_MOCK 1) + endif() +endif() + find_library(PROTOC_LIB NAMES protoc) if(NOT PROTOC_LIB) message(FATAL_ERROR "Fail to find protoc lib") @@ -342,6 +402,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 +436,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 +648,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 +696,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 1e71bfcb9d..860d5b3230 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -68,3 +68,14 @@ 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', + tag = 'v26.06.0_CAM', +) 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..b197d666f6 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -279,6 +279,13 @@ 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", + tag = "v26.06.0_CAM", +) + # 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 +324,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 e9d07eb73a..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"}, @@ -161,4 +167,4 @@ config_setting( name = "brpc_with_ubring", define_values = {"BRPC_WITH_UBRING": "true"}, visibility = ["//visibility:public"], -) \ No newline at end of file +) 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/config_brpc.sh b/config_brpc.sh index 85692de3cb..2c1394e840 100755 --- a/config_brpc.sh +++ b/config_brpc.sh @@ -54,10 +54,11 @@ 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-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_MESALINK=0 WITH_BTHREAD_TRACER=0 WITH_ASAN=0 @@ -90,6 +91,7 @@ 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-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 +540,26 @@ 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" + else + append_to_output "URMA_USE_MOCK=1" + print_info "liburma not found; using URMA link-time mock" + fi +fi + if [ $WITH_MESALINK != 0 ]; then CPPFLAGS="${CPPFLAGS} -DUSE_MESALINK" fi @@ -674,6 +696,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/urma.md b/docs/cn/urma.md new file mode 100644 index 0000000000..a9be634ec7 --- /dev/null +++ b/docs/cn/urma.md @@ -0,0 +1,149 @@ +# 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 +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) +``` + +`WITH_URMA=ON` 使用上游 UMDK 头文件进行编译。CMake 优先使用系统安装的 +SDK;找不到头文件时,会参照 Mooncake 的 mock 构建方式下载固定版本的 +UMDK,可通过 `DOWNLOAD_URMA_HEADERS=OFF` 禁止下载。找到 `liburma` 时使用 +真实硬件数据通路,否则链接 brpc 的 mock,使 URMA 代码和测试仍可在无硬件 +环境编译。 + +## 使用 + +通过在 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/urma.md b/docs/en/urma.md new file mode 100644 index 0000000000..964f648bd2 --- /dev/null +++ b/docs/en/urma.md @@ -0,0 +1,161 @@ +# 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 +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) +``` + +`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. + +## 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/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index 9eec3c0f86..6b2c7850ff 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -39,6 +39,52 @@ 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. @@ -81,6 +127,7 @@ macro(brpc_example_find_common_deps out_libs) Threads::Threads ${GFLAGS_LIBRARY} ${PROTOBUF_LIBRARIES} + ${_protobuf_absl_targets} ${LEVELDB_LIB} ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} @@ -118,13 +165,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 +200,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/urma_performance/CMakeLists.txt b/example/urma_performance/CMakeLists.txt new file mode 100644 index 0000000000..154970fbd3 --- /dev/null +++ b/example/urma_performance/CMakeLists.txt @@ -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. + +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) +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) +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/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/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/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 3bc90918d9..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; 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/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/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..bb8914d7d2 --- /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 = 32; // matches butil IOBuf + +// ---- 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..ceeeae9a1b --- /dev/null +++ b/src/brpc/urma/urma_helper.cpp @@ -0,0 +1,788 @@ +// 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"); + +constexpr size_t kIOBufBlockHeaderLen = 32; + +// 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) - + kIOBufBlockHeaderLen; + + // 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/test/brpc_urma_unittest.cpp b/test/brpc_urma_unittest.cpp new file mode 100644 index 0000000000..de3ce31228 --- /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_rdma_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(); +} From 5d7edc4a8b712a0c16ce5810eeb283873474d8f2 Mon Sep 17 00:00:00 2001 From: Winchell Date: Wed, 12 Aug 2026 18:01:41 +0800 Subject: [PATCH 35/48] fix: address review comments on naming, IOBuf sizing and UMDK pinning - Rename ack_bit_is_rdma_ok to ack_bit_is_urma_ok. - Replace hard-coded IOBuf block header size with sizeof(butil::IOBuf::Block). - Pin UMDK dependency to a specific commit instead of a mutable tag. --- MODULE.bazel | 2 +- WORKSPACE | 2 +- src/brpc/urma/urma_endpoint.cpp | 2 +- src/brpc/urma/urma_helper.cpp | 3 +-- test/brpc_urma_unittest.cpp | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 860d5b3230..c640a36236 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -77,5 +77,5 @@ git_repository( name = 'umdk', build_file = '//bazel/third_party/umdk:umdk.BUILD', remote = 'https://atomgit.com/openeuler/umdk.git', - tag = 'v26.06.0_CAM', + commit = '564ee727a55523d4351a8fb3c94292b388ebb924', # v26.06.0_CAM ) diff --git a/WORKSPACE b/WORKSPACE index b197d666f6..22fc411b32 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -283,7 +283,7 @@ git_repository( name = "umdk", build_file = "//bazel/third_party/umdk:umdk.BUILD", remote = "https://atomgit.com/openeuler/umdk.git", - tag = "v26.06.0_CAM", + commit = "564ee727a55523d4351a8fb3c94292b388ebb924", # v26.06.0_CAM ) # Header-only JSON library used by iobuf_unittest's IOBuf<->std::iostream diff --git a/src/brpc/urma/urma_endpoint.cpp b/src/brpc/urma/urma_endpoint.cpp index bb8914d7d2..78aa225989 100644 --- a/src/brpc/urma/urma_endpoint.cpp +++ b/src/brpc/urma/urma_endpoint.cpp @@ -72,7 +72,7 @@ DECLARE_bool(urma_poller_yield); 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 = 32; // matches butil IOBuf +static const size_t IOBUF_BLOCK_HEADER_LEN = sizeof(butil::IOBuf::Block); // ---- Globals: prepared jetty pool + poller groups ---- struct PreparedJetty { diff --git a/src/brpc/urma/urma_helper.cpp b/src/brpc/urma/urma_helper.cpp index ceeeae9a1b..648316f1ae 100644 --- a/src/brpc/urma/urma_helper.cpp +++ b/src/brpc/urma/urma_helper.cpp @@ -100,7 +100,6 @@ DEFINE_bool(urma_poller_yield, false, "Yield (bthread_yield) in the busy poll loop to let other " "bthreads run"); -constexpr size_t kIOBufBlockHeaderLen = 32; // Set to true to skip real URMA hardware initialization (unit tests). When // true, GlobalUrmaInitializeOrDie() returns without touching liburma and the @@ -581,7 +580,7 @@ static bool GlobalUrmaInitializeImpl() { } g_recv_block_size = static_cast(FLAGS_urma_buffer_size) - - kIOBufBlockHeaderLen; + sizeof(butil::IOBuf::Block); // User-segment table. g_user_segs_lock = new (std::nothrow) butil::Mutex; diff --git a/test/brpc_urma_unittest.cpp b/test/brpc_urma_unittest.cpp index de3ce31228..d05784d009 100644 --- a/test/brpc_urma_unittest.cpp +++ b/test/brpc_urma_unittest.cpp @@ -198,7 +198,7 @@ TEST(UrmaHandshakeTest, client_handshake_factory_respects_flag) { // --------------------------------------------------------------------------- // 4-byte ACK: HELLO_ACK_URMA_OK bit. // --------------------------------------------------------------------------- -TEST(UrmaHandshakeTest, ack_bit_is_rdma_ok) { +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 From 617e6d6e26fec831f1fba8f9189fc2de702cc3c3 Mon Sep 17 00:00:00 2001 From: Winchell Date: Fri, 14 Aug 2026 16:24:16 +0800 Subject: [PATCH 36/48] docs(urma): add Bazel build section and document its limitations Reviewer noted docs/cn/urma.md only covered the CMake build and that DOWNLOAD_URMA_HEADERS has no Bazel equivalent. Document the Bazel build command and clarify that Bazel always fetches UMDK headers from the pinned git_repository commit and always links the mock backend (no real-liburma detection yet), and that urma_performance has no Bazel target. --- docs/cn/urma.md | 15 +++++++++++++++ docs/en/urma.md | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/docs/cn/urma.md b/docs/cn/urma.md index a9be634ec7..2c31b0d9a3 100644 --- a/docs/cn/urma.md +++ b/docs/cn/urma.md @@ -36,6 +36,21 @@ UMDK,可通过 `DOWNLOAD_URMA_HEADERS=OFF` 禁止下载。找到 `liburma` 时 真实硬件数据通路,否则链接 brpc 的 mock,使 URMA 代码和测试仍可在无硬件 环境编译。 +### 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` 选择传输层: diff --git a/docs/en/urma.md b/docs/en/urma.md index 964f648bd2..ee38eb6359 100644 --- a/docs/en/urma.md +++ b/docs/en/urma.md @@ -38,6 +38,23 @@ 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. +### 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: From 52abfc0551e5b3d70db703e091c2426c9a0cb958 Mon Sep 17 00:00:00 2001 From: Winchell Date: Fri, 14 Aug 2026 16:45:57 +0800 Subject: [PATCH 37/48] fix(bazel): add missing package marker for umdk third-party build file bazel/third_party/umdk only contained umdk.BUILD, unlike every other bazel/third_party/ directory which pairs its .BUILD with an empty BUILD.bazel marking the directory as a package. Without it, resolving the git_repository(build_file = "//bazel/third_party/umdk:umdk.BUILD") label fails once the umdk repo is actually fetched: Error in read: Unable to load package for //bazel/third_party/umdk:umdk.BUILD: BUILD file not found ... This broke `bazel build --define=BRPC_WITH_URMA=true //:brpc` on both x86_64 and arm64 (confirmed via GitHub Actions CI on ubuntu-22.04 and ubuntu-24.04-arm). --- bazel/third_party/umdk/BUILD.bazel | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 bazel/third_party/umdk/BUILD.bazel 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. From 6d70397c5de2c8a8966c3dc89db84778499eb3ff Mon Sep 17 00:00:00 2001 From: Winchell Date: Fri, 14 Aug 2026 17:04:32 +0800 Subject: [PATCH 38/48] fix(bazel): strip upstream src/urma/BUILD.bazel so umdk headers glob works The umdk repo ships its own src/urma/BUILD.bazel, which makes Bazel treat src/urma/ as a separate package. glob() in our umdk.BUILD (rooted at the umdk repo root) can't cross that boundary, so hdrs = glob(["src/urma/lib/urma/**/include/*.h"]) silently resolved to an empty list. The cc_library then exported no header inputs, so compiling anything that #includes urma_api.h failed with "No such file or directory" even though the -isystem path was correct and the file existed on disk. Confirmed via GitHub Actions on both ubuntu-22.04 (x86_64) and ubuntu-24.04-arm (arm64): `bazel build --define=BRPC_WITH_URMA=true //:brpc` failed identically on both before this patch_cmds fix. --- MODULE.bazel | 8 ++++++++ WORKSPACE | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/MODULE.bazel b/MODULE.bazel index c640a36236..bb5e05b48c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -78,4 +78,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 From 917c11df156dec3d1b46553c6ceddcb44577201e Mon Sep 17 00:00:00 2001 From: Winchell Date: Mon, 17 Aug 2026 15:04:08 +0800 Subject: [PATCH 39/48] fix(urma): require explicit opt-in for the URMA link-time mock Reviewer dwh110 pointed out that src/brpc/urma/mock_urma.cpp had no independent feature switch: whenever liburma wasn't found, CMake/Make silently linked the mock, which can produce a binary that looks URMA-capable but can't reach real hardware. Add WITH_URMA_MOCK (CMake) / --with-urma-mock (config_brpc.sh), default OFF. When WITH_URMA is enabled and liburma isn't found, the build now fails with a clear message unless the mock is explicitly requested, instead of substituting it implicitly. Document the new flag in docs/en/urma.md and docs/cn/urma.md. Co-Authored-By: Claude Sonnet 5 --- CMakeLists.txt | 14 ++++++++++++-- config_brpc.sh | 11 ++++++++--- docs/cn/urma.md | 17 ++++++++++++++--- docs/en/urma.md | 20 ++++++++++++++++---- 4 files changed, 50 insertions(+), 12 deletions(-) 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/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/urma.md b/docs/cn/urma.md index 2c31b0d9a3..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,22 @@ 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 编译 diff --git a/docs/en/urma.md b/docs/en/urma.md index ee38eb6359..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,25 @@ 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 From e32985aa31677cf0987d6de07a0cbe2efeec46a4 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 14:58:46 +0800 Subject: [PATCH 40/48] Link liburma for all examples Add conditional linking for URMA library based on availability. --- example/cmake/BrpcExample.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index 6b2c7850ff..2f5050672d 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -122,6 +122,13 @@ macro(brpc_example_find_common_deps out_libs) endif() find_package(OpenSSL REQUIRED) + # brpc built with -DWITH_URMA=ON carries undefined urma_* symbols, so every + # example has to link liburma. Search by best effort: when brpc was built + # without URMA the symbols are absent and the library is not needed. + find_library(URMA_LIB NAMES urma) + if(NOT URMA_LIB) + set(URMA_LIB "") + endif() set(_common_libs Threads::Threads @@ -132,6 +139,7 @@ macro(brpc_example_find_common_deps out_libs) ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${THRIFT_LIB} + ${URMA_LIB} dl ) From 947df200b0dc0eb3ad0de7cccb549e6c4fda19e5 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 14:59:40 +0800 Subject: [PATCH 41/48] Drop duplicate liburma lookup in urma_performance --- example/urma_performance/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/example/urma_performance/CMakeLists.txt b/example/urma_performance/CMakeLists.txt index 154970fbd3..5140ea5036 100644 --- a/example/urma_performance/CMakeLists.txt +++ b/example/urma_performance/CMakeLists.txt @@ -26,13 +26,6 @@ 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) From 069df8550cf862eea38a100a6f9013f0c65db347 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 15:09:51 +0800 Subject: [PATCH 42/48] Add comment about linking liburma in BrpcExample.cmake Added a comment regarding linking with liburma based on brpc build options. --- example/cmake/BrpcExample.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index 2f5050672d..a6cf99e51d 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -122,6 +122,7 @@ macro(brpc_example_find_common_deps out_libs) endif() find_package(OpenSSL REQUIRED) + # brpc built with -DWITH_URMA=ON carries undefined urma_* symbols, so every # example has to link liburma. Search by best effort: when brpc was built # without URMA the symbols are absent and the library is not needed. From eda12bc383f9a60a4b497c8b39f99d9167d9e795 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 18:02:53 +0800 Subject: [PATCH 43/48] Revert liburma linking for diagnosis --- example/cmake/BrpcExample.cmake | 8 -------- 1 file changed, 8 deletions(-) diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index a6cf99e51d..5bc9307e9a 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -123,13 +123,6 @@ macro(brpc_example_find_common_deps out_libs) find_package(OpenSSL REQUIRED) - # brpc built with -DWITH_URMA=ON carries undefined urma_* symbols, so every - # example has to link liburma. Search by best effort: when brpc was built - # without URMA the symbols are absent and the library is not needed. - find_library(URMA_LIB NAMES urma) - if(NOT URMA_LIB) - set(URMA_LIB "") - endif() set(_common_libs Threads::Threads @@ -140,7 +133,6 @@ macro(brpc_example_find_common_deps out_libs) ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${THRIFT_LIB} - ${URMA_LIB} dl ) From fb3b3c9608cb9488015c52ead5e50a678d03e420 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 18:03:49 +0800 Subject: [PATCH 44/48] Check for URMA library and update build configuration Added logic to find the URMA library and handle its absence. --- example/urma_performance/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/example/urma_performance/CMakeLists.txt b/example/urma_performance/CMakeLists.txt index 5140ea5036..ae02a2cb52 100644 --- a/example/urma_performance/CMakeLists.txt +++ b/example/urma_performance/CMakeLists.txt @@ -27,6 +27,14 @@ 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) add_executable(urma_performance_server server.cpp ${PROTO_SRC} ${PROTO_HEADER}) From 3e36620a767e27d96c3167f231e1a9fb6a1ee7fd Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 18:31:30 +0800 Subject: [PATCH 45/48] Add URMA library search to CMake configuration --- example/cmake/BrpcExample.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index 5bc9307e9a..b85f278424 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -123,6 +123,10 @@ 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 @@ -133,6 +137,7 @@ macro(brpc_example_find_common_deps out_libs) ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${THRIFT_LIB} + ${URMA_LIB} dl ) From 78f8b08380c620d8fa3e0b1394c293dee6043fe6 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 19:02:40 +0800 Subject: [PATCH 46/48] Update CMake to link with URMA library conditionally --- example/cmake/BrpcExample.cmake | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index b85f278424..5eb2280120 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, so every + # example has to link liburma. Search by best effort: when brpc was built + # without URMA the symbols are absent and the library is not needed. + find_library(_brpc_example_urma_lib NAMES urma NO_CACHE) + if(NOT _brpc_example_urma_lib) + set(_brpc_example_urma_lib "") endif() find_path(BRPC_INCLUDE_PATH NAMES brpc/server.h) @@ -137,7 +138,7 @@ macro(brpc_example_find_common_deps out_libs) ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY} ${THRIFT_LIB} - ${URMA_LIB} + ${_brpc_example_urma_lib} dl ) From cbbf49514d5a26949ec76ae9bc12f1bd8d1ae621 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 19:30:23 +0800 Subject: [PATCH 47/48] Remove URMA library check from CMakeLists.txt Removed conditional check for URMA library and related messages. --- example/urma_performance/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/example/urma_performance/CMakeLists.txt b/example/urma_performance/CMakeLists.txt index ae02a2cb52..eae472fe90 100644 --- a/example/urma_performance/CMakeLists.txt +++ b/example/urma_performance/CMakeLists.txt @@ -27,13 +27,6 @@ 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) From 7949ceac7905860ee68b400cdf87942377707344 Mon Sep 17 00:00:00 2001 From: Winchell Date: Tue, 18 Aug 2026 20:27:18 +0800 Subject: [PATCH 48/48] Refactor URMA library linking logic in CMake Update logic for linking liburma based on header presence. --- example/cmake/BrpcExample.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake index 5eb2280120..e57cda196a 100644 --- a/example/cmake/BrpcExample.cmake +++ b/example/cmake/BrpcExample.cmake @@ -86,12 +86,12 @@ macro(brpc_example_find_common_deps out_libs) ) endif() - # brpc built with -DWITH_URMA=ON carries undefined urma_* symbols, so every - # example has to link liburma. Search by best effort: when brpc was built - # without URMA the symbols are absent and the library is not needed. - find_library(_brpc_example_urma_lib NAMES urma NO_CACHE) - if(NOT _brpc_example_urma_lib) - set(_brpc_example_urma_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)