Make the duplicate-reservation ack gate O(1) for fresh node ids

node_has_undrained_write_ack scanned ack_write_queue on every
reservation, including the per-request-per-chunk prepare path whose
node ids are freshly minted and can never be queued. Track the max
node id ever appended to the queue: any queued id is <= max by
construction (no monotonicity assumption needed for correctness), so
fresh ids exit on one integer compare and the scan remains only for
re-reservations of old ids (the rare write_backup fallback).

All three ack_write_queue append sites now go through a single
_append_write_ack funnel that maintains the max — the zero-owned-rank
and non-CP write acks previously would have bypassed it, allowing
false negatives on ranks owning no pages of a node.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 10:34:11 +00:00
parent 698a3e2431
commit 47cb9b9d11
2 changed files with 50 additions and 5 deletions

View File

@@ -2176,6 +2176,17 @@ class TestHiRadixCacheCPBackup(CustomTestCase):
self.assertEqual(cache.ongoing_write_through, {53: attached_node})
self.assertEqual(dec_locked, [])
@staticmethod
def _make_exploding_queue():
class _ExplodingQueue(list):
def __iter__(self):
raise AssertionError("fresh node ids must not scan the ack queue")
def __bool__(self):
return True
return _ExplodingQueue()
def test_reserve_write_cp_refuses_node_with_undrained_ack(self):
"""Producer-side invariant: at most one in-flight ack per node_id.
A reservation for a node whose previous final ack is still queued is
@@ -2190,6 +2201,7 @@ class TestHiRadixCacheCPBackup(CustomTestCase):
ack_write_queue=[
HiCacheAck(MagicMock(), MagicMock(), [4614]),
],
_max_write_ack_node_id=4614,
)
controller.node_has_undrained_write_ack = types.MethodType(
HiCacheController.node_has_undrained_write_ack, controller
@@ -2201,9 +2213,15 @@ class TestHiRadixCacheCPBackup(CustomTestCase):
)
self.assertIsInstance(result, HiCacheWriteFailure)
self.assertEqual(result.required_host_slots, 0)
# Different node id is not gated by the queue scan.
# An old (<= max) but absent node id is resolved by the queue scan.
self.assertFalse(
HiCacheController.node_has_undrained_write_ack(controller, 4615)
HiCacheController.node_has_undrained_write_ack(controller, 4613)
)
# Fresh ids (> max ever acked, i.e. every prepare-path reservation)
# take the O(1) fast path: no queue scan at all.
controller.ack_write_queue = self._make_exploding_queue()
self.assertFalse(
HiCacheController.node_has_undrained_write_ack(controller, 9999)
)
def test_rollback_pending_backup_scrubs_acks_and_cancels_state(self):