Refactoring apply

[?]
Dec 25, 2020, 12:14 PM
6YMDOZIB5LVYLFIDGN2WNT5JTHEAMS4TFPVDEZ3OWXWOKJOC5QDAC

Dependencies

  • [2] BD5PC25A Deleting conflict resolution vertices when the sides are deleted
  • [3] ATZ3BWSE Fixing the double-deletion of repairs for folder edges
  • [4] CFNFIUJV Parsing the correct flags for new vertices
  • [5] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [6] I52XSRUH Massive cleanup, and simplification
  • [7] KQTD46KV Unrecord: restore files *after* having unapplied the *entire* change
  • [8] L5PHFTIE Minor simplification
  • [9] KDF6FJRV bigger clippy refactors
  • [10] 43AJ37IX Getting rid of edge validation, which does not work for zombie conflicts
  • [11] ZXTHL45O address clippy lints
  • [12] BXD3IQYN Fixing --features git
  • [13] 7A2TSC4P Conflict solving code (FOLDER edges)
  • [14] BAUL3WR2 Format, versions, README
  • [15] HMMMKONL Fixing alive vertices
  • [16] 7FFFKQZU add 'Default' implementations
  • [17] WZVCLZKY address clippy lints
  • [18] VO5OQW4W Removing anyhow in libpijul

