Simplification of missing context repairs

pmeunier
Dec 18, 2023, 11:11 AM
OXZVZDQZEVP7NV3HS6HK5QA7RUD35ODVQ3LL7PWJHTS7DEFM3XTAC

Dependencies

  • [2] 3KHT2M5Z Fixing alive vertex detection in down contexts too
  • [3] L7S3MNQ4 When repairing down contexts, do not follow deleted edges if there is an block+alive outgoing edge
  • [4] L4EZSH6B Fixing zombie conflicts: known was computed on the wrong thing
  • [5] XNY6VDZS Fixing a bug in context repairs
  • [6] PNJL5TPZ Version bump
  • [7] X6EUOQ5O Adding more debugging checks in `pijul debug`
  • [8] T7YIRFWD Raising an error on corrupt patches rather than panicking
  • [9] PNKAJTFZ Fixing a caching mistake in find_alive
  • [10] X7OHUPL5 Fixing a bug in unrecord, and fixing the tests
  • [11] YTQS4ES3 Fixing a parsing problem (related to permissions), and the associated permissions
  • [12] QQZNSB26 Permission update (after #X243)
  • [13] ATZ3BWSE Fixing the double-deletion of repairs for folder edges
  • [14] SFQBWL6P Improving unrecord performance (8 times faster on my tests)
  • [15] AD6M434O find_alive performance (matters a lot for unrecord)
  • [16] I52XSRUH Massive cleanup, and simplification
  • [17] NMX52UOG Fixing the "invalid change" errors
  • [18] XGH2A4BO Formatting/Cleanup
  • [19] RSFUX6ML Correct find_alive cache system
  • [20] YN63NUZO Sanakirja 1.0
  • [21] ZJWCPRMH Fixing known patches in deleted contexts
  • [22] 5FI6SBEZ Re-implement change printing and parsing
  • [23] 3CFU4DQN Fixing a bug in unrecord, where a patch creating an undeletion conflict would not be properly unrecorded
  • [24] FAOGX7G3 Outputting the repo after the last Git import
  • [25] TNN56XYK libpijul alpha.43
  • [26] CD6XDYOH Fixing unrecord
  • [27] IACED7RW text_encoding module
  • [28] 7NSTS6PK Adding a cache in find_alive to improve performance in some cases
  • [29] 2BKYJ2JM Fixing a bug introduced by the recent refactoring
  • [30] HMMMKONL Fixing alive vertices
  • [31] CCLLB7OI Upgrading to Sanakirja 0.15 + version bump
  • [32] HDGRZISM Version updates
  • [33] EEBKW7VT Keys and identities
  • [34] UEWNF7X3 Detecting "self-solving" zombie folder (or file) conflicts
  • [35] JQR4Q2NK Fixing a cache miss/unwrap in find_alive for vertices that have been split during insertion
  • [36] QL6K2ZM3 Tags
  • [37] ZCPGCKKY Fixing a bug where zombie files could be deleted by unrecord, but not their contents
  • [38] MQ6ERQ43 Bug fixes when unrecording a patch that introduced zombie files
  • [39] 3I4PAA2A Making a few types and methods public
  • [40] GHO6DWPI Refactoring iterators
  • [41] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [42] VO5OQW4W Removing anyhow in libpijul
  • [43] X243Z3Y5 Recording only the required metadata (can even be changed later!)
  • [44] I24UEJQL Various post-fire fixes
  • [45] T7CAACFB Fixing zombie conflicts (some vertices were wrongly detected alive)
  • [46] KDF6FJRV bigger clippy refactors
  • [47] N3X5YP7P Adding tag/txn.rs, now that the parser allows it
  • [48] WUNYO4QB Forgot to add EdgeFlags::df()
  • [49] WZVCLZKY address clippy lints
  • [50] FABI77LL Cleaning up the cache in missing_context and find_alive
  • [51] RRCSHAYZ Formatting
  • [52] WBTE6H6V Solving a conflict
  • [53] 6YMDOZIB Refactoring apply
  • [54] JACZYXK4 Fixing a bug in unrecord
  • [55] ZDK3GNDB Tag transactions (including a massive refactoring of errors)

Change contents

  • file deletion: find_alive.rs (----------)find_alive.rs (-xw-x--x--)
    [10.198146][10.1295:1310](),[10.1310][10.763306:763306](),[10.198146][10.763290:763305](),[10.763305][10.763306:763306]()
    use crate::pristine::*;
    use crate::{HashMap, HashSet};
    // use std::collections::hash_map::Entry;
    /// The following is an unrolled DFS, where each alive vertex is
    /// inserted into each "alive set" along the current path (which is
    /// recognised by looking at the visited vertices on the stack).
    pub(crate) fn find_alive_down<'a, T: GraphTxnT>(
    txn: &T,
    channel: &T::Graph,
    vertex0: Vertex<ChangeId>,
    cache: &'a mut HashMap<Vertex<ChangeId>, Option<HashSet<Vertex<ChangeId>>>>,
    ) -> Result<&'a Option<HashSet<Vertex<ChangeId>>>, BlockError<T::GraphError>> {
    let mut stack: Vec<(_, Option<HashSet<Vertex<ChangeId>>>)> = vec![(
    SerializedEdge::empty(vertex0.start_pos(), ChangeId::ROOT),
    None,
    )];
    let mut visited = HashSet::default();
    while let Some((elt, alive)) = stack.pop() {
    if let Some(alive) = alive {
    // We've gone through all the descendants, put this in the
    // cache.
    let vertex = txn.find_block(&channel, elt.dest())?;
    if stack.is_empty() {
    // Done!
    cache.insert(*vertex, Some(alive.clone()));
    assert_eq!(vertex0.start_pos(), vertex.start_pos());
    return Ok(cache.get(&vertex).unwrap());
    }
    continue;
    }
    let vertex = txn.find_block(&channel, elt.dest())?;
    if let Some(c) = cache.get(vertex) {
    for st in stack.iter_mut() {
    if let Some(ref mut st) = st.1 {
    if let Some(c) = c {
    st.extend(c.iter().cloned());
    } else {
    st.insert(*vertex);
    }
    }
    }
    continue;
    }
    // A `None` in the cache means that the vertex
    // itself (the cache key) is alive.
    debug!("elt = {:?}, vertex = {:?}", elt, vertex);
    let elt_index = stack.len();
    for v in iter_adj_all(txn, &channel, *vertex)? {
    let v = v?;
    if v.flag().contains(EdgeFlags::FOLDER) {
    continue;
    }
    debug!("v = {:?}", v);
    if v.flag().contains(EdgeFlags::PARENT) {
    if (v.flag().contains(EdgeFlags::BLOCK) || vertex.is_empty())
    && !v.flag().contains(EdgeFlags::DELETED)
    && !v.flag().contains(EdgeFlags::PSEUDO)
    {
    if *vertex == vertex0 {
    // vertex0 is alive.
    stack.truncate(elt_index);
    let (_, alive) = stack.pop().unwrap();
    let alive = alive.unwrap();
    assert!(alive.is_empty());
    cache.insert(vertex0, None);
    return Ok(cache.get(&vertex0).unwrap());
    } else {
    // vertex is alive, insert it into all the
    // alive sets on the current DFS path
    // (including `vertex`).
    for st in stack.iter_mut() {
    if let Some(ref mut st) = st.1 {
    st.insert(*vertex);
    }
    }
    stack.truncate(elt_index);
    break;
    }
    }
    } else if v.flag().contains(EdgeFlags::DELETED) {
    if !has_alive_blocks {
    stack.push((*v, None))
    }
    }
    }
    }
    unreachable!()
    }
    pub fn find_alive_up<'a, T: GraphTxnT>(
    txn: &T,
    channel: &T::Graph,
    files: &mut HashSet<Vertex<ChangeId>>,
    vertex0: Vertex<ChangeId>,
    change: ChangeId,
    cache: &'a mut HashMap<
    Vertex<ChangeId>,
    (Option<HashSet<Vertex<ChangeId>>>, HashSet<Vertex<ChangeId>>),
    >,
    ) -> Result<&'a Option<HashSet<Vertex<ChangeId>>>, BlockError<T::GraphError>> {
    debug!("find alive up: {:?}", vertex0);
    let mut stack: Vec<(
    _,
    Option<(HashSet<Vertex<ChangeId>>, HashSet<Vertex<ChangeId>>)>,
    )> = vec![(
    SerializedEdge::empty(vertex0.end_pos(), ChangeId::ROOT),
    None,
    )];
    let mut visited = HashSet::default();
    while let Some((elt, alive)) = stack.pop() {
    debug!("pop {:?} {:?}", elt, alive);
    if elt.dest().is_root() {
    continue;
    }
    if let Some((alive, files_)) = alive {
    let vertex = *txn.find_block_end(&channel, elt.dest())?;
    if stack.is_empty() {
    // Done!
    cache.insert(vertex, (Some(alive), files_));
    assert_eq!(vertex.end_pos(), vertex0.end_pos());
    return Ok(&cache.get(&vertex).unwrap().0);
    }
    continue;
    }
    let vertex = *txn.find_block_end(&channel, elt.dest())?;
    debug!("vertex = {:?}", vertex);
    if let Some((c, d)) = cache.get(&vertex) {
    debug!("Cached: {:?} {:?}", c, d);
    for st in stack.iter_mut() {
    if let Some((ref mut al, ref mut f)) = st.1 {
    if let Some(c) = c {
    al.extend(c.iter().cloned());
    } else {
    al.insert(vertex);
    }
    f.extend(d.iter().cloned());
    files.extend(d.iter().cloned());
    }
    }
    continue;
    }
    stack.push((elt, Some((HashSet::new(), HashSet::new()))));
    continue;
    }
    if !visited.insert(elt.dest()) {
    }
    if visited.insert(elt.dest()) {
    stack.push((elt, Some((HashSet::new(), HashSet::new()))));
    debug!("find_alive_up: elt = {:?}, vertex = {:?}", elt, vertex);
    let elt_index = stack.len();
    let mut is_file = false; // Is this the "inode" vertex of a file?
    let mut it = iter_adj_all(txn, &channel, vertex)?;
    while let Some(v) = it.next() {
    let v = v?;
    debug!("find_alive_up: v = {:?} change = {:?}", v, change);
    if v.flag() & EdgeFlags::pseudof() == EdgeFlags::PSEUDO {
    continue;
    }
    if !v.flag().is_parent() {
    is_file |= !v.flag().is_folder();
    continue;
    }
    if !v.flag().is_deleted() {
    if v.flag().is_folder() {
    for e in it {
    let e = e?;
    is_file |= !e.flag().intersects(EdgeFlags::parent_folder())
    }
    if is_file {
    debug!("is alive + is file {:?}", vertex);
    for st in stack.iter_mut() {
    if let Some((ref mut al, ref mut fi)) = st.1 {
    al.insert(vertex);
    fi.insert(vertex);
    }
    }
    files.insert(vertex);
    }
    break;
    } else if v.flag().is_block() || vertex.is_empty() {
    debug!("is alive {:?}", vertex);
    for st in stack.iter_mut() {
    if let Some((ref mut st, _)) = st.1 {
    st.insert(vertex);
    }
    }
    stack.truncate(elt_index);
    break;
    }
    }
    if v.flag().is_folder() {
    if is_file {
    debug!("is pseudo-alive folder {:?}", vertex);
    for st in stack.iter_mut() {
    if let Some((ref mut al, ref mut fi)) = st.1 {
    al.insert(vertex);
    fi.insert(vertex);
    }
    }
    files.insert(vertex);
    }
    break;
    } else {
    stack.push((*v, None))
    }
    }
    }
    unreachable!()
    }
    debug!("is_file = {:?}", is_file);
    debug!("just push");
    for e in it {
    let e = e?;
    is_file |= !e.flag().intersects(EdgeFlags::parent_folder())
    }
    debug!("{:?} is a file ? {:?}", vertex, is_file);
    if v.flag().is_block() && vertex == vertex0 {
    // vertex0 is alive.
    stack.truncate(elt_index);
    let (_, alive) = stack.pop().unwrap();
    let (alive, _) = alive.unwrap();
    assert!(alive.is_empty());
    cache.insert(vertex0, (None, HashSet::new()));
    return Ok(&cache.get(&vertex0).unwrap().0);
    }
    debug!("is_file {:?} {:?}", is_file, !v.flag().is_folder());
    debug!("stack = {:?}", stack);
    // Each element of the stack is a pair of (1) an edge pointing to
    // the position we want to visit next and (2) optionally, a set of
    // alive vertices found until now.
    // Every time we find an alive vertex, we add it to the sets of
    // each element on the path to that vertex.
    } else {
    stack.push((*v, None));
    } else if v.flag().contains(EdgeFlags::BLOCK) {
    has_alive_blocks = true;
    stack.push((*v, None));
    let mut has_alive_blocks = false;
    } else {
    if !visited.insert(elt.dest()) {
    continue;
    }
    stack.push((elt, Some(HashSet::new())));
  • edit in libpijul/src/unrecord/mod.rs at line 4
    [10.231616][10.231616:231647]()
    use crate::missing_context::*;
  • replacement in libpijul/src/unrecord/mod.rs at line 206
    [10.234990][10.2131:2219]()
    repair_newvertex_contexts::<T, C>(txn, T::graph_mut(channel), &mut ws, change_id)?;
    [10.234990]
    [10.235104]
  • edit in libpijul/src/unrecord/mod.rs at line 213
    [10.189][10.2074:2154](),[10.2308][10.2074:2154](),[10.9861][10.2074:2154](),[10.24492][10.2074:2154](),[10.2074][10.2074:2154](),[10.2154][10.2309:2348](),[10.2348][10.2179:2287](),[10.24529][10.2179:2287](),[10.2179][10.2179:2287]()
    repair_edges_context(
    changes,
    txn,
    T::graph_mut(channel),
    &mut ws.apply.missing_context,
    change_id,
    n,
    )?
  • edit in libpijul/src/unrecord/mod.rs at line 260
    [10.1678]
    [10.1678]
    crate::apply::repair_zombies(txn, channel, inode)?;
  • edit in libpijul/src/unrecord/mod.rs at line 359
    [10.238934][10.11603:11677](),[10.10183][10.238976:238993](),[10.11677][10.238976:238993](),[10.25244][10.238976:238993](),[10.238976][10.238976:238993](),[10.238993][10.25245:25273](),[10.25273][10.239023:239047](),[10.239023][10.239023:239047](),[10.239047][10.1483:1508](),[10.1508][10.11678:11724](),[10.10237][10.239080:239152](),[10.11724][10.239080:239152](),[10.25332][10.239080:239152](),[10.239080][10.239080:239152](),[10.239152][10.17659:17702](),[10.17702][10.42:64](),[10.42][10.42:64](),[10.64][10.239430:239440](),[10.239430][10.239430:239440](),[10.239440][10.65:272](),[10.272][10.239440:239446](),[10.239440][10.239440:239446]()
    fn repair_newvertex_contexts<T: GraphMutTxnT + TreeTxnT, C: ChangeStore>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    change_id: ChangeId,
    ) -> Result<(), UnrecordError<C::Error, T>> {
    debug!("up = {:#?}", ws.up);
    for (up, inode) in ws.up.drain() {
    if !is_alive(txn, channel, &up)? {
    continue;
    }
    crate::missing_context::repair_missing_down_context(
    txn,
    channel,
    &mut ws.apply.missing_context,
    inode,
    up,
    &[up],
    )?
    }
  • edit in libpijul/src/unrecord/mod.rs at line 360
    [10.239447][10.239447:239484](),[10.239484][10.1509:1552](),[10.1552][10.17703:17748](),[10.17748][10.317:349](),[10.317][10.317:349](),[10.349][10.8261:8315](),[10.1552][10.8261:8315](),[10.239578][10.8261:8315](),[10.8315][10.239619:239740](),[10.239619][10.239619:239740](),[10.239740][10.25375:25422](),[10.25422][10.17749:17819](),[10.3007][10.25423:25473](),[10.17819][10.25423:25473](),[10.8385][10.25423:25473](),[10.25473][10.17820:17864](),[10.1596][10.239908:239932](),[10.17864][10.239908:239932](),[10.239908][10.239908:239932](),[10.239932][10.1597:1681](),[10.1681][10.240010:240166](),[10.240010][10.240010:240166](),[10.240166][10.1682:1709](),[10.1709][10.240166:240234](),[10.240166][10.240166:240234](),[10.240261][10.240261:240305](),[10.240305][10.10238:10239]()
    debug!("down = {:#?}", ws.down);
    for (down, inode) in ws.down.drain() {
    if !is_alive(txn, channel, &down)? {
    continue;
    }
    for parent in iter_adjacent(
    txn,
    channel,
    down,
    EdgeFlags::PARENT,
    EdgeFlags::all() - EdgeFlags::DELETED,
    )? {
    let parent = parent?;
    let parent = txn.find_block_end(channel, parent.dest())?;
    if !is_alive(txn, channel, parent)? {
    ws.parents.insert(*parent);
    }
    }
    debug!("parents {:#?}", ws.parents);
    for up in ws.parents.drain() {
    crate::missing_context::repair_missing_up_context(
    txn,
    channel,
    &mut ws.apply.missing_context,
    change_id,
    inode,
    up,
    &[down],
    )?
    }
    }
    Ok(())
    }
  • edit in libpijul/src/unrecord/mod.rs at line 699
    [10.3885][10.3885:3886](),[10.3886][10.12172:12241](),[10.12241][10.246914:246948](),[10.27114][10.246914:246948](),[10.246914][10.246914:246948](),[10.246948][10.27115:27143](),[10.27143][10.246978:247082](),[10.246978][10.246978:247082](),[10.247082][10.12242:12288](),[10.12288][10.461:497](),[10.27202][10.461:497](),[10.497][10.19248:19323](),[10.27202][10.19248:19323](),[10.19323][10.247175:247205](),[10.27263][10.247175:247205](),[10.247175][10.247175:247205](),[10.247205][10.191:240](),[10.240][10.247205:247259](),[10.247205][10.247205:247259](),[10.247259][10.27264:27338](),[10.4024][10.247259:247312](),[10.247259][10.247259:247312](),[10.247675][10.247675:247825](),[10.247825][10.356:418](),[10.418][10.4025:4072](),[10.247885][10.4025:4072](),[10.4072][10.247905:247937](),[10.247905][10.247905:247937](),[10.248081][10.10099:10170](),[10.10170][10.3314:3365](),[10.3365][10.498:535](),[10.535][10.27339:27385](),[10.3365][10.27339:27385](),[10.10222][10.27339:27385](),[10.27385][10.536:573](),[10.573][10.248246:248439](),[10.10267][10.248246:248439](),[10.27385][10.248246:248439](),[10.248246][10.248246:248439](),[10.62][10.4073:4120](),[10.248499][10.4073:4120](),[10.4120][10.248739:248783](),[10.248739][10.248739:248783]()
    fn repair_edges_context<T: GraphMutTxnT + TreeTxnT, P: ChangeStore>(
    changes: &P,
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut crate::missing_context::Workspace,
    change_id: ChangeId,
    n: &EdgeMap<Option<Hash>>,
    ) -> Result<(), UnrecordError<P::Error, T>> {
    debug!("repair_edges_context");
    let change_hash: Hash = txn.get_external(&change_id)?.unwrap().into();
    for e in n.edges.iter() {
    debug!("repair_edges_context: {:?}", e);
    assert!(!e.flag.contains(EdgeFlags::PARENT));
    let intro = internal(txn, &e.introduced_by, change_id)?.unwrap();
    if e.previous.contains(EdgeFlags::DELETED) {
    repair_context_deleted(
    txn,
    channel,
    ws,
    n.inode,
    intro,
    |h| changes.knows(&change_hash, &h).unwrap(),
    &e.reverse(Some(change_hash)),
    )?
    } else {
    let to = internal_pos(txn, &e.to.start_pos(), change_id)?;
    let to = txn.find_block(channel, to)?;
    debug!("to = {:?}", to);
    if !is_alive(txn, channel, to)? {
    debug!("not alive");
    continue;
    }
    repair_context_nondeleted(
    txn,
    channel,
    ws,
    n.inode,
    intro,
    &e.reverse(Some(change_hash)),
    )?
    }
    }
    Ok(())
    }
  • edit in libpijul/src/pristine/mod.rs at line 1338
    [7.65]
    [10.67345]
    let stack_len = stack.len();
  • edit in libpijul/src/pristine/mod.rs at line 1353
    [10.617113]
    [10.617156]
    (&mut stack[stack_len..]).reverse()
  • edit in libpijul/src/pristine/edge.rs at line 25
    [10.8459][10.8459:8549]()
    pub(crate) fn db() -> Self {
    Self::DELETED | Self::BLOCK
    }
    #[inline]
  • edit in libpijul/src/missing_context.rs at line 3
    [10.696575][10.696575:696601]()
    use crate::find_alive::*;
  • edit in libpijul/src/missing_context.rs at line 56
    [10.697932][10.697932:697950](),[10.697950][10.26444:26445](),[10.26445][10.698005:698054](),[10.698005][10.698005:698054](),[10.698054][10.89079:89100](),[10.89100][10.698070:698140](),[10.698070][10.698070:698140](),[10.698140][10.89101:89129](),[10.89129][10.698170:698194](),[10.698170][10.698170:698194](),[10.698194][10.9450:9475](),[10.9475][10.698194:698264](),[10.698194][10.698194:698264](),[10.698264][10.89130:89177](),[10.26488][10.698320:698361](),[10.89177][10.698320:698361](),[10.698320][10.698320:698361](),[10.698361][10.43:197](),[10.197][10.0:226](),[10.226][10.698527:698528](),[10.698527][10.698527:698528](),[10.698528][10.227:700](),[10.700][10.698931:698941](),[10.698931][10.698931:698941](),[10.698941][10.701:777](),[10.146][10.699912:699918](),[10.379][10.699912:699918](),[10.777][10.699912:699918](),[10.9719][10.699912:699918](),[10.89250][10.699912:699918](),[10.699912][10.699912:699918](),[10.48][10.699962:699976](),[10.699962][10.699962:699976](),[10.699976][10.89251:89290](),[10.9754][10.700008:700025](),[10.89290][10.700008:700025](),[10.700008][10.700008:700025](),[10.700025][10.89291:89319](),[10.89319][10.9755:9840](),[10.700055][10.9755:9840](),[10.9840][10.89320:89361](),[10.89361][10.9868:9904](),[10.9868][10.9868:9904](),[10.9904][10.380:444](),[10.444][10.9968:10155](),[10.9968][10.9968:10155](),[10.10215][10.10215:10293](),[10.105][10.700569:700588](),[10.10293][10.700569:700588](),[10.26694][10.700569:700588](),[10.700569][10.700569:700588](),[10.700588][10.26695:26696](),[10.26696][10.700643:700694](),[10.700643][10.700643:700694](),[10.700694][10.89362:89383](),[10.89383][10.700710:700780](),[10.700710][10.700710:700780](),[10.700780][10.89384:89412](),[10.89412][10.700810:700904](),[10.700810][10.700810:700904](),[10.700904][10.89413:89460](),[10.89460][10.445:496](),[10.496][10.700937:700978](),[10.26739][10.700937:700978](),[10.89460][10.700937:700978](),[10.700937][10.700937:700978](),[10.700978][10.497:574](),[10.574][10.778:1145]()
    }
    }
    }
    pub(crate) fn repair_missing_up_context<
    'a,
    T: GraphMutTxnT,
    I: IntoIterator<Item = &'a Vertex<ChangeId>>,
    >(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    change_id: ChangeId,
    inode: Position<Option<Hash>>,
    c: Vertex<ChangeId>,
    d: I,
    ) -> Result<(), MissingError<T::GraphError>> {
    let now = std::time::Instant::now();
    let alive = find_alive_up(
    txn,
    channel,
    &mut ws.files,
    c,
    change_id,
    &mut ws.alive_up_cache,
    )?;
    if let Some(alive) = alive {
    let mut alive = alive.clone();
    debug!("files = {:?}", ws.files);
    crate::TIMERS.lock().unwrap().find_alive += now.elapsed();
    ws.load_graph(txn, channel, inode)?;
    debug!("repair_missing_up_context, alive = {:?}", alive);
    for &d in d {
    if let Some((graph, vids)) = ws.graphs.0.get(&inode) {
    crate::alive::remove_redundant_parents(
    graph,
    vids,
    &mut alive,
    &mut ws.covered_parents,
    d,
    );
    }
    repair_regular_up(txn, channel, &alive, d, EdgeFlags::PSEUDO)?;
    }
    } else {
    debug!("repair_missing_up_context: {:?} is alive", c);
    }
    Ok(())
    }
    fn repair_regular_up<T: GraphMutTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    alive: &HashSet<Vertex<ChangeId>>,
    d: Vertex<ChangeId>,
    flag: EdgeFlags,
    ) -> Result<(), TxnErr<T::GraphError>> {
    for &ancestor in alive.iter() {
    debug!("repair_regular_up {:?} → {:?}", ancestor, d);
    if ancestor == d {
    info!(
    "repair_missing_up_context, alive: {:?} == {:?}",
    ancestor, d
    );
    continue;
    }
    put_graph_with_rev(txn, channel, flag, ancestor, d, ChangeId::ROOT)?;
    }
    Ok(())
    }
    pub(crate) fn repair_missing_down_context<
    'a,
    T: GraphMutTxnT,
    I: IntoIterator<Item = &'a Vertex<ChangeId>>,
    >(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    c: Vertex<ChangeId>,
    d: I,
    ) -> Result<(), MissingError<T::GraphError>> {
    debug!("repair_missing_down_context {:?}", c);
    let now = std::time::Instant::now();
    let alive = find_alive_down(txn, channel, c, &mut ws.alive_down_cache)?;
    if let Some(alive) = alive {
    let mut alive = alive.clone();
    debug!("alive = {:?}", alive);
    crate::TIMERS.lock().unwrap().find_alive += now.elapsed();
    ws.load_graph(txn, channel, inode)?;
    if let Some((graph, vids)) = ws.graphs.0.get(&inode) {
    crate::alive::remove_redundant_children(graph, vids, &mut alive, c);
  • edit in libpijul/src/missing_context.rs at line 57
    [10.1155][10.701277:701278](),[10.701277][10.701277:701278](),[10.701278][10.1156:1269](),[10.1269][10.701379:701380](),[10.701379][10.701379:701380](),[10.701380][10.1270:1660](),[10.1660][10.701647:701661](),[10.701647][10.701647:701661](),[10.10699][10.701825:701835](),[10.26796][10.701825:701835](),[10.57387][10.701825:701835](),[10.89552][10.701825:701835](),[10.701825][10.701825:701835](),[10.701835][10.1661:1731]()
    if !alive.is_empty() {
    debug!("repair_missing_down_context alive = {:#?}", alive);
    }
    for &d in d {
    for &desc in alive.iter() {
    if d == desc {
    info!("repair_missing_down_context, alive: {:?} == {:?}", d, desc);
    continue;
    }
    debug!("repair_missing_down {:?} {:?}", d, desc);
    put_graph_with_rev(txn, channel, EdgeFlags::PSEUDO, d, desc, ChangeId::ROOT)?;
    }
    }
    } else {
    debug!("repair_missing_down: {:?} is alive", c);
  • edit in libpijul/src/missing_context.rs at line 58
    [10.701841][10.701841:701852]()
    Ok(())
  • replacement in libpijul/src/missing_context.rs at line 60
    [10.26798][10.978:1036](),[10.1036][10.701965:701982](),[10.89614][10.701965:701982](),[10.701965][10.701965:701982](),[10.701982][10.89615:89643](),[10.89643][10.702012:702071](),[10.702012][10.702012:702071]()
    pub(crate) fn repair_context_nondeleted<T: GraphMutTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    [10.26798]
    [10.702071]
    pub(crate) fn has_missing_context_nondeleted<T: GraphMutTxnT>(
    txn: &T,
    channel: &T::Graph,
  • replacement in libpijul/src/missing_context.rs at line 65
    [10.702145][10.1037:1084]()
    ) -> Result<(), MissingError<T::GraphError>> {
    [10.702145]
    [10.10700]
    ) -> Result<bool, MissingError<T::GraphError>> {
  • replacement in libpijul/src/missing_context.rs at line 67
    [10.10744][10.10744:10767]()
    return Ok(());
    [10.10744]
    [10.703811]
    return Ok(false);
  • replacement in libpijul/src/missing_context.rs at line 75
    [5.113][10.1085:1172](),[10.123202][10.1085:1172](),[10.1172][10.11149:11219](),[10.11149][10.11149:11219](),[10.11219][10.482:525](),[10.525][5.114:260]()
    repair_missing_up_context(txn, channel, ws, change_id, inode, source, &[target])?;
    reconnect_target_up(txn, channel, ws, inode, target, change_id)?;
    if e.flag.contains(EdgeFlags::BLOCK) {
    let mut missing_down = std::mem::replace(&mut ws.missing_down, Vec::new());
    missing_down.clear();
    for e in iter_adjacent(
    [5.113]
    [5.260]
    if is_alive(txn, channel, &source)? && e.flag.contains(EdgeFlags::BLOCK) {
    Ok(iter_adjacent(
  • replacement in libpijul/src/missing_context.rs at line 82
    [5.400][5.400:644](),[5.644][10.123203:123252](),[10.607][10.123203:123252](),[10.123252][10.655:754](),[10.655][10.655:754](),[10.754][10.11301:11303](),[10.11301][10.11301:11303](),[10.11303][10.704008:704009](),[10.704008][10.704008:704009](),[10.704009][10.89765:89806](),[10.89806][10.11340:11357](),[10.11340][10.11340:11357](),[10.11357][10.89807:89835](),[10.89835][10.11387:11501](),[10.11387][10.11387:11501](),[10.11501][10.89836:89883](),[10.89883][10.83424:83466](),[10.83466][10.89884:89963](),[10.704213][10.89884:89963](),[10.89963][10.123253:123323](),[10.11668][10.704390:704422](),[10.123323][10.704390:704422](),[10.704390][10.704390:704422](),[10.704422][10.123324:123368](),[10.123368][10.11711:11759](),[10.11711][10.11711:11759](),[10.11759][10.704542:704620](),[10.704542][10.704542:704620](),[10.704620][10.11760:11822](),[10.11822][10.123369:123434](),[10.57866][10.704732:704770](),[10.59136][10.704732:704770](),[10.123434][10.704732:704770](),[10.704732][10.704732:704770](),[10.704770][10.11823:11910]()
    )? {
    let e = e?;
    ws.missing_down.push(*txn.find_block(&channel, e.dest())?)
    }
    repair_missing_down_context(txn, channel, ws, inode, target, &missing_down)?;
    ws.missing_down = missing_down;
    } else if is_alive(txn, channel, &source)? {
    repair_missing_down_context(txn, channel, ws, inode, target, &[source])?;
    }
    Ok(())
    }
    fn reconnect_target_up<T: GraphMutTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    target: Vertex<ChangeId>,
    change_id: ChangeId,
    ) -> Result<(), MissingError<T::GraphError>> {
    let mut unknown = HashSet::default();
    for v in iter_deleted_parents(txn, channel, target)? {
    let v = v?;
    if v.dest().change.is_root() || v.introduced_by().is_root() {
    continue;
    }
    if v.introduced_by() == change_id {
    unknown.clear();
    break;
    }
    // Else change ~v.introduced_by~ is a change we don't know,
    // since no change can create a conflict with itself.
    unknown.insert(*txn.find_block_end(channel, v.dest())?);
    }
    for up in unknown.drain() {
    repair_missing_up_context(txn, channel, ws, change_id, inode, up, &[target])?;
    [5.400]
    [10.705601]
    )?
    .next()
    .is_some())
    } else {
    Ok(true)
  • edit in libpijul/src/missing_context.rs at line 88
    [10.705736][10.705736:705747]()
    Ok(())
  • replacement in libpijul/src/missing_context.rs at line 90
    [10.705750][10.90568:90626](),[10.90626][10.705858:705875](),[10.705858][10.705858:705875](),[10.705875][10.90627:90655](),[10.90655][10.705905:705964](),[10.705905][10.705905:705964]()
    pub(crate) fn repair_context_deleted<T: GraphMutTxnT, K>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    [10.705750]
    [10.705964]
    pub(crate) fn has_missing_context_deleted<T: GraphMutTxnT, K>(
    txn: &T,
    channel: &T::Graph,
  • replacement in libpijul/src/missing_context.rs at line 96
    [10.706038][10.90656:90701]()
    ) -> Result<(), MissingError<T::GraphError>>
    [10.706038]
    [10.706069]
    ) -> Result<bool, MissingError<T::GraphError>>
  • replacement in libpijul/src/missing_context.rs at line 101
    [10.13117][10.13117:13140]()
    return Ok(());
    [10.13117]
    [10.13140]
    return Ok(false);
  • replacement in libpijul/src/missing_context.rs at line 107
    [10.706422][10.706422:706520]()
    repair_children_of_deleted(txn, channel, ws, inode, &mut known, change_id, dest_vertex)?;
    [10.706422]
    [10.13147]
    if has_unknown_children(txn, channel, dest_vertex, change_id, &mut known)? {
    return Ok(true);
    }
  • replacement in libpijul/src/missing_context.rs at line 118
    [10.706653][10.706653:706664]()
    Ok(())
    [10.706653]
    [10.706664]
    Ok(false)
  • replacement in libpijul/src/missing_context.rs at line 218
    [10.3800][10.5414:5505]()
    debug!("detect folder conflict resolution, deleting {:?} → {:?} {:?}", v, e, p);
    [10.3800]
    [10.3800]
    debug!(
    "detect folder conflict resolution, deleting {:?} → {:?} {:?}",
    v, e, p
    );
  • replacement in libpijul/src/missing_context.rs at line 316
    [10.708025][10.90795:90841]()
    fn collect_unknown_children<T: GraphTxnT, K>(
    [10.708025]
    [10.708066]
    fn has_unknown_children<T: GraphTxnT, K>(
  • edit in libpijul/src/missing_context.rs at line 319
    [10.90866][10.708105:708129](),[10.708105][10.708105:708129]()
    ws: &mut Workspace,
  • replacement in libpijul/src/missing_context.rs at line 322
    [10.708208][10.90867:90906]()
    ) -> Result<(), TxnErr<T::GraphError>>
    [10.708208]
    [10.90906]
    ) -> Result<bool, TxnErr<T::GraphError>>
  • edit in libpijul/src/missing_context.rs at line 336
    [10.123922][10.123922:123969]()
    ws.pseudo.push((dest_vertex, *v));
  • replacement in libpijul/src/missing_context.rs at line 355
    [10.709260][10.124107:124144](),[10.124144][10.709296:709326](),[10.709296][10.709296:709326](),[10.709326][10.91352:91363](),[10.91363][10.709326:709329](),[10.709326][10.709326:709329](),[10.709329][10.91364:91415](),[10.91415][10.709375:709392](),[10.709375][10.709375:709392](),[10.709392][10.91416:91444](),[10.91444][10.709422:709559](),[10.709422][10.709422:709559](),[10.709559][10.91445:91490](),[10.26923][10.709590:709626](),[10.91490][10.709590:709626](),[10.709590][10.709590:709626](),[10.709685][10.709685:709745](),[10.709745][10.91491:91576](),[10.91576][10.709829:709899](),[10.709829][10.709829:709899](),[10.709899][10.14431:14503](),[10.14503][10.710052:710088](),[10.710052][10.710052:710088](),[10.710088][10.124145:124260](),[10.124260][10.14561:14621](),[10.14561][10.14561:14621](),[10.14621][10.91577:91664](),[10.91664][10.14707:14730](),[10.26980][10.14707:14730](),[10.14730][10.124261:124327](),[10.59321][10.14796:14894](),[10.124327][10.14796:14894](),[10.14796][10.14796:14894](),[10.14894][10.91665:91750](),[10.91750][10.14978:15044](),[10.27053][10.14978:15044]()
    ws.unknown.push(*v);
    }
    }
    }
    Ok(())
    }
    fn repair_children_of_deleted<T: GraphMutTxnT, K>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    mut known: K,
    change_id: ChangeId,
    dest_vertex: Vertex<ChangeId>,
    ) -> Result<(), MissingError<T::GraphError>>
    where
    K: FnMut(Hash) -> bool,
    {
    trace!("repair_children_of_deleted {:?}", dest_vertex);
    collect_unknown_children(txn, channel, ws, dest_vertex, change_id, &mut known)?;
    let mut unknown = std::mem::replace(&mut ws.unknown, Vec::new());
    debug!("dest_vertex = {:?}, unknown = {:?}", dest_vertex, unknown);
    for edge in unknown.drain(..) {
    let p = *txn.find_block(channel, edge.dest())?;
    assert!(!edge.flag().contains(EdgeFlags::FOLDER));
    debug!("dest_vertex {:?}, p {:?}", dest_vertex, p);
    put_graph_with_rev(txn, channel, EdgeFlags::db(), dest_vertex, p, change_id)?;
    let mut u = p;
    while let Ok(&v) = txn.find_block(channel, u.end_pos()) {
    if u != v {
    debug!("repair_children_of_deleted: {:?} -> {:?}", u, v);
    put_graph_with_rev(txn, channel, EdgeFlags::db(), u, v, change_id)?;
    u = v
    } else {
    break;
    [10.709260]
    [10.711082]
    return Ok(true);
  • edit in libpijul/src/missing_context.rs at line 358
    [10.711106][10.124328:124369](),[10.91791][10.15084:15179](),[10.124369][10.15084:15179](),[10.15084][10.15084:15179](),[10.15179][10.711414:711431](),[10.711414][10.711414:711431](),[10.711431][10.1936:2029](),[10.2029][10.1091:1275](),[10.1091][10.1091:1275](),[10.1275][10.2030:2083](),[10.2083][10.1309:1325](),[10.1309][10.1309:1325](),[10.1325][10.711583:711593](),[10.15277][10.711583:711593](),[10.711583][10.711583:711593]()
    if is_alive(txn, channel, &p)? {
    repair_missing_up_context(txn, channel, ws, change_id, inode, dest_vertex, &[p])?;
    } else {
    let alive = find_alive_down(txn, channel, p, &mut ws.alive_down_cache)?.clone();
    repair_missing_up_context(
    txn,
    channel,
    ws,
    change_id,
    inode,
    dest_vertex,
    alive.iter().flat_map(|t| t.iter()),
    )?;
    }
  • replacement in libpijul/src/missing_context.rs at line 359
    [10.711599][10.711599:711636]()
    ws.unknown = unknown;
    Ok(())
    [10.711599]
    [10.711636]
    Ok(false)
  • edit in libpijul/src/missing_context.rs at line 361
    [10.711638][10.58890:58891](),[10.58891][10.91792:91844](),[10.91844][10.711740:711757](),[10.711740][10.711740:711757](),[10.711757][10.91845:91873](),[10.91873][10.711787:711811](),[10.711787][10.711787:711811](),[10.711811][10.91874:91921](),[10.27096][10.711844:711914](),[10.91921][10.711844:711914](),[10.711844][10.711844:711914](),[10.711914][10.15278:15332](),[10.15332][10.711964:712042](),[10.711964][10.711964:712042](),[10.712042][10.124370:124630](),[10.92062][10.59054:59118](),[10.124630][10.59054:59118](),[10.59054][10.59054:59118](),[10.59118][10.124631:124775](),[10.15530][10.712510:712549](),[10.27169][10.712510:712549](),[10.92159][10.712510:712549](),[10.124775][10.712510:712549](),[10.712510][10.712510:712549](),[10.712549][10.124776:124887](),[10.92209][10.59295:59363](),[10.124887][10.59295:59363](),[10.59295][10.59295:59363](),[10.59363][10.124888:124988](),[10.125429][10.714122:714140](),[10.714122][10.714122:714140](),[10.715906][10.715906:715930](),[10.716708][10.716708:716728](),[10.716728][10.92810:92868](),[10.92868][10.716781:716798](),[10.716781][10.716781:716798](),[10.716798][10.92869:92897](),[10.92897][10.716828:716852](),[10.716828][10.716828:716852](),[10.716852][10.92898:92945](),[10.27635][10.716885:717371](),[10.92945][10.716885:717371](),[10.716885][10.716885:717371]()
    pub(crate) fn delete_pseudo_edges<T: GraphMutTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    ) -> Result<(), MissingError<T::GraphError>> {
    if ws.pseudo.is_empty() {
    debug!("no pseudo edges")
    }
    for (dest_vertex, mut e) in ws.pseudo.drain(..) {
    debug!("repair_context_deleted, deleting {:?} {:?}", dest_vertex, e);
    if !is_alive(txn, channel, &dest_vertex)? && !ws.repaired.contains(&dest_vertex) {
    if e.flag().contains(EdgeFlags::PARENT) {
    let p = *txn.find_block_end(channel, e.dest())?;
    if !is_alive(txn, channel, &p)? {
    debug!("delete {:?} {:?}", p, dest_vertex);
    e -= EdgeFlags::PARENT;
    del_graph_with_rev(txn, channel, e.flag(), p, dest_vertex, e.introduced_by())?;
    }
    } else {
    let p = *txn.find_block(channel, e.dest())?;
    if !is_alive(txn, channel, &p)? {
    debug!("delete (2) {:?} {:?}", dest_vertex, p);
    del_graph_with_rev(txn, channel, e.flag(), dest_vertex, p, e.introduced_by())?;
    }
    }
    }
    }
    Ok(())
    }
    pub(crate) fn repair_parents_of_deleted<T: GraphMutTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    ) -> Result<(), MissingError<T::GraphError>> {
    debug!("repair_parents_of_deleted");
    let mut unknown = std::mem::replace(&mut ws.unknown_parents, Vec::new());
    for (dest_vertex, p, inode, flag) in unknown.drain(..) {
    if flag.contains(EdgeFlags::FOLDER) {
    repair_missing_down_context(txn, channel, ws, inode, dest_vertex, &[dest_vertex])?
    } else {
    repair_missing_down_context(txn, channel, ws, inode, dest_vertex, &[p])?
    }
    }
    ws.unknown_parents = unknown;
    Ok(())
    }
  • edit in libpijul/src/lib.rs at line 22
    [10.717679][10.4292:4312]()
    pub mod find_alive;
  • replacement in libpijul/src/apply.rs at line 51
    [8.16][10.752:810](),[10.123233][10.752:810]()
    MakeChange(#[from]crate::change::MakeChangeError<T>),
    [8.16]
    [10.94263]
    MakeChange(#[from] crate::change::MakeChangeError<T>),
  • replacement in libpijul/src/apply.rs at line 340
    [10.949433][10.5985:6337]()
    Atom::NewVertex(ref n) => {
    put_newvertex(
    txn,
    T::graph_mut(channel),
    changes,
    change,
    ws,
    change_id,
    n,
    )?
    },
    [10.949433]
    [10.949531]
    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 385
    [10.951555][10.6338:7040]()
    {
    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 387
    [10.951611][6.131:132]()
  • replacement in libpijul/src/apply.rs at line 391
    [10.951686][10.65200:65277]()
    clean_obsolete_pseudo_edges(txn, T::graph_mut(channel), ws, change_id)?;
    [10.951686]
    [10.951738]
    let mut inodes = clean_obsolete_pseudo_edges(txn, T::graph_mut(channel), ws, change_id)?;
    collect_missing_contexts(txn, txn.graph(channel), ws, &change, change_id, &mut inodes)?;
    for i in inodes {
    repair_zombies(txn, T::graph_mut(channel), i)?;
    }
  • edit in libpijul/src/apply.rs at line 397
    [10.951739][10.951739:951780](),[10.951780][10.65278:65359]()
    info!("repairing missing contexts");
    repair_missing_contexts(txn, T::graph_mut(channel), ws, change_id, change)?;
  • edit in libpijul/src/apply.rs at line 562
    [10.962677]
    [10.97503]
    pub(crate) fn repair_zombies<T: GraphMutTxnT + TreeTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    root: Position<ChangeId>,
    ) -> Result<(), LocalApplyError<T>> {
    let mut stack = vec![(root.inode_vertex(), true, false)];
    let mut visited = HashSet::new();
  • replacement in libpijul/src/apply.rs at line 572
    [10.97504][10.42243:42314]()
    pub(crate) fn clean_obsolete_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
    [10.97504]
    [10.971306]
    while let Some((current, alive, on_path)) = stack.pop() {
    stack.push((current, alive, true));
    let is_first_visit = visited.insert(current);
    let len = stack.len();
    if !on_path {
    // If this is the first visit, find the children, starting
    // with in flag order (alive first), since we don't want
    // to reconnect vertices multiple times.
    for e in iter_adjacent(txn, channel, current, EdgeFlags::empty(), EdgeFlags::all())? {
    let e = e?;
    if e.flag().contains(EdgeFlags::PARENT) {
    if e.flag() & (EdgeFlags::BLOCK | EdgeFlags::DELETED) == EdgeFlags::BLOCK {
    // This vertex is alive!
    stack[len - 1].1 = true;
    }
    continue;
    }
    if is_first_visit {
    let child = txn.find_block(channel, e.dest())?;
    stack.push((*child, false, false));
    }
    }
    }
    if len >= 2 && stack[len - 1].1 {
    if let Some(last_on_path) = (&stack[..len - 1]).iter().rev().position(|x| x.2) {
    let last_on_path = len - 2 - last_on_path;
    // If the last vertex on the path to `current` is not
    // alive, a reconnect is needed.
    if !stack[last_on_path].1 {
    if let Some(last_alive_on_path) =
    (&stack[..last_on_path]).iter().rev().position(|x| x.1)
    {
    let last_alive_on_path = last_on_path - 1 - last_alive_on_path;
    debug!("repair zombies {:?} {:?}", last_alive_on_path, len - 1);
    // 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,
    stack[last_alive_on_path].0,
    stack[len - 1].0,
    ChangeId::ROOT,
    )?;
    }
    }
    }
    }
    // If no children, pop.
    if stack.len() == len {
    stack.pop();
    }
    }
    Ok(())
    }
    pub fn clean_obsolete_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
  • replacement in libpijul/src/apply.rs at line 644
    [10.20894][10.42315:42353]()
    ) -> Result<(), LocalApplyError<T>> {
    [10.20894]
    [10.508]
    ) -> Result<HashSet<Position<ChangeId>>, LocalApplyError<T>> {
    info!(
    "clean_obsolete_pseudo_edges, ws.pseudo.len() = {}",
    ws.pseudo.len()
    );
  • edit in libpijul/src/apply.rs at line 651
    [10.672]
    [10.971451]
    let mut inodes = HashSet::new();
  • replacement in libpijul/src/apply.rs at line 655
    [10.971508][10.7041:7126]()
    debug!("clean_obsolete_pseudo_edges {:?} {:?} {:?}", next_vertex, p, inode);
    [10.971508]
    [10.7126]
    debug!(
    "clean_obsolete_pseudo_edges {:?} {:?} {:?}",
    next_vertex, p, inode
    );
  • replacement in libpijul/src/apply.rs at line 667
    [10.7334][10.7334:7453]()
    )?.collect();
    debug!("pseudo edge still here ? {:?} {:?}", next_vertex.change.0.0, still_here)
    [10.7334]
    [10.7453]
    )?
    .collect();
    debug!(
    "pseudo edge still here ? {:?} {:?}",
    next_vertex.change.0 .0, still_here
    )
  • edit in libpijul/src/apply.rs at line 744
    [10.21227][10.972853:972877](),[10.132503][10.972853:972877](),[10.972853][10.972853:972877](),[10.972877][10.284:319](),[10.319][10.21228:21333](),[10.972877][10.21228:21333](),[10.21333][10.71094:71140](),[10.71094][10.71094:71140](),[10.71140][10.21334:21398](),[10.21398][10.71203:71222](),[10.71203][10.71203:71222](),[10.71222][10.21399:21421](),[10.21421][10.99202:99216](),[10.71255][10.99202:99216](),[10.99216][10.21422:21475](),[10.21475][10.147383:147439](),[10.147439][10.374:407](),[10.374][10.374:407]()
    if a_is_alive {
    debug!("repair down");
    debug_assert!(!b_is_alive);
    crate::missing_context::repair_missing_down_context(
    txn,
    channel,
    &mut ws.missing_context,
    inode,
    b,
    &[a],
    )
    .map_err(LocalApplyError::from_missing)?
    } else if b_is_alive && !p.flag().is_folder() {
    debug!("repair up");
  • replacement in libpijul/src/apply.rs at line 745
    [10.1982][10.1982:2142](),[10.407][10.21515:21578](),[10.2142][10.21515:21578](),[10.21515][10.21515:21578](),[10.21578][10.71305:71351](),[10.71305][10.71305:71351](),[10.71351][10.21579:21670](),[10.21670][10.71395:71414](),[10.71395][10.71395:71414](),[10.71414][10.21671:21693](),[10.21693][10.99351:99365](),[10.71466][10.99351:99365](),[10.99365][10.21694:21747]()
    // Note: if this is a folder edge,
    // repair_missing_up_context will stop immediately, so we
    // don't even need to call it.
    crate::missing_context::repair_missing_up_context(
    txn,
    channel,
    &mut ws.missing_context,
    change_id,
    inode,
    a,
    &[b],
    )
    .map_err(LocalApplyError::from_missing)?
    [10.1982]
    [10.974222]
    if a_is_alive || (b_is_alive && !p.flag().is_folder()) {
    // A context repair is needed.
    inodes.insert(internal_pos(txn, &inode, change_id)?);
  • edit in libpijul/src/apply.rs at line 750
    [10.974238]
    [10.2143]
  • replacement in libpijul/src/apply.rs at line 753
    [10.2215][10.974238:974249](),[10.974238][10.974238:974249]()
    Ok(())
    [10.2215]
    [10.974249]
    Ok(inodes)
  • replacement in libpijul/src/apply.rs at line 807
    [10.3809][10.42354:42410](),[10.1060][10.42354:42410](),[10.42410][10.974346:974363](),[10.132549][10.974346:974363](),[10.974346][10.974346:974363](),[10.974363][10.132550:132578]()
    fn repair_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    [10.3809]
    [10.974393]
    fn collect_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
    txn: &T,
    channel: &T::Graph,
  • edit in libpijul/src/apply.rs at line 811
    [10.974417]
    [10.974417]
    change: &Change,
  • replacement in libpijul/src/apply.rs at line 813
    [10.974442][10.974442:974463]()
    change: &Change,
    [10.974442]
    [10.42411]
    inodes: &mut HashSet<Position<ChangeId>>,
  • replacement in libpijul/src/apply.rs at line 815
    [10.42449][10.974496:974537](),[10.99456][10.974496:974537](),[10.132629][10.974496:974537](),[10.974496][10.974496:974537](),[10.974537][10.99457:99600]()
    let now = std::time::Instant::now();
    crate::missing_context::repair_parents_of_deleted(txn, channel, &mut ws.missing_context)
    .map_err(LocalApplyError::from_missing)?;
    [10.42449]
    [10.974632]
    inodes.extend(
    ws.missing_context
    .unknown_parents
    .drain(..)
    .map(|x| internal_pos(txn, &x.2, change_id).unwrap()),
    );
  • replacement in libpijul/src/apply.rs at line 824
    [10.21811][10.974756:974920](),[10.974756][10.974756:974920](),[10.974920][10.21812:21988]()
    let vertex = Vertex {
    change: change_id,
    start: n.start,
    end: n.end,
    };
    repair_new_vertex_context_up(txn, channel, ws, change_id, n, vertex)?;
    repair_new_vertex_context_down(txn, channel, ws, change_id, n, vertex)?;
    [10.21811]
    [10.976945]
    let inode = internal_pos(txn, &n.inode, change_id)?;
    if !inodes.contains(&inode) {
    for up in n.up_context.iter() {
    let up =
    *txn.find_block_end(channel, internal_pos(txn, &up, change_id)?)?;
    if !is_alive(txn, channel, &up)? {
    inodes.insert(inode);
    break;
    }
    }
    for down in n.down_context.iter() {
    let down =
    *txn.find_block(channel, internal_pos(txn, &down, change_id)?)?;
    let mut down_has_other_parents = false;
    for e in iter_adjacent(
    txn,
    channel,
    down,
    EdgeFlags::PARENT,
    EdgeFlags::all() - EdgeFlags::DELETED,
    )? {
    let e = e?;
    if e.introduced_by() != change_id {
    down_has_other_parents = true;
    break;
    }
    }
    if !down_has_other_parents {
    inodes.insert(inode);
    break;
    }
    }
    }
  • replacement in libpijul/src/apply.rs at line 860
    [10.976997][10.22027:22105](),[10.22105][10.977637:977667](),[10.977637][10.977637:977667](),[10.978406][10.99969:100106](),[10.100106][10.978495:978575](),[10.978495][10.978495:978575](),[10.978575][10.1061:1062](),[10.1062][10.42450:42511](),[10.42511][10.22151:22168](),[10.132680][10.22151:22168](),[10.22151][10.22151:22168](),[10.22168][10.132681:132709](),[10.132709][10.22198:22310](),[10.22198][10.22198:22310](),[10.22310][10.42512:42550](),[10.42550][10.22355:22391](),[10.132760][10.22355:22391](),[10.22355][10.22355:22391](),[10.22391][10.147440:147567](),[10.132803][10.22516:22912](),[10.147567][10.22516:22912](),[10.22516][10.22516:22912](),[10.22912][10.42551:42614](),[10.42614][10.22959:22976](),[10.132856][10.22959:22976](),[10.22959][10.22959:22976](),[10.22976][10.132857:132885](),[10.132885][10.23006:23118](),[10.23006][10.23006:23118](),[10.23118][10.42615:42653](),[10.42653][10.23163:23294](),[10.132936][10.23163:23294](),[10.23163][10.23163:23294](),[10.23294][10.132937:132985](),[10.132985][10.147568:147652](),[10.66872][10.132986:133018](),[10.147652][10.132986:133018](),[10.23418][10.132986:133018](),[10.133018][10.23444:23582](),[10.23444][10.23444:23582](),[10.23582][10.133019:133056](),[10.133056][10.147653:147701](),[10.147701][10.133102:133135](),[10.133102][10.133102:133135]()
    repair_edge_context(txn, channel, ws, change_id, change, n)?;
    }
    }
    }
    crate::missing_context::delete_pseudo_edges(txn, channel, &mut ws.missing_context)
    .map_err(LocalApplyError::from_missing)?;
    crate::TIMERS.lock().unwrap().repair_context += now.elapsed();
    Ok(())
    }
    fn repair_new_vertex_context_up<T: GraphMutTxnT + TreeTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    change_id: ChangeId,
    n: &NewVertex<Option<Hash>>,
    vertex: Vertex<ChangeId>,
    ) -> Result<(), LocalApplyError<T>> {
    for up in n.up_context.iter() {
    let up = *txn.find_block_end(channel, internal_pos(txn, &up, change_id)?)?;
    if !is_alive(txn, channel, &up)? {
    debug!("repairing missing up context {:?} {:?}", up, vertex);
    repair_missing_up_context(
    txn,
    channel,
    &mut ws.missing_context,
    change_id,
    n.inode,
    up,
    &[vertex],
    )
    .map_err(LocalApplyError::from_missing)?
    }
    }
    Ok(())
    }
    fn repair_new_vertex_context_down<T: GraphMutTxnT + TreeTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    change_id: ChangeId,
    n: &NewVertex<Option<Hash>>,
    vertex: Vertex<ChangeId>,
    ) -> Result<(), LocalApplyError<T>> {
    debug!("repairing missing context for {:?}", vertex);
    if n.flag.contains(EdgeFlags::FOLDER) {
    return Ok(());
    }
    'outer: for down in n.down_context.iter() {
    let down = *txn.find_block(channel, internal_pos(txn, &down, change_id)?)?;
    for e in iter_adjacent(
    txn,
    channel,
    down,
    EdgeFlags::PARENT,
    EdgeFlags::all() - EdgeFlags::DELETED,
    )? {
    let e = e?;
    if e.introduced_by() != change_id {
    continue 'outer;
    [10.976997]
    [10.133135]
    has_missing_edge_context(txn, channel, change_id, change, n, inodes)?;
  • edit in libpijul/src/apply.rs at line 863
    [10.23681][10.23681:23988]()
    debug!("repairing missing down context {:?} {:?}", down, vertex);
    repair_missing_down_context(
    txn,
    channel,
    &mut ws.missing_context,
    n.inode,
    down,
    &[vertex],
    )
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 867
    [10.24008][10.42654:42706](),[10.24044][10.978666:978683](),[10.42706][10.978666:978683](),[10.133191][10.978666:978683](),[10.978666][10.978666:978683](),[10.978683][10.133192:133220](),[10.133220][10.978713:978737](),[10.978713][10.978713:978737]()
    fn repair_edge_context<T: GraphMutTxnT + TreeTxnT>(
    txn: &mut T,
    channel: &mut T::Graph,
    ws: &mut Workspace,
    [10.24008]
    [10.978737]
    fn has_missing_edge_context<T: GraphMutTxnT + TreeTxnT>(
    txn: &T,
    channel: &T::Graph,
  • edit in libpijul/src/apply.rs at line 873
    [10.24076]
    [10.42707]
    inodes: &mut HashSet<Position<ChangeId>>,
  • replacement in libpijul/src/apply.rs at line 875
    [10.42745][10.24121:24687](),[10.133271][10.24121:24687](),[10.24121][10.24121:24687](),[10.24687][10.1227:1327]()
    for e in n.edges.iter() {
    assert!(!e.flag.contains(EdgeFlags::PARENT));
    if e.flag.contains(EdgeFlags::DELETED) {
    trace!("repairing context deleted {:?}", e);
    repair_context_deleted(
    txn,
    channel,
    &mut ws.missing_context,
    n.inode,
    change_id,
    |h| change.knows(&h),
    e,
    )
    .map_err(LocalApplyError::from_missing)?
    } else {
    trace!("repairing context nondeleted {:?}", e);
    repair_context_nondeleted(txn, channel, &mut ws.missing_context, n.inode, change_id, e)
    [10.42745]
    [10.1327]
    let inode = internal_pos(txn, &n.inode, change_id)?;
    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,
    )
  • edit in libpijul/src/apply.rs at line 896
    [10.1384]
    [10.24989]
    {
    inodes.insert(inode);
    break;
    }
    }