1use crate::change::{Atom, Change, EdgeMap, NewVertex};
3use crate::changestore::ChangeStore;
4use crate::missing_context::*;
5use crate::pristine::*;
6use crate::record::InodeUpdate;
7use crate::{HashMap, HashSet};
8use std::collections::BTreeSet;
9use thiserror::Error;
10pub mod edge;
11pub(crate) use edge::*;
12pub mod vertex;
13pub(crate) use vertex::*;
14
15pub enum ApplyError<ChangestoreError: std::error::Error, T: GraphTxnT + TreeTxnT> {
16 Changestore(ChangestoreError),
17 LocalChange(LocalApplyError<T>),
18 MakeChange(crate::change::MakeChangeError<T>),
19}
20
21impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> std::fmt::Debug for ApplyError<C, T> {
22 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
23 match self {
24 ApplyError::Changestore(e) => std::fmt::Debug::fmt(e, fmt),
25 ApplyError::LocalChange(e) => std::fmt::Debug::fmt(e, fmt),
26 ApplyError::MakeChange(e) => std::fmt::Debug::fmt(e, fmt),
27 }
28 }
29}
30
31impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> std::fmt::Display for ApplyError<C, T> {
32 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
33 match self {
34 ApplyError::Changestore(e) => std::fmt::Display::fmt(e, fmt),
35 ApplyError::LocalChange(e) => std::fmt::Display::fmt(e, fmt),
36 ApplyError::MakeChange(e) => std::fmt::Display::fmt(e, fmt),
37 }
38 }
39}
40
41impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> std::error::Error for ApplyError<C, T> {}
42
43#[derive(Error)]
44pub enum LocalApplyError<T: GraphTxnT + TreeTxnT> {
45 DependencyMissing { hash: crate::pristine::Hash },
46 ChangeAlreadyOnChannel { hash: crate::pristine::Hash },
47 Txn(#[from] TxnErr<T::GraphError>),
48 Tree(#[from] TreeErr<T::TreeError>),
49 Block { block: Position<ChangeId> },
50 InvalidChange,
51 Corruption,
52 MakeChange(#[from] crate::change::MakeChangeError<T>),
53}
54
55impl<T: GraphTxnT + TreeTxnT> std::fmt::Debug for LocalApplyError<T> {
56 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
57 match self {
58 LocalApplyError::DependencyMissing { hash } => {
59 write!(fmt, "Dependency missing: {:?}", hash)
60 }
61 LocalApplyError::ChangeAlreadyOnChannel { hash } => {
62 write!(fmt, "Change already on channel: {:?}", hash)
63 }
64 LocalApplyError::Txn(e) => std::fmt::Debug::fmt(e, fmt),
65 LocalApplyError::Tree(e) => std::fmt::Debug::fmt(e, fmt),
66 LocalApplyError::Block { block } => write!(fmt, "Block error: {:?}", block),
67 LocalApplyError::InvalidChange => write!(fmt, "Invalid change"),
68 LocalApplyError::Corruption => write!(fmt, "Corruption"),
69 LocalApplyError::MakeChange(e) => std::fmt::Debug::fmt(e, fmt),
70 }
71 }
72}
73
74impl<T: GraphTxnT + TreeTxnT> std::fmt::Display for LocalApplyError<T> {
75 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
76 match self {
77 LocalApplyError::DependencyMissing { hash } => {
78 write!(fmt, "Dependency missing: {:?}", hash)
79 }
80 LocalApplyError::ChangeAlreadyOnChannel { hash } => {
81 write!(fmt, "Change already on channel: {:?}", hash)
82 }
83 LocalApplyError::Txn(e) => std::fmt::Display::fmt(e, fmt),
84 LocalApplyError::Tree(e) => std::fmt::Display::fmt(e, fmt),
85 LocalApplyError::Block { block } => write!(fmt, "Block error: {:?}", block),
86 LocalApplyError::InvalidChange => write!(fmt, "Invalid change"),
87 LocalApplyError::Corruption => write!(fmt, "Corruption"),
88 LocalApplyError::MakeChange(e) => std::fmt::Display::fmt(e, fmt),
89 }
90 }
91}
92
93impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> From<crate::pristine::TxnErr<T::GraphError>>
94 for ApplyError<C, T>
95{
96 fn from(err: crate::pristine::TxnErr<T::GraphError>) -> Self {
97 ApplyError::LocalChange(LocalApplyError::Txn(err))
98 }
99}
100
101impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> From<crate::change::MakeChangeError<T>>
102 for ApplyError<C, T>
103{
104 fn from(err: crate::change::MakeChangeError<T>) -> Self {
105 ApplyError::MakeChange(err)
106 }
107}
108
109impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> From<crate::pristine::TreeErr<T::TreeError>>
110 for ApplyError<C, T>
111{
112 fn from(err: crate::pristine::TreeErr<T::TreeError>) -> Self {
113 ApplyError::LocalChange(LocalApplyError::Tree(err))
114 }
115}
116
117impl<T: GraphTxnT + TreeTxnT> LocalApplyError<T> {
118 fn from_missing(err: MissingError<T::GraphError>) -> Self {
119 match err {
120 MissingError::Txn(e) => LocalApplyError::Txn(TxnErr(e)),
121 MissingError::Block(e) => e.into(),
122 MissingError::Inconsistent(_) => LocalApplyError::InvalidChange,
123 }
124 }
125}
126
127impl<T: GraphTxnT + TreeTxnT> From<crate::pristine::InconsistentChange<T::GraphError>>
128 for LocalApplyError<T>
129{
130 fn from(err: crate::pristine::InconsistentChange<T::GraphError>) -> Self {
131 match err {
132 InconsistentChange::Txn(e) => LocalApplyError::Txn(TxnErr(e)),
133 _ => LocalApplyError::InvalidChange,
134 }
135 }
136}
137
138impl<T: GraphTxnT + TreeTxnT> From<crate::pristine::BlockError<T::GraphError>>
139 for LocalApplyError<T>
140{
141 fn from(err: crate::pristine::BlockError<T::GraphError>) -> Self {
142 match err {
143 BlockError::Txn(e) => LocalApplyError::Txn(TxnErr(e)),
144 BlockError::Block { block } => LocalApplyError::Block { block },
145 }
146 }
147}
148
149impl<C: std::error::Error, T: GraphTxnT + TreeTxnT> From<crate::pristine::BlockError<T::GraphError>>
150 for ApplyError<C, T>
151{
152 fn from(err: crate::pristine::BlockError<T::GraphError>) -> Self {
153 ApplyError::LocalChange(LocalApplyError::from(err))
154 }
155}
156
157pub fn apply_change_ws<T: MutTxnT, P: ChangeStore>(
162 changes: &P,
163 txn: &mut T,
164 channel: &mut T::Channel,
165 hash: &Hash,
166 workspace: &mut Workspace,
167) -> Result<(u64, Merkle), ApplyError<P::Error, T>> {
168 debug!("apply_change {:?}", hash.to_base32());
169 workspace.clear();
170 let change = changes.get_change(hash).map_err(ApplyError::Changestore)?;
171
172 for hash in change.dependencies.iter() {
173 if let Hash::None = hash {
174 continue;
175 }
176 if let Some(int) = txn.get_internal(&hash.into())?
177 && txn.get_changeset(txn.changes(channel), int)?.is_some()
178 {
179 continue;
180 }
181 return Err(ApplyError::LocalChange(
182 LocalApplyError::DependencyMissing { hash: *hash },
183 ));
184 }
185
186 let internal = if let Some(&p) = txn.get_internal(&hash.into())? {
187 p
188 } else {
189 let internal: ChangeId = make_changeid(txn, hash)?;
190 register_change(txn, &internal, hash, &change)?;
191 internal
192 };
193 debug!("internal = {:?}", internal);
194 apply_change_to_channel(
195 txn,
196 channel,
197 &mut |h| changes.knows(h, hash).unwrap(),
198 internal,
199 hash,
200 &change,
201 workspace,
202 )
203 .map_err(ApplyError::LocalChange)
204}
205
206pub fn apply_change_rec_ws<T: TxnT + MutTxnT, P: ChangeStore>(
207 changes: &P,
208 txn: &mut T,
209 channel: &mut T::Channel,
210 hash: &Hash,
211 workspace: &mut Workspace,
212 deps_only: bool,
213) -> Result<(), ApplyError<P::Error, T>> {
214 debug!("apply_change {:?}", hash.to_base32());
215 workspace.clear();
216 let mut dep_stack = vec![(*hash, true, !deps_only)];
217 let mut visited = HashSet::default();
218 while let Some((hash, first, actually_apply)) = dep_stack.pop() {
219 let change = changes.get_change(&hash).map_err(ApplyError::Changestore)?;
220 let shash: SerializedHash = (&hash).into();
221 if first {
222 if !visited.insert(hash) {
223 continue;
224 }
225 if let Some(change_id) = txn.get_internal(&shash)?
226 && txn
227 .get_changeset(txn.changes(channel), change_id)?
228 .is_some()
229 {
230 continue;
231 }
232
233 dep_stack.push((hash, false, actually_apply));
234 for &hash in change.dependencies.iter() {
235 if let Hash::None = hash {
236 continue;
237 }
238 dep_stack.push((hash, true, true))
239 }
240 } else if actually_apply {
241 let applied = if let Some(int) = txn.get_internal(&shash)? {
242 txn.get_changeset(txn.changes(channel), int)?.is_some()
243 } else {
244 false
245 };
246 if !applied {
247 let internal = if let Some(&p) = txn.get_internal(&shash)? {
248 p
249 } else {
250 let internal: ChangeId = make_changeid(txn, &hash)?;
251 register_change(txn, &internal, &hash, &change)?;
252 internal
253 };
254 debug!("internal = {:?}", internal);
255 workspace.clear();
256 apply_change_to_channel(
257 txn,
258 channel,
259 &mut |h| changes.knows(h, &hash).unwrap(),
260 internal,
261 &hash,
262 &change,
263 workspace,
264 )
265 .map_err(ApplyError::LocalChange)?;
266 }
267 }
268 }
269 Ok(())
270}
271
272pub fn apply_change<T: MutTxnT, P: ChangeStore>(
274 changes: &P,
275 txn: &mut T,
276 channel: &mut T::Channel,
277 hash: &Hash,
278) -> Result<(u64, Merkle), ApplyError<P::Error, T>> {
279 apply_change_ws(changes, txn, channel, hash, &mut Workspace::new())
280}
281
282pub fn apply_change_arc<T: MutTxnT, P: ChangeStore>(
284 changes: &P,
285 txn: &ArcTxn<T>,
286 channel: &ChannelRef<T>,
287 hash: &Hash,
288) -> Result<(u64, Merkle), ApplyError<P::Error, T>> {
289 apply_change_ws(
290 changes,
291 &mut *txn.write(),
292 &mut *channel.write(),
293 hash,
294 &mut Workspace::new(),
295 )
296}
297
298pub fn apply_change_rec<T: MutTxnT, P: ChangeStore>(
300 changes: &P,
301 txn: &mut T,
302 channel: &mut T::Channel,
303 hash: &Hash,
304 deps_only: bool,
305) -> Result<(), ApplyError<P::Error, T>> {
306 apply_change_rec_ws(
307 changes,
308 txn,
309 channel,
310 hash,
311 &mut Workspace::new(),
312 deps_only,
313 )
314}
315
316fn apply_change_to_channel<T: ChannelMutTxnT + TreeTxnT, F: FnMut(&Hash) -> bool>(
317 txn: &mut T,
318 channel: &mut T::Channel,
319 changes: &mut F,
320 change_id: ChangeId,
321 hash: &Hash,
322 change: &Change,
323 ws: &mut Workspace,
324) -> Result<(u64, Merkle), LocalApplyError<T>> {
325 ws.assert_empty();
326 let n = txn.apply_counter(channel);
327 debug!("apply_change_to_channel {:?} {:?}", change_id, hash);
328 let merkle =
329 if let Some(m) = txn.put_changes(channel, change_id, txn.apply_counter(channel), hash)? {
330 m
331 } else {
332 return Err(LocalApplyError::ChangeAlreadyOnChannel { hash: *hash });
333 };
334 debug!("apply change to channel");
335 let now = std::time::Instant::now();
336 for (n, change_) in change.changes.iter().enumerate() {
337 debug!("Applying {} {:?} (1)", n, change_);
338 for change_ in change_.iter() {
339 match *change_ {
340 Atom::NewVertex(ref n) => put_newvertex(
341 txn,
342 T::graph_mut(channel),
343 changes,
344 change,
345 ws,
346 change_id,
347 n,
348 )?,
349 Atom::EdgeMap(ref n) => {
350 for edge in n.edges.iter() {
351 if !edge.flag.contains(EdgeFlags::DELETED) {
352 put_newedge(
353 txn,
354 T::graph_mut(channel),
355 ws,
356 change_id,
357 n.inode,
358 edge,
359 |_, _| true,
360 |h| change.knows(h),
361 )?;
362 }
363 }
364 }
365 }
366 }
367 }
368 for change_ in change.changes.iter() {
369 debug!("Applying {:?} (2)", change_);
370 for change_ in change_.iter() {
371 if let Atom::EdgeMap(ref n) = *change_ {
372 for edge in n.edges.iter() {
373 if edge.flag.contains(EdgeFlags::DELETED) {
374 put_newedge(
375 txn,
376 T::graph_mut(channel),
377 ws,
378 change_id,
379 n.inode,
380 edge,
381 |_, _| true,
382 |h| change.knows(h),
383 )?;
384 }
385 }
386 }
387 }
388 }
389 crate::TIMERS.lock().unwrap().apply += now.elapsed();
390
391 let mut inodes = clean_obsolete_pseudo_edges(txn, T::graph_mut(channel), ws, change_id)?;
392 collect_missing_contexts(txn, txn.graph(channel), ws, change, change_id, &mut inodes)?;
393 for &i in inodes.iter() {
394 repair_zombies(txn, T::graph_mut(channel), i)?;
395 }
396 for &i in inodes.iter() {
397 repair_up(txn, T::graph_mut(channel), i)?;
398 }
399
400 detect_folder_conflict_resolutions(
401 txn,
402 T::graph_mut(channel),
403 &mut ws.missing_context,
404 change_id,
405 change,
406 )
407 .map_err(LocalApplyError::from_missing)?;
408
409 repair_cyclic_paths(txn, T::graph_mut(channel), ws)?;
410 info!("done applying change");
411 Ok((n, merkle))
412}
413
414pub fn apply_local_change_ws<
420 T: ChannelMutTxnT + DepsMutTxnT<DepsError = <T as GraphTxnT>::GraphError> + TreeMutTxnT,
421>(
422 txn: &mut T,
423 channel: &ChannelRef<T>,
424 change: &Change,
425 hash: &Hash,
426 inode_updates: &HashMap<usize, InodeUpdate>,
427 workspace: &mut Workspace,
428) -> Result<(u64, Merkle), LocalApplyError<T>> {
429 let mut channel = channel.write();
430 let internal: ChangeId = make_changeid(txn, hash)?;
431 debug!("make_changeid {:?} {:?}", hash, internal);
432
433 for hash in change.dependencies.iter() {
434 if let Hash::None = hash {
435 continue;
436 }
437 if let Some(int) = txn.get_internal(&hash.into())?
438 && txn.get_changeset(txn.changes(&channel), int)?.is_some()
439 {
440 continue;
441 }
442 return Err(LocalApplyError::DependencyMissing { hash: *hash });
443 }
444
445 register_change(txn, &internal, hash, change)?;
446 let n = apply_change_to_channel(
447 txn,
448 &mut channel,
449 &mut |_| true,
450 internal,
451 hash,
452 change,
453 workspace,
454 )?;
455 for (_, update) in inode_updates.iter() {
456 info!("updating {:?}", update);
457 update_inode(txn, &channel, internal, update)?;
458 }
459 Ok(n)
460}
461
462pub fn apply_local_change<
464 T: ChannelMutTxnT + DepsMutTxnT<DepsError = <T as GraphTxnT>::GraphError> + TreeMutTxnT,
465>(
466 txn: &mut T,
467 channel: &ChannelRef<T>,
468 change: &Change,
469 hash: &Hash,
470 inode_updates: &HashMap<usize, InodeUpdate>,
471) -> Result<(u64, Merkle), LocalApplyError<T>> {
472 apply_local_change_ws(
473 txn,
474 channel,
475 change,
476 hash,
477 inode_updates,
478 &mut Workspace::new(),
479 )
480}
481
482fn update_inode<T: ChannelTxnT + TreeMutTxnT>(
483 txn: &mut T,
484 channel: &T::Channel,
485 internal: ChangeId,
486 update: &InodeUpdate,
487) -> Result<(), LocalApplyError<T>> {
488 debug!("update_inode {:?}", update);
489 match *update {
490 InodeUpdate::Add { inode, pos, .. } => {
491 let vertex = Position {
492 change: internal,
493 pos,
494 };
495 if txn
496 .get_graph(txn.graph(channel), &vertex.inode_vertex(), None)?
497 .is_some()
498 {
499 debug!("Adding inodes: {:?} {:?}", inode, vertex);
500 put_inodes_with_rev(txn, &inode, &vertex)?;
501 } else {
502 debug!("Not adding inodes: {:?} {:?}", inode, vertex);
503 }
504 }
505 InodeUpdate::Deleted { inode } => {
506 if let Some(parent) = txn.get_revtree(&inode, None)?.map(|x| x.to_owned()) {
507 del_tree_with_rev(txn, &parent, &inode)?;
508 }
509 txn.del_tree(&OwnedPathId::inode(inode), Some(&inode))?;
511 if let Some(&vertex) = txn.get_inodes(&inode, None)? {
512 del_inodes_with_rev(txn, &inode, &vertex)?;
513 }
514 }
515 }
516 Ok(())
517}
518
519#[derive(Default)]
520pub struct Workspace {
521 pub parents: HashSet<Vertex<ChangeId>>,
522 pub children: HashSet<Vertex<ChangeId>>,
523 pub pseudo: Vec<(Vertex<ChangeId>, SerializedEdge, Position<Option<Hash>>)>,
524 pub deleted_by: HashSet<ChangeId>,
525 pub up_context: Vec<Vertex<ChangeId>>,
526 pub down_context: Vec<Vertex<ChangeId>>,
527 pub missing_context: crate::missing_context::Workspace,
528 pub rooted: HashMap<Vertex<ChangeId>, bool>,
529 pub adjbuf: Vec<SerializedEdge>,
530 pub alive_folder: HashMap<Vertex<ChangeId>, bool>,
531 pub folder_stack: Vec<(Vertex<ChangeId>, bool)>,
532}
533
534impl Workspace {
535 pub fn new() -> Self {
536 Self::default()
537 }
538 fn clear(&mut self) {
539 self.children.clear();
540 self.parents.clear();
541 self.pseudo.clear();
542 self.deleted_by.clear();
543 self.up_context.clear();
544 self.down_context.clear();
545 self.missing_context.clear();
546 self.rooted.clear();
547 self.adjbuf.clear();
548 self.alive_folder.clear();
549 self.folder_stack.clear();
550 }
551 fn assert_empty(&self) {
552 assert!(self.children.is_empty());
553 assert!(self.parents.is_empty());
554 assert!(self.pseudo.is_empty());
555 assert!(self.deleted_by.is_empty());
556 assert!(self.up_context.is_empty());
557 assert!(self.down_context.is_empty());
558 self.missing_context.assert_empty();
559 assert!(self.rooted.is_empty());
560 assert!(self.adjbuf.is_empty());
561 assert!(self.alive_folder.is_empty());
562 assert!(self.folder_stack.is_empty());
563 }
564}
565
566#[derive(Debug)]
567struct StackElt {
568 vertex: Vertex<ChangeId>,
569 last_alive: Vertex<ChangeId>,
570 is_on_path: bool,
571}
572
573impl StackElt {
574 fn is_alive(&self) -> bool {
575 self.vertex == self.last_alive
576 }
577}
578
579pub(crate) fn repair_zombies<T: GraphMutTxnT + TreeTxnT>(
580 txn: &mut T,
581 channel: &mut T::Graph,
582 root: Position<ChangeId>,
583) -> Result<(), LocalApplyError<T>> {
584 info!("repair_zombies {:?}", root);
585 let mut stack = vec![StackElt {
586 vertex: root.inode_vertex(),
587 last_alive: root.inode_vertex(),
588 is_on_path: false,
589 }];
590
591 let mut visited = BTreeSet::new();
592 let mut descendants = BTreeSet::new();
593
594 while let Some(elt) = stack.pop() {
595 debug!("elt {:?}", elt);
596 if elt.is_on_path {
597 continue;
598 }
599
600 if !visited.insert(elt.vertex) {
602 debug!("already visited!");
603 for (_, r) in descendants.range((elt.vertex, Vertex::ROOT)..=(elt.vertex, Vertex::MAX))
604 {
605 debug!("put_pseudo, descendant {:?} {:?}", elt.last_alive, r);
606 if elt.last_alive != *r {
608 put_graph_with_rev(
609 txn,
610 channel,
611 EdgeFlags::PSEUDO,
612 elt.last_alive,
613 *r,
614 ChangeId::ROOT,
615 )?;
616 }
617 }
618 if !elt.is_alive() {
619 continue;
620 }
621
622 for v in stack.iter().rev() {
624 if v.is_on_path {
625 debug!("on path: {:?}", v);
626 if v.is_alive() {
629 if v.vertex != elt.vertex {
630 debug!("alive, put_pseudo {:?} {:?}", v.vertex, elt.vertex);
637 put_graph_with_rev(
638 txn,
639 channel,
640 EdgeFlags::PSEUDO,
641 v.vertex,
642 elt.vertex,
643 ChangeId::ROOT,
644 )?;
645 }
646 break;
647 } else {
648 descendants.insert((v.vertex, elt.vertex));
651 }
652 }
653 }
654
655 continue;
656 }
657
658 stack.push(StackElt {
660 is_on_path: true,
661 ..elt
662 });
663
664 let len = stack.len();
665 for e in iter_adjacent(
669 txn,
670 channel,
671 elt.vertex,
672 EdgeFlags::empty(),
673 EdgeFlags::all(),
674 )? {
675 let e = e?;
676
677 if e.flag().contains(EdgeFlags::PARENT) {
678 if e.flag() & (EdgeFlags::BLOCK | EdgeFlags::DELETED) == EdgeFlags::BLOCK {
679 stack[len - 1].last_alive = elt.vertex;
681 }
682 continue;
683 } else if e.flag().contains(EdgeFlags::FOLDER) {
684 return Ok(());
687 }
688
689 let child = txn.find_block(channel, e.dest())?;
690 stack.push(StackElt {
691 vertex: *child,
692 last_alive: elt.last_alive,
693 is_on_path: false,
694 });
695 }
696
697 if len >= 2 && stack[len - 1].is_alive() {
698 for x in &mut stack[len..] {
700 x.last_alive = elt.vertex
701 }
702
703 for v in (stack[..len - 1]).iter().rev() {
704 if v.is_on_path {
705 debug!("on path: {:?}", v);
706 if v.is_alive() {
709 debug!(
716 "put_pseudo, alive 2, {:?} {:?}",
717 v.last_alive,
718 stack[len - 1].vertex
719 );
720 debug!("{:?}", stack);
721 let edge = Edge {
722 dest: stack[len - 1].vertex.start_pos(),
723 flag: EdgeFlags::empty(),
724 introduced_by: ChangeId::ROOT,
725 };
726 match txn.get_graph(channel, &v.last_alive, Some(&edge.into()))? {
727 Some(e) if e.dest() == edge.dest && e.flag() == EdgeFlags::BLOCK => {}
728 _ => {
729 put_graph_with_rev(
730 txn,
731 channel,
732 EdgeFlags::PSEUDO,
733 v.last_alive,
734 stack[len - 1].vertex,
735 ChangeId::ROOT,
736 )?;
737 }
738 }
739 break;
740 } else {
741 descendants.insert((v.vertex, elt.vertex));
744 }
745 }
746 }
747 }
748
749 if stack.len() == len {
751 stack.pop();
752 }
753 }
754
755 Ok(())
756}
757
758pub(crate) fn repair_up<T: GraphMutTxnT + TreeTxnT>(
759 txn: &mut T,
760 channel: &mut T::Graph,
761 root: Position<ChangeId>,
762) -> Result<(), LocalApplyError<T>> {
763 info!("repair_zombies {:?}", root);
764 let mut stack = vec![root.inode_vertex()];
765 let mut visited = BTreeSet::new();
766 let mut add = Vec::new();
767 while let Some(elt) = stack.pop() {
768 if !visited.insert(elt) {
769 continue;
770 }
771 let mut is_alive = false;
772 let mut is_dead = false;
773 for e in iter_adjacent(
774 txn,
775 channel,
776 elt,
777 EdgeFlags::PARENT | EdgeFlags::FOLDER,
778 EdgeFlags::all(),
779 )? {
780 let e = e?;
781 let deleted = e.flag().contains(EdgeFlags::DELETED);
782 if e.flag().contains(EdgeFlags::PARENT | EdgeFlags::FOLDER) {
783 is_alive |= !deleted;
784 is_dead |= deleted;
785 }
786 }
787 if is_dead && !is_alive {
788 for e in iter_adjacent(
789 txn,
790 channel,
791 elt,
792 EdgeFlags::PARENT | EdgeFlags::FOLDER,
793 EdgeFlags::all(),
794 )? {
795 let e = e?;
796 if e.flag()
797 .contains(EdgeFlags::PARENT | EdgeFlags::DELETED | EdgeFlags::FOLDER)
798 {
799 let parent = txn.find_block_end(channel, e.dest())?;
800 add.push((*parent, elt));
801 stack.push(*parent)
802 }
803 }
804
805 for (a, b) in add.drain(..) {
806 put_graph_with_rev(
807 txn,
808 channel,
809 EdgeFlags::PSEUDO | EdgeFlags::FOLDER,
810 a,
811 b,
812 ChangeId::ROOT,
813 )?;
814 }
815 }
816 }
817
818 Ok(())
819}
820
821pub fn clean_obsolete_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
822 txn: &mut T,
823 channel: &mut T::Graph,
824 ws: &mut Workspace,
825 change_id: ChangeId,
826) -> Result<HashSet<Position<ChangeId>>, LocalApplyError<T>> {
827 info!(
828 "clean_obsolete_pseudo_edges, ws.pseudo.len() = {}",
829 ws.pseudo.len()
830 );
831 let mut alive_folder = std::mem::take(&mut ws.alive_folder);
832 let mut folder_stack = std::mem::take(&mut ws.folder_stack);
833
834 let mut inodes = HashSet::new();
835
836 for (next_vertex, p, inode) in ws.pseudo.drain(..) {
837 debug!(
838 "clean_obsolete_pseudo_edges {:?} {:?} {:?}",
839 next_vertex, p, inode
840 );
841
842 if log_enabled!(log::Level::Debug) {
843 let still_here: Vec<_> = iter_adjacent(
844 txn,
845 channel,
846 next_vertex,
847 EdgeFlags::empty(),
848 EdgeFlags::all(),
849 )?
850 .collect();
851 debug!(
852 "pseudo edge still here ? {:?} {:?}",
853 next_vertex.change.0.0, still_here
854 )
855 }
856
857 let (a, b) = if p.flag().is_parent() {
858 match txn.find_block_end(channel, p.dest()) {
859 Ok(&dest) => (dest, next_vertex),
860 _ => {
861 continue;
862 }
863 }
864 } else {
865 match txn.find_block(channel, p.dest()) {
866 Ok(&dest) => (next_vertex, dest),
867 _ => {
868 continue;
869 }
870 }
871 };
872 let a_is_alive = is_alive(txn, channel, &a)?;
873 let b_is_alive = is_alive(txn, channel, &b)?;
874 if a_is_alive && b_is_alive {
875 continue;
876 }
877
878 if p.flag().is_folder()
882 && folder_has_alive_descendants(txn, channel, &mut alive_folder, &mut folder_stack, b)?
883 {
884 continue;
885 }
886
887 if a.is_empty() && b_is_alive {
888 let mut is_inode = false;
894 for e in iter_adjacent(
895 txn,
896 channel,
897 a,
898 EdgeFlags::FOLDER | EdgeFlags::PARENT,
899 EdgeFlags::all(),
900 )? {
901 let e = e?;
902 if e.flag().contains(EdgeFlags::FOLDER | EdgeFlags::PARENT) {
903 is_inode = true;
904 break;
905 }
906 }
907 if is_inode {
908 continue;
909 }
910 }
911
912 debug!(
913 "deleting {:?} {:?} {:?} {:?} {:?} {:?}",
914 a,
915 b,
916 p.introduced_by(),
917 p.flag(),
918 a_is_alive,
919 b_is_alive,
920 );
921 del_graph_with_rev(
922 txn,
923 channel,
924 p.flag() - EdgeFlags::PARENT,
925 a,
926 b,
927 p.introduced_by(),
928 )?;
929
930 if a_is_alive || (b_is_alive && !p.flag().is_folder()) {
931 inodes.insert(internal_pos(txn, &inode, change_id)?);
933 }
934 }
935
936 ws.alive_folder = alive_folder;
937 ws.folder_stack = folder_stack;
938 Ok(inodes)
939}
940
941fn folder_has_alive_descendants<T: GraphMutTxnT + TreeTxnT>(
942 txn: &mut T,
943 channel: &mut T::Graph,
944 alive: &mut HashMap<Vertex<ChangeId>, bool>,
945 stack: &mut Vec<(Vertex<ChangeId>, bool)>,
946 b: Vertex<ChangeId>,
947) -> Result<bool, LocalApplyError<T>> {
948 if let Some(r) = alive.get(&b) {
949 return Ok(*r);
950 }
951 debug!("alive descendants");
952 stack.clear();
953 stack.push((b, false));
954 while let Some((b, visited)) = stack.pop() {
955 debug!("visiting {:?} {:?}", b, visited);
956 if visited {
957 alive.entry(b).or_insert(false);
958 continue;
959 }
960 stack.push((b, true));
961 for e in iter_adjacent(
962 txn,
963 channel,
964 b,
965 EdgeFlags::empty(),
966 EdgeFlags::all() - EdgeFlags::DELETED - EdgeFlags::PARENT,
967 )? {
968 let e = e?;
969 debug!("e = {:?}", e);
970 if e.flag().contains(EdgeFlags::FOLDER) {
971 let c = txn.find_block(channel, e.dest())?;
972 stack.push((*c, false));
973 } else {
974 let c = txn.find_block(channel, e.dest())?;
976 if is_alive(txn, channel, c)? {
977 for (x, on_path) in stack.iter() {
979 if *on_path {
980 alive.insert(*x, true);
981 }
982 }
983 }
984 }
985 }
986 }
987 Ok(*alive.get(&b).unwrap_or(&false))
988}
989
990pub fn collect_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
991 txn: &T,
992 channel: &T::Graph,
993 ws: &mut Workspace,
994 change: &Change,
995 change_id: ChangeId,
996 inodes: &mut HashSet<Position<ChangeId>>,
997) -> Result<(), LocalApplyError<T>> {
998 inodes.extend(
999 ws.missing_context
1000 .unknown_parents
1001 .drain(..)
1002 .map(|x| internal_pos(txn, &x.2, change_id).unwrap()),
1003 );
1004 for atom in change.changes.iter().flat_map(|r| r.iter()) {
1005 match atom {
1006 Atom::NewVertex(n) if !n.flag.is_folder() => {
1007 let inode = internal_pos(txn, &n.inode, change_id)?;
1008 if !inodes.contains(&inode) {
1009 for up in n.up_context.iter() {
1010 let up = *txn.find_block_end(channel, internal_pos(txn, up, change_id)?)?;
1011 if !is_alive(txn, channel, &up)? {
1012 inodes.insert(inode);
1013 break;
1014 }
1015 }
1016 for down in n.down_context.iter() {
1017 let down = *txn.find_block(channel, internal_pos(txn, down, change_id)?)?;
1018 let mut down_has_other_parents = false;
1019 for e in iter_adjacent(
1020 txn,
1021 channel,
1022 down,
1023 EdgeFlags::PARENT,
1024 EdgeFlags::all() - EdgeFlags::DELETED,
1025 )? {
1026 let e = e?;
1027 if e.introduced_by() != change_id {
1028 down_has_other_parents = true;
1029 break;
1030 }
1031 }
1032 if !down_has_other_parents {
1033 inodes.insert(inode);
1034 break;
1035 }
1036 }
1037 }
1038 }
1039 Atom::NewVertex(_) => {}
1040 Atom::EdgeMap(n) => {
1041 has_missing_edge_context(txn, channel, change_id, change, n, inodes, false)?;
1042 }
1043 }
1044 }
1045 Ok(())
1046}
1047
1048pub(crate) fn has_missing_edge_context<T: GraphMutTxnT + TreeTxnT>(
1050 txn: &T,
1051 channel: &T::Graph,
1052 change_id: ChangeId,
1053 change: &Change,
1054 n: &EdgeMap<Option<Hash>>,
1055 inodes: &mut HashSet<Position<ChangeId>>,
1056 reverse: bool,
1057) -> Result<(), LocalApplyError<T>> {
1058 let inode = internal_pos(txn, &n.inode, change_id)?;
1059 if inodes.contains(&inode) {
1061 return Ok(());
1062 }
1063
1064 let ext: Hash = if reverse {
1065 (*txn.get_external(&change_id).unwrap()).into()
1066 } else {
1067 Hash::None
1069 };
1070
1071 for e in n.edges.iter() {
1072 let e = if reverse {
1073 e.reverse(Some(ext))
1074 } else {
1075 e.clone()
1076 };
1077
1078 assert!(!e.flag.contains(EdgeFlags::PARENT));
1079 if e.flag.contains(EdgeFlags::DELETED) {
1080 trace!("repairing context deleted {:?}", e);
1081 if has_missing_context_deleted(txn, channel, change_id, |h| change.knows(&h), &e)
1082 .map_err(LocalApplyError::from_missing)?
1083 {
1084 inodes.insert(inode);
1085 break;
1086 }
1087 } else {
1088 trace!("repairing context nondeleted {:?}", e);
1089 if has_missing_context_nondeleted(txn, channel, change_id, &e)
1090 .map_err(LocalApplyError::from_missing)?
1091 {
1092 inodes.insert(inode);
1093 break;
1094 }
1095 }
1096 }
1097 Ok(())
1098}
1099
1100pub(crate) fn repair_cyclic_paths<T: GraphMutTxnT + TreeTxnT>(
1101 txn: &mut T,
1102 channel: &mut T::Graph,
1103 ws: &mut Workspace,
1104) -> Result<(), LocalApplyError<T>> {
1105 let now = std::time::Instant::now();
1106 let mut files = std::mem::take(&mut ws.missing_context.files);
1107 for file in files.drain() {
1108 if file.is_empty() {
1109 if !is_rooted(txn, channel, file, ws)? {
1110 repair_edge(txn, channel, file, ws)?
1111 }
1112 } else {
1113 let f0 = EdgeFlags::FOLDER;
1114 let f1 = EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO;
1115 let mut iter = iter_adjacent(txn, channel, file, f0, f1)?;
1116 if let Some(ee) = iter.next() {
1117 let ee = ee?;
1118 let dest = ee.dest().inode_vertex();
1119 if !is_rooted(txn, channel, dest, ws)? {
1120 repair_edge(txn, channel, dest, ws)?
1121 }
1122 }
1123 }
1124 }
1125 ws.missing_context.files = files;
1126 crate::TIMERS.lock().unwrap().check_cyclic_paths += now.elapsed();
1127 Ok(())
1128}
1129
1130fn repair_edge<T: GraphMutTxnT + TreeTxnT>(
1131 txn: &mut T,
1132 channel: &mut T::Graph,
1133 to0: Vertex<ChangeId>,
1134 ws: &mut Workspace,
1135) -> Result<(), LocalApplyError<T>> {
1136 debug!("repair_edge {:?}", to0);
1137 let mut stack = vec![(to0, true, true, true)];
1138 ws.parents.clear();
1139 while let Some((current, _, al, anc_al)) = stack.pop() {
1140 if !ws.parents.insert(current) {
1141 continue;
1142 }
1143 debug!("repair_cyclic {:?}", current);
1144 if current != to0 {
1145 stack.push((current, true, al, anc_al));
1146 }
1147 if current.is_root() {
1148 debug!("root");
1149 break;
1150 }
1151 if let Some(&true) = ws.rooted.get(¤t) {
1152 debug!("rooted");
1153 break;
1154 }
1155 let f = EdgeFlags::PARENT | EdgeFlags::FOLDER;
1156 let len = stack.len();
1157 for parent in iter_adjacent(txn, channel, current, f, EdgeFlags::all())? {
1158 let parent = parent?;
1159 if parent.flag().is_parent() {
1160 let anc = txn.find_block_end(channel, parent.dest())?;
1161 debug!("is_rooted, parent = {:?}", parent);
1162 let al = match iter_adjacent(
1163 txn,
1164 channel,
1165 *anc,
1166 f,
1167 f | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,
1168 )?
1169 .next()
1170 {
1171 Some(e) => {
1172 e?;
1173 true
1174 }
1175 _ => false,
1176 };
1177 debug!("al = {:?}, flag = {:?}", al, parent.flag());
1178 stack.push((*anc, false, parent.flag().is_deleted(), al));
1179 }
1180 }
1181 if stack.len() == len {
1182 stack.pop();
1183 } else {
1184 (stack[len..]).sort_unstable_by_key(|a| a.3)
1185 }
1186 }
1187 let mut current = to0;
1188 for (next, on_path, del, _) in stack {
1189 if on_path {
1190 if del {
1191 debug!("put_pseudo {:?} {:?}", next, current);
1192 put_graph_with_rev(
1193 txn,
1194 channel,
1195 EdgeFlags::FOLDER | EdgeFlags::PSEUDO,
1196 next,
1197 current,
1198 ChangeId::ROOT,
1199 )?;
1200 }
1201 current = next
1202 }
1203 }
1204 ws.parents.clear();
1205 Ok(())
1206}
1207
1208fn is_rooted<T: GraphTxnT + TreeTxnT>(
1209 txn: &T,
1210 channel: &T::Graph,
1211 v: Vertex<ChangeId>,
1212 ws: &mut Workspace,
1213) -> Result<bool, LocalApplyError<T>> {
1214 let mut alive = false;
1215 assert!(v.is_empty());
1216 for e in iter_adjacent(txn, channel, v, EdgeFlags::empty(), EdgeFlags::all())? {
1217 let e = e?;
1218 if e.flag().contains(EdgeFlags::PARENT) {
1219 if e.flag() & (EdgeFlags::FOLDER | EdgeFlags::DELETED) == EdgeFlags::FOLDER {
1220 alive = true;
1221 break;
1222 }
1223 } else if !e.flag().is_deleted() {
1224 alive = true;
1225 break;
1226 }
1227 }
1228 if !alive {
1229 debug!("is_rooted, not alive");
1230 return Ok(true);
1231 }
1232 let stack = &mut ws.up_context;
1235 stack.clear();
1236 stack.push(v);
1237 let visited = &mut ws.parents;
1238 visited.clear();
1239
1240 while let Some(to) = stack.pop() {
1241 debug!("is_rooted, pop = {:?}", to);
1242 if to.is_root() {
1243 stack.clear();
1244 for v in visited.drain() {
1245 ws.rooted.insert(v, true);
1246 }
1247 return Ok(true);
1248 }
1249 if !visited.insert(to) {
1250 continue;
1251 }
1252 if let Some(&rooted) = ws.rooted.get(&to) {
1253 if rooted {
1254 for v in visited.drain() {
1255 ws.rooted.insert(v, true);
1256 }
1257 return Ok(true);
1258 } else {
1259 continue;
1260 }
1261 }
1262 let f = EdgeFlags::PARENT | EdgeFlags::FOLDER;
1263 for parent in iter_adjacent(
1264 txn,
1265 channel,
1266 to,
1267 f,
1268 f | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
1269 )? {
1270 let parent = parent?;
1271 debug!("is_rooted, parent = {:?}", parent);
1272 stack.push(*txn.find_block_end(channel, parent.dest())?)
1273 }
1274 }
1275 for v in visited.drain() {
1276 ws.rooted.insert(v, false);
1277 }
1278 Ok(false)
1279}
1280
1281pub type AppliedRoot = (Hash, u64, Merkle);
1282
1283pub fn apply_root_change<R: rand::Rng, T: MutTxnT, P: ChangeStore>(
1284 txn: &mut T,
1285 channel: &ChannelRef<T>,
1286 store: &P,
1287 rng: R,
1288) -> Result<Option<AppliedRoot>, ApplyError<P::Error, T>> {
1289 let mut change = {
1290 {
1292 let channel = channel.read();
1293 let gr = txn.graph(&*channel);
1294 if let Some(v) = iter_adjacent(
1295 &*txn,
1296 gr,
1297 Vertex::ROOT,
1298 EdgeFlags::FOLDER,
1299 EdgeFlags::FOLDER | EdgeFlags::BLOCK,
1300 )?
1301 .next()
1302 {
1303 let v = txn.find_block(gr, v?.dest())?;
1304 if v.start == v.end {
1305 return Ok(None);
1307 }
1308 } else {
1309 }
1311 }
1314 let root = Position {
1315 change: Some(Hash::None),
1316 pos: ChangePosition(0u64.into()),
1317 };
1318 use rand::RngExt;
1319 let contents = rng
1320 .sample_iter(rand::distr::StandardUniform)
1321 .take(32)
1322 .collect();
1323 debug!(
1324 "change position {:?} {:?}",
1325 ChangePosition(1u64.into()),
1326 ChangePosition(1u64.into()).0.as_u64()
1327 );
1328 crate::change::LocalChange::make_change(
1329 txn,
1330 channel,
1331 vec![crate::change::Hunk::AddRoot {
1332 name: Atom::NewVertex(NewVertex {
1333 up_context: vec![root],
1334 down_context: Vec::new(),
1335 start: ChangePosition(0u64.into()),
1336 end: ChangePosition(0u64.into()),
1337 flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,
1338 inode: root,
1339 }),
1340 inode: Atom::NewVertex(NewVertex {
1341 up_context: vec![Position {
1342 change: None,
1343 pos: ChangePosition(0u64.into()),
1344 }],
1345 down_context: Vec::new(),
1346 start: ChangePosition(1u64.into()),
1347 end: ChangePosition(1u64.into()),
1348 flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,
1349 inode: root,
1350 }),
1351 }],
1352 contents,
1353 crate::change::ChangeHeader::default(),
1354 Vec::new(),
1355 )?
1356 };
1357 let h = store
1358 .save_change(&mut change, |_, _| Ok(()))
1359 .map_err(ApplyError::Changestore)?;
1360 let (n, merkle) = apply_change(store, txn, &mut channel.write(), &h)?;
1361 Ok(Some((h, n, merkle)))
1362}