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, None)?;
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(
453 txn,
454 &mut channel,
455 &mut |_| false,
456 internal,
457 hash,
458 change,
459 workspace,
460 )?;
461 for (_, update) in inode_updates.iter() {
462 info!("updating {:?}", update);
463 update_inode(txn, &channel, internal, update)?;
464 }
465 Ok(n)
466}
467
468pub fn apply_local_change<
470 T: ChannelMutTxnT + DepsMutTxnT<DepsError = <T as GraphTxnT>::GraphError> + TreeMutTxnT,
471>(
472 txn: &mut T,
473 channel: &ChannelRef<T>,
474 change: &Change,
475 hash: &Hash,
476 inode_updates: &HashMap<usize, InodeUpdate>,
477) -> Result<(u64, Merkle), LocalApplyError<T>> {
478 apply_local_change_ws(
479 txn,
480 channel,
481 change,
482 hash,
483 inode_updates,
484 &mut Workspace::new(),
485 )
486}
487
488fn update_inode<T: ChannelTxnT + TreeMutTxnT>(
489 txn: &mut T,
490 channel: &T::Channel,
491 internal: ChangeId,
492 update: &InodeUpdate,
493) -> Result<(), LocalApplyError<T>> {
494 debug!("update_inode {:?}", update);
495 match *update {
496 InodeUpdate::Add { inode, pos, .. } => {
497 let vertex = Position {
498 change: internal,
499 pos,
500 };
501 if txn
502 .get_graph(txn.graph(channel), &vertex.inode_vertex(), None)?
503 .is_some()
504 {
505 debug!("Adding inodes: {:?} {:?}", inode, vertex);
506 put_inodes_with_rev(txn, &inode, &vertex)?;
507 } else {
508 debug!("Not adding inodes: {:?} {:?}", inode, vertex);
509 }
510 }
511 InodeUpdate::Deleted { inode } => {
512 if let Some(parent) = txn.get_revtree(&inode, None)?.map(|x| x.to_owned()) {
513 del_tree_with_rev(txn, &parent, &inode)?;
514 }
515 txn.del_tree(&OwnedPathId::inode(inode), Some(&inode))?;
517 if let Some(&vertex) = txn.get_inodes(&inode, None)? {
518 del_inodes_with_rev(txn, &inode, &vertex)?;
519 }
520 }
521 }
522 Ok(())
523}
524
525#[derive(Default)]
526pub struct Workspace {
527 pub parents: HashSet<Vertex<ChangeId>>,
528 pub children: HashSet<Vertex<ChangeId>>,
529 pub pseudo: Vec<(Vertex<ChangeId>, SerializedEdge, Position<Option<Hash>>)>,
530 pub deleted_by: HashSet<ChangeId>,
531 pub up_context: Vec<Vertex<ChangeId>>,
532 pub down_context: Vec<Vertex<ChangeId>>,
533 pub missing_context: crate::missing_context::Workspace,
534 pub rooted: HashMap<Vertex<ChangeId>, bool>,
535 pub adjbuf: Vec<SerializedEdge>,
536 pub alive_folder: HashMap<Vertex<ChangeId>, bool>,
537 pub folder_stack: Vec<(Vertex<ChangeId>, bool)>,
538}
539
540impl Workspace {
541 pub fn new() -> Self {
542 Self::default()
543 }
544 fn clear(&mut self) {
545 self.children.clear();
546 self.parents.clear();
547 self.pseudo.clear();
548 self.deleted_by.clear();
549 self.up_context.clear();
550 self.down_context.clear();
551 self.missing_context.clear();
552 self.rooted.clear();
553 self.adjbuf.clear();
554 self.alive_folder.clear();
555 self.folder_stack.clear();
556 }
557 fn assert_empty(&self) {
558 assert!(self.children.is_empty());
559 assert!(self.parents.is_empty());
560 assert!(self.pseudo.is_empty());
561 assert!(self.deleted_by.is_empty());
562 assert!(self.up_context.is_empty());
563 assert!(self.down_context.is_empty());
564 self.missing_context.assert_empty();
565 assert!(self.rooted.is_empty());
566 assert!(self.adjbuf.is_empty());
567 assert!(self.alive_folder.is_empty());
568 assert!(self.folder_stack.is_empty());
569 }
570}
571
572#[derive(Debug)]
573struct StackElt {
574 vertex: Vertex<ChangeId>,
575 last_alive: Vertex<ChangeId>,
576 is_on_path: bool,
577}
578
579impl StackElt {
580 fn is_alive(&self) -> bool {
581 self.vertex == self.last_alive
582 }
583}
584
585#[derive(Default)]
589pub(crate) struct ZombieRepairLog {
590 pub leftover: Vec<(Vertex<ChangeId>, Vertex<ChangeId>)>,
593}
594
595pub(crate) fn repair_zombies<T: GraphMutTxnT + TreeTxnT>(
596 txn: &mut T,
597 channel: &mut T::Graph,
598 root: Position<ChangeId>,
599 mut log: Option<(&mut ZombieRepairLog, ChangeId)>,
600) -> Result<(), LocalApplyError<T>> {
601 info!("repair_zombies {:?}", root);
602 let mut stack = vec![StackElt {
603 vertex: root.inode_vertex(),
604 last_alive: root.inode_vertex(),
605 is_on_path: false,
606 }];
607
608 let mut visited = BTreeSet::new();
609 let mut descendants = BTreeSet::new();
610
611 while let Some(elt) = stack.pop() {
612 debug!("elt {:?}", elt);
613 if elt.is_on_path {
614 continue;
615 }
616
617 if !visited.insert(elt.vertex) {
619 debug!("already visited!");
620 for (_, r) in descendants.range((elt.vertex, Vertex::ROOT)..=(elt.vertex, Vertex::MAX))
621 {
622 debug!("put_pseudo, descendant {:?} {:?}", elt.last_alive, r);
623 if elt.last_alive != *r {
625 put_graph_with_rev(
626 txn,
627 channel,
628 EdgeFlags::PSEUDO,
629 elt.last_alive,
630 *r,
631 ChangeId::ROOT,
632 )?;
633 }
634 }
635 if !is_alive(txn, channel, &elt.vertex)? {
643 continue;
644 }
645
646 for v in stack.iter().rev() {
648 if v.is_on_path {
649 debug!("on path: {:?}", v);
650 if v.is_alive() {
653 if v.vertex != elt.vertex {
654 debug!("alive, put_pseudo {:?} {:?}", v.vertex, elt.vertex);
661 put_graph_with_rev(
662 txn,
663 channel,
664 EdgeFlags::PSEUDO,
665 v.vertex,
666 elt.vertex,
667 ChangeId::ROOT,
668 )?;
669 }
670 break;
671 } else {
672 descendants.insert((v.vertex, elt.vertex));
675 }
676 }
677 }
678
679 continue;
680 }
681
682 stack.push(StackElt {
684 is_on_path: true,
685 ..elt
686 });
687
688 let len = stack.len();
689 for e in iter_adjacent(
693 txn,
694 channel,
695 elt.vertex,
696 EdgeFlags::empty(),
697 EdgeFlags::all(),
698 )? {
699 let e = e?;
700
701 if e.flag().contains(EdgeFlags::PARENT) {
702 if e.flag() & (EdgeFlags::BLOCK | EdgeFlags::DELETED) == EdgeFlags::BLOCK {
703 stack[len - 1].last_alive = elt.vertex;
705 }
706 continue;
707 } else if e.flag().contains(EdgeFlags::FOLDER) {
708 return Ok(());
711 }
712
713 let child = txn.find_block(channel, e.dest())?;
714 if let Some((l, cid)) = log.as_mut() {
718 if e.introduced_by() == *cid && e.flag().is_deleted() && e.flag().is_block() {
719 l.leftover.push((elt.vertex, *child));
720 }
721 }
722 stack.push(StackElt {
723 vertex: *child,
724 last_alive: elt.last_alive,
725 is_on_path: false,
726 });
727 }
728
729 if len >= 2 && stack[len - 1].is_alive() {
730 for x in &mut stack[len..] {
732 x.last_alive = elt.vertex
733 }
734
735 for v in (stack[..len - 1]).iter().rev() {
736 if v.is_on_path {
737 debug!("on path: {:?}", v);
738 if v.is_alive() {
741 debug!(
748 "put_pseudo, alive 2, {:?} {:?}",
749 v.last_alive,
750 stack[len - 1].vertex
751 );
752 debug!("{:?}", stack);
753 let edge = Edge {
754 dest: stack[len - 1].vertex.start_pos(),
755 flag: EdgeFlags::empty(),
756 introduced_by: ChangeId::ROOT,
757 };
758 match txn.get_graph(channel, &v.last_alive, Some(&edge.into()))? {
759 Some(e) if e.dest() == edge.dest && e.flag() == EdgeFlags::BLOCK => {}
760 _ => {
761 put_graph_with_rev(
762 txn,
763 channel,
764 EdgeFlags::PSEUDO,
765 v.last_alive,
766 stack[len - 1].vertex,
767 ChangeId::ROOT,
768 )?;
769 }
770 }
771 break;
772 } else {
773 descendants.insert((v.vertex, elt.vertex));
776 }
777 }
778 }
779 }
780
781 if stack.len() == len {
783 stack.pop();
784 }
785 }
786
787 Ok(())
788}
789
790pub(crate) fn repair_up<T: GraphMutTxnT + TreeTxnT>(
791 txn: &mut T,
792 channel: &mut T::Graph,
793 root: Position<ChangeId>,
794) -> Result<(), LocalApplyError<T>> {
795 info!("repair_zombies {:?}", root);
796 let mut stack = vec![root.inode_vertex()];
797 let mut visited = BTreeSet::new();
798 let mut add = Vec::new();
799 while let Some(elt) = stack.pop() {
800 if !visited.insert(elt) {
801 continue;
802 }
803 let mut is_alive = false;
804 let mut is_dead = false;
805 for e in iter_adjacent(
806 txn,
807 channel,
808 elt,
809 EdgeFlags::PARENT | EdgeFlags::FOLDER,
810 EdgeFlags::all(),
811 )? {
812 let e = e?;
813 let deleted = e.flag().contains(EdgeFlags::DELETED);
814 if e.flag().contains(EdgeFlags::PARENT | EdgeFlags::FOLDER) {
815 is_alive |= !deleted;
816 is_dead |= deleted;
817 }
818 }
819 if is_dead && !is_alive {
820 for e in iter_adjacent(
821 txn,
822 channel,
823 elt,
824 EdgeFlags::PARENT | EdgeFlags::FOLDER,
825 EdgeFlags::all(),
826 )? {
827 let e = e?;
828 if e.flag()
829 .contains(EdgeFlags::PARENT | EdgeFlags::DELETED | EdgeFlags::FOLDER)
830 {
831 let parent = txn.find_block_end(channel, e.dest())?;
832 add.push((*parent, elt));
833 stack.push(*parent)
834 }
835 }
836
837 for (a, b) in add.drain(..) {
838 put_graph_with_rev(
839 txn,
840 channel,
841 EdgeFlags::PSEUDO | EdgeFlags::FOLDER,
842 a,
843 b,
844 ChangeId::ROOT,
845 )?;
846 }
847 }
848 }
849
850 Ok(())
851}
852
853pub fn clean_obsolete_pseudo_edges<T: GraphMutTxnT + TreeTxnT>(
854 txn: &mut T,
855 channel: &mut T::Graph,
856 ws: &mut Workspace,
857 change_id: ChangeId,
858) -> Result<HashSet<Position<ChangeId>>, LocalApplyError<T>> {
859 info!(
860 "clean_obsolete_pseudo_edges, ws.pseudo.len() = {}",
861 ws.pseudo.len()
862 );
863 let mut alive_folder = std::mem::take(&mut ws.alive_folder);
864 let mut folder_stack = std::mem::take(&mut ws.folder_stack);
865
866 let mut inodes = HashSet::new();
867
868 for (next_vertex, p, inode) in ws.pseudo.drain(..) {
869 debug!(
870 "clean_obsolete_pseudo_edges {:?} {:?} {:?}",
871 next_vertex, p, inode
872 );
873
874 if log_enabled!(log::Level::Debug) {
875 let still_here: Vec<_> = iter_adjacent(
876 txn,
877 channel,
878 next_vertex,
879 EdgeFlags::empty(),
880 EdgeFlags::all(),
881 )?
882 .collect();
883 debug!(
884 "pseudo edge still here ? {:?} {:?}",
885 next_vertex.change.0.0, still_here
886 )
887 }
888
889 let (a, b) = if p.flag().is_parent() {
890 match txn.find_block_end(channel, p.dest()) {
891 Ok(&dest) => (dest, next_vertex),
892 _ => {
893 continue;
894 }
895 }
896 } else {
897 match txn.find_block(channel, p.dest()) {
898 Ok(&dest) => (next_vertex, dest),
899 _ => {
900 continue;
901 }
902 }
903 };
904 let a_is_alive = is_alive(txn, channel, &a)?;
905 let b_is_alive = is_alive(txn, channel, &b)?;
906 if a_is_alive && b_is_alive {
907 continue;
908 }
909
910 if p.flag().is_folder()
914 && folder_has_alive_descendants(txn, channel, &mut alive_folder, &mut folder_stack, b)?
915 {
916 continue;
917 }
918
919 if a.is_empty() && b_is_alive {
920 let mut is_inode = false;
926 for e in iter_adjacent(
927 txn,
928 channel,
929 a,
930 EdgeFlags::FOLDER | EdgeFlags::PARENT,
931 EdgeFlags::all(),
932 )? {
933 let e = e?;
934 if e.flag().contains(EdgeFlags::FOLDER | EdgeFlags::PARENT) {
935 is_inode = true;
936 break;
937 }
938 }
939 if is_inode {
940 continue;
941 }
942 }
943
944 debug!(
945 "deleting {:?} {:?} {:?} {:?} {:?} {:?}",
946 a,
947 b,
948 p.introduced_by(),
949 p.flag(),
950 a_is_alive,
951 b_is_alive,
952 );
953 del_graph_with_rev(
954 txn,
955 channel,
956 p.flag() - EdgeFlags::PARENT,
957 a,
958 b,
959 p.introduced_by(),
960 )?;
961
962 if a_is_alive || (b_is_alive && !p.flag().is_folder()) {
963 inodes.insert(internal_pos(txn, &inode, change_id)?);
965 }
966 }
967
968 ws.alive_folder = alive_folder;
969 ws.folder_stack = folder_stack;
970 Ok(inodes)
971}
972
973fn folder_has_alive_descendants<T: GraphMutTxnT + TreeTxnT>(
974 txn: &mut T,
975 channel: &mut T::Graph,
976 alive: &mut HashMap<Vertex<ChangeId>, bool>,
977 stack: &mut Vec<(Vertex<ChangeId>, bool)>,
978 b: Vertex<ChangeId>,
979) -> Result<bool, LocalApplyError<T>> {
980 if let Some(r) = alive.get(&b) {
981 return Ok(*r);
982 }
983 debug!("alive descendants");
984 stack.clear();
985 stack.push((b, false));
986 while let Some((b, visited)) = stack.pop() {
987 debug!("visiting {:?} {:?}", b, visited);
988 if visited {
989 alive.entry(b).or_insert(false);
990 continue;
991 }
992 stack.push((b, true));
993 for e in iter_adjacent(
994 txn,
995 channel,
996 b,
997 EdgeFlags::empty(),
998 EdgeFlags::all() - EdgeFlags::DELETED - EdgeFlags::PARENT,
999 )? {
1000 let e = e?;
1001 debug!("e = {:?}", e);
1002 if e.flag().contains(EdgeFlags::FOLDER) {
1003 let c = txn.find_block(channel, e.dest())?;
1004 stack.push((*c, false));
1005 } else {
1006 let c = txn.find_block(channel, e.dest())?;
1008 if is_alive(txn, channel, c)? {
1009 for (x, on_path) in stack.iter() {
1011 if *on_path {
1012 alive.insert(*x, true);
1013 }
1014 }
1015 }
1016 }
1017 }
1018 }
1019 Ok(*alive.get(&b).unwrap_or(&false))
1020}
1021
1022pub fn collect_missing_contexts<T: GraphMutTxnT + TreeTxnT>(
1023 txn: &T,
1024 channel: &T::Graph,
1025 ws: &mut Workspace,
1026 change: &Change,
1027 change_id: ChangeId,
1028 inodes: &mut HashSet<Position<ChangeId>>,
1029) -> Result<(), LocalApplyError<T>> {
1030 inodes.extend(
1031 ws.missing_context
1032 .unknown_parents
1033 .drain(..)
1034 .map(|x| internal_pos(txn, &x.2, change_id).unwrap()),
1035 );
1036 for atom in change.changes.iter().flat_map(|r| r.iter()) {
1037 match atom {
1038 Atom::NewVertex(n) if !n.flag.is_folder() => {
1039 let inode = internal_pos(txn, &n.inode, change_id)?;
1040 if !inodes.contains(&inode) {
1041 for up in n.up_context.iter() {
1042 let up = *txn.find_block_end(channel, internal_pos(txn, up, change_id)?)?;
1043 if !is_alive(txn, channel, &up)? {
1044 inodes.insert(inode);
1045 break;
1046 }
1047 }
1048 for down in n.down_context.iter() {
1049 let down = *txn.find_block(channel, internal_pos(txn, down, change_id)?)?;
1050 let mut down_has_other_parents = false;
1051 for e in iter_adjacent(
1052 txn,
1053 channel,
1054 down,
1055 EdgeFlags::PARENT,
1056 EdgeFlags::all() - EdgeFlags::DELETED,
1057 )? {
1058 let e = e?;
1059 if e.introduced_by() != change_id {
1060 down_has_other_parents = true;
1061 break;
1062 }
1063 }
1064 if !down_has_other_parents {
1065 inodes.insert(inode);
1066 break;
1067 }
1068 }
1069 }
1070 }
1071 Atom::NewVertex(_) => {}
1072 Atom::EdgeMap(n) => {
1073 has_missing_edge_context(txn, channel, change_id, change, n, inodes, false)?;
1074 }
1075 }
1076 }
1077 Ok(())
1078}
1079
1080pub(crate) fn has_missing_edge_context<T: GraphMutTxnT + TreeTxnT>(
1082 txn: &T,
1083 channel: &T::Graph,
1084 change_id: ChangeId,
1085 change: &Change,
1086 n: &EdgeMap<Option<Hash>>,
1087 inodes: &mut HashSet<Position<ChangeId>>,
1088 reverse: bool,
1089) -> Result<(), LocalApplyError<T>> {
1090 let inode = internal_pos(txn, &n.inode, change_id)?;
1091 if inodes.contains(&inode) {
1093 return Ok(());
1094 }
1095
1096 let ext: Hash = if reverse {
1097 (*txn.get_external(&change_id).unwrap()).into()
1098 } else {
1099 Hash::None
1101 };
1102
1103 for e in n.edges.iter() {
1104 let e = if reverse {
1105 e.reverse(Some(ext))
1106 } else {
1107 e.clone()
1108 };
1109
1110 assert!(!e.flag.contains(EdgeFlags::PARENT));
1111 if e.flag.contains(EdgeFlags::DELETED) {
1112 trace!("repairing context deleted {:?}", e);
1113 if has_missing_context_deleted(txn, channel, change_id, |h| change.knows(&h), &e)
1114 .map_err(LocalApplyError::from_missing)?
1115 {
1116 inodes.insert(inode);
1117 break;
1118 }
1119 } else {
1120 trace!("repairing context nondeleted {:?}", e);
1121 if has_missing_context_nondeleted(txn, channel, change_id, &e)
1122 .map_err(LocalApplyError::from_missing)?
1123 {
1124 inodes.insert(inode);
1125 break;
1126 }
1127 }
1128 }
1129 Ok(())
1130}
1131
1132pub(crate) fn repair_cyclic_paths<T: GraphMutTxnT + TreeTxnT>(
1133 txn: &mut T,
1134 channel: &mut T::Graph,
1135 ws: &mut Workspace,
1136) -> Result<(), LocalApplyError<T>> {
1137 let now = std::time::Instant::now();
1138 let mut files = std::mem::take(&mut ws.missing_context.files);
1139 for file in files.drain() {
1140 if file.is_empty() {
1141 if !is_rooted(txn, channel, file, ws)? {
1142 repair_edge(txn, channel, file, ws)?
1143 }
1144 } else {
1145 let f0 = EdgeFlags::FOLDER;
1146 let f1 = EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::PSEUDO;
1147 let mut iter = iter_adjacent(txn, channel, file, f0, f1)?;
1148 if let Some(ee) = iter.next() {
1149 let ee = ee?;
1150 let dest = ee.dest().inode_vertex();
1151 if !is_rooted(txn, channel, dest, ws)? {
1152 repair_edge(txn, channel, dest, ws)?
1153 }
1154 }
1155 }
1156 }
1157 ws.missing_context.files = files;
1158 crate::TIMERS.lock().unwrap().check_cyclic_paths += now.elapsed();
1159 Ok(())
1160}
1161
1162fn repair_edge<T: GraphMutTxnT + TreeTxnT>(
1163 txn: &mut T,
1164 channel: &mut T::Graph,
1165 to0: Vertex<ChangeId>,
1166 ws: &mut Workspace,
1167) -> Result<(), LocalApplyError<T>> {
1168 debug!("repair_edge {:?}", to0);
1169 let mut stack = vec![(to0, true, true, true)];
1170 ws.parents.clear();
1171 while let Some((current, _, al, anc_al)) = stack.pop() {
1172 if !ws.parents.insert(current) {
1173 continue;
1174 }
1175 debug!("repair_cyclic {:?}", current);
1176 if current != to0 {
1177 stack.push((current, true, al, anc_al));
1178 }
1179 if current.is_root() {
1180 debug!("root");
1181 break;
1182 }
1183 if let Some(&true) = ws.rooted.get(¤t) {
1184 debug!("rooted");
1185 break;
1186 }
1187 let f = EdgeFlags::PARENT | EdgeFlags::FOLDER;
1188 let len = stack.len();
1189 for parent in iter_adjacent(txn, channel, current, f, EdgeFlags::all())? {
1190 let parent = parent?;
1191 if parent.flag().is_parent() {
1192 let anc = txn.find_block_end(channel, parent.dest())?;
1193 debug!("is_rooted, parent = {:?}", parent);
1194 let al = match iter_adjacent(
1195 txn,
1196 channel,
1197 *anc,
1198 f,
1199 f | EdgeFlags::BLOCK | EdgeFlags::PSEUDO,
1200 )?
1201 .next()
1202 {
1203 Some(e) => {
1204 e?;
1205 true
1206 }
1207 _ => false,
1208 };
1209 debug!("al = {:?}, flag = {:?}", al, parent.flag());
1210 stack.push((*anc, false, parent.flag().is_deleted(), al));
1211 }
1212 }
1213 if stack.len() == len {
1214 stack.pop();
1215 } else {
1216 (stack[len..]).sort_unstable_by_key(|a| a.3)
1217 }
1218 }
1219 let mut current = to0;
1220 for (next, on_path, del, _) in stack {
1221 if on_path {
1222 if del {
1223 debug!("put_pseudo {:?} {:?}", next, current);
1224 put_graph_with_rev(
1225 txn,
1226 channel,
1227 EdgeFlags::FOLDER | EdgeFlags::PSEUDO,
1228 next,
1229 current,
1230 ChangeId::ROOT,
1231 )?;
1232 }
1233 current = next
1234 }
1235 }
1236 ws.parents.clear();
1237 Ok(())
1238}
1239
1240fn is_rooted<T: GraphTxnT + TreeTxnT>(
1241 txn: &T,
1242 channel: &T::Graph,
1243 v: Vertex<ChangeId>,
1244 ws: &mut Workspace,
1245) -> Result<bool, LocalApplyError<T>> {
1246 let mut alive = false;
1247 assert!(v.is_empty());
1248 for e in iter_adjacent(txn, channel, v, EdgeFlags::empty(), EdgeFlags::all())? {
1249 let e = e?;
1250 if e.flag().contains(EdgeFlags::PARENT) {
1251 if e.flag() & (EdgeFlags::FOLDER | EdgeFlags::DELETED) == EdgeFlags::FOLDER {
1252 alive = true;
1253 break;
1254 }
1255 } else if !e.flag().is_deleted() {
1256 alive = true;
1257 break;
1258 }
1259 }
1260 if !alive {
1261 debug!("is_rooted, not alive");
1262 return Ok(true);
1263 }
1264 let stack = &mut ws.up_context;
1267 stack.clear();
1268 stack.push(v);
1269 let visited = &mut ws.parents;
1270 visited.clear();
1271
1272 while let Some(to) = stack.pop() {
1273 debug!("is_rooted, pop = {:?}", to);
1274 if to.is_root() {
1275 stack.clear();
1276 for v in visited.drain() {
1277 ws.rooted.insert(v, true);
1278 }
1279 return Ok(true);
1280 }
1281 if !visited.insert(to) {
1282 continue;
1283 }
1284 if let Some(&rooted) = ws.rooted.get(&to) {
1285 if rooted {
1286 for v in visited.drain() {
1287 ws.rooted.insert(v, true);
1288 }
1289 return Ok(true);
1290 } else {
1291 continue;
1292 }
1293 }
1294 let f = EdgeFlags::PARENT | EdgeFlags::FOLDER;
1295 for parent in iter_adjacent(
1296 txn,
1297 channel,
1298 to,
1299 f,
1300 f | EdgeFlags::PSEUDO | EdgeFlags::BLOCK,
1301 )? {
1302 let parent = parent?;
1303 debug!("is_rooted, parent = {:?}", parent);
1304 stack.push(*txn.find_block_end(channel, parent.dest())?)
1305 }
1306 }
1307 for v in visited.drain() {
1308 ws.rooted.insert(v, false);
1309 }
1310 Ok(false)
1311}
1312
1313pub type AppliedRoot = (Hash, u64, Merkle);
1314
1315pub fn apply_root_change<R: rand::Rng, T: MutTxnT, P: ChangeStore>(
1316 txn: &mut T,
1317 channel: &ChannelRef<T>,
1318 store: &P,
1319 rng: R,
1320) -> Result<Option<AppliedRoot>, ApplyError<P::Error, T>> {
1321 let mut change = {
1322 {
1324 let channel = channel.read();
1325 let gr = txn.graph(&*channel);
1326 if let Some(v) = iter_adjacent(
1327 &*txn,
1328 gr,
1329 Vertex::ROOT,
1330 EdgeFlags::FOLDER,
1331 EdgeFlags::FOLDER | EdgeFlags::BLOCK,
1332 )?
1333 .next()
1334 {
1335 let v = txn.find_block(gr, v?.dest())?;
1336 if v.start == v.end {
1337 return Ok(None);
1339 }
1340 } else {
1341 }
1343 }
1346 let root = Position {
1347 change: Some(Hash::None),
1348 pos: ChangePosition(0u64.into()),
1349 };
1350 use rand::RngExt;
1351 let contents = rng
1352 .sample_iter(rand::distr::StandardUniform)
1353 .take(32)
1354 .collect();
1355 debug!(
1356 "change position {:?} {:?}",
1357 ChangePosition(1u64.into()),
1358 ChangePosition(1u64.into()).0.as_u64()
1359 );
1360 crate::change::LocalChange::make_change(
1361 txn,
1362 channel,
1363 vec![crate::change::Hunk::AddRoot {
1364 name: Atom::NewVertex(NewVertex {
1365 up_context: vec![root],
1366 down_context: Vec::new(),
1367 start: ChangePosition(0u64.into()),
1368 end: ChangePosition(0u64.into()),
1369 flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,
1370 inode: root,
1371 }),
1372 inode: Atom::NewVertex(NewVertex {
1373 up_context: vec![Position {
1374 change: None,
1375 pos: ChangePosition(0u64.into()),
1376 }],
1377 down_context: Vec::new(),
1378 start: ChangePosition(1u64.into()),
1379 end: ChangePosition(1u64.into()),
1380 flag: EdgeFlags::FOLDER | EdgeFlags::BLOCK,
1381 inode: root,
1382 }),
1383 }],
1384 contents,
1385 crate::change::ChangeHeader::default(),
1386 Vec::new(),
1387 )?
1388 };
1389 let h = store
1390 .save_change(&mut change, |_, _| Ok(()))
1391 .map_err(ApplyError::Changestore)?;
1392 let (n, merkle) = apply_change(store, txn, &mut channel.write(), &h)?;
1393 Ok(Some((h, n, merkle)))
1394}