Repository navigation
Conversation
…s RootBlock BlockRadixTree.clear() shrinks self.next only as a side effect of detaching a RootBlock's last child. A childless RootBlock (published by add_or_get_existing before any block is attached) has no child to detach, so the loop re-selected the same root forever, clear() never returned, and KVCacheManager.shutdown() hung behind it. Detach childless roots explicitly. Root-edge bookkeeping now lives in a single detach_root_block() helper shared by the eager prune path in detach_next() and the explicit teardown path in clear(), so the two cannot diverge. Adds CPU-only regression tests covering childless roots, populated chains, mixed trees, and reuse of the tree after clear(). Signed-off-by: Gawr Gura 0721 <LiRunGuo@users.noreply.github.com>
|
/bot run |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review. WalkthroughThe change centralizes root detachment and updates ChangesRoot clear lifecycle
Priority: ➖ Normal — Schedule the BlockRadixTree cleanup fix because a childless root can make KVCacheManager shutdown hang, while the change remains an internal, narrowly scoped lifecycle correction. Estimated code review effort: 3 (Moderate) | ~20 minutes Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to This change prevents shutdown hangs caused by childless cache-tree roots and preserves tree cleanup behavior across populated, mixed, and reused trees. The change is ready to merge. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Hi team, gentle follow-up on this PR — the fix for #17908 (BlockRadixTree.clear() hangs on childless RootBlock, blocking KVCacheManager.shutdown()) is ready for review. It is rebased on the latest main (917cbfc), CodeRabbit reported no actionable comments, and the new CPU-only regression tests pass locally alongside the existing kv_cache_manager_v2 unit tests, with a clean ruff run. Could a maintainer trigger the standard CI pipeline (e.g. /bot run) when convenient, or let us know if anything else is needed from our side? Thanks! |
|
Hi @lowsfer @eopXD, following up here with a direct ping, since you work on This fixes #17908. As an external contributor I can't start the CI pipeline myself. Could one of you trigger |
|
[by Codex] @lowsfer Friendly reminder: could you review this PR? Thanks! |
|
@nvpohanh thanks for routing this to @lowsfer last week. It's been quiet since, so if lowsfer is busy, is there someone else on the KV cache manager v2 side who could review it? The change is still small ( |
|
[by Claude Code] @lowsfer Could you review this PR? Thanks! |
1 similar comment
|
[by Claude Code] @lowsfer Could you review this PR? Thanks! |
|
Thanks for the fix and your follow-ups, and sorry we left this waiting for review. The Python KVCacheManagerV2 implementation targeted by this PR was removed in #19154; the C++ implementation is now the supported path. Would you be interested in checking whether the same edge case applies to C++ V2 and carrying over a regression test? Otherwise, we can close this PR as superseded by the removal. |
|
[by Claude Code] @lowsfer Could you review this PR? Thanks! |
1 similar comment
|
[by Claude Code] @lowsfer Could you review this PR? Thanks! |
|
Current |
[#17908][fix] Make
BlockRadixTree.clear()terminate on a childlessRootBlockBackground
BlockRadixTree.clear()(intensorrt_llm/runtime/kv_cache_manager_v2/_block_radix_tree.py)shrinks
self.nextonly as a side effect of the inner loop:detach_next()prunes aRootBlockwhen its last child is detached. ARootBlockthat is already childless hasno child to detach, so the outer
while self.next:loop re-selects the same root foreverand
clear()never returns. The trailingassert not self.nextis unreachable in that state.A childless root is not exotic:
RootBlock.__init__ends withprev.next[self.key] = self,so
add_or_get_existing()publishes an empty root by construction before its callerattaches a block; any interruption between those two steps leaves the tree permanently
unclearable. The only production caller is
KVCacheManager.shutdown(), which thereforehangs whenever the tree holds a childless root.
Summary
Root-edge bookkeeping is centralised into a single new helper,
detach_root_block(root), that removes aRootBlockfrom its tree's top-levelnextregistry:
detach_next()now calls it when the last child of aRootBlockis detached(eager prune path — unchanged behaviour, same bookkeeping).
clear()now calls it directly for a root that never gained a child, so everyiteration of the loop makes explicit progress (detach a childless root, or remove one
subtree) and the loop provably terminates.
Changes:
tensorrt_llm/runtime/kv_cache_manager_v2/_block_radix_tree.pydetach_root_block();detach_next()'s root pruning through it;BlockRadixTree.clear()detach childless roots explicitly.tests/unittest/kv_cache_manager_v2_tests/test_block_radix_tree.py(new)pytest.mark.cpu_only): empty tree, childless-rootregression, single chain removal (incl. orphan checks), mixed childless + populated
roots, multi-branch subtrees, idempotence and post-clear reuse of the same reuse scope.
Impacts
clear()terminates for every reachable tree state;KVCacheManager.shutdown()can nolonger hang behind a childless root.
existing
remove_subtreepath), so page-cleanup semantics ofBlock.__del__andevent-manager notifications are untouched.
tests in the
kv_cache_manager_v2fast mode(
TLLM_KV_CACHE_MANAGER_V2_BACKEND=python).Verification
Reproduced the hang on
main(777a2c7) with the snippet above (process does not return;killed by
timeout). After the fix the snippet returns immediately and the new test filepasses; pre-fix, the same tests hang at the first childless-root case.
Existing related tests still pass:
test_kv_cache_salting.py(3 tests).Dev Engineer Review
BlockRadixTree.clear()now removes childless roots and always makes progress.detach_root_block()centralizes root cleanup for explicit clearing and eager pruning.QA Engineer Review
tests/unittest/kv_cache_manager_v2_tests/test_block_radix_tree.py.tests/integration/test_lists/test-db/l0_cpu.ymland other applicable test lists.Per-File QA Perspective
tensorrt_llm/runtime/kv_cache_manager_v2/_block_radix_tree.py: Verify childless-root removal, populated-subtree cleanup, eager pruning, and repeated clearing. No API or default behavior changes are introduced.tests/unittest/kv_cache_manager_v2_tests/test_block_radix_tree.py: CoversBlockRadixTree.clear()lifecycle and regression paths with CPU-only tests. The containing suite is listed in the CPU CI test list.