Change contents

  • replacement in libpijul/src/unrecord/mod.rs at line 124
    [5.234263][5.234263:234298]()
    let mut ws = Workspace::new();
    [5.234263]
    [5.234298]
    let mut ws = Workspace::default();
  • replacement in libpijul/src/unrecord/mod.rs at line 143
    [5.234990][5.9732:9795]()
    repair_newvertex_contexts::<T, C>(txn, channel, &mut ws)?;
    [5.234990]
    [5.235104]
    repair_newvertex_contexts::<T, C>(txn, channel, &mut ws, change_id)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 146
    [5.2017][5.9796:9861]()
    remove_zombies::<T, C>(txn, channel, change_id, n)?;
    [5.2017]
    [5.2074]
    remove_zombies::<_, C>(txn, channel, &mut ws, change_id, n)?;
  • replacement in libpijul/src/unrecord/mod.rs at line 178
    [5.2289][5.235597:235674](),[5.1137][5.235597:235674](),[5.235597][5.235597:235674]()
    crate::apply::clean_obsolete_pseudo_edges(txn, channel, &mut ws.apply)?;
    [5.1137]
    [5.235674]
    crate::apply::clean_obsolete_pseudo_edges(txn, channel, &mut ws.apply, change_id)?;
    crate::apply::repair_cyclic_paths(txn, channel, &mut ws.apply)?;
  • edit in libpijul/src/unrecord/mod.rs at line 184
    [5.235774]
    [5.235774]
    #[derive(Default)]
  • replacement in libpijul/src/unrecord/mod.rs at line 187
    [5.235852][5.235852:235921]()
    down: HashMap<Vertex<ChangeId>, (Position<Option<Hash>>, bool)>,
    [5.235852]
    [5.235921]
    down: HashMap<Vertex<ChangeId>, Position<Option<Hash>>>,
    parents: HashSet<Vertex<ChangeId>>,
  • edit in libpijul/src/unrecord/mod.rs at line 191
    [5.235977]
    [5.235977]
    stack: Vec<Vertex<ChangeId>>,
    del_edges: Vec<(Vertex<ChangeId>, Edge)>,
  • edit in libpijul/src/unrecord/mod.rs at line 195
    [5.235980][5.235980:236205]()
    impl Workspace {
    fn new() -> Self {
    Workspace {
    up: HashMap::new(),
    down: HashMap::new(),
    del: Vec::new(),
    apply: crate::apply::Workspace::new(),
    }
    }
    }
  • replacement in libpijul/src/unrecord/mod.rs at line 207
    [5.236556][5.236556:236629](),[5.236629][5.7507:7575](),[5.7575][5.236696:237011](),[5.236696][5.236696:237011](),[5.237011][5.7576:7645](),[5.7645][5.237079:237184](),[5.237079][5.237079:237184]()
    while pos.pos <= new_vertex.end {
    debug!("pos = {:?}", pos);
    let vertex = if let Ok(v) = find_block(txn, channel, pos) {
    v
    } else {
    // This means that the only edges to this block were
    // removed from the graph, which can only happen if this
    // block is the bottommost vertex in the graph.
    if cfg!(debug_assertions) {
    while pos.pos <= new_vertex.end {
    assert!(find_block(txn, channel, pos).is_err());
    pos.pos = pos.pos + 1;
    }
    }
    break;
    };
    [5.236556]
    [5.237184]
    while let Ok(vertex) = find_block(txn, channel, pos) {
  • replacement in libpijul/src/unrecord/mod.rs at line 209
    [5.237225][5.7646:7739]()
    for e in iter_adjacent(txn, channel, vertex, EdgeFlags::empty(), EdgeFlags::all()) {
    [5.237225]
    [5.237317]
    for e in iter_adj_all(txn, channel, vertex) {
  • replacement in libpijul/src/unrecord/mod.rs at line 211
    [5.237352][5.237352:237523]()
    if !e.flag.contains(EdgeFlags::DELETED) {
    if e.flag.contains(EdgeFlags::PARENT) {
    if !e.flag.contains(EdgeFlags::FOLDER) {
    [5.237352]
    [5.7740]
    if !e.flag.is_deleted() {
    if e.flag.is_parent() {
    if !e.flag.is_folder() {
  • replacement in libpijul/src/unrecord/mod.rs at line 219
    [5.7883][5.237772:237943](),[5.237772][5.237772:237943]()
    ws.down.insert(
    down_v,
    (new_vertex.inode, e.flag.contains(EdgeFlags::FOLDER)),
    );
    [5.7883]
    [5.237943]
    ws.down.insert(down_v, new_vertex.inode);
    if e.flag.is_folder() {
    ws.apply.missing_context.files.insert(down_v);
    }
  • edit in libpijul/src/unrecord/mod.rs at line 230
    [5.238115]
    [5.238115]
    ws.perform_del::<C, T>(txn, channel, vertex)?;
    if vertex.end < new_vertex.end {
    pos.pos = vertex.end
    }
    }
    Ok(())
    }
  • replacement in libpijul/src/unrecord/mod.rs at line 238
    [5.238116][5.238116:238184](),[5.238184][5.238184:238249]()
    // Delete all in `del`.
    for e in ws.del.drain(..) {
    let (a, b) = if e.flag.contains(EdgeFlags::PARENT) {
    [5.238116]
    [5.7884]
    impl Workspace {
    fn perform_del<C: ChangeStore, T: MutTxnT>(
    &mut self,
    txn: &mut T,
    channel: &mut Channel<T>,
    vertex: Vertex<ChangeId>,
    ) -> Result<(), UnrecordError<C::Error, T::Error>> {
    for e in self.del.drain(..) {
    let (a, b) = if e.flag.is_parent() {
  • replacement in libpijul/src/unrecord/mod.rs at line 261
    [5.238514][5.238514:238598]()
    // Move on to the next split of ~new_vertex~.
    pos.pos = vertex.end
    [5.238514]
    [5.238914]
    Ok(())
  • edit in libpijul/src/unrecord/mod.rs at line 263
    [5.238920][5.238920:238931]()
    Ok(())
  • edit in libpijul/src/unrecord/mod.rs at line 269
    [5.239047]
    [5.10184]
    change_id: ChangeId,
  • replacement in libpijul/src/unrecord/mod.rs at line 286
    [5.239484][5.239484:239522](),[5.239522][5.239522:239578]()
    let mut parents = HashSet::new();
    for (down, (inode, is_folder)) in ws.down.drain() {
    [5.239484]
    [5.8261]
    for (down, inode) in ws.down.drain() {
  • replacement in libpijul/src/unrecord/mod.rs at line 296
    [5.8434][5.239868:239908](),[5.239868][5.239868:239908]()
    parents.insert(parent);
    [5.8434]
    [5.239908]
    ws.parents.insert(parent);
  • replacement in libpijul/src/unrecord/mod.rs at line 299
    [5.239932][5.239932:240010]()
    debug!("parents {:#?}", parents);
    for up in parents.drain() {
    [5.239932]
    [5.240010]
    debug!("parents {:#?}", ws.parents);
    for up in ws.parents.drain() {
  • edit in libpijul/src/unrecord/mod.rs at line 305
    [5.240166]
    [5.240166]
    change_id,
  • edit in libpijul/src/unrecord/mod.rs at line 309
    [5.240234][5.240234:240261]()
    is_folder,
  • replacement in libpijul/src/unrecord/mod.rs at line 326
    [5.240797][5.240797:240867](),[5.240867][5.8435:8509]()
    // This is ok: since this change is applied, this can't fail.
    let int = internal(txn, &edge.introduced_by, change_id).unwrap();
    [5.240797]
    [5.240940]
    let intro = internal(txn, &edge.introduced_by, change_id).unwrap();
  • replacement in libpijul/src/unrecord/mod.rs at line 331
    [5.241053][5.241053:241070]()
    int,
    [5.241053]
    [5.241070]
    intro,
  • replacement in libpijul/src/unrecord/mod.rs at line 333
    [5.241098][5.241098:241314]()
    &NewEdge {
    previous: edge.flag,
    flag: edge.previous,
    from: edge.from,
    to: edge.to,
    introduced_by: Some(ext),
    },
    [5.241098]
    [5.241314]
    &edge.reverse(Some(ext)),
  • replacement in libpijul/src/unrecord/mod.rs at line 335
    [5.241349][5.241349:241586](),[5.241586][5.241586:241604]()
    must_reintroduce(
    txn,
    channel,
    changes,
    a,
    b,
    edge.introduced_by.unwrap(),
    int,
    )
    [5.241349]
    [5.241604]
    must_reintroduce(txn, channel, changes, a, b, ext, intro, change_id)
  • edit in libpijul/src/unrecord/mod.rs at line 350
    [5.242168]
    [5.10378]
    current_id: ChangeId,
  • replacement in libpijul/src/unrecord/mod.rs at line 360
    [5.242478][5.8510:8605](),[5.8605][5.8605:8706]()
    for e in iter_adjacent(txn, channel, a, EdgeFlags::empty(), EdgeFlags::all()).filter(|e| {
    !e.flag.contains(EdgeFlags::PARENT) && e.dest == b.start_pos() && !e.introduced_by.is_root()
    [5.242478]
    [5.8706]
    for e in iter_adj_all(txn, channel, a).filter(|e| {
    !e.flag.contains(EdgeFlags::PARENT)
    && e.dest == b.start_pos()
    && !e.introduced_by.is_root()
    && e.introduced_by != current_id
  • replacement in libpijul/src/unrecord/mod.rs at line 366
    [5.8715][5.242744:243116](),[5.242744][5.242744:243116]()
    // Optimisation to avoid opening change files
    // in the vast majority of cases: if there is
    // an edge `e` parallel to a -> b introduced
    // by the change that introduced a or b, don't
    // reinsert a -> b: that edge was removed by
    // `e`.
    if !cfg!(debug_assertions) && (a.change == intro_id || b.change == intro_id) {
    [5.8715]
    [5.243116]
    // Optimisation to avoid opening change files in the vast
    // majority of cases: if there is an edge `e` parallel to a ->
    // b introduced by the change that introduced a or b, don't
    // reinsert a -> b: that edge was removed by `e`.
    if a.change == intro_id || b.change == intro_id {
  • edit in libpijul/src/unrecord/mod.rs at line 406
    [5.244016]
    [5.244016]
    ws: &mut Workspace,
  • edit in libpijul/src/unrecord/mod.rs at line 410
    [5.10634][5.244112:244208](),[5.244112][5.244112:244208]()
    let mut del = Vec::new();
    let mut stack = vec![];
    let mut visited = HashSet::new();
  • edit in libpijul/src/unrecord/mod.rs at line 412
    [5.244307][5.244307:244357]()
    // Remove zombies caused by this EdgeMap.
  • replacement in libpijul/src/unrecord/mod.rs at line 413
    [5.8786][5.8786:8837](),[5.8837][5.244476:244670](),[5.244476][5.244476:244670](),[5.244670][5.8838:8930](),[5.8930][5.244761:244800](),[5.244761][5.244761:244800](),[5.244800][5.244800:244866](),[5.244866][5.244866:245084](),[5.245084][5.245084:245085](),[5.245085][5.2568:2629](),[5.2629][5.2629:2659](),[5.2659][5.245224:245298](),[5.245224][5.245224:245298](),[5.245298][5.8931:9001](),[5.9001][5.245367:245392](),[5.245367][5.245367:245392](),[5.245392][5.9002:9068](),[5.9068][5.245457:245604](),[5.245457][5.245457:245604](),[5.245604][5.245604:245689]()
    stack.push(find_block(txn, channel, to)?);
    visited.clear();
    while let Some(v) = stack.pop() {
    debug!("remove_zombies, v = {:?}", v);
    if !visited.insert(v) {
    continue;
    }
    for e in iter_adjacent(txn, channel, v, EdgeFlags::empty(), EdgeFlags::all()) {
    debug!("e = {:?}", e);
    // If the edge is a parent-non-block edge, go up.
    let mut follow =
    e.flag.contains(EdgeFlags::DELETED) && e.introduced_by != change_id;
    follow |= e.flag & (EdgeFlags::BLOCK | EdgeFlags::PARENT) == EdgeFlags::PARENT;
    if !follow && e.introduced_by != change_id {
    continue;
    }
    if e.flag.contains(EdgeFlags::PARENT) {
    stack.push(find_block_end(txn, channel, e.dest)?)
    } else {
    stack.push(find_block(txn, channel, e.dest)?)
    }
    if e.introduced_by == change_id {
    del.push((v, e))
    }
    }
    }
    debug!("remove_zombies = {:#?}", del);
    for (v, e) in del.drain(..) {
    [5.8786]
    [5.245689]
    collect_zombies(txn, channel, change_id, to, ws)?;
    debug!("remove_zombies = {:#?}", ws.del_edges);
    for (v, mut e) in ws.del_edges.drain(..) {
  • replacement in libpijul/src/unrecord/mod.rs at line 418
    [5.9132][5.9132:9353](),[5.9353][5.10635:10700](),[5.10700][5.9373:9621](),[5.9373][5.9373:9621](),[5.9621][5.2660:2711](),[5.2711][5.9698:9725](),[5.9698][5.9698:9725](),[5.9725][5.246288:246511](),[5.246288][5.246288:246511](),[5.246511][5.10701:10828](),[5.9800][5.246584:246602](),[5.10828][5.246584:246602](),[5.246584][5.246584:246602]()
    del_graph_with_rev(
    txn,
    channel,
    e.flag - EdgeFlags::PARENT,
    u,
    v,
    e.introduced_by,
    )
    .map_err(UnrecordError::Txn)?;
    if iter_adjacent(
    txn,
    channel,
    u,
    EdgeFlags::empty(),
    EdgeFlags::all() - EdgeFlags::DELETED - EdgeFlags::PARENT,
    )
    .find(|e| e.dest == v.start_pos())
    .is_none()
    {
    let f = if e.flag.contains(EdgeFlags::FOLDER) {
    EdgeFlags::FOLDER
    } else {
    EdgeFlags::empty()
    };
    put_graph_with_rev(txn, channel, f, u, v, u.change)
    .map_err(UnrecordError::Txn)?;
    }
    [5.9132]
    [5.246602]
    e.flag -= EdgeFlags::PARENT;
    del_graph_with_rev(txn, channel, e.flag, u, v, e.introduced_by)
    .map_err(UnrecordError::Txn)?;
  • edit in libpijul/src/unrecord/mod.rs at line 431
    [5.246806]
    [5.246861]
    fn collect_zombies<T: TxnT>(
    txn: &mut T,
    channel: &mut Channel<T>,
    change_id: ChangeId,
    to: Position<ChangeId>,
    ws: &mut Workspace,
    ) -> Result<(), BlockError> {
    ws.stack.push(find_block(txn, channel, to)?);
    while let Some(v) = ws.stack.pop() {
    debug!("remove_zombies, v = {:?}", v);
    if !ws.parents.insert(v) {
    continue;
    }
    for e in iter_adj_all(txn, channel, v) {
    debug!("e = {:?}", e);
    if !(e.introduced_by == change_id || e.flag & EdgeFlags::bp() == EdgeFlags::PARENT) {
    continue;
    }
    if e.flag.contains(EdgeFlags::PARENT) {
    ws.stack.push(find_block_end(txn, channel, e.dest)?)
    } else {
    ws.stack.push(find_block(txn, channel, e.dest)?)
    }
    if e.introduced_by == change_id {
    ws.del_edges.push((v, e))
    }
    }
    }
    ws.stack.clear();
    ws.parents.clear();
    Ok(())
    }
  • edit in libpijul/src/unrecord/mod.rs at line 475
    [5.247259]
    [5.247259]
    let intro = internal(txn, &e.introduced_by, change_id).unwrap();
    let intro_ext = e.introduced_by.unwrap_or(change_hash);
  • edit in libpijul/src/unrecord/mod.rs at line 478
    [5.247312][5.247312:247531](),[5.247531][5.9943:10020](),[5.10020][5.247607:247675](),[5.247607][5.247607:247675]()
    let e = NewEdge {
    previous: e.flag,
    flag: e.previous,
    from: e.from,
    to: e.to,
    introduced_by: Some(change_hash),
    };
    let intro = internal(txn, &e.introduced_by, change_id).unwrap();
    let intro_ext = e.introduced_by.unwrap_or(change_hash);
  • replacement in libpijul/src/unrecord/mod.rs at line 485
    [5.247885][5.247885:247905]()
    &e,
    [5.247885]
    [5.247905]
    &e.reverse(Some(change_hash)),
  • edit in libpijul/src/unrecord/mod.rs at line 488
    [5.247937][5.10021:10098](),[5.10098][5.248013:248081](),[5.248013][5.248013:248081]()
    let intro = internal(txn, &e.introduced_by, change_id).unwrap();
    let intro_ext = e.introduced_by.unwrap_or(change_hash);
  • replacement in libpijul/src/unrecord/mod.rs at line 500
    [5.248499][5.248499:248739]()
    &NewEdge {
    previous: e.flag,
    flag: e.previous,
    from: e.from,
    to: e.to,
    introduced_by: Some(change_hash),
    },
    [5.248499]
    [5.248739]
    &e.reverse(Some(change_hash)),
  • replacement in libpijul/src/tests/missing_context.rs at line 120
    [5.294504][5.14404:14575]()
    &"a\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nx\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\ny\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nz\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nf\n"
    [5.294504]
    [5.294603]
    &"a\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nx\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\ny\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nz\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nf\n"
  • replacement in libpijul/src/tests/missing_context.rs at line 127
    [5.294725][5.14576:14745]()
    Ok(&">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nx\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\ny\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nz\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"[..])
    [5.294725]
    [5.294822]
    Ok(&">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nx\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\ny\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\nz\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"[..])
  • replacement in libpijul/src/tests/file_conflicts.rs at line 414
    [5.17241][5.318427:318478](),[5.318427][5.318427:318478]()
    let files_charlie = repo_charlie.list_files();
    [5.17241]
    [5.318478]
    let mut files_charlie = repo_charlie.list_files();
    files_charlie.sort();
    // Two files with the same name (file), one of which also has another name (file3). This means that we don't know which one of the two names crate::output will pick, between "file3" and the conflicting name.
    // This depends on which file gets output first.
    assert_eq!(files_charlie[0], "file");
    assert!(files_charlie[1] == "file3" || files_charlie[1].starts_with("file."));
  • edit in libpijul/src/tests/file_conflicts.rs at line 422
    [5.318528]
    [5.318528]
    repo_charlie.rename(&files_charlie[1], "file3")?;
    txn_charlie.move_file(&files_charlie[1], "file3")?;
    let _charlie_solution = record_all(
    &mut repo_charlie,
    &changes,
    &mut txn_charlie,
    &mut channel_charlie,
    "",
    )
    .unwrap();
    debug_to_file(&txn_charlie, &channel_charlie, "debug_charlie3")?;
    output::output_repository_no_pending(
    &mut repo_charlie,
    &changes,
    &mut txn_charlie,
    &mut channel_charlie,
    "",
    true,
    )?;
    let mut files_charlie = repo_charlie.list_files();
    files_charlie.sort();
    assert_eq!(files_charlie, &["file", "file3"]);
  • replacement in libpijul/src/tests/file_conflicts.rs at line 457
    [5.318979][5.318979:319026]()
    let files_alice = repo_alice.list_files();
    [5.318979]
    [5.319026]
    let mut files_alice = repo_alice.list_files();
    files_alice.sort();
  • replacement in libpijul/src/tests/file_conflicts.rs at line 471
    [5.319354][5.319354:319388]()
    // Bob applies Alice's change
    [5.319354]
    [5.319388]
    // Bob applies Alice's change and Charlie's change
  • replacement in libpijul/src/tests/file_conflicts.rs at line 1195
    [5.342672][5.342672:342721]()
    // Charlie applies Alice's move and deletes.
    [5.342672]
    [5.342721]
    // Charlie applies Alice's move and deletes (i.e. does the same as Bob).
  • edit in libpijul/src/tests/file_conflicts.rs at line 1225
    [5.343693]
    [5.343693]
    debug!("Charlie applies Bob's deletion");
  • edit in libpijul/src/tests/file_conflicts.rs at line 1228
    [5.20732]
    [5.343852]
    debug!("Charlie applies Bob's resolution");
  • replacement in libpijul/src/tests/file_conflicts.rs at line 1245
    [5.344257][5.344257:344572]()
    assert_eq!(conflicts.len(), 2);
    match (&conflicts[0], &conflicts[1]) {
    (Conflict::ZombieFile { ref path }, Conflict::MultipleNames { .. })
    | (Conflict::MultipleNames { .. }, Conflict::ZombieFile { ref path }) => {
    assert!(path == "a/b/c/alice" || path == "a/b/c/file")
    }
    [5.344257]
    [5.344572]
    assert_eq!(conflicts.len(), 1);
    match conflicts[0] {
    Conflict::ZombieFile { ref path } => assert_eq!(path, "a/b/c/alice"),
  • edit in libpijul/src/tests/file_conflicts.rs at line 1252
    [5.344643]
    [5.344643]
    debug!("Alice applies Charlie's deletion");
  • replacement in libpijul/src/record.rs at line 262
    [5.497606][5.497606:497652]()
    flag: EdgeFlags::empty(),
    [5.497606]
    [5.497652]
    flag: EdgeFlags::BLOCK,
  • edit in libpijul/src/record.rs at line 572
    [5.508937]
    [5.508937]
    if !moved.need_new_name {
    moved.resurrect.extend(moved.edges.drain(..));
    }
  • edit in libpijul/src/record.rs at line 584
    [5.509246][5.509246:509247]()
  • replacement in libpijul/src/record.rs at line 784
    [5.517750][5.517750:517779]()
    if intro.len() > 1 {
    [5.517750]
    [5.517779]
    if intro.len() > 1 || !moved.resurrect.is_empty() {
  • edit in libpijul/src/pristine/vertex.rs at line 34
    [5.526409][5.526409:526416](),[5.526416][5.0:107]()
    }
    /// Is this vertex of zero length?
    pub fn is_empty(&self) -> bool {
    self.end == self.start
  • edit in libpijul/src/pristine/vertex.rs at line 66
    [5.527253]
    [5.527253]
    /// Is this vertex of zero length?
    pub fn is_empty(&self) -> bool {
    self.end == self.start
    }
  • edit in libpijul/src/pristine/mod.rs at line 63
    [5.588093]
    [5.588093]
    }
    }
    impl<T: MutTxnT> Channel<T> {
    pub(crate) fn touch(&mut self) {
    use std::time::SystemTime;
    if let Ok(duration) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
    self.last_modified = duration.as_secs();
    }
  • edit in libpijul/src/pristine/mod.rs at line 307
    [5.607395]
    [5.37846]
    }
    pub(crate) fn iter_alive_children<'db, 'txn: 'db, T: TxnT>(
    txn: &'txn T,
    channel: &'db Channel<T>,
    key: Vertex<ChangeId>,
    ) -> AdjacentIterator<'txn, T> {
    iter_adjacent(
    txn,
    channel,
    key,
    EdgeFlags::empty(),
    EdgeFlags::alive_children(),
    )
  • edit in libpijul/src/pristine/mod.rs at line 323
    [5.607396]
    [5.37849]
    pub(crate) fn iter_deleted_parents<'db, 'txn: 'db, T: TxnT>(
    txn: &'txn T,
    channel: &'db Channel<T>,
    key: Vertex<ChangeId>,
    ) -> AdjacentIterator<'txn, T> {
    iter_adjacent(
    txn,
    channel,
    key,
    EdgeFlags::DELETED | EdgeFlags::PARENT,
    EdgeFlags::all(),
    )
    }
    pub(crate) fn iter_adj_all<'db, 'txn: 'db, T: TxnT>(
    txn: &'txn T,
    channel: &'db Channel<T>,
    key: Vertex<ChangeId>,
    ) -> AdjacentIterator<'txn, T> {
    iter_adjacent(txn, channel, key, EdgeFlags::empty(), EdgeFlags::all())
    }
  • replacement in libpijul/src/pristine/mod.rs at line 766
    [5.49443][5.49443:49532]()
    for e in iter_adjacent(txn, &channel, v, EdgeFlags::empty(), EdgeFlags::all()) {
    [5.49443]
    [2.507]
    for e in iter_adj_all(txn, &channel, v) {
  • replacement in libpijul/src/pristine/mod.rs at line 1457
    [5.1067][5.1067:1275]()
    for e in iter_adjacent(
    txn,
    &channel,
    vertex.inode_vertex(),
    EdgeFlags::empty(),
    EdgeFlags::all(),
    ) {
    [5.1067]
    [5.1275]
    for e in iter_adj_all(txn, &channel, vertex.inode_vertex()) {
  • replacement in libpijul/src/pristine/edge.rs at line 5
    [5.649074][5.649074:649577]()
    /// Possible flags of edges.
    #[derive(Serialize, Deserialize)]
    pub struct EdgeFlags: u8 {
    const BLOCK = 1;
    /// A pseudo-edge, computed when applying the change to
    /// restore connectivity, and/or mark conflicts.
    const PSEUDO = 4;
    /// An edge encoding file system hierarchy.
    const FOLDER = 16;
    /// A "reverse" edge (all edges in the graph have a reverse edge).
    const PARENT = 32;
    /// An edge whose target (if not also `PARENT`) or
    /// source (if also `PARENT`) is marked as deleted.
    const DELETED = 128;
    [5.649074]
    [5.649577]
    /// Possible flags of edges.
    #[derive(Serialize, Deserialize)]
    pub struct EdgeFlags: u8 {
    const BLOCK = 1;
    /// A pseudo-edge, computed when applying the change to
    /// restore connectivity, and/or mark conflicts.
    const PSEUDO = 4;
    /// An edge encoding file system hierarchy.
    const FOLDER = 16;
    /// A "reverse" edge (all edges in the graph have a reverse edge).
    const PARENT = 32;
    /// An edge whose target (if not also `PARENT`) or
    /// source (if also `PARENT`) is marked as deleted.
    const DELETED = 128;
    }
  • edit in libpijul/src/pristine/edge.rs at line 21
    [5.649579]
    [5.649579]
    impl EdgeFlags {
    #[inline]
    pub(crate) fn db() -> Self {
    Self::DELETED | Self::BLOCK
    }
    #[inline]
    pub(crate) fn bp() -> Self {
    Self::BLOCK | Self::PARENT
    }
    #[inline]
    pub(crate) fn pseudof() -> Self {
    Self::PSEUDO | Self::FOLDER
    }
    #[inline]
    pub(crate) fn alive_children() -> Self {
    Self::BLOCK | Self::PSEUDO | Self::FOLDER
    }
    #[inline]
    pub(crate) fn parent_folder() -> Self {
    Self::PARENT | Self::FOLDER
    }
    #[inline]
    pub(crate) fn is_deleted(&self) -> bool {
    self.contains(EdgeFlags::DELETED)
    }
    #[inline]
    pub(crate) fn is_parent(&self) -> bool {
    self.contains(EdgeFlags::PARENT)
    }
    #[inline]
    pub(crate) fn is_folder(&self) -> bool {
    self.contains(EdgeFlags::FOLDER)
    }
    #[inline]
    pub(crate) fn is_block(&self) -> bool {
    self.contains(EdgeFlags::BLOCK)
    }
  • replacement in libpijul/src/output/output.rs at line 98
    [5.675153][5.675153:675184]()
    b.sort_by(|u, v| {
    [5.675153]
    [5.675184]
    b.sort_unstable_by(|u, v| {
  • replacement in libpijul/src/missing_context.rs at line 26
    [5.697000][5.697000:697045]()
    match self.graphs.entry(inode) {
    [5.697000]
    [5.697045]
    match self.graphs.0.entry(inode) {
  • edit in libpijul/src/missing_context.rs at line 60
    [5.698194]
    [5.698194]
    change_id: ChangeId,
  • edit in libpijul/src/missing_context.rs at line 64
    [5.698264][5.698264:698287]()
    d_is_folder: bool,
  • replacement in libpijul/src/missing_context.rs at line 66
    [5.698361][5.698361:698423]()
    let (mut alive, files) = find_alive_up(txn, channel, c)?;
    [5.698361]
    [5.698423]
    let mut alive = find_alive_up(txn, channel, &mut ws.files, c, change_id)?;
  • edit in libpijul/src/missing_context.rs at line 71
    [5.698590][5.698590:698652]()
    debug!("repair_missing_up_context, files = {:?}", files);
  • replacement in libpijul/src/missing_context.rs at line 72
    [5.698670][5.698670:698731]()
    if let Some((graph, vids)) = ws.graphs.get(&inode) {
    [5.698670]
    [5.698731]
    if let Some((graph, vids)) = ws.graphs.0.get(&inode) {
  • replacement in libpijul/src/missing_context.rs at line 81
    [5.698941][5.698941:699328](),[5.699328][5.56974:57027](),[5.57027][5.699364:699639](),[5.699364][5.699364:699639](),[5.699639][5.26489:26545](),[5.26545][5.699655:699665](),[5.699655][5.699655:699665](),[5.699665][5.699665:699700](),[5.699700][5.57028:57081](),[5.57081][5.699736:699886](),[5.699736][5.699736:699886](),[5.699886][5.26546:26602](),[5.26602][5.699902:699912](),[5.699902][5.699902:699912]()
    for &ancestor in alive.iter() {
    debug!("put_graph_with_rev {:?} -> {:?}", ancestor, d);
    if ancestor == d {
    info!(
    "repair_missing_up_context, alive: {:?} == {:?}",
    ancestor, d
    );
    continue;
    }
    debug!("repair_missing_up {:?} {:?}", ancestor, d);
    put_graph_with_rev(
    txn,
    channel,
    if d_is_folder {
    EdgeFlags::PSEUDO | EdgeFlags::FOLDER
    } else {
    EdgeFlags::PSEUDO
    },
    ancestor,
    d,
    ChangeId::ROOT,
    )
    .map_err(MissingError::Txn)?;
    }
    if d_is_folder && c != d {
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::PSEUDO | EdgeFlags::FOLDER,
    c,
    d,
    ChangeId::ROOT,
    )
    .map_err(MissingError::Txn)?;
    }
    [5.698941]
    [5.699912]
    repair_regular_up(txn, channel, &alive, d, EdgeFlags::PSEUDO).map_err(MissingError::Txn)?;
  • edit in libpijul/src/missing_context.rs at line 83
    [5.699918][3.0:48]()
    repair_files_up(txn, channel, &files, ws)?;
  • replacement in libpijul/src/missing_context.rs at line 86
    [5.699976][5.699976:700008]()
    fn repair_files_up<T: MutTxnT>(
    [5.699976]
    [5.700008]
    fn repair_regular_up<T: MutTxnT>(
  • replacement in libpijul/src/missing_context.rs at line 89
    [5.700055][5.700055:700095](),[5.700095][3.49:73](),[3.73][5.26603:26645](),[5.700095][5.26603:26645](),[5.26645][5.700128:700155](),[5.700128][5.700128:700155](),[5.700155][5.700155:700193](),[5.700193][5.57082:57132](),[5.57132][5.700242:700395](),[5.700242][5.700242:700395](),[5.700395][5.57133:57178](),[5.57178][5.700427:700557](),[5.700427][5.700427:700557](),[5.700557][5.26646:26694](),[5.26694][3.74:105]()
    files: &[(Vertex<ChangeId>, Edge)],
    ws: &mut Workspace,
    ) -> Result<(), MissingError<T::Error>> {
    for &(a, b) in files {
    let b = if a.start == a.end {
    find_block_end(txn, channel, b.dest)?
    } else {
    b.dest.inode_vertex()
    };
    debug!("put_graph_with_rev (files) {:?} -> {:?}", b, a);
    assert_ne!(a, b);
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO,
    b,
    a,
    ChangeId::ROOT,
    )
    .map_err(MissingError::Txn)?;
    ws.repaired.insert(a);
    [5.700055]
    [5.700569]
    alive: &HashSet<Vertex<ChangeId>>,
    d: Vertex<ChangeId>,
    flag: EdgeFlags,
    ) -> Result<(), T::Error> {
    for &ancestor in alive.iter() {
    debug!("put_graph_with_rev {:?} -> {:?}", ancestor, d);
    if ancestor == d {
    info!(
    "repair_missing_up_context, alive: {:?} == {:?}",
    ancestor, d
    );
    continue;
    }
    debug!("repair_missing_up {:?} {:?}", ancestor, d);
    put_graph_with_rev(txn, channel, flag, ancestor, d, ChangeId::ROOT)?;
  • replacement in libpijul/src/missing_context.rs at line 124
    [5.701137][5.701137:701194]()
    if let Some((graph, vids)) = ws.graphs.get(&inode) {
    [5.701137]
    [5.701194]
    if let Some((graph, vids)) = ws.graphs.0.get(&inode) {
  • replacement in libpijul/src/missing_context.rs at line 133
    [5.701398][5.701398:701621]()
    for &descendant in alive.iter() {
    if d == descendant {
    info!(
    "repair_missing_down_context, alive: {:?} == {:?}",
    d, descendant
    );
    [5.701398]
    [5.701621]
    for &desc in alive.iter() {
    if d == desc {
    info!("repair_missing_down_context, alive: {:?} == {:?}", d, desc);
  • replacement in libpijul/src/missing_context.rs at line 138
    [5.701661][5.701661:701729](),[5.701729][5.57179:57371](),[5.57371][5.26740:26796]()
    debug!("repair_missing_down {:?} {:?}", d, descendant);
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::PSEUDO,
    d,
    descendant,
    ChangeId::ROOT,
    )
    .map_err(MissingError::Txn)?;
    [5.701661]
    [5.701825]
    debug!("repair_missing_down {:?} {:?}", d, desc);
    put_graph_with_rev(txn, channel, EdgeFlags::PSEUDO, d, desc, ChangeId::ROOT)
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/missing_context.rs at line 158
    [5.702212][5.57388:57622](),[5.57622][5.702442:702686](),[5.702442][5.702442:702686](),[5.702686][5.702686:702821](),[5.702821][5.702821:702861](),[5.702861][5.702861:702899](),[5.702899][5.57623:57712](),[5.57712][5.702987:703036](),[5.702987][5.702987:703036](),[5.703036][5.703036:703103](),[5.703103][5.703103:703217](),[5.703217][5.703217:703315](),[5.703315][5.703315:703347](),[5.703347][5.703347:703470](),[5.703470][5.703470:703471](),[5.703471][5.703471:703497](),[5.703497][5.703497:703811]()
    let source = internal_pos(txn, &e.from, change_id)?;
    let source = find_block_end(txn, &channel, source)?;
    let target = internal_pos(txn, &e.to.start_pos(), change_id)?;
    let target = find_block(txn, &channel, target)?;
    debug!(
    "repair_context_nondeleted: source = {:?}, target: {:?}",
    source, target
    );
    // Fixing the connection from root to the source: if the source is
    // deleted by an unknown patch, or if the target is deleted
    // (necessarily by unknown patch), then `target` might be
    // disconnected from the alive graph, so we need to fix the context.
    let mut deleted_by_unknown = false;
    let mut target_is_folder = false;
    for v in iter_adjacent(txn, channel, source, EdgeFlags::empty(), EdgeFlags::all()) {
    if !v.flag.contains(EdgeFlags::PARENT) {
    target_is_folder = v.flag.contains(EdgeFlags::FOLDER);
    continue;
    }
    if !v.flag.contains(EdgeFlags::DELETED) {
    continue;
    }
    if v.introduced_by == change_id || v.dest.change.is_root() || v.introduced_by.is_root() {
    continue;
    }
    // This unwrap is ok, since `v` is in the channel.
    let intro = txn.get_external(v.introduced_by).unwrap();
    if known(intro) {
    // If a known change also delete the context, we're good.
    deleted_by_unknown = false;
    break;
    } else {
    // If an unknown change deletes the context, wait: maybe a
    // known change will delete it too.
    deleted_by_unknown = true;
    }
    [5.702212]
    [5.703811]
    if e.flag.contains(EdgeFlags::FOLDER) {
    return Ok(());
  • replacement in libpijul/src/missing_context.rs at line 161
    [5.703817][5.703817:703904](),[5.703904][5.703904:704002]()
    debug!("deleted_by_unknown {:?}", deleted_by_unknown);
    if deleted_by_unknown {
    repair_missing_up_context(txn, channel, ws, inode, source, &[target], target_is_folder)?;
    [5.703817]
    [5.704002]
    let source = find_block_end(txn, &channel, internal_pos(txn, &e.from, change_id)?)?;
    let target = find_block(
    txn,
    &channel,
    internal_pos(txn, &e.to.start_pos(), change_id)?,
    )?;
    if deleted_by_unknown(txn, channel, source, change_id, &mut known) {
    repair_missing_up_context(txn, channel, ws, change_id, inode, source, &[target])?;
  • edit in libpijul/src/missing_context.rs at line 170
    [5.704008]
    [5.704008]
    reconnect_target_up(txn, channel, ws, inode, target, change_id)?;
    reconnect_target_down(txn, channel, ws, inode, target, change_id, &mut known)
    }
  • replacement in libpijul/src/missing_context.rs at line 175
    [5.704009][5.704009:704175]()
    // Now, maybe ~source~ was deleted by known changes, but
    // accessibility to ~target~ was provided by other edges that got
    // deleted by unknown changes.
    [5.704009]
    [5.704175]
    fn reconnect_target_up<T: MutTxnT>(
    txn: &mut T,
    channel: &mut Channel<T>,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    target: Vertex<ChangeId>,
    change_id: ChangeId,
    ) -> Result<(), MissingError<T::Error>> {
  • replacement in libpijul/src/missing_context.rs at line 184
    [5.704213][5.57713:57802](),[5.57802][5.704301:704390](),[5.704301][5.704301:704390]()
    for v in iter_adjacent(txn, channel, target, EdgeFlags::empty(), EdgeFlags::all()) {
    if !v.flag.contains(EdgeFlags::PARENT) || !v.flag.contains(EdgeFlags::DELETED) {
    [5.704213]
    [5.704390]
    for v in iter_deleted_parents(txn, channel, target) {
    if v.dest.change.is_root() || v.introduced_by.is_root() {
  • replacement in libpijul/src/missing_context.rs at line 188
    [5.704422][5.704422:704520](),[5.704520][5.704520:704542]()
    if v.introduced_by == change_id || v.dest.change.is_root() || v.introduced_by.is_root() {
    continue;
    [5.704422]
    [5.704542]
    if v.introduced_by == change_id {
    unknown.clear();
    break;
  • replacement in libpijul/src/missing_context.rs at line 193
    [5.704620][5.704620:704670]()
    // since no change can create a conflict.
    [5.704620]
    [5.57803]
    // since no change can create a conflict with itself.
  • replacement in libpijul/src/missing_context.rs at line 197
    [5.704770][5.704770:704864]()
    repair_missing_up_context(txn, channel, ws, inode, up, &[target], target_is_folder)?;
    [5.704770]
    [5.704864]
    repair_missing_up_context(txn, channel, ws, change_id, inode, up, &[target])?;
  • edit in libpijul/src/missing_context.rs at line 199
    [5.704870]
    [5.704870]
    Ok(())
    }
  • edit in libpijul/src/missing_context.rs at line 202
    [5.704871]
    [5.704871]
    fn reconnect_target_down<T: MutTxnT, K>(
    txn: &mut T,
    channel: &mut Channel<T>,
    ws: &mut Workspace,
    inode: Position<Option<Hash>>,
    target: Vertex<ChangeId>,
    change_id: ChangeId,
    known: &mut K,
    ) -> Result<(), MissingError<T::Error>>
    where
    K: FnMut(Hash) -> bool,
    {
  • replacement in libpijul/src/missing_context.rs at line 216
    [5.705017][5.57867:57956]()
    for v in iter_adjacent(txn, channel, target, EdgeFlags::empty(), EdgeFlags::all()) {
    [5.705017]
    [5.705105]
    for v in iter_adj_all(txn, channel, target) {
  • edit in libpijul/src/missing_context.rs at line 237
    [5.705747]
    [5.705747]
    }
    fn deleted_by_unknown<T: TxnT, K>(
    txn: &T,
    channel: &Channel<T>,
    source: Vertex<ChangeId>,
    change_id: ChangeId,
    known: &mut K,
    ) -> bool
    where
    K: FnMut(Hash) -> bool,
    {
    let mut deleted_by_unknown = false;
    for v in iter_deleted_parents(txn, channel, source) {
    if v.dest.change.is_root() || v.introduced_by.is_root() {
    continue;
    }
    if v.introduced_by == change_id || known(txn.get_external(v.introduced_by).unwrap()) {
    // If a known change also delete the context, we're good.
    return false;
    } else {
    // If an unknown change deletes the context, wait: maybe a
    // known change will delete it too.
    deleted_by_unknown = true;
    }
    }
    deleted_by_unknown
  • edit in libpijul/src/missing_context.rs at line 278
    [5.706105]
    [5.706105]
    if e.flag.contains(EdgeFlags::FOLDER) {
    return Ok(());
    }
  • edit in libpijul/src/missing_context.rs at line 283
    [5.58025][5.58025:58091]()
    let end_pos = internal_pos(txn, &e.to.end_pos(), change_id)?;
  • replacement in libpijul/src/missing_context.rs at line 286
    [5.706520][5.706520:706563]()
    if dest_vertex.end < end_pos.pos {
    [5.706520]
    [5.706563]
    if dest_vertex.end < e.to.end {
  • replacement in libpijul/src/missing_context.rs at line 307
    [3.147][5.706977:707101](),[5.706977][5.706977:707101]()
    pub(crate) graphs:
    HashMap<Position<Option<Hash>>, (Graph, HashMap<Vertex<ChangeId>, crate::alive::VertexId>)>,
    [3.147]
    [5.707101]
    pub(crate) graphs: Graphs,
  • edit in libpijul/src/missing_context.rs at line 309
    [5.707180]
    [5.707180]
    pub(crate) files: HashSet<Vertex<ChangeId>>,
  • edit in libpijul/src/missing_context.rs at line 312
    [5.707183]
    [5.707183]
    #[derive(Debug, Default)]
    pub(crate) struct Graphs(
    pub HashMap<Position<Option<Hash>>, (Graph, HashMap<Vertex<ChangeId>, crate::alive::VertexId>)>,
    );
    impl Graphs {
    pub(crate) fn get(
    &self,
    inode: Position<Option<Hash>>,
    ) -> Result<&(Graph, HashMap<Vertex<ChangeId>, VertexId>), InconsistentChange> {
    if let Some(n) = self.0.get(&inode) {
    Ok(n)
    } else {
    Err(InconsistentChange {})
    }
    }
    pub fn split(
    &mut self,
    inode: Position<Option<Hash>>,
    vertex: Vertex<ChangeId>,
    mid: ChangePosition,
    ) {
    if let Some((_, vids)) = self.0.get_mut(&inode) {
    if let Some(vid) = vids.remove(&vertex) {
    vids.insert(Vertex { end: mid, ..vertex }, vid);
    vids.insert(
    Vertex {
    start: mid,
    ..vertex
    },
    vid,
    );
    }
    }
    }
    }
  • replacement in libpijul/src/missing_context.rs at line 356
    [5.707644][5.707644:707673]()
    self.graphs.clear();
    [5.707644]
    [3.148]
    self.graphs.0.clear();
  • replacement in libpijul/src/missing_context.rs at line 365
    [5.707925][5.707925:707966]()
    assert!(self.graphs.is_empty());
    [5.707925]
    [3.180]
    assert!(self.graphs.0.is_empty());
  • replacement in libpijul/src/missing_context.rs at line 381
    [5.708246][5.58157:58198](),[5.58198][5.708278:708419](),[5.708278][5.708278:708419]()
    for v in iter_adjacent(
    txn,
    channel,
    dest_vertex,
    EdgeFlags::empty(),
    EdgeFlags::all() - EdgeFlags::DELETED - EdgeFlags::PARENT,
    ) {
    [5.708246]
    [5.58199]
    for v in iter_alive_children(txn, channel, dest_vertex) {
  • edit in libpijul/src/missing_context.rs at line 393
    [5.708668][5.708668:708829]()
    // If `dest_vertex` is not also deleted by the same change
    // that introduced unknown edge `v`, then `v` is really
    // a missing context.
  • edit in libpijul/src/missing_context.rs at line 402
    [5.709098][5.709098:709161]()
    // This unwrap is ok, since `v` is in the channel.
  • replacement in libpijul/src/missing_context.rs at line 425
    [5.709899][5.709899:710052]()
    if unknown.is_empty() {
    trace!("unknown = []")
    } else {
    debug!("dest_vertex = {:?}, unknown = {:?}", dest_vertex, unknown)
    }
    [5.709899]
    [5.710052]
    debug!("dest_vertex = {:?}, unknown = {:?}", dest_vertex, unknown);
  • replacement in libpijul/src/missing_context.rs at line 428
    [5.58613][5.710141:710193](),[5.710141][5.710141:710193](),[5.710260][5.710260:710324](),[5.710324][5.58614:58667](),[5.58667][5.710360:710515](),[5.710360][5.710360:710515](),[5.710515][5.26924:26938]()
    if !edge.flag.contains(EdgeFlags::FOLDER) {
    debug!("dest_vertex {:?}, p {:?}", dest_vertex, p);
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::DELETED | EdgeFlags::BLOCK,
    dest_vertex,
    p,
    change_id,
    )
    [5.58613]
    [5.26938]
    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)
  • replacement in libpijul/src/missing_context.rs at line 432
    [5.26980][5.710531:710558](),[5.710531][5.710531:710558](),[5.710558][5.58668:58738](),[5.58738][5.710627:710733](),[5.710627][5.710627:710733](),[5.710733][5.58739:58808](),[5.58808][5.710777:710962](),[5.710777][5.710777:710962](),[5.710962][5.26981:27003]()
    let mut u = p;
    while let Ok(v) = find_block(txn, channel, u.end_pos()) {
    if u != v {
    debug!("repair_children_of_deleted: {:?} -> {:?}", u, v);
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::DELETED | EdgeFlags::BLOCK,
    u,
    v,
    change_id,
    )
    [5.26980]
    [5.27003]
    let mut u = p;
    while let Ok(v) = find_block(txn, 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)
  • replacement in libpijul/src/missing_context.rs at line 438
    [5.27053][5.710986:711082](),[5.710986][5.710986:711082]()
    u = v
    } else {
    break;
    }
    [5.27053]
    [5.711082]
    u = v
    } else {
    break;
  • replacement in libpijul/src/missing_context.rs at line 443
    [5.711169][5.58809:58889](),[5.58889][5.711248:711317](),[5.711248][5.711248:711317](),[5.711317][5.711317:711414]()
    if is_alive(txn, channel, p) || edge.flag.contains(EdgeFlags::FOLDER) {
    let p_is_folder = edge.flag.contains(EdgeFlags::FOLDER);
    repair_missing_up_context(txn, channel, ws, inode, dest_vertex, &[p], p_is_folder)?;
    [5.711106]
    [5.711414]
    if is_alive(txn, channel, p) {
    repair_missing_up_context(txn, channel, ws, change_id, inode, dest_vertex, &[p])?;
  • replacement in libpijul/src/missing_context.rs at line 447
    [5.711490][5.711490:711583]()
    repair_missing_up_context(txn, channel, ws, inode, dest_vertex, &alive, false)?;
    [5.711490]
    [5.711583]
    repair_missing_up_context(txn, channel, ws, change_id, inode, dest_vertex, &alive)?;
  • replacement in libpijul/src/missing_context.rs at line 462
    [5.711914][5.711914:711964]()
    for (dest_vertex, e) in ws.pseudo.drain(..) {
    [5.711914]
    [5.711964]
    for (dest_vertex, mut e) in ws.pseudo.drain(..) {
  • replacement in libpijul/src/missing_context.rs at line 469
    [5.59118][5.59118:59187](),[5.59187][5.712296:712486](),[5.712296][5.712296:712486](),[5.712486][5.27097:27169]()
    del_graph_with_rev(
    txn,
    channel,
    e.flag - EdgeFlags::PARENT,
    p,
    dest_vertex,
    e.introduced_by,
    )
    .map_err(MissingError::Txn)?;
    [5.59118]
    [5.712510]
    e.flag -= EdgeFlags::PARENT;
    del_graph_with_rev(txn, channel, e.flag, p, dest_vertex, e.introduced_by)
    .map_err(MissingError::Txn)?;
  • replacement in libpijul/src/find_alive.rs at line 23
    [5.764294][5.64513:64607]()
    for v in iter_adjacent(txn, &channel, vertex, EdgeFlags::empty(), EdgeFlags::all()) {
    [5.764231]
    [5.764387]
    for v in iter_adj_all(txn, &channel, vertex) {
  • edit in libpijul/src/find_alive.rs at line 50
    [5.765267]
    [5.765267]
    files: &mut HashSet<Vertex<ChangeId>>,
  • replacement in libpijul/src/find_alive.rs at line 52
    [5.765298][5.32415:32501]()
    ) -> Result<(HashSet<Vertex<ChangeId>>, Vec<(Vertex<ChangeId>, Edge)>), BlockError> {
    [5.765298]
    [5.765386]
    change: ChangeId,
    ) -> Result<HashSet<Vertex<ChangeId>>, BlockError> {
  • edit in libpijul/src/find_alive.rs at line 55
    [5.765422][5.765422:765454]()
    let mut files = Vec::new();
  • replacement in libpijul/src/find_alive.rs at line 71
    [5.766107][5.766107:766141](),[5.766141][5.64786:64879]()
    let mut next_file = None;
    for v in iter_adjacent(txn, &channel, vertex, EdgeFlags::PARENT, EdgeFlags::all()) {
    [5.766044]
    [5.766233]
    let mut is_file = false;
    let mut it = iter_adj_all(txn, &channel, vertex);
    while let Some(v) = it.next() {
  • replacement in libpijul/src/find_alive.rs at line 75
    [5.766283][5.766283:766374]()
    if !v.flag.contains(EdgeFlags::PARENT) || v.flag.contains(EdgeFlags::PSEUDO) {
    [5.766283]
    [5.766374]
    if !v.flag.is_parent() {
    is_file |= !v.flag.is_folder();
  • replacement in libpijul/src/find_alive.rs at line 79
    [5.766481][5.766481:766828](),[5.766828][5.5337:5422](),[5.5422][5.64922:65388](),[5.64922][5.64922:65388](),[5.65388][5.5423:5472]()
    if !v.flag.contains(EdgeFlags::DELETED) {
    if v.flag.contains(EdgeFlags::FOLDER) {
    // check whether `vertex` is a "file" inode,
    // i.e. if it has non-folder children. We're never
    // in the case of an empty file if we call this
    // function.
    if next_file.is_none()
    && iter_adjacent(
    txn,
    &channel,
    vertex,
    EdgeFlags::empty(),
    EdgeFlags::all(),
    )
    .any(|e| {
    e.flag.contains(EdgeFlags::BLOCK)
    && !e.flag.contains(EdgeFlags::PARENT)
    && !e.flag.contains(EdgeFlags::FOLDER)
    })
    {
    [5.766414]
    [5.5472]
    if v.flag & EdgeFlags::pseudof() == EdgeFlags::PSEUDO {
    continue;
    }
    if !v.flag.is_deleted() {
    if v.flag.is_folder() {
    is_file |= it.any(|e| !e.flag.intersects(EdgeFlags::parent_folder()));
    if is_file {
  • edit in libpijul/src/find_alive.rs at line 87
    [5.5518]
    [5.767318]
    files.insert(vertex);
  • replacement in libpijul/src/find_alive.rs at line 89
    [5.767340][5.767340:767378]()
    next_file = None;
    [5.767340]
    [5.767378]
    break;
  • edit in libpijul/src/find_alive.rs at line 92
    [5.767445]
    [5.767445]
    if v.introduced_by != change {
    stack.truncate(elt_index);
    break;
    }
  • edit in libpijul/src/find_alive.rs at line 97
    [5.767463][5.767463:767529]()
    stack.truncate(elt_index);
    break;
  • replacement in libpijul/src/find_alive.rs at line 98
    [5.767610][5.767610:767662](),[5.767662][5.767662:768099](),[5.768099][5.768099:768226](),[5.768226][5.65418:65516](),[5.65516][5.768348:768567](),[5.768348][5.768348:768567](),[5.768567][5.768567:768635]()
    if v.flag.contains(EdgeFlags::FOLDER) {
    let v_age = txn
    .get_changeset(&channel.changes, v.introduced_by, None)
    .unwrap();
    if let Some((ref mut file, ref mut age)) = next_file {
    if v_age > *age {
    *age = v_age;
    *file = (vertex, v)
    }
    } else {
    next_file = Some(((vertex, v), v_age));
    // If `vertex` is a "file" inode (as opposed to a
    // "folder" inode), mark it "alive".
    if iter_adjacent(txn, &channel, vertex, EdgeFlags::empty(), EdgeFlags::all())
    .any(|e| {
    !e.flag.contains(EdgeFlags::PARENT)
    && !e.flag.contains(EdgeFlags::FOLDER)
    })
    {
    alive.insert(vertex);
    }
    [5.767543]
    [5.768635]
    if v.flag.is_folder() {
    if is_file {
    alive.insert(vertex);
    files.insert(vertex);
  • edit in libpijul/src/find_alive.rs at line 103
    [5.768653]
    [5.768653]
    break;
  • edit in libpijul/src/find_alive.rs at line 107
    [5.768718][5.768718:768834]()
    }
    if let Some((file, _)) = next_file {
    files.push(file);
    stack.push(file.1)
  • edit in libpijul/src/find_alive.rs at line 108
    [5.768844]
    [5.768844]
    debug!("is_file = {:?}", is_file);
  • replacement in libpijul/src/find_alive.rs at line 110
    [5.768850][5.768850:768873]()
    Ok((alive, files))
    [5.768850]
    [5.768873]
    Ok(alive)
  • replacement in libpijul/src/diff/delete.rs at line 176
    [5.810948][4.0:68]()
    flag: previous | EdgeFlags::BLOCK | EdgeFlags::DELETED,
    [5.810948]
    [5.810997]
    flag: previous | EdgeFlags::DELETED,
  • edit in libpijul/src/change.rs at line 84
    [5.832924]
    [5.832924]
    }
    impl<T: Clone> NewEdge<T> {
    pub(crate) fn reverse(&self, introduced_by: T) -> Self {
    NewEdge {
    previous: self.flag,
    flag: self.previous,
    from: self.from.clone(),
    to: self.to.clone(),
    introduced_by,
    }
    }
  • replacement in libpijul/src/change.rs at line 285
    [5.66514][5.66514:66604]()
    for edge in iter_adjacent(txn, channel, from, EdgeFlags::empty(), EdgeFlags::all()) {
    [5.66514]
    [5.838760]
    for edge in iter_adj_all(txn, channel, from) {
  • replacement in libpijul/src/change.rs at line 317
    [5.839576][5.66666:66758]()
    for edge in iter_adjacent(txn, channel, to, EdgeFlags::empty(), EdgeFlags::all()) {
    [5.839576]
    [5.839667]
    for edge in iter_adj_all(txn, channel, to) {
  • edit in libpijul/src/change/text_changes.rs at line 783
    [5.68233]
    [5.68233]
    v.flag = EdgeFlags::BLOCK;
  • replacement in libpijul/src/apply.rs at line 2
    [5.944165][5.944165:944220]()
    use crate::change::{Atom, Change, NewEdge, NewVertex};
    [5.944165]
    [5.944220]
    use crate::change::{Atom, Change, EdgeMap, NewEdge, NewVertex};
  • edit in libpijul/src/apply.rs at line 35
    [5.94266]
    [5.94266]
    impl<E: std::error::Error> LocalApplyError<E> {
    const INCONSISTENT: Self =
    LocalApplyError::InconsistentChange(crate::pristine::InconsistentChange {});
    }
  • replacement in libpijul/src/apply.rs at line 219
    [5.95841][5.950069:950100](),[5.950069][5.950069:950100]()
    )?
    [5.95841]
    [5.950100]
    )?;
  • replacement in libpijul/src/apply.rs at line 252
    [5.951686][5.951686:951738]()
    clean_obsolete_pseudo_edges(txn, channel, ws)?;
    [5.951686]
    [5.951738]
    clean_obsolete_pseudo_edges(txn, channel, ws, change_id)?;
  • replacement in libpijul/src/apply.rs at line 256
    [5.951847][5.951847:951910]()
    repair_cyclic_paths(txn, channel, ws, change_id, change)?;
    [5.951847]
    [5.951910]
    repair_cyclic_paths(txn, channel, ws)?;
  • replacement in libpijul/src/apply.rs at line 258
    [5.951945][5.96007:96184]()
    if let Ok(duration) =
    std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)
    {
    channel.last_modified = duration.as_secs();
    }
    [5.951945]
    [5.952082]
    channel.touch();
  • replacement in libpijul/src/apply.rs at line 382
    [5.67490][5.956100:956160](),[5.956100][5.956100:956160]()
    put_up_context(txn, channel, ch, n.inode, ws, up)?;
    [5.67490]
    [5.956160]
    if put_up_context(txn, channel, ch, ws, up)? && n.flag.contains(EdgeFlags::FOLDER) {
    return Err(LocalApplyError::INCONSISTENT);
    }
  • replacement in libpijul/src/apply.rs at line 388
    [5.67544][5.956258:956322](),[5.956258][5.956258:956322]()
    put_down_context(txn, channel, ch, n.inode, ws, down)?;
    [5.67544]
    [5.956322]
    if down.change == change {
    return Err((InconsistentChange {}).into());
    }
    if put_down_context(txn, channel, ch, ws, down)? && !n.flag.contains(EdgeFlags::FOLDER) {
    return Err(LocalApplyError::INCONSISTENT);
    }
  • edit in libpijul/src/apply.rs at line 397
    [5.956376]
    [5.956376]
    let up_flag = n.flag | EdgeFlags::BLOCK | EdgeFlags::DELETED;
  • replacement in libpijul/src/apply.rs at line 401
    [5.956497][5.956497:956626](),[5.956626][5.96887:96963]()
    for (change, _) in ws.deleted_by.iter() {
    let flag = n.flag | EdgeFlags::BLOCK | EdgeFlags::DELETED;
    put_graph_with_rev(txn, channel, flag, up, vertex, *change)
    [5.956497]
    [5.96963]
    for change in ws.deleted_by.iter() {
    put_graph_with_rev(txn, channel, up_flag, up, vertex, *change)
  • replacement in libpijul/src/apply.rs at line 406
    [5.956727][5.67624:67684](),[5.67684][5.965:1046](),[5.1046][5.250:354](),[5.250][5.250:354](),[5.354][5.97017:97116]()
    debug!("put_graph_with_rev {:?} {:?}", up, vertex);
    let flag = if n.flag.contains(EdgeFlags::FOLDER) || !vertex.is_empty() {
    n.flag | EdgeFlags::BLOCK
    } else {
    n.flag - EdgeFlags::BLOCK
    };
    put_graph_with_rev(txn, channel, flag, up, vertex, change).map_err(LocalApplyError::Txn)?;
    [5.956727]
    [5.956816]
    put_graph_with_rev(txn, channel, n.flag | EdgeFlags::BLOCK, up, vertex, change)
    .map_err(LocalApplyError::Txn)?;
  • edit in libpijul/src/apply.rs at line 410
    [5.956872]
    [5.67775]
    let mut down_flag = n.flag;
    if !n.flag.is_folder() {
    down_flag -= EdgeFlags::BLOCK
    }
  • replacement in libpijul/src/apply.rs at line 416
    [5.956966][5.67820:68059](),[5.68059][5.97117:97131]()
    if n.flag.contains(EdgeFlags::FOLDER) {
    put_graph_with_rev(
    txn,
    channel,
    n.flag | EdgeFlags::BLOCK,
    vertex,
    down,
    change,
    )
    [5.956966]
    [5.97131]
    put_graph_with_rev(txn, channel, down_flag, vertex, down, change)
  • replacement in libpijul/src/apply.rs at line 418
    [5.68075][5.957404:957421](),[5.97176][5.957404:957421](),[5.957404][5.957404:957421](),[5.957421][5.68076:68267](),[5.68267][5.97177:97191](),[5.97191][5.97191:97236]()
    } else {
    put_graph_with_rev(
    txn,
    channel,
    n.flag - EdgeFlags::BLOCK,
    vertex,
    down,
    change,
    )
    .map_err(LocalApplyError::Txn)?;
    [5.97176]
    [5.957497]
    if n.flag.is_folder() {
    ws.missing_context.files.insert(down);
  • edit in libpijul/src/apply.rs at line 430
    [5.957703][5.957703:957738]()
    inode: Position<Option<Hash>>,
  • replacement in libpijul/src/apply.rs at line 432
    [5.957790][5.97237:97282]()
    ) -> Result<(), LocalApplyError<T::Error>> {
    [5.957790]
    [5.957823]
    ) -> Result<bool, LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 442
    [5.958151][5.958151:958453]()
    if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
    if let Some(vid) = vids.remove(&k) {
    vids.insert(Vertex { end: up.pos, ..k }, vid);
    vids.insert(Vertex { start: up.pos, ..k }, vid);
    }
    }
    [5.958151]
    [5.97283]
    // The missing context "graphs" are only used at the
    // DELETION stage, check that:
    assert!(ws.missing_context.graphs.0.is_empty());
  • edit in libpijul/src/apply.rs at line 456
    [5.68505]
    [5.68505]
    let mut is_non_folder = false;
  • edit in libpijul/src/apply.rs at line 458
    [5.68579]
    [5.68579]
    is_non_folder |= parent.flag & (EdgeFlags::PARENT | EdgeFlags::FOLDER) == EdgeFlags::PARENT;
  • edit in libpijul/src/apply.rs at line 463
    [5.68706][5.68706:68768]()
    // This unwrap is ok: `parent` is in the channel.
  • replacement in libpijul/src/apply.rs at line 465
    [5.68892][5.68892:69008]()
    ws.deleted_by
    .insert((parent.introduced_by, parent.flag - EdgeFlags::PARENT));
    [5.68892]
    [5.69008]
    ws.deleted_by.insert(parent.introduced_by);
  • edit in libpijul/src/apply.rs at line 467
    [5.69022][5.69022:69101](),[5.69101][5.69101:69243](),[5.69243][5.69243:69262]()
    } else if parent.flag.contains(EdgeFlags::PARENT | EdgeFlags::BLOCK) {
    // This vertex is alive, even if its parent is in conflict.
    debug!("up_context: alive {:?} {:?}", up_vertex, parent);
    break;
  • replacement in libpijul/src/apply.rs at line 470
    [5.959194][5.959194:959205]()
    Ok(())
    [5.959194]
    [5.959205]
    Ok(is_non_folder)
  • edit in libpijul/src/apply.rs at line 477
    [5.959359][5.959359:959394]()
    inode: Position<Option<Hash>>,
  • replacement in libpijul/src/apply.rs at line 479
    [5.959448][5.97364:97423]()
    ) -> Result<Vertex<ChangeId>, LocalApplyError<T::Error>> {
    [5.959448]
    [5.69263]
    ) -> Result<bool, LocalApplyError<T::Error>> {
  • replacement in libpijul/src/apply.rs at line 484
    [5.959659][5.959659:960068]()
    if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
    if let Some(vid) = vids.remove(&k) {
    vids.insert(Vertex { end: down.pos, ..k }, vid);
    vids.insert(
    Vertex {
    start: down.pos,
    ..k
    },
    vid,
    );
    }
    }
    [5.959659]
    [5.97424]
    // The missing context "graphs" are only used at the
    // DELETION stage, check that:
    assert!(ws.missing_context.graphs.0.is_empty());
  • edit in libpijul/src/apply.rs at line 498
    [5.960393]
    [5.69361]
    let mut is_folder = false;
  • edit in libpijul/src/apply.rs at line 500
    [5.69437]
    [5.69437]
    is_folder |= parent.flag.contains(EdgeFlags::PARENT | EdgeFlags::FOLDER);
  • edit in libpijul/src/apply.rs at line 503
    [5.960613][5.960613:960679]()
    // This unwrap is ok: `parent` is in the channel.
  • replacement in libpijul/src/apply.rs at line 505
    [5.960811][5.960811:960935]()
    ws.deleted_by
    .insert((parent.introduced_by, parent.flag - EdgeFlags::PARENT));
    [5.960811]
    [5.960935]
    ws.deleted_by.insert(parent.introduced_by);
  • edit in libpijul/src/apply.rs at line 507
    [5.960953][5.960953:960974](),[5.960974][5.69510:69550](),[5.69550][5.69550:69573]()
    } else {
    // This parent is alive
    break;
  • replacement in libpijul/src/apply.rs at line 511
    [5.69613][5.961095:961115](),[5.961095][5.961095:961115]()
    Ok(down_vertex)
    [5.69613]
    [5.961115]
    Ok(is_folder)
  • replacement in libpijul/src/apply.rs at line 519
    [5.961343][5.961343:961391]()
    deleted_by: HashSet<(ChangeId, EdgeFlags)>,
    [5.961343]
    [5.961391]
    deleted_by: HashSet<ChangeId>,
  • edit in libpijul/src/apply.rs at line 566
    [5.963319]
    [5.963319]
    debug!("put_newedge {:?} {:?}", n, change);
  • edit in libpijul/src/apply.rs at line 572
    [5.963431]
    [5.963431]
    if (n.previous.is_block() != n.flag.is_block())
    || (n.previous.is_folder() != n.flag.is_folder())
    {
    return Err(LocalApplyError::INCONSISTENT.into());
    }
  • replacement in libpijul/src/apply.rs at line 578
    [5.963432][5.963432:963505](),[5.963505][5.963505:963553]()
    assert!(ws.children.is_empty());
    assert!(ws.parents.is_empty());
    debug!("put_newedge {:?} {:?}", n, change);
    [5.963432]
    [5.69656]
    debug_assert!(ws.children.is_empty());
    debug_assert!(ws.parents.is_empty());
  • replacement in libpijul/src/apply.rs at line 583
    [5.963660][5.97826:97953]()
    return Err(
    LocalApplyError::InconsistentChange(crate::pristine::InconsistentChange {}).into(),
    );
    [5.963660]
    [5.963721]
    return Err(LocalApplyError::INCONSISTENT.into());
  • edit in libpijul/src/apply.rs at line 589
    [5.963912]
    [5.963912]
    if n.flag.contains(EdgeFlags::FOLDER) {
    ws.missing_context.files.insert(target);
    }
  • replacement in libpijul/src/apply.rs at line 596
    [5.964016][5.964016:964639]()
    if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
    if let Some(vid) = vids.remove(&target) {
    vids.insert(
    Vertex {
    end: n.to.end,
    ..target
    },
    vid,
    );
    vids.insert(
    Vertex {
    start: n.to.end,
    ..target
    },
    vid,
    );
    }
    }
    [5.964016]
    [5.97954]
    ws.missing_context.graphs.split(inode, target, n.to.end);
  • edit in libpijul/src/apply.rs at line 607
    [5.965032]
    [5.965032]
    ws.parents.clear();
  • replacement in libpijul/src/apply.rs at line 610
    [5.965043][5.965043:965101](),[5.965101][5.98043:98139]()
    debug!("deleting {:?} {:?}", n.previous, n.flag);
    let del = del_graph_with_rev(txn, channel, n.previous, source, target, n_introduced_by)
    [5.965043]
    [5.98139]
    del_graph_with_rev(txn, channel, n.previous, source, target, n_introduced_by)
  • edit in libpijul/src/apply.rs at line 612
    [5.69899][5.965198:965236](),[5.98184][5.965198:965236](),[5.965198][5.965198:965236](),[5.965631][5.965631:965742]()
    debug!("deleted: {:?}", del);
    debug!("put_graph {:?} {:?}, intro {:?}", source, target, change);
    assert_ne!(source, target);
  • replacement in libpijul/src/apply.rs at line 618
    [5.965923][5.965923:965969]()
    assert_eq!(target.end, n.to.end);
    [5.965923]
    [5.965969]
    debug!("{:?} {:?}", target, n.to);
    debug_assert_eq!(target.end, n.to.end);
  • replacement in libpijul/src/apply.rs at line 644
    [5.966729][5.966729:967280]()
    if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
    if let Some(vid) = vids.remove(&source) {
    vids.insert(
    Vertex {
    end: from.pos,
    ..source
    },
    vid,
    );
    vids.insert(
    Vertex {
    start: from.pos,
    ..source
    },
    vid,
    );
    }
    }
    [5.966729]
    [5.98467]
    ws.missing_context.graphs.split(inode, source, from.pos);
  • replacement in libpijul/src/apply.rs at line 661
    [5.70249][5.967711:967745](),[5.967711][5.967711:967745]()
    debug!("find_target_vertex");
    [5.70249]
    [5.70250]
    debug!("find_target_vertex, to = {:?}", to);
  • replacement in libpijul/src/apply.rs at line 666
    [5.967922][5.967922:968473]()
    if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
    if let Some(vid) = vids.remove(&target) {
    vids.insert(
    Vertex {
    end: to.start,
    ..target
    },
    vid,
    );
    vids.insert(
    Vertex {
    start: to.start,
    ..target
    },
    vid,
    );
    }
    }
    [5.967922]
    [5.98612]
    ws.missing_context.graphs.split(inode, target, to.start);
  • replacement in libpijul/src/apply.rs at line 713
    [5.98788][5.969844:970152](),[5.969844][5.969844:970152]()
    debug!(
    "reconnect: parents.len() = {:?} to children.len() = {:?}",
    ws.parents.len(),
    ws.children.len()
    );
    debug!(
    "reconnect: parents = {:#?} to children = {:#?}",
    ws.parents, ws.children
    );
    if ws.parents.is_empty() {
    ws.children.clear();
    [5.98788]
    [5.970152]
    if ws.parents.is_empty() || ws.children.is_empty() {
  • replacement in libpijul/src/apply.rs at line 716
    [5.970181][5.970181:970241](),[5.970241][5.970241:970270]()
    if ws.children.is_empty() {
    ws.parents.clear();
    return Ok(());
    }
    [5.970181]
    [5.970270]
    let (graph, vids) = ws.missing_context.graphs.get(inode)?;
  • edit in libpijul/src/apply.rs at line 719
    [5.970271][5.970271:970375](),[5.970375][5.98789:98841](),[5.98841][5.970436:970443](),[5.970436][5.970436:970443]()
    let (graph, vids) = if let Some(n) = ws.missing_context.graphs.get(&inode) {
    n
    } else {
    return Err((InconsistentChange {}).into());
    };
  • edit in libpijul/src/apply.rs at line 731
    [5.970806][5.970806:970906]()
    debug!(
    "reconnect (nonredundant) {:?} to {:?}",
    ws.parents, ws.children
    );
  • replacement in libpijul/src/apply.rs at line 732
    [5.970907][5.970907:970979](),[5.970979][5.70575:70659](),[5.70659][5.98842:98933]()
    for p in ws.parents.drain() {
    for c in ws.children.iter() {
    if p != *c && is_alive(txn, channel, p) && is_alive(txn, channel, *c) {
    put_graph_with_rev(txn, channel, EdgeFlags::PSEUDO, p, *c, ChangeId::ROOT)
    [5.970907]
    [5.98933]
    for &p in ws.parents.iter() {
    debug_assert!(is_alive(txn, channel, p));
    for &c in ws.children.iter() {
    if p != c {
    debug_assert!(is_alive(txn, channel, c));
    put_graph_with_rev(txn, channel, EdgeFlags::PSEUDO, p, c, ChangeId::ROOT)
  • edit in libpijul/src/apply.rs at line 749
    [5.971377]
    [5.98987]
    change_id: ChangeId,
  • edit in libpijul/src/apply.rs at line 751
    [5.99032][5.971410:971451](),[5.971410][5.971410:971451]()
    debug!("pseudo = {:#?}", ws.pseudo);
  • replacement in libpijul/src/apply.rs at line 752
    [5.971508][5.971508:971636](),[5.971636][5.971636:971697]()
    // Reorder next_vertex and p.dest to reformulate this as an "a -> b" edge.
    debug!("{:?} {:?}", next_vertex, p);
    let (a, b) = if p.flag.contains(EdgeFlags::PARENT) {
    [5.971508]
    [5.70753]
    let (a, b) = if p.flag.is_parent() {
  • edit in libpijul/src/apply.rs at line 763
    [5.972425][5.972425:972426]()
  • replacement in libpijul/src/apply.rs at line 765
    [5.70993][5.972799:972853](),[5.972799][5.972799:972853]()
    debug!("{:?} {:?}", a_is_alive, b_is_alive);
    [5.70993]
    [5.972853]
    if a_is_alive && b_is_alive {
    continue;
    }
    del_graph_with_rev(
    txn,
    channel,
    p.flag - EdgeFlags::PARENT,
    a,
    b,
    p.introduced_by,
    )
    .map_err(LocalApplyError::Txn)?;
  • replacement in libpijul/src/apply.rs at line 778
    [5.972877][5.972877:972961](),[5.972961][5.70994:71058](),[5.71058][5.973004:973164](),[5.973004][5.973004:973164](),[5.973164][5.99033:99117](),[5.99117][5.973185:973501](),[5.973185][5.973185:973501](),[5.973501][5.99118:99201](),[5.99201][5.973524:973638](),[5.973524][5.973524:973638](),[5.973638][5.71059:71094]()
    if !b_is_alive {
    debug!("deleting {:?} -> {:?}", a, b);
    if del_graph_with_rev(
    txn,
    channel,
    p.flag - EdgeFlags::PARENT,
    a,
    b,
    p.introduced_by,
    )
    .map_err(LocalApplyError::Txn)?
    {
    // repair down context.
    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 {
    debug!("deleting {:?} -> {:?}", a, b);
    if del_graph_with_rev(
    [5.972877]
    [5.71094]
    debug_assert!(!b_is_alive);
    crate::missing_context::repair_missing_down_context(
  • replacement in libpijul/src/apply.rs at line 782
    [5.71140][5.71140:71203]()
    p.flag - EdgeFlags::PARENT,
    a,
    [5.71140]
    [5.71203]
    &mut ws.missing_context,
    inode,
  • replacement in libpijul/src/apply.rs at line 785
    [5.71222][5.71222:71255]()
    p.introduced_by,
    [5.71222]
    [5.99202]
    &[a],
  • replacement in libpijul/src/apply.rs at line 787
    [5.99216][5.99216:99260](),[5.99260][5.99260:99274](),[5.71272][5.973739:973844](),[5.99274][5.973739:973844](),[5.973739][5.973739:973844](),[5.973844][5.973844:973970](),[5.973970][5.973970:974075](),[5.974075][5.99275:99350](),[5.99350][5.974094:974108](),[5.974094][5.974094:974108](),[5.974108][5.974108:974125](),[5.974125][5.71273:71305]()
    .map_err(LocalApplyError::Txn)?
    {
    // repair up context.
    crate::missing_context::repair_missing_up_context(
    txn,
    channel,
    &mut ws.missing_context,
    inode,
    a,
    &[b],
    p.flag.contains(EdgeFlags::FOLDER),
    )
    .map_err(LocalApplyError::from_missing)?
    }
    } else {
    del_graph_with_rev(
    [5.99216]
    [5.71305]
    .map_err(LocalApplyError::from_missing)?
    } else if !p.flag.is_folder() {
    crate::missing_context::repair_missing_up_context(
  • replacement in libpijul/src/apply.rs at line 792
    [5.71351][5.71351:71395]()
    p.flag - EdgeFlags::PARENT,
    [5.71351]
    [5.71395]
    &mut ws.missing_context,
    change_id,
    inode,
  • replacement in libpijul/src/apply.rs at line 796
    [5.71414][5.71414:71466]()
    b,
    p.introduced_by,
    [5.71414]
    [5.99351]
    &[b],
  • replacement in libpijul/src/apply.rs at line 798
    [5.99365][5.99365:99410]()
    .map_err(LocalApplyError::Txn)?;
    [5.99365]
    [5.974222]
    .map_err(LocalApplyError::from_missing)?
  • replacement in libpijul/src/apply.rs at line 816
    [5.974716][5.974716:974756]()
    Atom::NewVertex(ref n) => {
    [5.974716]
    [5.974756]
    Atom::NewVertex(ref n) if !n.flag.is_folder() => {
  • replacement in libpijul/src/apply.rs at line 822
    [5.974920][5.974920:975038](),[5.975038][5.71483:71579](),[5.71579][5.975132:975133](),[5.975132][5.975132:975133](),[5.975133][5.71580:71633](),[5.71633][5.975185:975617](),[5.975185][5.975185:975617](),[5.975617][5.99601:99692](),[5.99692][5.975644:975797](),[5.975644][5.975644:975797](),[5.975797][5.71634:72020](),[5.72020][5.1712:1776](),[5.1776][5.72118:72153](),[5.72118][5.72118:72153](),[5.72153][5.976346:976780](),[5.976346][5.976346:976780](),[5.976780][5.99693:99792](),[5.99792][5.976811:976945](),[5.976811][5.976811:976945]()
    debug!("repairing missing context for {:?}", vertex);
    for up in n.up_context.iter() {
    let up = find_block_end(txn, 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,
    n.inode,
    up,
    &[vertex],
    n.flag.contains(EdgeFlags::FOLDER),
    )
    .map_err(LocalApplyError::from_missing)?
    }
    }
    if !n.flag.contains(EdgeFlags::FOLDER) {
    for down in n.down_context.iter() {
    let down = find_block(txn, channel, internal_pos(txn, &down, change_id)?)?;
    if iter_adjacent(
    txn,
    channel,
    down,
    EdgeFlags::PARENT,
    EdgeFlags::all() - EdgeFlags::DELETED,
    )
    .find(|e| e.introduced_by != change_id)
    .is_none()
    {
    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)?
    }
    }
    }
    debug!("done repairing contexts for {:?}", vertex);
    [5.974920]
    [5.976945]
    repair_new_vertex_context_up(txn, channel, ws, change_id, n, vertex)?;
    repair_new_vertex_context_down(txn, channel, ws, change_id, n, vertex)?;
  • edit in libpijul/src/apply.rs at line 825
    [5.976959]
    [5.976959]
    Atom::NewVertex(_) => {}
  • replacement in libpijul/src/apply.rs at line 827
    [5.976997][5.976997:977570](),[5.977570][5.99793:99884](),[5.99884][5.977597:977637](),[5.977597][5.977597:977637]()
    for e in n.edges.iter() {
    assert!(!e.flag.contains(EdgeFlags::PARENT));
    if !e.flag.contains(EdgeFlags::DELETED) {
    trace!("repairing context nondeleted {:?}", e);
    repair_context_nondeleted(
    txn,
    channel,
    &mut ws.missing_context,
    n.inode,
    change_id,
    |h| change.knows(&h),
    e,
    )
    .map_err(LocalApplyError::from_missing)?
    }
    }
    [5.976997]
    [5.977637]
    repair_edge_context(txn, channel, ws, change_id, change, n)?;
  • edit in libpijul/src/apply.rs at line 831
    [5.977667][5.977667:977730](),[5.977730][5.7144:7639](),[5.7639][5.99885:99968](),[5.7662][5.978338:978356](),[5.99968][5.978338:978356](),[5.978338][5.978338:978356](),[5.978356][5.978356:978370](),[5.978390][5.978390:978406]()
    for atom in change.changes.iter().flat_map(|r| r.iter()) {
    if let Atom::EdgeMap(ref n) = atom {
    for e in &n.edges {
    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)?
    }
    }
    }
    }
  • replacement in libpijul/src/apply.rs at line 837
    [5.1062][5.978630:978666](),[5.978630][5.978630:978666]()
    fn repair_cyclic_paths<T: MutTxnT>(
    [5.1062]
    [5.978666]
    fn repair_new_vertex_context_up<T: MutTxnT>(
    txn: &mut T,
    channel: &mut Channel<T>,
    ws: &mut Workspace,
    change_id: ChangeId,
    n: &NewVertex<Option<Hash>>,
    vertex: Vertex<ChangeId>,
    ) -> Result<(), LocalApplyError<T::Error>> {
    for up in n.up_context.iter() {
    let up = find_block_end(txn, 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: MutTxnT>(
    txn: &mut T,
    channel: &mut Channel<T>,
    ws: &mut Workspace,
    change_id: ChangeId,
    n: &NewVertex<Option<Hash>>,
    vertex: Vertex<ChangeId>,
    ) -> Result<(), LocalApplyError<T::Error>> {
    debug!("repairing missing context for {:?}", vertex);
    if n.flag.contains(EdgeFlags::FOLDER) {
    return Ok(());
    }
    for down in n.down_context.iter() {
    let down = find_block(txn, channel, internal_pos(txn, &down, change_id)?)?;
    if iter_adjacent(
    txn,
    channel,
    down,
    EdgeFlags::PARENT,
    EdgeFlags::all() - EdgeFlags::DELETED,
    )
    .any(|e| e.introduced_by != change_id)
    {
    continue;
    }
    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)?
    }
    Ok(())
    }
    fn repair_edge_context<T: MutTxnT>(
  • edit in libpijul/src/apply.rs at line 909
    [5.978783]
    [5.100107]
    n: &EdgeMap<Option<Hash>>,
    ) -> Result<(), LocalApplyError<T::Error>> {
    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,
    |h| change.knows(&h),
    e,
    )
    .map_err(LocalApplyError::from_missing)?
    }
    }
    Ok(())
    }
    pub(crate) fn repair_cyclic_paths<T: MutTxnT>(
    txn: &mut T,
    channel: &mut Channel<T>,
    ws: &mut Workspace,
  • replacement in libpijul/src/apply.rs at line 948
    [5.978857][5.978857:978920](),[5.978920][5.1777:2083]()
    for atom in change.changes.iter().flat_map(|r| r.iter()) {
    if let Atom::EdgeMap(ref n) = atom {
    for e in n.edges.iter() {
    assert!(!e.flag.contains(EdgeFlags::PARENT));
    if e.flag.contains(EdgeFlags::FOLDER | EdgeFlags::DELETED) && e.to.len() > 0 {
    repair_edge(txn, channel, e, change_id, ws)?;
    [5.978857]
    [5.979334]
    let mut files = std::mem::replace(&mut ws.missing_context.files, HashSet::new());
    for file in files.drain() {
    if file.is_empty() {
    if !is_rooted(txn, channel, file, ws)? {
    repair_edge(txn, channel, file, ws)?
    }
    } else {
    let f0 = EdgeFlags::FOLDER;
    let f1 = EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO;
    if let Some(ee) = iter_adjacent(txn, channel, file, f0, f1).next() {
    let dest = ee.dest.inode_vertex();
    if !is_rooted(txn, channel, dest, ws)? {
    repair_edge(txn, channel, dest, ws)?
  • edit in libpijul/src/apply.rs at line 965
    [5.979402]
    [5.979402]
    ws.missing_context.files = files;
  • replacement in libpijul/src/apply.rs at line 973
    [5.979562][5.979562:979618]()
    e: &NewEdge<Option<Hash>>,
    change_id: ChangeId,
    [5.979562]
    [5.979618]
    to0: Vertex<ChangeId>,
  • replacement in libpijul/src/apply.rs at line 976
    [5.100198][5.979675:979916](),[5.979675][5.979675:979916]()
    // If we're deleting a name and not a whole file.
    let h = if let Some(h) = e.to.change {
    h
    } else {
    return Ok(());
    };
    let to = Vertex {
    change: if let Some(h) = txn.get_internal(h) {
    h
    [5.100198]
    [5.979916]
    debug!("repair_edge {:?}", to0);
    let mut stack = vec![(to0, true, true, true)];
    ws.parents.clear();
    while let Some((current, _, al, anc_al)) = stack.pop() {
    if !ws.parents.insert(current) {
    continue;
    }
    debug!("repair_cyclic {:?}", current);
    if current != to0 {
    stack.push((current, true, al, anc_al));
    }
    if current.is_root() {
    debug!("root");
    break;
    }
    if let Some(&true) = ws.rooted.get(&current) {
    debug!("rooted");
    break;
    }
    let f = EdgeFlags::PARENT | EdgeFlags::FOLDER;
    let len = stack.len();
    for parent in iter_adjacent(txn, channel, current, f, EdgeFlags::all()) {
    if parent.flag.is_parent() {
    let anc = find_block_end(txn, channel, parent.dest)?;
    debug!("is_rooted, parent = {:?}", parent);
    let al = iter_adjacent(
    txn,
    channel,
    anc,
    f,
    f | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,
    )
    .next()
    .is_some();
    debug!("al = {:?}, flag = {:?}", al, parent.flag);
    stack.push((anc, false, parent.flag.is_deleted(), al));
    }
    }
    if stack.len() == len {
    stack.pop();
  • replacement in libpijul/src/apply.rs at line 1017
    [5.979933][5.100199:100272](),[5.100272][5.979998:980262](),[5.979998][5.979998:980262](),[5.980262][5.72154:72210](),[5.72210][5.980317:980413](),[5.980317][5.980317:980413]()
    return Err((crate::pristine::InconsistentChange {}).into());
    },
    start: e.to.start,
    end: e.to.end,
    };
    // Check that the inode descendant of this name is rooted.
    let mut unrooted = false;
    let f0 = EdgeFlags::FOLDER;
    let f1 = EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO;
    for ee in iter_adjacent(txn, channel, to, f0, f1) {
    if !is_rooted(txn, channel, ee.dest.inode_vertex(), ws)? {
    unrooted = true;
    [5.979933]
    [5.980413]
    (&mut stack[len..]).sort_unstable_by(|a, b| a.3.cmp(&b.3))
  • replacement in libpijul/src/apply.rs at line 1020
    [5.980429][5.980429:980470](),[5.980470][5.72211:72301](),[5.72301][5.980558:980617](),[5.980558][5.980558:980617](),[5.980617][5.72302:72347](),[5.72347][5.980649:980783](),[5.980649][5.980649:980783](),[5.980783][5.100273:100324]()
    // If not, repair.
    if unrooted {
    let from = find_block_end(txn, channel, internal_pos(txn, &e.from, change_id)?)?;
    debug!("repairing unrooted: {:?} {:?}", from, to);
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO,
    from,
    to,
    ChangeId::ROOT,
    )
    .map_err(LocalApplyError::Txn)?;
    [5.980429]
    [5.980795]
    let mut current = to0;
    for (next, on_path, del, _) in stack {
    if on_path {
    if del {
    put_graph_with_rev(
    txn,
    channel,
    EdgeFlags::FOLDER | EdgeFlags::PSEUDO,
    next,
    current,
    ChangeId::ROOT,
    )
    .map_err(LocalApplyError::Txn)?;
    }
    current = next
    }
  • edit in libpijul/src/apply.rs at line 1046
    [5.100372]
    [5.980960]
    let mut alive = false;
    assert!(v.is_empty());
    for e in iter_adjacent(txn, channel, v, EdgeFlags::empty(), EdgeFlags::all()) {
    if e.flag.contains(EdgeFlags::PARENT) {
    if e.flag & (EdgeFlags::FOLDER | EdgeFlags::DELETED) == EdgeFlags::FOLDER {
    alive = true;
    break;
    }
    } else if !e.flag.is_deleted() {
    alive = true;
    break;
    }
    }
    if !alive {
    debug!("is_rooted, not alive");
    return Ok(true);
    }
  • replacement in libpijul/src/apply.rs at line 1102
    [5.982036][5.72521:72590](),[5.72590][5.982104:982135](),[5.982104][5.982104:982135]()
    let parent = find_block_end(txn, channel, parent.dest)?;
    stack.push(parent)
    [5.982036]
    [5.982135]
    stack.push(find_block_end(txn, channel, parent.dest)?)