1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! Shared reachability walk (STORAGE-VACUUM.md §2).
//!
//! The crate-internal reusable form of `branch::prune::collect_reachable`:
//! ONE depth-first walk — dedup by hash, push every internal node's children,
//! fail-fast the instant a referenced node cannot be resolved — parameterised
//! over a [`NodeSource`] so its two callers share the traversal by
//! construction rather than by duplicated skeleton:
//!
//! - `branch::prune` (a [`crate::store::NodeStore`]-cached source, LOGICAL
//! serialised bytes, must-resolve-here — a missing node is [`PruneError`]);
//! - `db::vacuum::mark` (a verified-file-map source that recomputes every
//! traversed node's content hash before trusting its child list — COMPRESSED
//! file bytes, and DUAL fail-mode: a declared root must resolve here, while a
//! probed root may legitimately resolve in another store).
//!
//! The two axes the design names — byte-mode and fail-mode — live in the
//! caller, not here: byte-mode is the source's [`NodeSource::Bytes`] measure,
//! and fail-mode is how the caller maps [`ReachError::Missing`] (a hard
//! refusal for the declared walk, "try the next store" for the probe). The
//! walk itself is fail-fast and mode-free, so prune's observable behaviour is
//! unchanged: same dedup, same traversal order, same logical-byte measure, and
//! a missing node still stops the walk before any deletion.
//!
//! [`PruneError`]: crate::branch::prune::PruneError
use HashMap;
use crateHash;
/// A source of nodes for a reachability walk.
///
/// [`resolve`](NodeSource::resolve) reports one node's byte weight and pushes
/// its child hashes onto the walk's stack, or signals the node's absence, or
/// fails hard. Pushing children through the caller-owned stack (rather than
/// returning them) keeps the walk allocation-free per node — the same shape
/// both callers had before the extraction.
/// Why a walk stopped before resolving every reachable node.
/// Depth-first walk from `roots`, deduplicating by hash.
///
/// Returns every reached node mapped to its byte weight. Fail-fast: the first
/// hard error or first absent node stops the walk immediately — nothing is
/// deleted or marked on a partial result, which is what earns the "fail loud
/// on any missing or unreadable referenced node" contract (§2).