Fix SWA eviction tombstoning the last leaf (#29860)

This commit is contained in:
Ke Bao
2026-07-02 21:42:30 +08:00
committed by GitHub
parent 3c1adddff9
commit a375e9f3da
5 changed files with 20 additions and 15 deletions
@@ -7,7 +7,7 @@ handling for this, creating an incorrect non-tombstone node that caused
inflated swa_evictable_size_, negative usage, and potential double-free.
Two-sided fix:
1. _evict_swa subtracts extra page_size (preventive).
1. _evict_swa subtracts max(window, page) on the radix path (preventive).
2. _insert_helper early-returns on case 3 (defensive).
Tests use real tree/allocator/pool with mock Req/ScheduleBatch wrappers.
@@ -195,7 +195,7 @@ class TestSWAEvictionBoundary(unittest.TestCase):
# -- Eviction formula: page_size == 1 --
def test_formula_page_size_1(self):
"""page_size=1: no floor alignment, -1 just means one less token evicted."""
"""page_size=1: radix keeps max(window, page)=window, so the frontier is pre_len - window."""
page_size, window = 1, 4
tree, allocator, pool = _build_swa_tree(
page_size=page_size, sliding_window_size=window
@@ -210,7 +210,9 @@ class TestSWAEvictionBoundary(unittest.TestCase):
ScheduleBatch._evict_swa(batch, req, seq_len - 1)
self.assertLess(req.swa_evicted_seqlen, seq_len)
self.assertEqual(req.swa_evicted_seqlen, max(0, seq_len - 1 - window - 1))
self.assertEqual(
req.swa_evicted_seqlen, max(0, seq_len - 1 - max(window, page_size))
)
tree.cache_finished_req(req, is_insert=True)
tree.sanity_check()
@@ -383,7 +385,9 @@ class TestSWAEvictionBoundary(unittest.TestCase):
batch = _make_batch(tree, allocator, pool)
ScheduleBatch._evict_swa(batch, req, seq_len - 1)
self.assertEqual(req.swa_evicted_seqlen, max(0, seq_len - 1 - window - 1))
self.assertEqual(
req.swa_evicted_seqlen, max(0, seq_len - 1 - max(window, page_size))
)
tree.cache_finished_req(req, is_insert=True)
tree.sanity_check()
@@ -1977,7 +1977,7 @@ class UnifiedRadixCacheSuite:
with envs.SGLANG_OPT_UNIFIED_CACHE_FREE_OUT_OF_WINDOW_SLOTS.override(True):
tree.cache_unfinished_req(req)
cushion = self.cfg.sliding_window_size + self.cfg.page_size
cushion = max(self.cfg.sliding_window_size, self.cfg.page_size)
expected_evicted = (pre_len - 1) - cushion
self.assertEqual(
req.swa_evicted_seqlen,