Fixing a bug in unrecord, where a patch creating an undeletion conflict would not be properly unrecorded

pmeunier
Feb 23, 2023, 1:07 PM
3CFU4DQNHPPJC2B63RSVAVGHTQZT3RT5CCHHYC4ZM6DQ4GVQULSQC

Dependencies

  • [2] ZDK3GNDB Tag transactions (including a massive refactoring of errors)
  • [3] CCLLB7OI Upgrading to Sanakirja 0.15 + version bump
  • [4] ZJWCPRMH Fixing known patches in deleted contexts
  • [5] I24UEJQL Various post-fire fixes
  • [6] GHO6DWPI Refactoring iterators
  • [7] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [8] OFQY3GUU Formatting and versions
  • [*] 6YMDOZIB Refactoring apply
  • [*] WZVCLZKY address clippy lints
  • [*] KQTD46KV Unrecord: restore files *after* having unapplied the *entire* change
  • [*] YN63NUZO Sanakirja 1.0

Change contents

  • edit in libpijul/src/unrecord/mod.rs at line 169
    [2.11372]
    [3.234220]
    // `clean_inodes` is used to check whether we're seeing this file
    // for the first time.
  • edit in libpijul/src/unrecord/mod.rs at line 172
    [3.234263]
    [10.0]
    let mut touched_inodes = HashSet::new();
  • replacement in libpijul/src/unrecord/mod.rs at line 177
    [3.234399][3.23917:24021](),[3.24021][3.1821:1860](),[3.1860][3.24057:24110](),[3.24057][3.24057:24110](),[3.30188][3.24110:24151](),[3.24110][3.24110:24151]()
    Atom::EdgeMap(ref newedges) => unapply_edges(
    changes,
    txn,
    T::graph_mut(channel),
    change_id,
    newedges,
    &mut ws,
    )?,
    [3.234399]
    [3.234542]
    Atom::EdgeMap(ref newedges) => {
    touched_inodes.insert(newedges.inode);
    unapply_edges(
    changes,
    txn,
    T::graph_mut(channel),
    change_id,
    newedges,
    &mut ws,
    )?
    }
  • edit in libpijul/src/unrecord/mod.rs at line 189
    [3.234590]
    [3.234590]
    touched_inodes.insert(newvertex.inode);
  • edit in libpijul/src/unrecord/mod.rs at line 210
    [11.2017]
    [3.2220]
    // If we are restoring a vertex that was deleted by the
    // patch we are unrecording, remove its zombie status
    // (extra pseudo-edges) if necessary.
  • edit in libpijul/src/unrecord/mod.rs at line 247
    [12.1137]
    [3.2349]
    // Check each touched inode for zombieness, and remove files that
    // aren't zombies anymore.
    for inode in touched_inodes {
    // This inode is actually dead if its only alive adjacent
    // edges are PSEUDO.
    if let Ok(inode) = internal_pos(txn, &inode, change_id) {
    let channel = T::graph_mut(channel);
    collect_zombies_pseudo(txn, channel, inode, &mut ws)?;
    for (v, mut e) in ws.del_edges.drain(..) {
    if e.flag().contains(EdgeFlags::PARENT) {
    let u = *txn.find_block_end(channel, e.dest())?;
    e -= EdgeFlags::PARENT;
    del_graph_with_rev(txn, channel, e.flag(), u, v, e.introduced_by())?;
    } else {
    let w = *txn.find_block(channel, e.dest())?;
    del_graph_with_rev(txn, channel, e.flag(), v, w, e.introduced_by())?;
    }
    }
    }
    }
  • edit in libpijul/src/unrecord/mod.rs at line 595
    [3.246806]
    [3.26863]
    /// Collect the edges introduced by the patch we're unrecording to
    /// mark zombie conflicts.
  • edit in libpijul/src/unrecord/mod.rs at line 627
    [13.19204]
    [13.19204]
    ws.del_edges.push((v, *e))
    }
    }
    }
    ws.stack.clear();
    ws.parents.clear();
    Ok(())
    }
    /// Collect the paths going through `to` whose vertices' adjacent
    /// edges are all PSEUDO or DELETED
    fn collect_zombies_pseudo<T: GraphTxnT>(
    txn: &T,
    channel: &T::Graph,
    to: Position<ChangeId>,
    ws: &mut Workspace,
    ) -> Result<(), BlockError<T::GraphError>> {
    ws.stack.push(*txn.find_block(channel, to)?);
    while let Some(v) = ws.stack.pop() {
    debug!("remove_zombies, v = {:?}", v);
    if !ws.parents.insert(v) {
    continue;
    }
    let del_len = ws.del_edges.len();
    let stack_len = ws.stack.len();
    for e in iter_adj_all(txn, channel, v)? {
    let e = e?;
    debug!("e = {:?}", e);
    if (e.flag() & (EdgeFlags::PSEUDO | EdgeFlags::DELETED)).is_empty() {
    // This isn't a pseudo edge, `v` isn't part
    ws.del_edges.truncate(del_len);
    ws.stack.truncate(stack_len);
    break
    }
    if e.flag().contains(EdgeFlags::PARENT) {
    ws.stack.push(*txn.find_block_end(channel, e.dest())?)
    } else {
    ws.stack.push(*txn.find_block(channel, e.dest())?)
    }
    if e.flag().contains(EdgeFlags::PSEUDO) {