fix: align write-through pending across tree cores (#37278)
This commit is contained in:
@@ -928,8 +928,10 @@ class RustUnifiedTreeCore(UnifiedTreeCoreInterface):
|
||||
result = DropSubtreeNoHostResult(is_dropped=binding_result.dropped)
|
||||
return _fill_evict_result(binding_result, result)
|
||||
|
||||
def mark_write_through_pending(self, node_id: NodeId) -> None:
|
||||
self._binding.mark_write_through_pending(node_id)
|
||||
def mark_write_through_pending(
|
||||
self, node_ids: list[NodeId], ack_id: NodeId
|
||||
) -> list[NodeId]:
|
||||
return self._binding.mark_write_through_pending(list(node_ids), ack_id)
|
||||
|
||||
def finish_write_through(self, node_ids: list[NodeId], ack_id: int) -> None:
|
||||
self._binding.finish_write_through(list(node_ids), ack_id)
|
||||
|
||||
@@ -485,7 +485,7 @@ class UnifiedCacheLinkerWrapper:
|
||||
cache.dec_lock_ref(node_id, lock_params)
|
||||
return
|
||||
|
||||
cache.tree_core.mark_write_through_pending(node_id)
|
||||
cache.tree_core.mark_write_through_pending([node_id], ack_id=node_id)
|
||||
node.external_cache_stored = True
|
||||
self.pending_offloads.append(_PendingOffload(node_id, lock_params, [node_id]))
|
||||
|
||||
|
||||
@@ -2203,10 +2203,29 @@ class UnifiedTreeCore(UnifiedTreeCoreInterface):
|
||||
self._update_duplicate_tracking(node)
|
||||
node = node.parent
|
||||
|
||||
def mark_write_through_pending(self, node_id: NodeId) -> None:
|
||||
"""Mark a node as having an in-flight write-through backup."""
|
||||
node = self.node_by_id(node_id)
|
||||
node.write_through_pending_id = node_id
|
||||
def mark_write_through_pending(
|
||||
self, node_ids: list[NodeId], ack_id: NodeId
|
||||
) -> list[NodeId]:
|
||||
"""Stamp ack_id on every covered node; returns them ancestors first."""
|
||||
marked: list[tuple[int, NodeId]] = []
|
||||
for node_id in node_ids:
|
||||
node = self.node_by_id(node_id)
|
||||
assert node.write_through_pending_id in (
|
||||
None,
|
||||
ack_id,
|
||||
), f"node {node.id} is already pending under a different write-through ack"
|
||||
node.write_through_pending_id = ack_id
|
||||
marked.append((self._depth_from_root(node), node_id))
|
||||
marked.sort()
|
||||
return [node_id for _, node_id in marked]
|
||||
|
||||
@staticmethod
|
||||
def _depth_from_root(node: UnifiedTreeNode) -> int:
|
||||
depth = 0
|
||||
while node.parent is not None:
|
||||
depth += 1
|
||||
node = node.parent
|
||||
return depth
|
||||
|
||||
def finish_write_through(self, node_ids: list[NodeId], ack_id: int) -> None:
|
||||
"""Clear the write-through-pending mark (when it matches ack_id) and record the
|
||||
|
||||
@@ -537,8 +537,11 @@ class UnifiedTreeCoreInterface(ABC):
|
||||
write_back_duplicate_reclaim_digest: int = 0
|
||||
|
||||
@abstractmethod
|
||||
def mark_write_through_pending(self, node_id: NodeId) -> None:
|
||||
"""Mark a node as having an in-flight write-through backup."""
|
||||
def mark_write_through_pending(
|
||||
self, node_ids: list[NodeId], ack_id: NodeId
|
||||
) -> list[NodeId]:
|
||||
"""Mark every node covered by one in-flight write-through backup, and return
|
||||
them ancestors first: publish links each host store event to its parent."""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -1370,10 +1370,26 @@ class UnifiedRadixCache(BasePrefixCache):
|
||||
lock_params = None
|
||||
if not write_back:
|
||||
lock_params = self.inc_lock_ref(node_id).to_dec_params()
|
||||
self._track_write_through_node(node_id, lock_params)
|
||||
publish_node_ids = self._backup_publish_node_ids(node_id, comp_xfers)
|
||||
self._track_write_through_node(
|
||||
node_id, lock_params, publish_node_ids=publish_node_ids
|
||||
)
|
||||
written = len(host_indices)
|
||||
return written
|
||||
|
||||
@staticmethod
|
||||
def _backup_publish_node_ids(
|
||||
node_id: NodeId, comp_xfers: dict[ComponentType, list[PoolTransfer]]
|
||||
) -> list[NodeId]:
|
||||
"""The acked node plus every node a component backup transfer covers."""
|
||||
publish_node_ids: list[NodeId] = []
|
||||
for transfers in comp_xfers.values():
|
||||
for transfer in transfers:
|
||||
publish_node_ids.extend(transfer.nodes_to_load or ())
|
||||
if node_id not in publish_node_ids:
|
||||
publish_node_ids.append(node_id)
|
||||
return list(dict.fromkeys(publish_node_ids))
|
||||
|
||||
def _build_backup_sidecar(self, device_value, comp_xfers):
|
||||
"""Gather sidecar transfer spec."""
|
||||
kv_xfer = PoolTransfer(name=PoolName.KV, device_indices=device_value)
|
||||
@@ -1399,10 +1415,13 @@ class UnifiedRadixCache(BasePrefixCache):
|
||||
self,
|
||||
node_id: NodeId,
|
||||
lock_params: Optional[DecLockRefParams],
|
||||
publish_node_ids: list[NodeId],
|
||||
) -> None:
|
||||
self.tree_core.mark_write_through_pending(node_id)
|
||||
publish_node_ids = self.tree_core.mark_write_through_pending(
|
||||
publish_node_ids, ack_id=node_id
|
||||
)
|
||||
self.ongoing_write_through[node_id] = _OngoingWriteThrough(
|
||||
node_id, lock_params, [node_id]
|
||||
node_id, lock_params, publish_node_ids
|
||||
)
|
||||
|
||||
def _replace_pending_write_through_node(
|
||||
|
||||
Reference in New Issue
Block a user