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

Function select_linear_successor

atomic-repository/src/repository/content.rs:898–959  ·  view source on GitHub ↗

Choose the single live successor of `current` for a linear content walk. In the additive graph model a superseded span keeps its original alive `BLOCK` edge *alongside* a new `DELETED` edge. A walk that merely skipped `DELETED` edges would therefore still follow the alive edge into the superseded span and resurrect stale content. This helper instead treats any destination that has a visible `DELE

(
    txn: &T,
    inode: Inode,
    adj: &mut atomic_core::pristine::InodeAdjState,
    options: &atomic_core::output::alive::RetrieveOptions,
)

Source from the content-addressed store, hash-verified

896/// resolves to just the new span. Genuine conflict forks and delete-throughs
897/// return [`LinearStep::Bail`] so the caller defers to the full graph walk.
898fn select_linear_successor<T>(
899 txn: &T,
900 inode: Inode,
901 adj: &mut atomic_core::pristine::InodeAdjState,
902 options: &atomic_core::output::alive::RetrieveOptions,
903) -> atomic_core::record::RecordResult<LinearStep>
904where
905 T: atomic_core::pristine::GraphTxnT + atomic_core::pristine::InodeGraphOps,
906{
907 use atomic_core::types::EdgeFlags;
908
909 let mut alive: Vec<atomic_core::types::GraphNode<NodeId>> = Vec::new();
910 let mut deleted: std::collections::HashSet<atomic_core::types::GraphNode<NodeId>> =
911 std::collections::HashSet::new();
912
913 while let Some(edge_result) = txn.next_inode_adj(adj) {
914 let edge = match edge_result {
915 Ok(edge) => edge,
916 Err(_) => return Ok(LinearStep::Bail),
917 };
918 let flags = edge.flag();
919 if flags.contains(EdgeFlags::PARENT)
920 || flags.contains(EdgeFlags::PSEUDO)
921 || flags.contains(EdgeFlags::FOLDER)
922 {
923 continue;
924 }
925 if !options.passes_filter(edge.introduced_by()) {
926 continue;
927 }
928 let dest = match txn.find_block_in_inode(inode, edge.dest()) {
929 Ok(Some(d)) => d,
930 Ok(None) | Err(_) => return Ok(LinearStep::Bail),
931 };
932 if !options.passes_filter(dest.change) {
933 continue;
934 }
935 if flags.contains(EdgeFlags::DELETED) {
936 deleted.insert(dest);
937 } else if !alive.contains(&dest) {
938 alive.push(dest);
939 }
940 }
941
942 // A destination that is both alive (original edge) and deleted (superseding
943 // edge) is dead from this view's perspective.
944 alive.retain(|d| !deleted.contains(d));
945
946 match alive.len() {
947 0 => {
948 if deleted.is_empty() {
949 Ok(LinearStep::End)
950 } else {
951 // The only successors here were deleted; the live continuation
952 // lies past a dead vertex — defer to the full graph walk.
953 Ok(LinearStep::Bail)
954 }
955 }

Calls 11

flagMethod · 0.80
passes_filterMethod · 0.80
next_inode_adjMethod · 0.45
containsMethod · 0.45
introduced_byMethod · 0.45
find_block_in_inodeMethod · 0.45
destMethod · 0.45
insertMethod · 0.45
pushMethod · 0.45
lenMethod · 0.45
is_emptyMethod · 0.45

Tested by

no test coverage detected