Route undrained-ack reservation refusal around the capacity retry

The reserve_write_cp undrained-ack refusal returned a bare
HiCacheWriteFailure, which _reserve_write_cp_indices_no_collective
interpreted as a host-capacity failure: with free host space the
retry path tripped the predicted-no-deficit RuntimeError (crashing
the scheduler in exactly the scenario the gate exists to handle
gracefully), and with a deficit it triggered pointless evictions
before refusing again.

Give HiCacheWriteFailure an explicit reason (default host_capacity
keeps all existing constructors/semantics); the wrapper returns
non-capacity failures immediately as skip-this-round, and a
wrapper-level test pins that undrained_ack reaches neither the retry
admission nor host eviction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 10:41:39 +00:00
parent 47cb9b9d11
commit ecf7998c80
3 changed files with 47 additions and 1 deletions

View File

@@ -321,6 +321,11 @@ class HiCacheWriteResult:
class HiCacheWriteFailure:
required_host_slots: int
metadata: object = None
# Why the reservation failed. "host_capacity" failures are retryable via
# deterministic host eviction; "undrained_ack" means the node's previous
# backup ack has not been drained yet — callers must skip this backup
# round instead of entering the capacity retry/eviction path.
reason: str = "host_capacity"
@dataclass
@@ -1039,7 +1044,7 @@ class HiCacheController:
"has an undrained write ack; skipping duplicate backup",
node_id,
)
return HiCacheWriteFailure(required_host_slots=0)
return HiCacheWriteFailure(required_host_slots=0, reason="undrained_ack")
page_size = self.page_size
layout = self.cp_shared_kv_layout

View File

@@ -2212,6 +2212,12 @@ class HiRadixCache(RadixCache):
)
if not isinstance(result, HiCacheWriteFailure):
return result
if getattr(result, "reason", "host_capacity") != "host_capacity":
# Not a capacity failure (e.g. undrained_ack: the node's previous
# backup ack is still queued). Eviction cannot help, and entering
# the retry path would trip the predicted-no-deficit fail-fast
# below. Skip this backup round.
return result
retry_admission = self._cp_build_write_admission(
device_indices, node_id=node_id, phase="retry_after_local_failure"