MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / output_graph_content

Function output_graph_content

atomic-core/src/output/repo/content.rs:137–281  ·  view source on GitHub ↗

Output the content of an alive graph to a span buffer. This function traverses the graph in SCC order (as computed by [`compute_order`](crate::output::alive::compute_order)) and writes each span's content to the buffer. Conflicts are handled by: - **Cyclic conflicts**: Multi-span SCCs are output with conflict markers - **Zombie content**: Deleted vertices with live edges get zombie markers # Ar

(
    changes: &C,
    hash_fn: F,
    graph: &AliveGraph,
    order: &OrderResult,
    buffer: &mut V,
)

Source from the content-addressed store, hash-verified

135/// 3. For zombie vertices: wrap in zombie conflict markers
136/// 4. Track and report any content retrieval errors
137pub fn output_graph_content<C, F, V>(
138 changes: &C,
139 hash_fn: F,
140 graph: &AliveGraph,
141 order: &OrderResult,
142 buffer: &mut V,
143) -> OutputResult<()>
144where
145 C: ChangeStore,
146 F: Fn(NodeId) -> Option<Hash>,
147 V: VertexBuffer,
148{
149 // Track conflict IDs
150 let mut conflict_id: usize = 0;
151
152 // Track zombie state
153 let mut in_zombie: Option<usize> = None;
154
155 // Debug-only guard: each vertex's content must be emitted at most once.
156 // Emitting a vertex twice is the silent-duplication signature (e.g. a
157 // conflict tail written once per side). Zero cost in release builds.
158 #[cfg(debug_assertions)]
159 let mut emitted_content: std::collections::HashSet<VertexId> = std::collections::HashSet::new();
160
161 // Process SCCs in reverse order (Tarjan produces reverse topological order,
162 // so we iterate in reverse to get forward topological order for correct output)
163 for scc in order.sccs.iter().rev() {
164 // Skip empty SCCs (shouldn't happen, but be safe)
165 if scc.is_empty() {
166 continue;
167 }
168
169 // Check if this is a cyclic conflict (multi-span SCC)
170 let is_cyclic = scc.len() > 1;
171
172 if is_cyclic {
173 conflict_id += 1;
174 buffer
175 .begin_cyclic_conflict(conflict_id)
176 .map_err(OutputError::io)?;
177 }
178
179 // Output each span in the SCC
180 for (i, &vertex_id) in scc.iter().enumerate() {
181 // Get span data
182 let vertex_data = match graph.try_get_vertex(vertex_id) {
183 Some(v) => v,
184 None => continue,
185 };
186
187 let node = vertex_data.node;
188
189 // Handle zombie state transitions
190 let is_zombie = vertex_data.is_zombie();
191
192 if is_zombie && in_zombie.is_none() {
193 // Entering zombie region
194 conflict_id += 1;

Calls 15

try_get_vertexMethod · 0.80
is_noneMethod · 0.80
getMethod · 0.65
iterMethod · 0.45
is_emptyMethod · 0.45
lenMethod · 0.45
begin_cyclic_conflictMethod · 0.45
is_zombieMethod · 0.45
into_iterMethod · 0.45
begin_zombie_conflictMethod · 0.45
end_zombie_conflictMethod · 0.45
conflict_nextMethod · 0.45