Bug fixes when unrecording a patch that introduced zombie files
Dependencies
- [2]
UEWNF7X3Detecting "self-solving" zombie folder (or file) conflicts - [3]
RSFUX6MLCorrect find_alive cache system - [4]
YXAVFTPPAllowing vertex buffer to use references to the transaction, by changing `output::output` to take an ArcTxn<T> instead of a simple T - [5]
ZJWCPRMHFixing known patches in deleted contexts - [6]
BOJEBIOIFixing "block error" in unrecord - [7]
QY4E6CLEReplacing a panic with a proper error - [8]
6YMDOZIBRefactoring apply - [9]
YRBOKAWJFormatting (why wasn't this recorded before? I'm not sure) - [10]
I52XSRUHMassive cleanup, and simplification - [11]
I24UEJQLVarious post-fire fixes - [12]
ZDK3GNDBTag transactions (including a massive refactoring of errors) - [13]
HMMMKONLFixing alive vertices - [14]
CCLLB7OIUpgrading to Sanakirja 0.15 + version bump - [15]
G55Y75FUAvoiding deadlocks when using output.rs with a non-filesystem output - [16]
KQTD46KVUnrecord: restore files *after* having unapplied the *entire* change - [17]
SXEYMYF7Fixing the bad changes in history (unfortunately, by rebooting). - [18]
A3RM526YIntegrating identity malleability - [19]
RMDMAYRXAdding a root inode (aka supporting submodules) - [20]
MDADYULSFix a panic when switching between channels that have different files - [21]
AD6M434Ofind_alive performance (matters a lot for unrecord) - [22]
VO5OQW4WRemoving anyhow in libpijul - [23]
GHO6DWPIRefactoring iterators - [24]
3AMEP2Y5More convenient interface for channels - [25]
I3OVP3NHArchive: set the accurate and deterministic mtime - [26]
YN63NUZOSanakirja 1.0 - [27]
BXD3IQYNFixing --features git - [28]
7ZFRYVVQCargo.nix and formatting - [29]
KDF6FJRVbigger clippy refactors - [30]
3QXUJMZDMore detailed display of conflicts - [31]
3CFU4DQNFixing a bug in unrecord, where a patch creating an undeletion conflict would not be properly unrecorded - [32]
BD5PC25ADeleting conflict resolution vertices when the sides are deleted - [*]
IXC43DSHFixing a bug in unrecord
Change contents
- edit in pijul/src/commands/debug.rs at line 7
use log::*; - replacement in pijul/src/commands/debug.rs at line 44
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}}; - edit in pijul/src/commands/debug.rs at line 80
}}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 - replacement in libpijul/src/unrecord/mod.rs at line 251
// edges are PSEUDO.// edges are PSEUDO|FOLDER. - edit in libpijul/src/unrecord/mod.rs at line 259
debug!("line {}, del {:?} {:?} {:?}", line!(), u, v, e); - edit in libpijul/src/unrecord/mod.rs at line 264
debug!("line {}, del {:?} {:?} {:?}", line!(), v, w, e); - edit in libpijul/src/unrecord/mod.rs at line 293[34.69][8.235977]
zombies_stack: Vec<(Vertex<ChangeId>, bool, bool)>, - edit in libpijul/src/unrecord/mod.rs at line 353
debug!("line {}, del {:?} {:?} {:?}", line!(), a, b, e); - edit in libpijul/src/unrecord/mod.rs at line 591
debug!("line {}, del {:?} {:?} {:?}", line!(), u, v, e); - edit in libpijul/src/unrecord/mod.rs at line 595
debug!("line {}, del {:?} {:?} {:?}", line!(), v, w, e); - replacement in libpijul/src/unrecord/mod.rs at line 614
debug!("remove_zombies, v = {:?}", v);debug!("collect_zombies, v = {:?}", v); - edit in libpijul/src/unrecord/mod.rs at line 652
// First, collect the paths downwards. - replacement in libpijul/src/unrecord/mod.rs at line 655
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); - edit in libpijul/src/unrecord/mod.rs at line 727
- edit in libpijul/src/unrecord/mod.rs at line 738
if (e.flag() & (EdgeFlags::PSEUDO | EdgeFlags::DELETED)).is_empty() {// This isn't a pseudo edge, `v` isn't partws.del_edges.truncate(del_len);ws.stack.truncate(stack_len);break} - edit in libpijul/src/unrecord/mod.rs at line 739
assert!(e.flag().contains(EdgeFlags::FOLDER));if !e.flag().intersects(EdgeFlags::PSEUDO | EdgeFlags::DELETED) {// Neither a pseudo edge nor a deleted edge.ws.del_edges.truncate(del_len);ws.stack.truncate(stack_len);break} - replacement in libpijul/src/unrecord/mod.rs at line 751
} else {if let Ok(x) = txn.find_block(channel, e.dest()) {ws.stack.push(*x)if e.flag().contains(EdgeFlags::PSEUDO) {ws.del_edges.push((v, *e)) - edit in libpijul/src/unrecord/mod.rs at line 755[8.3096]→[8.3096:3150](∅→∅),[8.3150]→[8.19204:19247](∅→∅),[8.19204]→[8.19204:19247](∅→∅),[8.19247]→[8.3796:3810](∅→∅),[8.3796]→[8.3796:3810](∅→∅)
if e.flag().contains(EdgeFlags::PSEUDO) {ws.del_edges.push((v, *e))} - replacement in libpijul/src/record.rs at line 1220
retrieve(&*txn, txn.graph(&*channel), vertex)?retrieve(&*txn, txn.graph(&*channel), vertex, false)? - replacement in libpijul/src/pristine/mod.rs at line 1339
if e.flag().contains(EdgeFlags::PARENT) ^ down {if e.flag().contains(EdgeFlags::PARENT) != down { - replacement in libpijul/src/pristine/mod.rs at line 2211
let graph = crate::alive::retrieve::retrieve(txn, txn.graph(channel), file_).unwrap();let graph = crate::alive::retrieve::retrieve(txn, txn.graph(channel), file_, true).unwrap(); - replacement in libpijul/src/pristine/mod.rs at line 2215
debug_root(txn, txn.graph(channel), file.unwrap(), &mut f, false)?;debug_root(txn, txn.graph(channel), file.unwrap(), &mut f, true)?; - replacement in libpijul/src/output/output.rs at line 770
retrieve(&*txn, txn.graph(&*channel), output_item.pos)?retrieve(&*txn, txn.graph(&*channel), output_item.pos, false)? - edit in libpijul/src/output/mod.rs at line 258
return Ok(());// The following was supposed to be a panic, but actually it// doesn't need to be one, there just wasn't any file to// output./* - edit in libpijul/src/output/mod.rs at line 281
*/ - replacement in libpijul/src/output/mod.rs at line 339
crate::alive::retrieve(&*txn, txn.graph(&*channel), v0)?crate::alive::retrieve(&*txn, txn.graph(&*channel), v0, false)? - replacement in libpijul/src/output/archive.rs at line 268
crate::alive::retrieve(&*txn_, txn_.graph(&channel_), output_item.pos)?;crate::alive::retrieve(&*txn_, txn_.graph(&channel_), output_item.pos, false)?; - replacement in libpijul/src/missing_context.rs at line 46
let mut graph = crate::alive::retrieve(txn, channel, pos)?;let mut graph = crate::alive::retrieve(txn, channel, pos, false)?; - edit in libpijul/src/missing_context.rs at line 367
debug!("detect folder conflict resolution, deleting {:?} → {:?} {:?}", v, e, p); - edit in libpijul/src/find_alive.rs at line 166
if v.flag() & EdgeFlags::pseudof() == EdgeFlags::PSEUDO {continue;} - edit in libpijul/src/find_alive.rs at line 170
debug!("is_file {:?} {:?}", is_file, !v.flag().is_folder()); - edit in libpijul/src/find_alive.rs at line 172[8.15924]→[8.766374:766414](∅→∅),[8.135145]→[8.766374:766414](∅→∅),[8.766374]→[8.766374:766414](∅→∅),[8.766414]→[8.135146:135216](∅→∅)
continue;}if v.flag() & EdgeFlags::pseudof() == EdgeFlags::PSEUDO { - replacement in libpijul/src/find_alive.rs at line 175
if vertex == vertex0 {if v.flag().is_block() && vertex == vertex0 { - edit in libpijul/src/find_alive.rs at line 212
for e in it {let e = e?;is_file |= !e.flag().intersects(EdgeFlags::parent_folder())}debug!("{:?} is a file ? {:?}", vertex, is_file); - replacement in libpijul/src/apply.rs at line 337
Atom::NewVertex(ref n) => put_newvertex(txn,T::graph_mut(channel),changes,change,ws,change_id,n,)?,Atom::NewVertex(ref n) => {put_newvertex(txn,T::graph_mut(channel),changes,change,ws,change_id,n,)?}, - edit in libpijul/src/apply.rs at line 384
{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);} - edit in libpijul/src/apply.rs at line 586
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)} - edit in libpijul/src/apply/edge.rs at line 270
debug!("reconnect pseudo edges, parents = {:?}", ws.parents);debug!("reconnect pseudo edges, children = {:?}", ws.children); - edit in libpijul/src/alive/retrieve.rs at line 10
include_deleted: bool, - replacement in libpijul/src/alive/retrieve.rs at line 42
EdgeFlags::PSEUDO | EdgeFlags::BLOCK,if include_deleted {EdgeFlags::PSEUDO | EdgeFlags::BLOCK | EdgeFlags::DELETED} else {EdgeFlags::PSEUDO | EdgeFlags::BLOCK}, - edit in libpijul/src/alive/retrieve.rs at line 49
if e.flag().intersects(EdgeFlags::PARENT) {continue} - replacement in libpijul/src/alive/retrieve.rs at line 123
let mut graph = retrieve(txn, channel, pos)?;let mut graph = retrieve(txn, channel, pos, false)?;