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

Function select_linear_successor

atomic-repository/src/repository/content.rs:924–985  ·  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

922/// resolves to just the new span. Genuine conflict forks and delete-throughs
923/// return [`LinearStep::Bail`] so the caller defers to the full graph walk.
924fn select_linear_successor<T>(
925 txn: &T,
926 inode: Inode,
927 adj: &mut atomic_core::pristine::InodeAdjState,
928 options: &atomic_core::output::alive::RetrieveOptions,
929) -> atomic_core::record::RecordResult<LinearStep>
930where
931 T: atomic_core::pristine::GraphTxnT + atomic_core::pristine::InodeGraphOps,
932{
933 use atomic_core::types::EdgeFlags;
934
935 let mut alive: Vec<atomic_core::types::GraphNode<NodeId>> = Vec::new();
936 let mut deleted: std::collections::HashSet<atomic_core::types::GraphNode<NodeId>> =
937 std::collections::HashSet::new();
938
939 while let Some(edge_result) = txn.next_inode_adj(adj) {
940 let edge = match edge_result {
941 Ok(edge) => edge,
942 Err(_) => return Ok(LinearStep::Bail),
943 };
944 let flags = edge.flag();
945 if flags.contains(EdgeFlags::PARENT)
946 || flags.contains(EdgeFlags::PSEUDO)
947 || flags.contains(EdgeFlags::FOLDER)
948 {
949 continue;
950 }
951 if !options.passes_filter(edge.introduced_by()) {
952 continue;
953 }
954 let dest = match txn.find_block_in_inode(inode, edge.dest()) {
955 Ok(Some(d)) => d,
956 Ok(None) | Err(_) => return Ok(LinearStep::Bail),
957 };
958 if !options.passes_filter(dest.change) {
959 continue;
960 }
961 if flags.contains(EdgeFlags::DELETED) {
962 deleted.insert(dest);
963 } else if !alive.contains(&dest) {
964 alive.push(dest);
965 }
966 }
967
968 // A destination that is both alive (original edge) and deleted (superseding
969 // edge) is dead from this view's perspective.
970 alive.retain(|d| !deleted.contains(d));
971
972 match alive.len() {
973 0 => {
974 if deleted.is_empty() {
975 Ok(LinearStep::End)
976 } else {
977 // The only successors here were deleted; the live continuation
978 // lies past a dead vertex — defer to the full graph walk.
979 Ok(LinearStep::Bail)
980 }
981 }

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