replacement in libpijul/src/unrecord/mod.rs at line 264
[5.1695]→[5.2349:2396](∅→∅),
[5.1137]→[5.2349:2396](∅→∅) − crate::apply::clean_obsolete_pseudo_edges(
+ let mut inodes = crate::apply::clean_obsolete_pseudo_edges(
edit in libpijul/src/unrecord/mod.rs at line 270
+ debug!("inodes = {:?}", inodes);
+ collect_missing_contexts(
+ txn,
+ txn.graph(channel),
+ &mut ws.apply,
+ &change,
+ change_id,
+ &mut inodes,
+ )?;
+ for i in inodes {
+ debug!("inodes: repair zombie {:?}", i);
+ crate::apply::repair_zombies(txn, T::graph_mut(channel), i)?;
+ }
edit in libpijul/src/unrecord/mod.rs at line 285
+ debug!("unapply done");
edit in libpijul/src/unrecord/mod.rs at line 422
− let hash: Hash = (*txn.get_external(&change_id).unwrap().unwrap()).into();
replacement in libpijul/src/unrecord/mod.rs at line 433
replacement in libpijul/src/unrecord/mod.rs at line 441
− .knows(edge.introduced_by.as_ref().unwrap_or(&hash), h)
+ .knows(edge.introduced_by.as_ref().unwrap_or(&ext), h)
replacement in libpijul/src/unrecord/mod.rs at line 470
[5.242243]→[5.242243:242346](∅→∅) − // does a patch introduced by an edge parallel to
− // this one remove this edge from the graph?
+ // does a patch (call it q) other than the one (p) we're
+ // unrecording remove this same edge (a, b, intro) from the graph?
+ // This can happen e.g. if an edge is deleted twice, in which case
+ // this unrecord is likely to introduce a zombie conflict between
+ // p and q.
replacement in libpijul/src/unrecord/mod.rs at line 492
[5.2391]→[5.2391:2449](∅→∅) − // reinsert a -> b: that edge was removed by `e`.
+ // reinsert a -> b: that edge was removed when introducing
+ // `e`.
edit in libpijul/src/unrecord/mod.rs at line 529
+ /// Remove extra pseudo-edges introduced to mark a zombie conflict, if
+ /// the conflict is indeed removed by this unrecord.
edit in libpijul/src/unrecord/mod.rs at line 572
+ debug!("already seen");
edit in libpijul/src/unrecord/mod.rs at line 598
+ debug!("zombies collected");
edit in libpijul/src/unrecord/mod.rs at line 716
+
+ /// Same as crate::apply::collect_missing_contexts, but with the
+ /// directions reversed.
+ fn collect_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
+ txn: &T,
+ channel: &T::Graph,
+ ws: &mut crate::apply::Workspace,
+ change: &Change,
+ change_id: ChangeId,
+ inodes: &mut HashSet<Position<ChangeId>>,
+ ) -> Result<(), crate::apply::LocalApplyError<T>> {
+ debug!("collect_missing_contexts");
+ inodes.extend(
+ ws.missing_context
+ .unknown_parents
+ .drain(..)
+ .map(|x| internal_pos(txn, &x.2, change_id).unwrap()),
+ );
+ for atom in change.changes.iter().flat_map(|r| r.iter()) {
+ match atom {
+ // NewVertex is already collected when applying.
+ Atom::NewVertex(_) => {}
+ Atom::EdgeMap(ref n) => {
+ crate::apply::has_missing_edge_context(
+ txn, channel, change_id, change, &n, inodes, true,
+ )?;
+ }
+ }
+ }
+ Ok(())
+ }
replacement in libpijul/src/missing_context.rs at line 24
[5.696724]→[5.88638:88682](∅→∅) − pub(crate) fn load_graph<T: GraphTxnT>(
+ pub fn load_graph<T: GraphTxnT>(
replacement in libpijul/src/missing_context.rs at line 236
[5.706744]→[5.83467:83505](∅→∅) − pub(crate) unknown_parents: Vec<(
+ pub unknown_parents: Vec<(
replacement in libpijul/src/missing_context.rs at line 243
[5.123715]→[5.83506:83619](∅→∅) − pub(crate) parents: HashSet<SerializedEdge>,
− pub(crate) pseudo: Vec<(Vertex<ChangeId>, SerializedEdge)>,
+ pub parents: HashSet<SerializedEdge>,
+ pub pseudo: Vec<(Vertex<ChangeId>, SerializedEdge)>,
replacement in libpijul/src/missing_context.rs at line 246
[5.147]→[5.13188:13219](∅→∅),
[5.13219]→[5.707101:707180](∅→∅),
[5.707101]→[5.707101:707180](∅→∅),
[5.707180]→[5.13220:13269](∅→∅) − pub(crate) graphs: Graphs,
− pub(crate) covered_parents: HashSet<(Vertex<ChangeId>, Vertex<ChangeId>)>,
− pub(crate) files: HashSet<Vertex<ChangeId>>,
+ pub graphs: Graphs,
+ pub covered_parents: HashSet<(Vertex<ChangeId>, Vertex<ChangeId>)>,
+ pub files: HashSet<Vertex<ChangeId>>,
replacement in libpijul/src/missing_context.rs at line 256
[5.13296]→[5.13296:13322](∅→∅) − pub(crate) struct Graphs(
replacement in libpijul/src/lib.rs at line 18
[5.717621]→[5.717621:717632](∅→∅) replacement in libpijul/src/lib.rs at line 23
[5.717722]→[5.717722:717743](∅→∅) + pub mod missing_context;
edit in libpijul/src/change.rs at line 215
replacement in libpijul/src/change.rs at line 250
[5.837662]→[5.118124:118177](∅→∅),
[5.118177]→[5.837714:837741](∅→∅),
[5.837714]→[5.837714:837741](∅→∅) − let deps = minimize_deps(txn, &channel, &deps)?;
− for d in deps.iter() {
+ debug!("minimize");
+ let deps_ = minimize_deps(txn, &channel, &deps)?;
+ for d in deps_.iter() {
edit in libpijul/src/change.rs at line 330
+ debug!("add_zombie_deps_from {:?}", edge);
edit in libpijul/src/change.rs at line 355
+ debug!("e_to {:?}", e_to);
edit in libpijul/src/change.rs at line 369
+ debug!("to_pos {:?} to {:?}", to_pos, to);
+ let mut h = HashSet::new();
edit in libpijul/src/change.rs at line 372
+ if !h.insert(*to) {
+ error!("seen twice: {:?}", to);
+ break;
+ }
edit in libpijul/src/change.rs at line 377
+ debug!("add_zombie_deps_to {:?}", edge);
edit in libpijul/src/change.rs at line 394
+ debug!("to {:?} {:?}", to, e_to);
replacement in libpijul/src/change.rs at line 418
[5.840736]→[5.7238:7313](∅→∅),
[5.7313]→[5.139419:139460](∅→∅),
[5.7313]→[5.840811:840887](∅→∅),
[5.64432]→[5.840811:840887](∅→∅),
[5.120185]→[5.840811:840887](∅→∅),
[5.139460]→[5.840811:840887](∅→∅),
[5.840811]→[5.840811:840887](∅→∅) − let time = txn.get_changeset(txn.changes(&channel), id)?.unwrap();
− let time = u64::from_le(time.0);
− debug!("time = {:?}", time);
− min_time = min_time.min(time);
+ if let Some(time) = txn.get_changeset(txn.changes(&channel), id)? {
+ let time = u64::from_le(time.0);
+ debug!("time = {:?}", time);
+ min_time = min_time.min(time);
+ }
edit in libpijul/src/change.rs at line 1090
replacement in libpijul/src/change.rs at line 1099
[5.860484]→[5.120625:120674](∅→∅),
[5.120674]→[5.860530:860639](∅→∅),
[5.860530]→[5.860530:860639](∅→∅),
[5.860639]→[5.19658:19856](∅→∅),
[5.19856]→[5.860716:860923](∅→∅),
[5.120761]→[5.860716:860923](∅→∅),
[5.139684]→[5.860716:860923](∅→∅),
[5.860716]→[5.860716:860923](∅→∅),
[5.860923]→[5.19857:20057](∅→∅),
[5.20057]→[5.861002:861217](∅→∅),
[5.120850]→[5.861002:861217](∅→∅),
[5.139798]→[5.861002:861217](∅→∅),
[5.861002]→[5.861002:861217](∅→∅),
[5.861217]→[5.20058:20243](∅→∅),
[5.20243]→[5.861293:861348](∅→∅),
[5.120936]→[5.861293:861348](∅→∅),
[5.139909]→[5.861293:861348](∅→∅),
[5.861293]→[5.861293:861348](∅→∅),
[5.861348]→[5.120937:121036](∅→∅),
[5.121036]→[5.861443:861673](∅→∅),
[5.861443]→[5.861443:861673](∅→∅),
[5.861673]→[5.20244:20323](∅→∅) − }) => Ok(Atom::NewVertex(NewVertex {
− up_context: up_context
− .iter()
− .map(|&up| Position {
− change: up
− .change
− .as_ref()
− .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
− pos: up.pos,
− })
− .collect(),
− down_context: down_context
− .iter()
− .map(|&down| Position {
− change: down
− .change
− .as_ref()
− .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
− pos: down.pos,
− })
− .collect(),
− start: *start,
− end: *end,
− flag: *flag,
− inode: Position {
− change: inode
− .change
− .as_ref()
− .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
− pos: inode.pos,
− },
− })),
− Atom::EdgeMap(EdgeMap { edges, inode }) => Ok(Atom::EdgeMap(EdgeMap {
− edges: edges
− .iter()
− .map(|edge| NewEdge {
− previous: edge.previous,
− flag: edge.flag,
− from: Position {
− change: edge
− .from
+ }) => {
+ debug!(
+ "globalize vertex {:?} {:?}",
+ up_context.len(),
+ down_context.len()
+ );
+ Ok(Atom::NewVertex(NewVertex {
+ up_context: up_context
+ .iter()
+ .map(|&up| Position {
+ change: up
replacement in libpijul/src/change.rs at line 1113
[5.20498]→[5.861761:861873](∅→∅),
[5.121134]→[5.861761:861873](∅→∅),
[5.140032]→[5.861761:861873](∅→∅),
[5.861761]→[5.861761:861873](∅→∅),
[5.861873]→[5.20499:20576](∅→∅) − pos: edge.from.pos,
− },
− to: Vertex {
− change: edge
− .to
+ pos: up.pos,
+ })
+ .collect(),
+ down_context: down_context
+ .iter()
+ .map(|&down| Position {
+ change: down
replacement in libpijul/src/change.rs at line 1123
[5.20751]→[5.861959:862082](∅→∅),
[5.121230]→[5.861959:862082](∅→∅),
[5.140153]→[5.861959:862082](∅→∅),
[5.861959]→[5.861959:862082](∅→∅),
[5.862082]→[5.140154:140231](∅→∅),
[5.140231]→[5.121231:121307](∅→∅),
[5.862150]→[5.121231:121307](∅→∅),
[5.121307]→[5.140232:140273](∅→∅),
[5.140273]→[5.862251:862500](∅→∅),
[5.862251]→[5.862251:862500](∅→∅),
[5.862500]→[5.20752:20937](∅→∅),
[5.20937]→[5.862576:862631](∅→∅),
[5.121393]→[5.862576:862631](∅→∅),
[5.140384]→[5.862576:862631](∅→∅),
[5.862576]→[5.862576:862631](∅→∅),
[5.862631]→[5.121394:121411](∅→∅) − start: edge.to.start,
− end: edge.to.end,
− },
− introduced_by: edge.introduced_by.as_ref().map(|a| {
− if let Some(a) = txn.get_external(a).unwrap() {
− a.into()
− } else {
− panic!("introduced by {:?}", a);
− }
− }),
− })
− .collect(),
− inode: Position {
− change: inode
− .change
− .as_ref()
− .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
− pos: inode.pos,
− },
− })),
+ pos: down.pos,
+ })
+ .collect(),
+ start: *start,
+ end: *end,
+ flag: *flag,
+ inode: Position {
+ change: inode
+ .change
+ .as_ref()
+ .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
+ pos: inode.pos,
+ },
+ }))
+ }
+ Atom::EdgeMap(EdgeMap { edges, inode }) => {
+ debug!("globalize edgemap {:?}", edges.len());
+ Ok(Atom::EdgeMap(EdgeMap {
+ edges: edges
+ .iter()
+ .map(|edge| NewEdge {
+ previous: edge.previous,
+ flag: edge.flag,
+ from: Position {
+ change: edge
+ .from
+ .change
+ .as_ref()
+ .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
+ pos: edge.from.pos,
+ },
+ to: Vertex {
+ change: edge
+ .to
+ .change
+ .as_ref()
+ .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
+ start: edge.to.start,
+ end: edge.to.end,
+ },
+ introduced_by: edge.introduced_by.as_ref().map(|a| {
+ if let Some(a) = txn.get_external(a).unwrap() {
+ a.into()
+ } else {
+ panic!("introduced by {:?}", a);
+ }
+ }),
+ })
+ .collect(),
+ inode: Position {
+ change: inode
+ .change
+ .as_ref()
+ .and_then(|a| txn.get_external(a).unwrap().map(Into::into)),
+ pos: inode.pos,
+ },
+ }))
+ }
edit in libpijul/src/change.rs at line 1391
+ info!("computing dependencies");
edit in libpijul/src/change.rs at line 1394
+ info!("hashing patch");
edit in libpijul/src/change/text_changes.rs at line 265
+ debug!("dep hash {:?}", dep.hash);
replacement in libpijul/src/apply.rs at line 10
[5.93417]→[5.1216:1237](∅→∅) replacement in libpijul/src/apply.rs at line 12
[5.89954]→[5.89954:89966](∅→∅) replacement in libpijul/src/apply.rs at line 519
[5.961195]→[5.961195:961276](∅→∅),
[5.961276]→[5.145857:145934](∅→∅),
[5.145934]→[5.19463:19498](∅→∅),
[5.961343]→[5.19463:19498](∅→∅),
[5.19498]→[5.961391:961430](∅→∅),
[5.961391]→[5.961391:961430](∅→∅),
[5.961430]→[5.69614:69655](∅→∅),
[5.69655]→[5.961479:961591](∅→∅),
[5.961479]→[5.961479:961591](∅→∅),
[5.961591]→[5.145935:145968](∅→∅),
[5.145968]→[5.241:341](∅→∅) − parents: HashSet<Vertex<ChangeId>>,
− children: HashSet<Vertex<ChangeId>>,
− pseudo: Vec<(Vertex<ChangeId>, SerializedEdge, Position<Option<Hash>>)>,
− deleted_by: HashSet<ChangeId>,
− up_context: Vec<Vertex<ChangeId>>,
− down_context: Vec<Vertex<ChangeId>>,
− pub(crate) missing_context: crate::missing_context::Workspace,
− rooted: HashMap<Vertex<ChangeId>, bool>,
− adjbuf: Vec<SerializedEdge>,
− alive_folder: HashMap<Vertex<ChangeId>, bool>,
− folder_stack: Vec<(Vertex<ChangeId>, bool)>,
+ pub parents: HashSet<Vertex<ChangeId>>,
+ pub children: HashSet<Vertex<ChangeId>>,
+ pub pseudo: Vec<(Vertex<ChangeId>, SerializedEdge, Position<Option<Hash>>)>,
+ pub deleted_by: HashSet<ChangeId>,
+ pub up_context: Vec<Vertex<ChangeId>>,
+ pub down_context: Vec<Vertex<ChangeId>>,
+ pub missing_context: crate::missing_context::Workspace,
+ pub rooted: HashMap<Vertex<ChangeId>, bool>,
+ pub adjbuf: Vec<SerializedEdge>,
+ pub alive_folder: HashMap<Vertex<ChangeId>, bool>,
+ pub folder_stack: Vec<(Vertex<ChangeId>, bool)>,
edit in libpijul/src/apply.rs at line 598
− debug!("visited {:?}", visited);
edit in libpijul/src/apply.rs at line 600
− debug!("descendants {:#?}", descendants);
edit in libpijul/src/apply.rs at line 602
+ debug!("descendant {:#?}", r);
edit in libpijul/src/apply.rs at line 613
+ // Reconnect with ancestor.
+ for v in stack.iter().rev() {
+ if v.is_on_path {
+ debug!("on path: {:?}", v);
+ // If the last vertex on the path to `current` is not
+ // alive, a reconnect is needed.
+ if v.is_alive() {
+ // We need to reconnect, and we can do it now
+ // since we won't have a chance to visit that
+ // edge (because non-PARENT edge we are
+ // inserting now starts from a vertex that is
+ // on the path, which means we've already
+ // pushed all its children onto the stack.).
+ put_graph_with_rev(
+ txn,
+ channel,
+ EdgeFlags::PSEUDO,
+ v.vertex,
+ elt.vertex,
+ ChangeId::ROOT,
+ )?;
+ break;
+ } else {
+ // Remember that those dead vertices have
+ // `elt.vertex` as a descendant.
+ descendants.insert((v.vertex, elt.vertex));
+ }
+ }
+ }
+
edit in libpijul/src/apply.rs at line 693
+ debug!("on path: {:?}", v);
replacement in libpijul/src/apply.rs at line 707
[4.2971]→[4.2971:3015](∅→∅) replacement in libpijul/src/apply.rs at line 715
[4.3330]→[4.3330:3409](∅→∅) − descendants.insert((v.vertex, stack[len - 1].vertex));
+ descendants.insert((v.vertex, elt.vertex));
replacement in libpijul/src/apply.rs at line 898
[5.3809]→[5.5424:5481](∅→∅) − fn collect_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
+ pub fn collect_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
replacement in libpijul/src/apply.rs at line 951
[5.976997]→[5.7258:7345](∅→∅) − has_missing_edge_context(txn, channel, change_id, change, n, inodes)?;
+ has_missing_edge_context(txn, channel, change_id, change, n, inodes, false)?;
replacement in libpijul/src/apply.rs at line 958
[5.24008]→[5.7346:7403](∅→∅) − fn has_missing_edge_context<T: GraphMutTxnT + TreeTxnT>(
+ /// Collect inodes with missing contexts into `inodes`.
+ pub(crate) fn has_missing_edge_context<T: GraphMutTxnT + TreeTxnT>(
edit in libpijul/src/apply.rs at line 966
replacement in libpijul/src/apply.rs at line 969
[5.7545]→[5.7545:8133](∅→∅),
[5.8133]→[5.36342:36481](∅→∅),
[5.36481]→[5.8311:8416](∅→∅),
[5.1384]→[5.8311:8416](∅→∅) − if !inodes.contains(&inode) {
− for e in n.edges.iter() {
− assert!(!e.flag.contains(EdgeFlags::PARENT));
− if e.flag.contains(EdgeFlags::DELETED) {
− trace!("repairing context deleted {:?}", e);
− if has_missing_context_deleted(txn, channel, change_id, |h| change.knows(&h), e)
− .map_err(LocalApplyError::from_missing)?
− {
− inodes.insert(inode);
− break;
− }
− } else {
− trace!("repairing context nondeleted {:?}", e);
− if has_missing_context_nondeleted(txn, channel, change_id, e)
− .map_err(LocalApplyError::from_missing)?
− {
− inodes.insert(inode);
− break;
− }
+ // If the inode is already in there, no need to do anything.
+ if inodes.contains(&inode) {
+ return Ok(());
+ }
+
+ let ext: Hash = if reverse {
+ (*txn.get_external(&change_id).unwrap().unwrap()).into()
+ } else {
+ // Unused, hence we avoid one Sanakirja lookup.
+ Hash::None
+ };
+
+ for e in n.edges.iter() {
+ let e = if reverse {
+ e.reverse(Some(ext))
+ } else {
+ e.clone()
+ };
+
+ assert!(!e.flag.contains(EdgeFlags::PARENT));
+ if e.flag.contains(EdgeFlags::DELETED) {
+ trace!("repairing context deleted {:?}", e);
+ if has_missing_context_deleted(txn, channel, change_id, |h| change.knows(&h), &e)
+ .map_err(LocalApplyError::from_missing)?
+ {
+ inodes.insert(inode);
+ break;
+ }
+ } else {
+ trace!("repairing context nondeleted {:?}", e);
+ if has_missing_context_nondeleted(txn, channel, change_id, &e)
+ .map_err(LocalApplyError::from_missing)?
+ {
+ inodes.insert(inode);
+ break;
replacement in libpijul/src/apply/edge.rs at line 118
[5.99267]→[5.1552:1589](∅→∅) − fn collect_nondeleted_zombies<T, K>(
+ pub fn collect_nondeleted_zombies<T, K>(
replacement in libpijul/src/apply/edge.rs at line 224
[5.102516]→[5.43866:43919](∅→∅) − fn collect_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
+ pub fn collect_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
replacement in libpijul/src/apply/edge.rs at line 263
[5.103722]→[5.43959:44014](∅→∅) − fn reconnect_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
+ pub fn reconnect_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
edit in libpijul/src/alive/output.rs at line 130
+ debug!("end zombie conflict {id} (line {})", line!());
edit in libpijul/src/alive/output.rs at line 137
+ debug!("end zombie conflict {id} (line {})", line!());
replacement in libpijul/src/alive/output.rs at line 213
− vbuf.begin_cyclic_conflict::<P>(*id)?;
+ debug!("begin cyclic conflict {id_cyclic}");
+ vbuf.begin_cyclic_conflict::<P>(id_cyclic)?;
edit in libpijul/src/alive/output.rs at line 222
+ debug!("begin zombie conflict {id}");
edit in libpijul/src/alive/output.rs at line 228
+ debug!("end zombie conflict {id}");