Apply CP HiCache page-floor policy before backup and insert

Backed CP HiCache tail splits were floored during match, but write preparation and radix insertion could still observe the raw sub-page prefix. That could skip one token during pre-forward reservation or call CpHiCacheNodeMetadata.split() with a non-page boundary. The shared helper now floors backed partial-tail prefixes before probe, match, and insert.

Constraint: CP HiCache uses page-granular physical ownership while radix keys may keep valid-tail lengths.

Rejected: Let probe and insert keep token-precise tail prefixes | it reintroduces half-page ownership through a different entry point.

Confidence: high

Scope-risk: moderate

Directive: Any CP radix path that can split or reserve against backed HiCache metadata must use the same page-floor policy.

Tested: Remote red tests first for probe and insert failures in g0034 container.

Tested: Remote py_compile for hiradix_cache.py and test_cp_hicache_metadata.py.

Tested: Remote targeted C7 tests: 4 passed, 3 warnings.

Tested: Remote pytest test_cp_hicache_metadata.py test_cp_hicache_load_back_owner_lanes.py: 94 passed, 5 warnings.

Not-tested: Live ETE traffic with concurrent divergent tail prompts.

Co-authored-by: OmX <omx@oh-my-codex.dev>
This commit is contained in:
laoyao0822
2026-05-29 07:10:53 +08:00
parent 8001c4ae8e
commit 2b1524bd8c
3 changed files with 134 additions and 1 deletions

View File

@@ -2009,6 +2009,12 @@ class HiRadixCache(RadixCache):
prefix_len = self.key_match_fn(child.key, key)
if prefix_len <= 0:
break
if prefix_len < len(child.key):
prefix_len = self._cp_floor_backed_partial_split_len(
child, prefix_len
)
if prefix_len <= 0:
break
total_prefix_len += prefix_len
if prefix_len < len(child.key):
@@ -2021,6 +2027,19 @@ class HiRadixCache(RadixCache):
return total_prefix_len
def _cp_floor_backed_partial_split_len(
self, child: TreeNode, prefix_len: int
) -> int:
if (
not self._uses_cp_hicache
or self.page_size <= 1
or prefix_len <= 0
or prefix_len % self.page_size == 0
or not self._node_backuped(child)
):
return prefix_len
return prefix_len // self.page_size * self.page_size
def prepare_write_backup_for_req(self, req) -> None:
if self.disable or not self._uses_cp_hicache:
return
@@ -3356,7 +3375,9 @@ class HiRadixCache(RadixCache):
and self._node_backuped(child)
and prefix_len % self.page_size != 0
):
prefix_len = prefix_len // self.page_size * self.page_size
prefix_len = self._cp_floor_backed_partial_split_len(
child, prefix_len
)
if prefix_len == 0:
break
new_node = self._split_node(child.key, child, prefix_len)
@@ -3464,6 +3485,11 @@ class HiRadixCache(RadixCache):
total_prefix_length += prefix_len
else:
# partial match, split the node
prefix_len = self._cp_floor_backed_partial_split_len(
node, prefix_len
)
if prefix_len <= 0:
break
new_node = self._split_node(node.key, node, prefix_len)
# shared-prefix node should also reflect max priority
new_node.priority = max(new_node.priority, priority)