1use crate::change::{Atom, Change3, NewEdge, NewVertex};
4use crate::changestore::ChangeStore;
5use crate::missing_context::*;
6use crate::pristine::*;
7use crate::record::InodeUpdate;
8use crate::Error;
9use std::collections::{HashMap, HashSet};
10pub fn apply_change_ws<T: MutTxnT, P: ChangeStore>(
16 changes: &P,
17 txn: &mut T,
18 channel: &mut ChannelRef<T>,
19 hash: Hash,
20 workspace: &mut Workspace,
21) -> Result<(u64, Merkle), anyhow::Error> {
22 debug!("apply_change {:?}", hash.to_base32());
23 workspace.clear();
24 let mut channel = channel.r.borrow_mut();
25 let change = changes.get_change(&hash)?;
26
27 for &hash in change.dependencies.iter() {
28 if let Hash::None = hash {
29 continue;
30 }
31 if let Some(int) = txn.get_internal(hash) {
32 if txn.get_changeset(&channel.changes, int, None).is_some() {
33 continue;
34 }
35 }
36 return Err((Error::DependencyMissing { hash }).into());
37 }
38
39 let internal = if let Some(p) = txn.get_internal(hash) {
40 p
41 } else {
42 let internal: ChangeId = txn.make_changeid(&hash);
43 txn.register_change(internal, hash, &change)?;
44 internal
45 };
46 debug!("internal = {:?}", internal);
47 assert!(workspace.is_empty());
48 apply_change_to_channel(txn, &mut channel, internal, &hash, &change, workspace)
49}
50
51pub fn apply_change_rec_ws<T: MutTxnT, P: ChangeStore>(
52 changes: &P,
53 txn: &mut T,
54 channel: &mut ChannelRef<T>,
55 hash: Hash,
56 workspace: &mut Workspace,
57 deps_only: bool,
58) -> Result<(), anyhow::Error> {
59 debug!("apply_change {:?}", hash.to_base32());
60 workspace.clear();
61 let mut channel = channel.r.borrow_mut();
62
63 let mut dep_stack = vec![(hash, true, !deps_only)];
64 while let Some((hash, first, actually_apply)) = dep_stack.pop() {
65 let change = changes.get_change(&hash)?;
66 if first {
67 dep_stack.push((hash, false, actually_apply));
68 for &hash in change.dependencies.iter() {
69 if let Hash::None = hash {
70 continue;
71 }
72 dep_stack.push((hash, true, true))
73 }
74 } else if actually_apply {
75 let applied = if let Some(int) = txn.get_internal(hash) {
76 txn.get_changeset(&channel.changes, int, None).is_some()
77 } else {
78 false
79 };
80 if !applied {
81 let internal = if let Some(p) = txn.get_internal(hash) {
82 p
83 } else {
84 let internal: ChangeId = txn.make_changeid(&hash);
85 txn.register_change(internal, hash, &change)?;
86 internal
87 };
88 debug!("internal = {:?}", internal);
89 assert!(workspace.is_empty());
90 apply_change_to_channel(txn, &mut channel, internal, &hash, &change, workspace)?;
91 }
92 }
93 }
94 Ok(())
95}
96
97pub fn apply_change<T: MutTxnT, P: ChangeStore>(
99 changes: &P,
100 txn: &mut T,
101 channel: &mut ChannelRef<T>,
102 hash: Hash,
103) -> Result<(u64, Merkle), anyhow::Error> {
104 apply_change_ws(changes, txn, channel, hash, &mut Workspace::new())
105}
106
107pub fn apply_change_rec<T: MutTxnT, P: ChangeStore>(
109 changes: &P,
110 txn: &mut T,
111 channel: &mut ChannelRef<T>,
112 hash: Hash,
113 deps_only: bool,
114) -> Result<(), anyhow::Error> {
115 apply_change_rec_ws(
116 changes,
117 txn,
118 channel,
119 hash,
120 &mut Workspace::new(),
121 deps_only,
122 )
123}
124
125fn apply_change_to_channel<T: MutTxnT>(
127 txn: &mut T,
128 channel: &mut Channel<T>,
129 change_id: ChangeId,
130 hash: &Hash,
131 change: &Change3,
132 ws: &mut Workspace,
133) -> Result<(u64, Merkle), anyhow::Error> {
134 let n = channel.apply_counter;
135 let merkle =
136 if let Some(m) = txn.put_changes(channel, change_id, channel.apply_counter, hash)? {
137 m
138 } else {
139 return Err((Error::ChangeAlreadyOnChannel { hash: *hash }).into());
140 };
141 debug!("apply change to channel");
142 let now = std::time::Instant::now();
143 for change_ in change.changes.iter() {
144 debug!("Applying {:?} (1)", change_);
145 for change_ in change_.iter() {
146 match *change_ {
147 Atom::NewVertex(ref n) => put_newvertex(txn, channel, change, ws, change_id, n)?,
148 Atom::EdgeMap(ref n) if !n.flag.contains(EdgeFlags::DELETED) => {
149 for edge in n.edges.iter() {
150 put_newedge(
151 txn,
152 channel,
153 ws,
154 change_id,
155 n.inode,
156 n.previous,
157 n.flag,
158 edge,
159 |_, _, _, _| Ok(true),
160 )?
161 }
162 }
163 _ => {}
164 }
165 }
166 }
167 for change_ in change.changes.iter() {
168 debug!("Applying {:?} (2)", change_);
169 for change_ in change_.iter() {
170 match *change_ {
171 Atom::EdgeMap(ref n) if n.flag.contains(EdgeFlags::DELETED) => {
172 for edge in n.edges.iter() {
173 put_newedge(
174 txn,
175 channel,
176 ws,
177 change_id,
178 n.inode,
179 n.previous,
180 n.flag,
181 edge,
182 |_, _, _, _| Ok(true),
183 )?;
184 crate::missing_context::collect_zombie_context(
186 txn,
187 channel,
188 &mut ws.missing_context,
189 n.inode,
190 edge,
191 n.flag,
192 change_id,
193 |h| change.knows(&h),
194 )?
195 }
197 }
198 _ => {}
199 }
200 }
201 }
202 crate::TIMERS.lock().unwrap().apply += now.elapsed();
203
204 clean_obsolete_pseudo_edges(txn, channel, ws)?;
205
206 info!("repairing missing contexts");
207 repair_missing_contexts(txn, channel, ws, change_id, change)?;
208 repair_cyclic_paths(txn, channel, ws, change_id, change)?;
209 info!("done applying change");
210 channel.last_modified = std::time::SystemTime::now()
211 .duration_since(std::time::SystemTime::UNIX_EPOCH)?
212 .as_secs();
213 Ok((n, merkle))
214}
215pub fn apply_local_change_ws<T: MutTxnT>(
222 txn: &mut T,
223 channel: &mut ChannelRef<T>,
224 change: &Change3,
225 hash: Hash,
226 inode_updates: &HashMap<usize, InodeUpdate>,
227 workspace: &mut Workspace,
228) -> Result<(u64, Merkle), anyhow::Error> {
229 let mut channel = channel.r.borrow_mut();
231 let internal: ChangeId = txn.make_changeid(&hash);
232 txn.register_change(internal, hash, &change)?;
233 let n = apply_change_to_channel(txn, &mut channel, internal, &hash, &change, workspace)?;
235 for (_, update) in inode_updates.iter() {
237 info!("updating {:?}", update);
238 update_inode(txn, &channel, internal, update)?;
239 }
240 Ok(n)
241}
242
243pub fn apply_local_change<T: MutTxnT>(
245 txn: &mut T,
246 channel: &mut ChannelRef<T>,
247 change: &Change3,
248 hash: Hash,
249 inode_updates: &HashMap<usize, InodeUpdate>,
250) -> Result<(u64, Merkle), anyhow::Error> {
251 apply_local_change_ws(
252 txn,
253 channel,
254 change,
255 hash,
256 inode_updates,
257 &mut Workspace::new(),
258 )
259}
260fn update_inode<T: MutTxnT>(
262 txn: &mut T,
263 channel: &Channel<T>,
264 internal: ChangeId,
265 update: &InodeUpdate,
266) -> Result<(), anyhow::Error> {
267 debug!("update_inode {:?}", update);
268 match *update {
269 InodeUpdate::Add { inode, pos, .. } => {
271 let vertex = Position {
272 change: internal,
273 pos,
274 };
275 if txn
276 .get_graph(&channel.graph, vertex.inode_vertex(), None)
277 .is_some()
278 {
279 debug!("Adding inodes: {:?} {:?}", inode, vertex);
280 txn.put_inodes_with_rev(inode, vertex)?;
281 } else {
282 debug!("Not adding inodes: {:?} {:?}", inode, vertex);
283 }
284 }
285 InodeUpdate::Deleted { inode } => {
287 if let Some(parent) = txn.get_revtree(inode, None).map(|x| x.to_owned()) {
288 txn.del_revtree(inode, Some(parent.as_file_id()))?;
289 txn.del_tree(parent.as_file_id(), Some(inode))?;
290 }
291 txn.del_tree(
292 (OwnedPathId {
293 parent_inode: inode,
294 basename: crate::small_string::SmallString::new(),
295 })
296 .as_file_id(),
297 Some(inode),
298 )?;
299 if let Some(vertex) = txn.get_inodes(inode, None) {
300 txn.del_inodes(inode, Some(vertex))?;
301 txn.del_revinodes(vertex, Some(inode))?;
302 }
303 }
304 }
305 Ok(())
306}
307fn put_newvertex<T: MutTxnT>(
309 txn: &mut T,
310 channel: &mut Channel<T>,
311 ch: &Change3,
312 ws: &mut Workspace,
313 change: ChangeId,
314 n: &NewVertex<Option<Hash>>,
315) -> Result<(), anyhow::Error> {
316 let vertex = Vertex {
317 change,
318 start: n.start,
319 end: n.end,
320 };
321 debug!(
322 "put_newvertex {:?} {:?} {:?} {:?} {:?}",
323 vertex, n.up_context, n.down_context, n.flag, change
324 );
325 assert!(ws.deleted_by.is_empty());
326 for up in n.up_context.iter() {
327 let up = txn.internal_pos(up, change)?;
328 put_up_context(txn, channel, ch, n.inode, ws, up)?;
329 }
330 for down in n.down_context.iter() {
331 let down = txn.internal_pos(down, change)?;
332 put_down_context(txn, channel, ch, n.inode, ws, down)?;
333 }
334 debug!("deleted by: {:?}", ws.deleted_by);
335
336 for up in ws.up_context.drain(..) {
337 assert_ne!(up, vertex);
338 if !n.flag.contains(EdgeFlags::FOLDER) {
339 for (change, _) in ws.deleted_by.iter() {
340 let flag = n.flag | EdgeFlags::DELETED | EdgeFlags::BLOCK;
341 txn.put_graph_with_rev(channel, flag, up, vertex, *change)?;
342 }
343 }
344 txn.put_graph_with_rev(channel, n.flag | EdgeFlags::BLOCK, up, vertex, change)?;
345 }
346 debug!("down_context {:?}", ws.down_context);
347 for (down, alive_parent) in ws.down_context.drain(..) {
348 assert_ne!(down, vertex);
349 if !alive_parent && !n.flag.contains(EdgeFlags::FOLDER) {
350 for (change, _) in ws.deleted_by.iter() {
351 let flag = n.flag | EdgeFlags::DELETED | EdgeFlags::BLOCK;
352 txn.put_graph_with_rev(channel, flag, vertex, down, *change)?;
353 }
354 } else {
355 txn.put_graph_with_rev(channel, n.flag, vertex, down, change)?;
356 }
357 }
358 ws.deleted_by.clear();
359 Ok(())
360}
361fn put_up_context<T: MutTxnT>(
363 txn: &mut T,
364 channel: &mut Channel<T>,
365 ch: &Change3,
366 inode: Position<Option<Hash>>,
367 ws: &mut Workspace,
368 up: Position<ChangeId>,
369) -> Result<(), anyhow::Error> {
370 let up_vertex = if up.change.is_root() {
371 Vertex::ROOT
372 } else {
373 debug!("put_up_context {:?}", up);
374 let k = txn.find_block_end(channel, up)?;
375 assert_eq!(k.change, up.change);
376 assert!(k.start <= up.pos);
377 debug!("k = {:?}", k);
378 if k.start < up.pos && k.end > up.pos {
379 if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
380 if let Some(vid) = vids.remove(&k) {
381 vids.insert(Vertex { end: up.pos, ..k }, vid);
382 vids.insert(Vertex { start: up.pos, ..k }, vid);
383 }
384 }
385 txn.split_block(channel, k, up.pos)?
386 }
387 Vertex {
388 change: k.change,
389 start: k.start,
390 end: up.pos,
391 }
392 };
393 debug!("up_vertex {:?}", up_vertex);
394 let flag0 = EdgeFlags::PARENT | EdgeFlags::DELETED;
395 let flag1 = flag0 | EdgeFlags::FOLDER | EdgeFlags::BLOCK;
396 for parent in txn.iter_adjacent(&channel, up_vertex, flag0, flag1) {
397 let introduced_by = txn.get_external(parent.introduced_by).unwrap();
399 if !ch.knows(&introduced_by) {
400 ws.deleted_by
401 .insert((parent.introduced_by, parent.flag - EdgeFlags::PARENT));
402 }
403 }
404 ws.up_context.push(up_vertex);
405 Ok(())
406}
407fn put_down_context<T: MutTxnT>(
409 txn: &mut T,
410 channel: &mut Channel<T>,
411 ch: &Change3,
412 inode: Position<Option<Hash>>,
413 ws: &mut Workspace,
414 down: Position<ChangeId>,
415) -> Result<Vertex<ChangeId>, anyhow::Error> {
416 let k = txn.find_block(&channel, down)?;
417 assert_eq!(k.change, down.change);
418 assert!(k.end >= down.pos);
419 if k.start < down.pos && k.end > down.pos {
420 if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
421 if let Some(vid) = vids.remove(&k) {
422 vids.insert(Vertex { end: down.pos, ..k }, vid);
423 vids.insert(
424 Vertex {
425 start: down.pos,
426 ..k
427 },
428 vid,
429 );
430 }
431 }
432 txn.split_block(channel, k, down.pos)?
433 }
434 let down_vertex = Vertex {
435 change: k.change,
436 start: down.pos,
437 end: k.end,
438 };
439 debug!("down_vertex {:?}", down_vertex);
440 let flag0 = EdgeFlags::PARENT;
441 let flag1 = flag0 | EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::DELETED;
442 let mut alive_parent = false;
443 for parent in txn.iter_adjacent(&channel, down_vertex, flag0, flag1) {
444 if parent.flag.contains(EdgeFlags::PARENT) {
445 if parent.flag.contains(EdgeFlags::DELETED) {
446 let introduced_by = txn.get_external(parent.introduced_by).unwrap();
448 if !ch.knows(&introduced_by) {
449 ws.deleted_by
450 .insert((parent.introduced_by, parent.flag - EdgeFlags::PARENT));
451 }
452 } else {
453 alive_parent = true
454 }
455 }
456 }
457 ws.down_context.push((down_vertex, alive_parent));
458 Ok(down_vertex)
459}
460pub struct Workspace {
462 parents: HashSet<Vertex<ChangeId>>,
463 children: HashSet<Vertex<ChangeId>>,
464 pseudo: Vec<(Vertex<ChangeId>, Edge, Position<Option<Hash>>)>,
465 deleted_by: HashSet<(ChangeId, EdgeFlags)>,
466 up_context: Vec<Vertex<ChangeId>>,
467 down_context: Vec<(Vertex<ChangeId>, bool)>,
468 pub(crate) missing_context: crate::missing_context::Workspace,
469 rooted: HashMap<Vertex<ChangeId>, bool>,
470}
471
472impl Workspace {
473 pub fn new() -> Self {
474 Workspace {
475 children: HashSet::new(),
476 parents: HashSet::new(),
477 pseudo: Vec::new(),
478 deleted_by: HashSet::new(),
479 up_context: Vec::new(),
480 down_context: Vec::new(),
481 missing_context: crate::missing_context::Workspace::new(),
482 rooted: HashMap::new(),
483 }
484 }
485 fn clear(&mut self) {
486 self.children.clear();
487 self.parents.clear();
488 self.pseudo.clear();
489 self.deleted_by.clear();
490 self.up_context.clear();
491 self.down_context.clear();
492 self.missing_context.clear();
493 self.rooted.clear();
494 }
495 fn is_empty(&self) -> bool {
496 self.children.is_empty()
497 && self.parents.is_empty()
498 && self.pseudo.is_empty()
499 && self.deleted_by.is_empty()
500 && self.up_context.is_empty()
501 && self.down_context.is_empty()
502 && self.missing_context.is_empty()
503 && self.rooted.is_empty()
504 }
505}
506pub(crate) fn put_newedge<T, F>(
508 txn: &mut T,
509 channel: &mut Channel<T>,
510 ws: &mut Workspace,
511 change: ChangeId,
512 inode: Position<Option<Hash>>,
513 previous: EdgeFlags,
514 flag: EdgeFlags,
515 n: &NewEdge<Option<Hash>>,
516 apply_check: F,
517) -> Result<(), anyhow::Error>
518where
519 T: MutTxnT,
520 F: Fn(
521 &mut T,
522 &mut Channel<T>,
523 Vertex<ChangeId>,
524 Vertex<ChangeId>,
525 ) -> Result<bool, anyhow::Error>,
526{
527 if flag.contains(EdgeFlags::DELETED) {
528 ws.missing_context.load_graph(txn, channel, inode)?;
529 }
530
531 let flag = flag | EdgeFlags::BLOCK;
532 assert!(ws.children.is_empty());
533 assert!(ws.parents.is_empty());
534 debug!(
535 "put_newedge {:?} -> {:?}, {:?} {:?}",
536 previous, flag, n, change
537 );
538 let n_introduced_by = if let Some(n) = txn.internal(&n.introduced_by, change) {
539 n
540 } else {
541 return Err(crate::Error::InconsistentChange.into());
542 };
543 let mut source = find_source_vertex(txn, channel, &n.from, change, inode, flag, ws)?;
545 let mut target = find_target_vertex(txn, channel, &n.to, change, inode, flag, ws)?;
546 loop {
548 if target.end > n.to.end {
549 assert!(!flag.contains(EdgeFlags::FOLDER));
550 if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
551 if let Some(vid) = vids.remove(&target) {
552 vids.insert(
553 Vertex {
554 end: n.to.end,
555 ..target
556 },
557 vid,
558 );
559 vids.insert(
560 Vertex {
561 start: n.to.end,
562 ..target
563 },
564 vid,
565 );
566 }
567 }
568 txn.split_block(channel, target, n.to.end)?;
569 target.end = n.to.end
570 }
571 if flag.contains(EdgeFlags::DELETED) {
573 collect_pseudo_edges(txn, channel, ws, inode, target)?;
574 if !flag.contains(EdgeFlags::FOLDER) {
575 reconnect_pseudo_edges(txn, channel, inode, ws, target)?;
576 }
577 ws.children.clear();
578 }
579 debug!("deleting {:?} {:?}", previous, flag);
581 if !txn.del_graph_with_rev(channel, previous, source, target, n_introduced_by)? {
582 let del = txn.del_graph_with_rev(
583 channel,
584 previous | EdgeFlags::BLOCK,
585 source,
586 target,
587 n_introduced_by,
588 )?;
589 debug!("deleted: {:?}", del);
590 }
591 debug!("put_graph {:?} {:?}", source, target);
592 assert_ne!(source, target);
593 if apply_check(txn, channel, source, target)? {
594 txn.put_graph_with_rev(channel, flag, source, target, change)?;
595 }
596 if target.end >= n.to.end {
598 assert_eq!(target.end, n.to.end);
599 break;
600 }
601
602 source = target;
603 target = txn.find_block(channel, target.end_pos())?;
604 assert_ne!(source, target);
605 }
606 Ok(())
607}
608fn find_source_vertex<T: MutTxnT>(
610 txn: &mut T,
611 channel: &mut Channel<T>,
612 from: &Position<Option<Hash>>,
613 change: ChangeId,
614 inode: Position<Option<Hash>>,
615 flag: EdgeFlags,
616 ws: &mut Workspace,
617) -> Result<Vertex<ChangeId>, anyhow::Error> {
618 let mut source = txn.find_block_end(&channel, txn.internal_pos(&from, change)?)?;
619 if source.start < from.pos && source.end > from.pos {
620 assert!(!flag.contains(EdgeFlags::FOLDER));
621 if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
622 if let Some(vid) = vids.remove(&source) {
623 vids.insert(
624 Vertex {
625 end: from.pos,
626 ..source
627 },
628 vid,
629 );
630 vids.insert(
631 Vertex {
632 start: from.pos,
633 ..source
634 },
635 vid,
636 );
637 }
638 }
639 txn.split_block(channel, source, from.pos)?;
640 source.end = from.pos;
641 }
642 Ok(source)
643}
644
645fn find_target_vertex<T: MutTxnT>(
646 txn: &mut T,
647 channel: &mut Channel<T>,
648 to: &Vertex<Option<Hash>>,
649 change: ChangeId,
650 inode: Position<Option<Hash>>,
651 flag: EdgeFlags,
652 ws: &mut Workspace,
653) -> Result<Vertex<ChangeId>, anyhow::Error> {
654 let to_pos = txn.internal_pos(&to.start_pos(), change)?;
655 let mut target = txn.find_block(channel, to_pos)?;
656 if target.start < to.start {
657 assert!(!flag.contains(EdgeFlags::FOLDER));
658 if let Some((_, vids)) = ws.missing_context.graphs.get_mut(&inode) {
659 if let Some(vid) = vids.remove(&target) {
660 vids.insert(
661 Vertex {
662 end: to.start,
663 ..target
664 },
665 vid,
666 );
667 vids.insert(
668 Vertex {
669 start: to.start,
670 ..target
671 },
672 vid,
673 );
674 }
675 }
676 txn.split_block(channel, target, to.start)?;
677 target.start = to.start;
678 }
679 Ok(target)
680}
681fn collect_pseudo_edges<T: MutTxnT>(
683 txn: &mut T,
684 channel: &mut Channel<T>,
685 apply: &mut Workspace,
686 inode: Position<Option<Hash>>,
687 v: Vertex<ChangeId>,
688) -> Result<(), anyhow::Error> {
689 for e in txn.iter_adjacent(
690 &channel,
691 v,
692 EdgeFlags::empty(),
693 EdgeFlags::all() - EdgeFlags::DELETED,
694 ) {
695 debug!("collect_pseudo_edges {:?} {:?}", v, e);
696 if !e.flag.contains(EdgeFlags::FOLDER) {
697 if e.flag.contains(EdgeFlags::PARENT) {
698 let p = txn.find_block_end(channel, e.dest)?;
699 if txn.is_alive(channel, p) {
700 apply.parents.insert(p);
701 }
702 } else {
703 let p = txn.find_block(channel, e.dest)?;
704 apply.children.insert(p);
705 }
706 }
707 if e.flag.contains(EdgeFlags::PSEUDO) {
708 apply.pseudo.push((v, e, inode));
709 }
710 }
711 Ok(())
712}
713fn reconnect_pseudo_edges<T: MutTxnT>(
715 txn: &mut T,
716 channel: &mut Channel<T>,
717 inode: Position<Option<Hash>>,
718 ws: &mut Workspace,
719 target: Vertex<ChangeId>,
720) -> Result<(), anyhow::Error> {
721 debug!(
722 "reconnect: parents.len() = {:?} to children.len() = {:?}",
723 ws.parents.len(),
724 ws.children.len()
725 );
726 debug!(
727 "reconnect: parents = {:#?} to children = {:#?}",
728 ws.parents, ws.children
729 );
730 if ws.parents.is_empty() {
731 ws.children.clear();
732 return Ok(());
733 }
734 if ws.children.is_empty() {
735 ws.parents.clear();
736 return Ok(());
737 }
738
739 let (graph, vids) = if let Some(n) = ws.missing_context.graphs.get(&inode) {
740 n
741 } else {
742 return Err(crate::Error::InconsistentChange.into());
743 };
744 crate::alive::remove_redundant_parents(
745 &graph,
746 &vids,
747 &mut ws.parents,
748 &mut ws.missing_context.covered_parents,
749 target,
750 );
751 for &p in ws.parents.iter() {
752 ws.missing_context.covered_parents.insert((p, target));
753 }
754
755 crate::alive::remove_redundant_children(&graph, &vids, &mut ws.children, target);
756 debug!(
757 "reconnect (nonredundant) {:?} to {:?}",
758 ws.parents, ws.children
759 );
760
761 for p in ws.parents.drain() {
762 for c in ws.children.iter() {
763 if p != *c && txn.is_alive(channel, p) && txn.is_alive(channel, *c) {
764 txn.put_graph_with_rev(channel, EdgeFlags::PSEUDO, p, *c, ChangeId::ROOT)?;
765 }
766 }
767 }
768 Ok(())
769}
770pub(crate) fn clean_obsolete_pseudo_edges<T: MutTxnT>(
772 txn: &mut T,
773 channel: &mut Channel<T>,
774 ws: &mut Workspace,
775) -> Result<(), anyhow::Error> {
776 debug!("pseudo = {:#?}", ws.pseudo);
777 for (next_vertex, p, inode) in ws.pseudo.drain(..) {
778 debug!("{:?} {:?}", next_vertex, p);
780 let (a, b) = if p.flag.contains(EdgeFlags::PARENT) {
781 if let Ok(dest) = txn.find_block_end(channel, p.dest) {
782 (dest, next_vertex)
783 } else {
784 continue;
785 }
786 } else {
787 if let Ok(dest) = txn.find_block(channel, p.dest) {
788 (next_vertex, dest)
789 } else {
790 continue;
791 }
792 };
793
794 let a_is_alive = a.is_root()
795 || txn
796 .iter_adjacent(
797 channel,
798 a,
799 EdgeFlags::PARENT,
800 EdgeFlags::all() - EdgeFlags::DELETED,
801 )
802 .filter(|e| !e.flag.contains(EdgeFlags::PSEUDO))
803 .next()
804 .is_some();
805
806 let b_is_alive = b.is_root()
807 || txn
808 .iter_adjacent(
809 channel,
810 b,
811 EdgeFlags::PARENT,
812 EdgeFlags::all() - EdgeFlags::DELETED,
813 )
814 .filter(|e| !e.flag.contains(EdgeFlags::PSEUDO))
815 .next()
816 .is_some();
817
818 debug!("{:?} {:?}", a_is_alive, b_is_alive);
819 if a_is_alive {
820 if !b_is_alive {
821 debug!("deleting {:?} -> {:?}", a, b);
822 if txn.del_graph_with_rev(
823 channel,
824 p.flag - EdgeFlags::PARENT,
825 a,
826 b,
827 p.introduced_by,
828 )? {
829 crate::missing_context::repair_missing_down_context(
831 txn,
832 channel,
833 &mut ws.missing_context,
834 inode,
835 b,
836 &[a],
837 )?
838 }
839 }
840 } else if b_is_alive {
841 debug!("deleting {:?} -> {:?}", a, b);
842 if txn.del_graph_with_rev(channel, p.flag - EdgeFlags::PARENT, a, b, p.introduced_by)? {
843 crate::missing_context::repair_missing_up_context(
845 txn,
846 channel,
847 &mut ws.missing_context,
848 inode,
849 a,
850 &[b],
851 p.flag.contains(EdgeFlags::FOLDER),
852 )?
853 }
854 } else {
855 txn.del_graph_with_rev(channel, p.flag - EdgeFlags::PARENT, a, b, p.introduced_by)?;
856 }
857 }
858 Ok(())
859}
860fn repair_missing_contexts<T: MutTxnT>(
862 txn: &mut T,
863 channel: &mut Channel<T>,
864 ws: &mut Workspace,
865 change_id: ChangeId,
866 change: &Change3,
867) -> Result<(), anyhow::Error> {
868 let now = std::time::Instant::now();
869 crate::missing_context::repair_parents_of_deleted(txn, channel, &mut ws.missing_context)?;
870 for atom in change.changes.iter().flat_map(|r| r.iter()) {
871 match atom {
872 Atom::NewVertex(ref n) => {
873 let vertex = Vertex {
874 change: change_id,
875 start: n.start,
876 end: n.end,
877 };
878 debug!("repairing missing context for {:?}", vertex);
879 for up in n.up_context.iter() {
880 let up = txn.find_block_end(channel, txn.internal_pos(&up, change_id)?)?;
881
882 if !txn.is_alive(channel, up) {
883 debug!("repairing missing up context {:?} {:?}", up, vertex);
884 repair_missing_up_context(
885 txn,
886 channel,
887 &mut ws.missing_context,
888 n.inode,
889 up,
890 &[vertex],
891 n.flag.contains(EdgeFlags::FOLDER),
892 )?
893 }
894 }
895 if !n.flag.contains(EdgeFlags::FOLDER) {
896 for down in n.down_context.iter() {
897 let down = txn.find_block(channel, txn.internal_pos(&down, change_id)?)?;
898 if txn
899 .iter_adjacent(
900 channel,
901 down,
902 EdgeFlags::PARENT,
903 EdgeFlags::all() - EdgeFlags::DELETED,
904 )
905 .filter(|e| e.introduced_by != change_id)
906 .next()
907 .is_none()
908 {
909 debug!("repairing missing down context {:?} {:?}", down, vertex);
910 repair_missing_down_context(
911 txn,
912 channel,
913 &mut ws.missing_context,
914 n.inode,
915 down,
916 &[vertex],
917 )?
918 }
919 }
920 }
921 debug!("done repairing contexts for {:?}", vertex);
922 }
923 Atom::EdgeMap(ref n) if !n.flag.contains(EdgeFlags::DELETED) => {
924 assert!(!n.flag.contains(EdgeFlags::PARENT));
925 for e in n.edges.iter() {
926 trace!("repairing context nondeleted {:?}", e);
927 repair_context_nondeleted(
928 txn,
929 channel,
930 &mut ws.missing_context,
931 n.inode,
932 change_id,
933 |h| change.knows(&h),
934 e,
935 )?
936 }
937 }
938 _ => {}
939 }
940 }
941 for atom in change.changes.iter().flat_map(|r| r.iter()) {
942 match atom {
943 Atom::EdgeMap(ref n) if n.flag.contains(EdgeFlags::DELETED) => {
944 for e in n.edges.iter() {
945 trace!("repairing context deleted {:?}", e);
946 repair_context_deleted(
947 txn,
948 channel,
949 &mut ws.missing_context,
950 n.inode,
951 change_id,
952 |h| change.knows(&h),
953 e,
954 )?
955 }
956 }
957 _ => {}
958 }
959 }
960 crate::missing_context::delete_pseudo_edges(txn, channel, &mut ws.missing_context)?;
961 crate::TIMERS.lock().unwrap().repair_context += now.elapsed();
962 Ok(())
963}
964fn repair_cyclic_paths<T: MutTxnT>(
966 txn: &mut T,
967 channel: &mut Channel<T>,
968 ws: &mut Workspace,
969 change_id: ChangeId,
970 change: &Change3,
971) -> Result<(), anyhow::Error> {
972 let now = std::time::Instant::now();
973 for atom in change.changes.iter().flat_map(|r| r.iter()) {
974 match atom {
975 Atom::EdgeMap(ref n) if n.flag.contains(EdgeFlags::FOLDER | EdgeFlags::DELETED) => {
976 assert!(!n.flag.contains(EdgeFlags::PARENT));
977 for e in n.edges.iter() {
978 if e.to.len() > 0 {
979 repair_edge(txn, channel, e, change_id, ws)?;
980 }
981 }
982 }
983 _ => {}
984 }
985 }
986 crate::TIMERS.lock().unwrap().check_cyclic_paths += now.elapsed();
987 Ok(())
988}
989
990fn repair_edge<T: MutTxnT>(
991 txn: &mut T,
992 channel: &mut Channel<T>,
993 e: &NewEdge<Option<Hash>>,
994 change_id: ChangeId,
995 ws: &mut Workspace,
996) -> Result<(), anyhow::Error> {
997 let h = if let Some(h) = e.to.change {
999 h
1000 } else {
1001 return Ok(());
1002 };
1003 let to = Vertex {
1004 change: if let Some(h) = txn.get_internal(h) {
1005 h
1006 } else {
1007 return Err(crate::Error::InconsistentChange.into());
1008 },
1009 start: e.to.start,
1010 end: e.to.end,
1011 };
1012 let mut unrooted = false;
1014 let f0 = EdgeFlags::FOLDER;
1015 let f1 = EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO;
1016 for ee in txn.iter_adjacent(channel, to, f0, f1) {
1017 if !is_rooted(txn, channel, ee.dest.inode_vertex(), ws)? {
1018 unrooted = true;
1019 }
1020 }
1021 if unrooted {
1023 let from = txn.find_block_end(channel, txn.internal_pos(&e.from, change_id)?)?;
1024 debug!("repairing unrooted: {:?} {:?}", from, to);
1025 txn.put_graph_with_rev(
1026 channel,
1027 EdgeFlags::FOLDER | EdgeFlags::PSEUDO,
1028 from,
1029 to,
1030 ChangeId::ROOT,
1031 )?;
1032 }
1033 Ok(())
1034}
1035
1036fn is_rooted<T: TxnT>(
1037 txn: &T,
1038 channel: &Channel<T>,
1039 v: Vertex<ChangeId>,
1040 ws: &mut Workspace,
1041) -> Result<bool, crate::Error> {
1042 let ref mut stack = ws.up_context;
1045 stack.clear();
1046 stack.push(v);
1047 let ref mut visited = ws.parents;
1048 visited.clear();
1049
1050 while let Some(to) = stack.pop() {
1051 debug!("is_rooted, pop = {:?}", to);
1052 if to.is_root() {
1053 stack.clear();
1054 for v in visited.drain() {
1055 ws.rooted.insert(v, true);
1056 }
1057 return Ok(true);
1058 }
1059 if !visited.insert(to) {
1060 continue;
1061 }
1062 if let Some(&rooted) = ws.rooted.get(&to) {
1063 if rooted {
1064 for v in visited.drain() {
1065 ws.rooted.insert(v, true);
1066 }
1067 return Ok(true);
1068 } else {
1069 continue;
1070 }
1071 }
1072 let f = EdgeFlags::PARENT | EdgeFlags::FOLDER;
1073 for parent in txn.iter_adjacent(channel, to, f, f | EdgeFlags::PSEUDO | EdgeFlags::BLOCK) {
1074 debug!("is_rooted, parent = {:?}", parent);
1075 let parent = txn.find_block_end(channel, parent.dest)?;
1076 stack.push(parent)
1077 }
1078 }
1079 for v in visited.drain() {
1080 ws.rooted.insert(v, false);
1081 }
1082 Ok(false)
1083}