Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors the UBRing/UBShmTransport timer and teardown machinery to use bthread timers, with additional lifecycle-safety mechanisms (generation checks + anchored cleanup control objects) to prevent stale timer/callback paths from touching reused trx slots and to avoid blocking work on the timer thread.
Changes:
- Replace the custom timerfd/epoll timer subsystem with a bthread-timer-based facade (
UbrTimerStart/UbrTimerDel/UbrTimerDelAndWait) and update call sites accordingly. - Introduce explicit delayed-cleanup ownership tracking via
UbrCleanupCtlanchored inUBRingManager, plus generation checks to avoid slot-reuse races. - Reduce idle close-check polling via exponential backoff, and improve teardown ordering (e.g., stop UBS SHM cleanup timer before SDK finalize).
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/brpc_ubring_unittest.cpp | Extends configuration tests to cover the new close-check backoff cap flag default. |
| src/brpc/ubshm/ubr_trx.h | Replaces fd-based timers with bthread timer handles; adds cleanup control state and makes hot counters atomic. |
| src/brpc/ubshm/ub_ring.h | Updates UBRing APIs to remove timer-fd parameters and align cleanup entry points with new lifecycle model. |
| src/brpc/ubshm/ub_ring.cpp | Implements bthread-timer scheduling, delayed cleanup ownership, close-check backoff, and atomic I/O sequencing. |
| src/brpc/ubshm/ub_ring_manager.h | Adds per-slot generation + cleanup-ctl anchoring APIs to coordinate delayed cleanup across slot reuse. |
| src/brpc/ubshm/ub_ring_manager.cpp | Implements generation-safe release and teardown-time cancellation/waiting for in-flight cleanups. |
| src/brpc/ubshm/ub_helper.cpp | Removes eager timer module init (timers become lazy via bthread facade). |
| src/brpc/ubshm/ub_endpoint.cpp | Fixes poller SID updates by replacing existing set entries on ADD/MOD. |
| src/brpc/ubshm/timer/timer_mgr.h | Defines the bthread-timer facade API and documents callback/teardown expectations. |
| src/brpc/ubshm/timer/timer_mgr.cpp | Replaces timerfd/epoll/kqueue implementation with bthread timer task management and delete/wait semantics. |
| src/brpc/ubshm/shm/shm_ubs.cpp | Moves UBS cleanup work outside locks, switches cleanup timer to bthread, and fixes teardown ordering vs SDK finalize. |
| src/brpc/ubshm/common/common.h | Adds SEC_TO_USEC for consistent time conversions used by the new timer paths. |
| docs/en/ubring.md | Updates timer documentation to reflect bthread timer usage and backoff policy. |
| docs/cn/ubring.md | Same as English docs: updates timer documentation to reflect new bthread timer approach. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // Non-blocking delete, safe from inside the timer callback itself. Does | ||
| // not wait for a running callback and does not protect `arg' on its own. | ||
| // Returns 0 when the call won the slot competition: a one-shot callback | ||
| // is guaranteed never to run, and the caller consumes any per-task | ||
| // resources it tracks for this timer (ownership of them transfers to the | ||
| // caller); for a periodic timer an already-started callback is not | ||
| // interrupted. Returns 1 when the callback has been dispatched (it | ||
| // consumes those resources itself on every exit) or its fate is still | ||
| // being settled by the scheduler -- the caller must not consume anything | ||
| // then. |
|
I've updated the timer deletion contract to clarify the one-shot and periodic timer semantics, and addressed the related comments. @wwbmmm could you please take another look when you have time? |
|
LGTM |
|
@wwbmmm Thanks for the LGTM! If there are no further concerns, I'll go ahead and merge this PR. |
|
@chenBright Do you have any further concerns about this PR? If not, I'll go ahead and merge it. |
| if (ret != UBSM_OK) { | ||
| LOG(ERROR) << "Ubs shm finalize fail, ret=" << ret; | ||
| // Stop the cleanup timer before finalizing the SDK it calls into. | ||
| if (UNLIKELY(DestroyShmTimer(g_shm_list) != UBRING_OK)) { |
There was a problem hiding this comment.
UNLIKELY -> BAIDU_UNLIKELY
| // a slow daemon cannot stall the timer thread for the whole list. | ||
| SHM shm; | ||
| { | ||
| LOCK_GUARD(shm_list->shm_lock); |
There was a problem hiding this comment.
LOCK_GUARD -> BAIDU_SCOPED_LOCK
| LOG(ERROR) << "Ubs unmap shm=" << shm.name << " length=" << shm.len << " failed, ret=" << ret; | ||
| return nullptr; // node stays at head, retried | ||
| } | ||
| LOG(INFO) << "Ubs unmap shm=" << shm.name << " length=" << shm.len << " success."; |
There was a problem hiding this comment.
Is this INFO log necessary?
| LOG(ERROR) << "Ubs delete shm=" << shm.name << " failed, ret=" << ret; | ||
| return nullptr; | ||
| } | ||
| LOG(INFO) << "Ubs free local shm=" << shm.name << " length=" << shm.len << " success."; |
There was a problem hiding this comment.
Is this INFO log necessary?
| // the slot is the single arbiter. | ||
| UbrTimerId expected = task; | ||
| const bool owned = | ||
| __atomic_compare_exchange_n(task->slot, &expected, (UbrTimerId) nullptr, |
There was a problem hiding this comment.
Why not use butil::atomic?
| // free the task while a callback or the starter still touches it. | ||
| struct UbrTimerTask { | ||
| UbrTimerId* slot; | ||
| std::atomic<bthread_timer_t> id; |
There was a problem hiding this comment.
std::atomic -> butil::atomic
|
@chenBright Thanks for the review! I'll address the comments and update the PR. |
) Make the whole ubring shared-memory module follow the current brpc conventions, addressing review feedback: - Replace the module-local LIKELY/UNLIKELY aliases with BAIDU_LIKELY/ BAIDU_UNLIKELY and drop the aliases from common.h. - Use BAIDU_SCOPED_LOCK instead of the local GNU cleanup-attribute LOCK_GUARD. The pthread_mutex_t members keep their type, allocation and lifetime, so no static-init or placement-new change is needed. - Use butil::atomic instead of std::atomic. The timer handle slots and the trx cleanup slot are now real butil::atomic objects, so plain storage is never reinterpreted as an atomic: the timer API takes butil::atomic<UbrTimerId>* and UbrTrx/UbrCleanupCtl hold atomic handles. UbrTrx slots are value-initialized with placement new so those atomics are constructed, replacing the per-acquisition memset. - Drop the two per-node INFO logs on the shm cleanup retry path in UbsShmCallback; DeleteShmToList still records each drained node. No behavioral change: the removed aliases expanded 1:1, BAIDU_SCOPED_LOCK locks the same pthread_mutex_t, butil::atomic is layout-identical to std::atomic, and placement-new value-initialization zeroes exactly what memset zeroed while also constructing the atomic members.
What problem does this PR solve?
Issue Number: #3463(Phase2)
Problem Summary:
This PR addresses the Phase 2 timer and lifecycle stability improvements for UBShmTransport/UBRing discussed in #3463.
The existing UBRing timer and teardown implementation has several lifecycle and scalability issues, including:
UbrTrxrelease and slot reuse;What is changed and the side effects?
Changed:
bthread_timer_add/bthread_timer_del.UbrTimerDelAndWaitfor teardown paths that need to wait for in-flight callbacks.UbrCleanupCtlto coordinate delayed cleanup and force-close ownership independently of pooledUbrTrxobjects.ub_flying_io_timeout_ssleep from the timer callback and use delayed cleanup instead.shm_lockand stop the cleanup timer beforeubsmem_finalize.Side effects:
Performance effects:
Breaking backward compatibility:
Check List:
brpc_ubring_unittestpasses.environment.