When unrecording a patch that introduced a zombie file by deleting a file, we must delete the paths made of pseudo-edges that represent the zombie conflict. The algorithm for finding that path was wrong, this patch replaces it with a proper one.
MQ6ERQ43MWASF2OSG65FHKWHCWT35BJVFJWKHAFPVCTLICCTJWUAC UEWNF7X3S5V6N2LEJCFMZKFZZHQUCAF6FZF5DYO5XATNDEQ4G35QC RSFUX6MLPHII3DRELHN62DOJCHFCDNKSRMWJDSFGTWN5S4RJVSSQC YXAVFTPP2PQAYMKGQH7QNKFVGKDI2UHVWB7SIDA4QEYSBP75ZGUQC ZJWCPRMHAYZYGCPYBTBIPBBFVCVDSFNGUL36HMC2DHCWZZKNA7PAC BOJEBIOIRT73FEVDUZPKRIBQMP3XX2HCZQ6CIB2AGMWTGNN47JRQC QY4E6CLE6MFO6GGT5XVCPMGJQK22W4FZNLWRZKVMYYPOMAAZUX4AC BD5PC25AB5MKVIYDFSDGRZ4YGX4PKW4SMZ3YAYAPNA5HLDVJUR3QC SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC I24UEJQLCH2SOXA4UHIYWTRDCHSOPU7AFTRUOTX7HZIAV4AZKYEQC 3CFU4DQNHPPJC2B63RSVAVGHTQZT3RT5CCHHYC4ZM6DQ4GVQULSQC IXC43DSHDSXCE2X6H6N47GGVKTYM2D2BUUWF34CFWMFT6Z45NOOAC I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC YN63NUZO4LVJ7XPMURDULTXBVJKW5MVCTZ24R7Z52QMHO3HPDUVQC 6YMDOZIB5LVYLFIDGN2WNT5JTHEAMS4TFPVDEZ3OWXWOKJOC5QDAC CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC HMMMKONLCRAXVT7SO2ITTFDOJIQKKVSRIZPXYVPDC34RCBHWMHVAC 3AMEP2Y5J6GA4AWQONF4JVA3XSR3ASLHHKMYG44R72SOUY3UQCDAC BXD3IQYNMKMI5BTANCF6NZHZP4CKPWADGJMBT2R3WTMKVKONT5QAC G55Y75FUL4LWA346HQCZ5EVA5G54EDTZAW7MPVTO44BP6D5UMURAC RMDMAYRXYBU5OQXV5HSF6LFD4NBMKRNH5EPIVW3K5HAV6D56IG6QC YRBOKAWJVS24QTCEMYIUWTEE6HE7BM5OBF5U5MPYFTYW4ZYV2THQC AD6M434OFUCH6ISHP7GXSNNRBHEWP242ZDH7QCVCYLHMRASGE5MQC ZDK3GNDBWXJ2OXFDYB72ZCEBGLBF4MKE5K3PVHDZATHJ7HJIDPRQC let (pos, _) = txn.follow_oldest_path(&repo.changes, &channel, &root)?;
let pos = if let Some(pos) = parse_pos(&root) {pos} else {let inode = libpijul::fs::find_inode(&txn, &root)?;debug!("inode {:?}", inode);use libpijul::TreeTxnT;if let Ok(Some(pos)) = txn.get_inodes(&inode, None) {debug!("inode {:?}", pos);*pos} else {debug!("no inode");txn.follow_oldest_path(&repo.changes, &channel, &root)?.0}};
}}fn parse_pos(s: &str) -> Option<libpijul::pristine::Position<libpijul::pristine::ChangeId>> {let mut it = s.split('.');if let (Some(a), Some(b)) = (it.next(),it.next()) {use libpijul::pristine::{Position, ChangeId, ChangePosition, Base32};let change = ChangeId::from_base32(a.as_bytes())?;let pos: u64 = b.parse().ok()?;Some(Position {change,pos: ChangePosition(pos.into()),})} else {None
ws.stack.push(*to);
ws.zombies_stack.push((*to, false, false))}while let Some((v, alive, on_path)) = ws.zombies_stack.pop() {if on_path {// Already visited. If not alive, delete PSEUDO edges.if !alive {for e in iter_adj_all(txn, channel, v)? {let e = e?;if e.flag().contains(EdgeFlags::PSEUDO) {ws.del_edges.push((v, *e))}}if ws.zombies_stack.is_empty() {debug_assert_eq!(v.start_pos(), to);// Collect all the pseudo-paths up.ws.parents.clear();collect_zombies_up(txn, channel, to, ws)?}}continue}// A vertex cannot be marked alive if it wasn't on the path.assert!(!alive);// If the vertex was already visited in another path, pass.if !ws.parents.insert(v) {continue;}// Else, iterate through all children. If any of them is// alive, mark the entire path as alive. Else, just push onto// the stack and continue the DFS.let mut is_first = true;for e in iter_alive_children(txn, channel, v)? {let e = e?;if e.flag().intersects(EdgeFlags::PARENT | EdgeFlags::DELETED) {continue}let x = txn.find_block(channel, e.dest())?;if is_alive(txn, channel, x)? {// Mark all edges on the path as alive.for (_, alive, on_path) in ws.zombies_stack.iter_mut() {if *on_path {*alive = true}}} else {if is_first {is_first = false;ws.zombies_stack.push((v, false, true))}ws.zombies_stack.push((*x, false, false))}}}ws.zombies_stack.clear();ws.parents.clear();Ok(())}fn collect_zombies_up<T: GraphTxnT>(txn: &T,channel: &T::Graph,to: Position<ChangeId>,ws: &mut Workspace,) -> Result<(), BlockError<T::GraphError>> {if let Ok(&to) = txn.find_block(channel, to) {ws.stack.push(to);
{let file = Vertex {change: ChangeId(L64(5867590239053715538)),start: ChangePosition(204370u64.into()),end: ChangePosition(204370u64.into()),};let still_here: Vec<_> = iter_adjacent(txn,T::graph_mut(channel),file,EdgeFlags::empty(),EdgeFlags::all(),)?.collect();debug!("still here! {:?}", still_here);}
debug!("clean_obsolete_pseudo_edges {:?} {:?} {:?}", next_vertex, p, inode);{let still_here: Vec<_> = iter_adjacent(txn,channel,next_vertex,EdgeFlags::empty(),EdgeFlags::all(),)?.collect();debug!("pseudo edge still here ? {:?} {:?}", next_vertex.change.0.0, still_here)}