1use std::{
16 collections::{hash_map::Entry, HashMap, HashSet, VecDeque},
17 fmt, mem,
18};
19
20use crate::driver::{AbortSignal, DefaultAbortSignal, DefaultDriver, Driver};
21use crate::error::{ErrorKind, Result};
22use crate::guid::{Guid, IsValidGuid, TAGS_GUID};
23use crate::tree::{Content, MergeState, MergedNode, Node, Tree, Validity};
24
25#[derive(Eq, PartialEq)]
28enum StructureChange {
29 Unchanged,
31 Moved,
33 Deleted,
35}
36
37#[derive(Clone, Copy, Default, Debug, Eq, Hash, PartialEq)]
39pub struct StructureCounts {
40 pub remote_revives: usize,
42 pub local_deletes: usize,
44 pub local_revives: usize,
46 pub remote_deletes: usize,
48 pub dupes: usize,
50 pub merged_nodes: usize,
53}
54
55type MatchingDupes<'t> = (HashMap<Guid, Node<'t>>, HashMap<Guid, Node<'t>>);
58
59#[derive(Clone, Copy, Debug)]
61enum ConflictResolution {
62 Local,
63 Remote,
64 Unchanged,
65}
66
67#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
69enum DupeKey<'a> {
70 WithoutPosition(&'a Content),
73 WithPosition(&'a Content, usize),
75}
76
77pub struct Merger<'t, D = DefaultDriver, A = DefaultAbortSignal> {
100 driver: &'t D,
101 signal: &'t A,
102 local_tree: &'t Tree,
103 remote_tree: &'t Tree,
104 matching_dupes_by_local_parent_guid: HashMap<Guid, MatchingDupes<'t>>,
105 merged_guids: HashSet<Guid>,
106 delete_locally: HashSet<Guid>,
107 delete_remotely: HashSet<Guid>,
108 structure_counts: StructureCounts,
109}
110
111impl<'t> Merger<'t, DefaultDriver, DefaultAbortSignal> {
112 pub fn new(local_tree: &'t Tree, remote_tree: &'t Tree) -> Merger<'t> {
114 Merger {
115 driver: &DefaultDriver,
116 signal: &DefaultAbortSignal,
117 local_tree,
118 remote_tree,
119 matching_dupes_by_local_parent_guid: HashMap::new(),
120 merged_guids: HashSet::new(),
121 delete_locally: HashSet::new(),
122 delete_remotely: HashSet::new(),
123 structure_counts: StructureCounts::default(),
124 }
125 }
126}
127
128impl<'t, D: Driver, A: AbortSignal> Merger<'t, D, A> {
129 pub fn with_driver(
131 driver: &'t D,
132 signal: &'t A,
133 local_tree: &'t Tree,
134 remote_tree: &'t Tree,
135 ) -> Merger<'t, D, A> {
136 Merger {
137 driver,
138 signal,
139 local_tree,
140 remote_tree,
141 matching_dupes_by_local_parent_guid: HashMap::new(),
142 merged_guids: HashSet::new(),
143 delete_locally: HashSet::new(),
144 delete_remotely: HashSet::new(),
145 structure_counts: StructureCounts::default(),
146 }
147 }
148
149 pub fn merge(mut self) -> Result<MergedRoot<'t>> {
151 let merged_root_node = {
152 let local_root_node = self.local_tree.root();
153 let remote_root_node = self.remote_tree.root();
154 self.two_way_merge(local_root_node, remote_root_node)?
155 };
156
157 for guid in self.local_tree.deletions() {
162 self.signal.err_if_aborted()?;
163 if !self.mentions(guid) {
164 self.delete_remotely.insert(guid.clone());
165 }
166 }
167 for guid in self.remote_tree.deletions() {
168 self.signal.err_if_aborted()?;
169 if !self.mentions(guid) {
170 self.delete_locally.insert(guid.clone());
171 }
172 }
173
174 for guid in self.local_tree.guids() {
178 self.signal.err_if_aborted()?;
179 if !self.mentions(guid) {
180 return Err(ErrorKind::UnmergedLocalItems.into());
181 }
182 }
183 for guid in self.remote_tree.guids() {
184 self.signal.err_if_aborted()?;
185 if !self.mentions(guid) {
186 return Err(ErrorKind::UnmergedRemoteItems.into());
187 }
188 }
189
190 Ok(MergedRoot {
191 local_tree: self.local_tree,
192 remote_tree: self.remote_tree,
193 node: merged_root_node,
194 merged_guids: self.merged_guids,
195 delete_locally: self.delete_locally,
196 delete_remotely: self.delete_remotely,
197 structure_counts: self.structure_counts,
198 })
199 }
200
201 #[inline]
202 fn mentions(&self, guid: &Guid) -> bool {
203 self.merged_guids.contains(guid)
204 || self.delete_locally.contains(guid)
205 || self.delete_remotely.contains(guid)
206 }
207
208 fn merge_local_only_node(&mut self, local_node: Node<'t>) -> Result<MergedNode<'t>> {
209 trace!(self.driver, "Item {} only exists locally", local_node);
210
211 self.merged_guids.insert(local_node.guid.clone());
212
213 let merged_guid = if local_node.guid.is_valid_guid() {
214 local_node.guid.clone()
215 } else {
216 warn!(
217 self.driver,
218 "Generating new GUID for local node {}", local_node
219 );
220 self.signal.err_if_aborted()?;
221 let new_guid = self.driver.generate_new_guid(&local_node.guid)?;
222 if new_guid != local_node.guid {
223 if self.merged_guids.contains(&new_guid) {
224 return Err(ErrorKind::DuplicateItem(new_guid).into());
225 }
226 self.merged_guids.insert(new_guid.clone());
227 }
228 new_guid
229 };
230
231 let mut merged_node = MergedNode::new(merged_guid, MergeState::LocalOnly(local_node));
232 for local_child_node in local_node.children() {
237 self.signal.err_if_aborted()?;
238 self.merge_local_child_into_merged_node(
239 &mut merged_node,
240 local_node,
241 None,
242 local_child_node,
243 )?;
244 }
245
246 if local_node.diverged() {
247 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
248 }
249
250 Ok(merged_node)
251 }
252
253 fn merge_remote_only_node(&mut self, remote_node: Node<'t>) -> Result<MergedNode<'t>> {
254 trace!(self.driver, "Item {} only exists remotely", remote_node);
255
256 self.merged_guids.insert(remote_node.guid.clone());
257
258 let merged_guid = if remote_node.guid.is_valid_guid() {
259 remote_node.guid.clone()
260 } else {
261 warn!(
262 self.driver,
263 "Generating new GUID for remote node {}", remote_node
264 );
265 self.signal.err_if_aborted()?;
266 let new_guid = self.driver.generate_new_guid(&remote_node.guid)?;
267 if new_guid != remote_node.guid {
268 if self.merged_guids.contains(&new_guid) {
269 return Err(ErrorKind::DuplicateItem(new_guid).into());
270 }
271 self.merged_guids.insert(new_guid.clone());
272 self.delete_remotely.insert(remote_node.guid.clone());
274 }
275 new_guid
276 };
277 let mut merged_node = MergedNode::new(merged_guid, MergeState::RemoteOnly(remote_node));
278 for remote_child_node in remote_node.children() {
282 self.signal.err_if_aborted()?;
283 self.merge_remote_child_into_merged_node(
284 &mut merged_node,
285 None,
286 remote_node,
287 remote_child_node,
288 )?;
289 }
290
291 if remote_node.diverged()
292 || merged_node.remote_guid_changed()
293 || remote_node.validity != Validity::Valid
294 {
295 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
298 }
299
300 Ok(merged_node)
301 }
302
303 fn two_way_merge(
305 &mut self,
306 local_node: Node<'t>,
307 remote_node: Node<'t>,
308 ) -> Result<MergedNode<'t>> {
309 trace!(
310 self.driver,
311 "Item exists locally as {} and remotely as {}",
312 local_node,
313 remote_node
314 );
315
316 if !local_node.has_compatible_kind(&remote_node) {
317 error!(
318 self.driver,
319 "Merging local {} and remote {} with different kinds", local_node, remote_node
320 );
321 return Err(ErrorKind::MismatchedItemKind(
322 local_node.item().clone(),
323 remote_node.item().clone(),
324 )
325 .into());
326 }
327
328 self.merged_guids.insert(local_node.guid.clone());
329 self.merged_guids.insert(remote_node.guid.clone());
330
331 let merged_guid = if remote_node.guid.is_valid_guid() {
332 remote_node.guid.clone()
333 } else {
334 warn!(
335 self.driver,
336 "Generating new valid GUID for node {}", remote_node
337 );
338 self.signal.err_if_aborted()?;
339 let new_guid = self.driver.generate_new_guid(&remote_node.guid)?;
340 if new_guid != remote_node.guid {
341 if self.merged_guids.contains(&new_guid) {
342 return Err(ErrorKind::DuplicateItem(new_guid).into());
343 }
344 self.merged_guids.insert(new_guid.clone());
345 self.delete_remotely.insert(remote_node.guid.clone());
347 }
348 new_guid
349 };
350
351 let (item, children) = self.resolve_value_conflict(local_node, remote_node);
352
353 let mut merged_node = MergedNode::new(
354 merged_guid,
355 match item {
356 ConflictResolution::Local => MergeState::Local {
357 local_node,
358 remote_node,
359 },
360 ConflictResolution::Remote => MergeState::Remote {
361 local_node,
362 remote_node,
363 },
364 ConflictResolution::Unchanged => MergeState::Unchanged {
365 local_node,
366 remote_node,
367 },
368 },
369 );
370
371 match children {
372 ConflictResolution::Local => {
373 for local_child_node in local_node.children() {
374 self.signal.err_if_aborted()?;
375 self.merge_local_child_into_merged_node(
376 &mut merged_node,
377 local_node,
378 Some(remote_node),
379 local_child_node,
380 )?;
381 }
382 for remote_child_node in remote_node.children() {
383 self.signal.err_if_aborted()?;
384 self.merge_remote_child_into_merged_node(
385 &mut merged_node,
386 Some(local_node),
387 remote_node,
388 remote_child_node,
389 )?;
390 }
391 }
392
393 ConflictResolution::Remote => {
394 for remote_child_node in remote_node.children() {
395 self.signal.err_if_aborted()?;
396 self.merge_remote_child_into_merged_node(
397 &mut merged_node,
398 Some(local_node),
399 remote_node,
400 remote_child_node,
401 )?;
402 }
403 for local_child_node in local_node.children() {
404 self.signal.err_if_aborted()?;
405 self.merge_local_child_into_merged_node(
406 &mut merged_node,
407 local_node,
408 Some(remote_node),
409 local_child_node,
410 )?;
411 }
412 }
413
414 ConflictResolution::Unchanged => {
415 for (local_child_node, remote_child_node) in
417 local_node.children().zip(remote_node.children())
418 {
419 self.signal.err_if_aborted()?;
420 self.merge_unchanged_child_into_merged_node(
421 &mut merged_node,
422 local_node,
423 local_child_node,
424 remote_node,
425 remote_child_node,
426 )?;
427 }
428 }
429 }
430
431 if local_node.diverged() {
432 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
433 }
434
435 if remote_node.diverged() || remote_node.validity != Validity::Valid {
436 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
438 }
439
440 Ok(merged_node)
441 }
442
443 fn merge_unchanged_child_into_merged_node(
448 &mut self,
449 merged_node: &mut MergedNode<'t>,
450 local_parent_node: Node<'t>,
451 local_child_node: Node<'t>,
452 remote_parent_node: Node<'t>,
453 remote_child_node: Node<'t>,
454 ) -> Result<()> {
455 assert!(
456 !self.merged_guids.contains(&local_child_node.guid),
457 "Unchanged local child shouldn't have been merged"
458 );
459 assert!(
460 !self.merged_guids.contains(&remote_child_node.guid),
461 "Unchanged remote child shouldn't have been merged"
462 );
463
464 let local_structure_change = self.check_for_local_structure_change_of_remote_node(
468 merged_node,
469 remote_parent_node,
470 remote_child_node,
471 )?;
472 let remote_structure_change = self.check_for_remote_structure_change_of_local_node(
473 merged_node,
474 local_parent_node,
475 local_child_node,
476 )?;
477 match (local_structure_change, remote_structure_change) {
478 (StructureChange::Deleted, StructureChange::Deleted) => {
479 merged_node.merge_state = merged_node
482 .merge_state
483 .with_new_local_structure()
484 .with_new_remote_structure();
485 }
486 (StructureChange::Deleted, _) => {
487 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
490 }
491 (_, StructureChange::Deleted) => {
492 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
495 }
496 (_, _) => {
497 let mut merged_child_node =
501 self.two_way_merge(local_child_node, remote_child_node)?;
502 if merged_child_node.local_guid_changed() {
503 merged_child_node.merge_state =
504 merged_child_node.merge_state.with_new_local_structure();
505 }
506 if merged_node.remote_guid_changed() {
507 merged_child_node.merge_state =
510 merged_child_node.merge_state.with_new_remote_structure();
511 }
512 if merged_child_node.remote_guid_changed() {
513 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
516 }
517 merged_node.merged_children.push(merged_child_node);
518 self.structure_counts.merged_nodes += 1;
519 }
520 }
521
522 Ok(())
523 }
524
525 fn merge_remote_child_into_merged_node(
540 &mut self,
541 merged_node: &mut MergedNode<'t>,
542 local_parent_node: Option<Node<'t>>,
543 remote_parent_node: Node<'t>,
544 remote_child_node: Node<'t>,
545 ) -> Result<()> {
546 if self.merged_guids.contains(&remote_child_node.guid) {
547 trace!(
548 self.driver,
549 "Remote child {} already seen in another folder and merged",
550 remote_child_node
551 );
552 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
555 return Ok(());
556 }
557
558 trace!(
559 self.driver,
560 "Merging remote child {} of {} into {}",
561 remote_child_node,
562 remote_parent_node,
563 merged_node
564 );
565
566 if self.check_for_local_structure_change_of_remote_node(
573 merged_node,
574 remote_parent_node,
575 remote_child_node,
576 )? == StructureChange::Deleted
577 {
578 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
581 return Ok(());
582 }
583
584 if let Some(local_child_node) = self.local_tree.node_for_guid(&remote_child_node.guid) {
586 let local_parent_node = local_child_node
588 .parent()
589 .expect("Can't merge existing remote child without local parent");
590
591 trace!(
592 self.driver,
593 "Remote child {} exists locally in {} and remotely in {}",
594 remote_child_node,
595 local_parent_node,
596 remote_parent_node
597 );
598
599 if self.remote_tree.is_deleted(&local_parent_node.guid) {
600 trace!(
601 self.driver,
602 "Unconditionally taking remote move for {} to {} because local parent {} is \
603 deleted remotely",
604 remote_child_node,
605 remote_parent_node,
606 local_parent_node
607 );
608
609 let mut merged_child_node =
610 self.two_way_merge(local_child_node, remote_child_node)?;
611 merged_child_node.merge_state =
612 merged_child_node.merge_state.with_new_local_structure();
613 if merged_node.remote_guid_changed() {
614 merged_child_node.merge_state =
617 merged_child_node.merge_state.with_new_remote_structure();
618 }
619 if merged_child_node.remote_guid_changed() {
620 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
623 }
624 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
625 merged_node.merged_children.push(merged_child_node);
626 self.structure_counts.merged_nodes += 1;
627 return Ok(());
628 }
629
630 match self.resolve_structure_conflict(
631 local_parent_node,
632 local_child_node,
633 remote_parent_node,
634 remote_child_node,
635 ) {
636 ConflictResolution::Local => {
637 trace!(
641 self.driver,
642 "Remote child {} moved locally to {} and remotely to {}; \
643 keeping child in newer local parent and position",
644 remote_child_node,
645 local_parent_node,
646 remote_parent_node
647 );
648
649 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
654 }
655
656 ConflictResolution::Remote | ConflictResolution::Unchanged => {
657 let mut merged_child_node = if local_parent_node.guid != remote_parent_node.guid
660 {
661 trace!(
662 self.driver,
663 "Remote child {} reparented locally to {} and remotely to {}; \
664 keeping child in newer remote parent",
665 remote_child_node,
666 local_parent_node,
667 remote_parent_node
668 );
669 let mut merged_child_node =
670 self.two_way_merge(local_child_node, remote_child_node)?;
671 merged_child_node.merge_state =
672 merged_child_node.merge_state.with_new_local_structure();
673 merged_child_node
674 } else {
675 trace!(
676 self.driver,
677 "Remote child {} repositioned locally in {} and remotely in {}; \
678 keeping child in newer remote position",
679 remote_child_node,
680 local_parent_node,
681 remote_parent_node
682 );
683 self.two_way_merge(local_child_node, remote_child_node)?
684 };
685 if merged_child_node.local_guid_changed() {
686 merged_child_node.merge_state =
687 merged_child_node.merge_state.with_new_local_structure();
688 }
689 if merged_node.remote_guid_changed() {
690 merged_child_node.merge_state =
693 merged_child_node.merge_state.with_new_remote_structure();
694 }
695 if merged_child_node.remote_guid_changed() {
696 merged_node.merge_state =
699 merged_node.merge_state.with_new_remote_structure();
700 }
701 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
702 merged_node.merged_children.push(merged_child_node);
703 self.structure_counts.merged_nodes += 1;
704 }
705 }
706
707 return Ok(());
708 }
709
710 trace!(
714 self.driver,
715 "Remote child {} doesn't exist locally; looking for local content match",
716 remote_child_node
717 );
718
719 let mut merged_child_node = if let Some(local_child_node_by_content) = self
720 .find_local_node_matching_remote_node(
721 merged_node,
722 local_parent_node,
723 remote_parent_node,
724 remote_child_node,
725 )? {
726 self.two_way_merge(local_child_node_by_content, remote_child_node)
727 } else {
728 self.merge_remote_only_node(remote_child_node)
729 }?;
730 if merged_child_node.local_guid_changed() {
731 merged_child_node.merge_state =
732 merged_child_node.merge_state.with_new_local_structure();
733 }
734 if merged_node.remote_guid_changed() {
735 merged_child_node.merge_state =
736 merged_child_node.merge_state.with_new_remote_structure();
737 }
738 if merged_child_node.remote_guid_changed() {
739 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
740 }
741 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
742 merged_node.merged_children.push(merged_child_node);
743 self.structure_counts.merged_nodes += 1;
744 Ok(())
745 }
746
747 fn merge_local_child_into_merged_node(
751 &mut self,
752 merged_node: &mut MergedNode<'t>,
753 local_parent_node: Node<'t>,
754 remote_parent_node: Option<Node<'t>>,
755 local_child_node: Node<'t>,
756 ) -> Result<()> {
757 if self.merged_guids.contains(&local_child_node.guid) {
758 trace!(
762 self.driver,
763 "Local child {} already seen in another folder and merged",
764 local_child_node
765 );
766 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
767 return Ok(());
768 }
769
770 trace!(
771 self.driver,
772 "Merging local child {} of {} into {}",
773 local_child_node,
774 local_parent_node,
775 merged_node
776 );
777
778 if self.check_for_remote_structure_change_of_local_node(
781 merged_node,
782 local_parent_node,
783 local_child_node,
784 )? == StructureChange::Deleted
785 {
786 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
789 return Ok(());
790 }
791
792 if let Some(remote_child_node) = self.remote_tree.node_for_guid(&local_child_node.guid) {
795 let remote_parent_node = remote_child_node
798 .parent()
799 .expect("Can't merge existing local child without remote parent");
800
801 trace!(
802 self.driver,
803 "Local child {} exists locally in {} and remotely in {}",
804 local_child_node,
805 local_parent_node,
806 remote_parent_node
807 );
808
809 if self.local_tree.is_deleted(&remote_parent_node.guid) {
810 trace!(
811 self.driver,
812 "Unconditionally taking local move for {} to {} because remote parent {} is \
813 deleted locally",
814 local_child_node,
815 local_parent_node,
816 remote_parent_node
817 );
818
819 let mut merged_child_node =
829 self.two_way_merge(local_child_node, remote_child_node)?;
830 if merged_child_node.local_guid_changed() {
831 merged_child_node.merge_state =
832 merged_child_node.merge_state.with_new_local_structure();
833 }
834 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
835 merged_child_node.merge_state =
836 merged_child_node.merge_state.with_new_remote_structure();
837 merged_node.merged_children.push(merged_child_node);
838 self.structure_counts.merged_nodes += 1;
839 return Ok(());
840 }
841
842 match self.resolve_structure_conflict(
843 local_parent_node,
844 local_child_node,
845 remote_parent_node,
846 remote_child_node,
847 ) {
848 ConflictResolution::Local => {
849 if local_parent_node.guid != remote_parent_node.guid {
852 trace!(
854 self.driver,
855 "Local child {} reparented locally to {} and remotely to {}; \
856 keeping child in newer local parent",
857 local_child_node,
858 local_parent_node,
859 remote_parent_node
860 );
861
862 let mut merged_child_node =
865 self.two_way_merge(local_child_node, remote_child_node)?;
866 if merged_child_node.local_guid_changed() {
867 merged_child_node.merge_state =
868 merged_child_node.merge_state.with_new_local_structure();
869 }
870 merged_node.merge_state =
871 merged_node.merge_state.with_new_remote_structure();
872 merged_child_node.merge_state =
873 merged_child_node.merge_state.with_new_remote_structure();
874 merged_node.merged_children.push(merged_child_node);
875 self.structure_counts.merged_nodes += 1;
876 } else {
877 trace!(
878 self.driver,
879 "Local child {} repositioned locally in {} and remotely in {}; \
880 keeping child in newer local position",
881 local_child_node,
882 local_parent_node,
883 remote_parent_node
884 );
885
886 let mut merged_child_node =
889 self.two_way_merge(local_child_node, remote_child_node)?;
890 if merged_child_node.local_guid_changed() {
891 merged_child_node.merge_state =
892 merged_child_node.merge_state.with_new_local_structure();
893 }
894 merged_node.merge_state =
895 merged_node.merge_state.with_new_remote_structure();
896 if merged_node.remote_guid_changed() {
897 merged_child_node.merge_state =
902 merged_child_node.merge_state.with_new_remote_structure();
903 }
904
905 merged_node.merged_children.push(merged_child_node);
906 self.structure_counts.merged_nodes += 1;
907 }
908 }
909
910 ConflictResolution::Remote | ConflictResolution::Unchanged => {
911 if local_parent_node.guid != remote_parent_node.guid {
915 trace!(
916 self.driver,
917 "Local child {} reparented locally to {} and remotely to {}; \
918 keeping child in newer remote parent",
919 local_child_node,
920 local_parent_node,
921 remote_parent_node
922 );
923 } else {
924 trace!(
925 self.driver,
926 "Local child {} repositioned locally in {} and remotely in {}; \
927 keeping child in newer remote position",
928 local_child_node,
929 local_parent_node,
930 remote_parent_node
931 );
932 }
933 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
934 }
935 }
936
937 return Ok(());
938 }
939
940 trace!(
944 self.driver,
945 "Local child {} doesn't exist remotely; looking for remote content match",
946 local_child_node
947 );
948
949 let merged_child_node = if let Some(remote_child_node_by_content) = self
950 .find_remote_node_matching_local_node(
951 merged_node,
952 local_parent_node,
953 remote_parent_node,
954 local_child_node,
955 )? {
956 let mut merged_child_node =
959 self.two_way_merge(local_child_node, remote_child_node_by_content)?;
960 if merged_child_node.local_guid_changed() {
961 merged_child_node.merge_state =
962 merged_child_node.merge_state.with_new_local_structure();
963 }
964 if merged_node.remote_guid_changed() {
965 merged_child_node.merge_state =
966 merged_child_node.merge_state.with_new_remote_structure();
967 }
968 if merged_child_node.remote_guid_changed() {
969 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
970 }
971 merged_node.merge_state = merged_node.merge_state.with_new_local_structure();
972 merged_child_node
973 } else {
974 let mut merged_child_node = self.merge_local_only_node(local_child_node)?;
977 if merged_child_node.local_guid_changed() {
978 merged_child_node.merge_state =
979 merged_child_node.merge_state.with_new_local_structure();
980 }
981 merged_node.merge_state = merged_node.merge_state.with_new_remote_structure();
982 merged_child_node.merge_state =
983 merged_child_node.merge_state.with_new_remote_structure();
984 merged_child_node
985 };
986 merged_node.merged_children.push(merged_child_node);
987 self.structure_counts.merged_nodes += 1;
988 Ok(())
989 }
990
991 fn resolve_value_conflict(
994 &self,
995 local_node: Node<'t>,
996 remote_node: Node<'t>,
997 ) -> (ConflictResolution, ConflictResolution) {
998 if remote_node.is_root() {
999 return (ConflictResolution::Unchanged, ConflictResolution::Local);
1001 }
1002
1003 match (local_node.needs_merge, remote_node.needs_merge) {
1004 (true, true) => {
1005 let item = if local_node.is_built_in_root() {
1007 ConflictResolution::Local
1010 } else {
1011 match (local_node.validity, remote_node.validity) {
1014 (Validity::Replace, Validity::Replace) => ConflictResolution::Unchanged,
1017 (Validity::Replace, _) => ConflictResolution::Remote,
1021 (_, Validity::Replace) => ConflictResolution::Local,
1022 (_, _) => {
1023 if local_node.age < remote_node.age {
1027 ConflictResolution::Local
1028 } else {
1029 ConflictResolution::Remote
1030 }
1031 }
1032 }
1033 };
1034 let children = if local_node.has_matching_children(remote_node) {
1037 ConflictResolution::Unchanged
1038 } else if local_node.age < remote_node.age {
1039 ConflictResolution::Local
1042 } else {
1043 ConflictResolution::Remote
1046 };
1047 (item, children)
1048 }
1049
1050 (true, false) => {
1051 let item = match local_node.validity {
1055 Validity::Valid | Validity::Reupload => ConflictResolution::Local,
1056 Validity::Replace => ConflictResolution::Remote,
1057 };
1058 let children = if local_node.has_matching_children(remote_node) {
1059 ConflictResolution::Unchanged
1060 } else {
1061 ConflictResolution::Local
1062 };
1063 (item, children)
1064 }
1065
1066 (false, true) => {
1067 let item = if local_node.is_built_in_root() {
1069 ConflictResolution::Unchanged
1071 } else {
1072 match remote_node.validity {
1073 Validity::Valid | Validity::Reupload => ConflictResolution::Remote,
1074 Validity::Replace => ConflictResolution::Local,
1078 }
1079 };
1080 let children = if local_node.has_matching_children(remote_node) {
1081 ConflictResolution::Unchanged
1082 } else {
1083 ConflictResolution::Remote
1084 };
1085 (item, children)
1087 }
1088
1089 (false, false) => {
1090 let item = match (local_node.validity, remote_node.validity) {
1091 (Validity::Replace, Validity::Replace) => ConflictResolution::Unchanged,
1092 (_, Validity::Replace) => ConflictResolution::Local,
1093 (Validity::Replace, _) => ConflictResolution::Remote,
1094 (_, _) => ConflictResolution::Unchanged,
1095 };
1096 let children = if local_node.has_matching_children(remote_node) {
1100 ConflictResolution::Unchanged
1101 } else if local_node.age < remote_node.age {
1102 ConflictResolution::Local
1103 } else {
1104 ConflictResolution::Remote
1105 };
1106 (item, children)
1107 }
1108 }
1109 }
1110
1111 fn resolve_structure_conflict(
1113 &self,
1114 local_parent_node: Node<'t>,
1115 local_child_node: Node<'t>,
1116 remote_parent_node: Node<'t>,
1117 remote_child_node: Node<'t>,
1118 ) -> ConflictResolution {
1119 if remote_child_node.is_built_in_root() {
1120 return ConflictResolution::Local;
1122 }
1123
1124 match (
1125 local_parent_node.needs_merge,
1126 remote_parent_node.needs_merge,
1127 ) {
1128 (true, true) => {
1129 let latest_local_age = local_child_node.age.min(local_parent_node.age);
1132 let latest_remote_age = remote_child_node.age.min(remote_parent_node.age);
1133
1134 if latest_local_age < latest_remote_age {
1135 ConflictResolution::Local
1136 } else {
1137 ConflictResolution::Remote
1138 }
1139 }
1140
1141 (true, false) => ConflictResolution::Local,
1144 (false, true) => ConflictResolution::Remote,
1145
1146 (false, false) => ConflictResolution::Unchanged,
1147 }
1148 }
1149
1150 fn check_for_local_structure_change_of_remote_node(
1156 &mut self,
1157 merged_node: &mut MergedNode<'t>,
1158 remote_parent_node: Node<'t>,
1159 remote_node: Node<'t>,
1160 ) -> Result<StructureChange> {
1161 if !remote_node.is_syncable() {
1162 trace!(
1165 self.driver,
1166 "Deleting non-syncable remote node {}",
1167 remote_node
1168 );
1169 return self.delete_remote_node(merged_node, remote_node);
1170 }
1171
1172 if !self.local_tree.is_deleted(&remote_node.guid) {
1173 if let Some(local_node) = self.local_tree.node_for_guid(&remote_node.guid) {
1174 if !local_node.is_syncable() {
1175 trace!(
1178 self.driver,
1179 "Remote node {} is syncable, but local node {} isn't; deleting",
1180 remote_node,
1181 local_node
1182 );
1183 return self.delete_remote_node(merged_node, remote_node);
1184 }
1185 if local_node.validity == Validity::Replace
1186 && remote_node.validity == Validity::Replace
1187 {
1188 return self.delete_remote_node(merged_node, remote_node);
1191 }
1192 let local_parent_node = local_node
1193 .parent()
1194 .expect("Can't check for structure changes without local parent");
1195 if local_parent_node.guid != remote_parent_node.guid {
1196 return Ok(StructureChange::Moved);
1197 }
1198 return Ok(StructureChange::Unchanged);
1199 }
1200 if remote_node.validity == Validity::Replace {
1201 return self.delete_remote_node(merged_node, remote_node);
1204 }
1205 return Ok(StructureChange::Unchanged);
1206 }
1207
1208 if remote_node.validity == Validity::Replace {
1209 return self.delete_remote_node(merged_node, remote_node);
1212 }
1213
1214 if remote_node.is_built_in_root() {
1215 return Ok(StructureChange::Unchanged);
1217 }
1218
1219 if remote_node.needs_merge {
1220 if !remote_node.is_folder() {
1221 trace!(
1224 self.driver,
1225 "Remote non-folder {} deleted locally and changed remotely; \
1226 taking remote change",
1227 remote_node
1228 );
1229 self.structure_counts.remote_revives += 1;
1230 return Ok(StructureChange::Unchanged);
1231 }
1232 trace!(
1237 self.driver,
1238 "Remote folder {} deleted locally and changed remotely; \
1239 taking local deletion",
1240 remote_node
1241 );
1242 self.structure_counts.local_deletes += 1;
1243 } else {
1244 trace!(
1245 self.driver,
1246 "Remote node {} deleted locally and not changed remotely; \
1247 taking local deletion",
1248 remote_node
1249 );
1250 }
1251
1252 self.delete_remote_node(merged_node, remote_node)
1255 }
1256
1257 fn check_for_remote_structure_change_of_local_node(
1263 &mut self,
1264 merged_node: &mut MergedNode<'t>,
1265 local_parent_node: Node<'t>,
1266 local_node: Node<'t>,
1267 ) -> Result<StructureChange> {
1268 if !local_node.is_syncable() {
1269 trace!(
1272 self.driver,
1273 "Deleting non-syncable local node {}",
1274 local_node
1275 );
1276 return self.delete_local_node(merged_node, local_node);
1277 }
1278
1279 if !self.remote_tree.is_deleted(&local_node.guid) {
1280 if let Some(remote_node) = self.remote_tree.node_for_guid(&local_node.guid) {
1281 if !remote_node.is_syncable() {
1282 trace!(
1288 self.driver,
1289 "Local node {} is syncable, but remote node {} isn't; deleting",
1290 local_node,
1291 remote_node
1292 );
1293 return self.delete_local_node(merged_node, local_node);
1294 }
1295 if remote_node.validity == Validity::Replace
1296 && local_node.validity == Validity::Replace
1297 {
1298 return self.delete_local_node(merged_node, local_node);
1301 }
1302 let remote_parent_node = remote_node
1306 .parent()
1307 .expect("Can't check for structure changes without remote parent");
1308 if remote_parent_node.guid != local_parent_node.guid {
1309 return Ok(StructureChange::Moved);
1310 }
1311 return Ok(StructureChange::Unchanged);
1312 }
1313 if local_node.validity == Validity::Replace {
1314 return self.delete_local_node(merged_node, local_node);
1317 }
1318 return Ok(StructureChange::Unchanged);
1319 }
1320
1321 if local_node.validity == Validity::Replace {
1322 return self.delete_local_node(merged_node, local_node);
1325 }
1326
1327 if local_node.is_built_in_root() {
1328 return Ok(StructureChange::Unchanged);
1330 }
1331
1332 if local_node.needs_merge {
1335 if !local_node.is_folder() {
1336 trace!(
1337 self.driver,
1338 "Local non-folder {} deleted remotely and changed locally; taking local change",
1339 local_node
1340 );
1341 self.structure_counts.local_revives += 1;
1342 return Ok(StructureChange::Unchanged);
1343 }
1344 trace!(
1345 self.driver,
1346 "Local folder {} deleted remotely and changed locally; taking remote deletion",
1347 local_node
1348 );
1349 self.structure_counts.remote_deletes += 1;
1350 } else {
1351 trace!(
1352 self.driver,
1353 "Local node {} deleted remotely and not changed locally; taking remote deletion",
1354 local_node
1355 );
1356 }
1357
1358 self.delete_local_node(merged_node, local_node)
1361 }
1362
1363 fn delete_remote_node(
1370 &mut self,
1371 merged_node: &mut MergedNode<'t>,
1372 remote_node: Node<'t>,
1373 ) -> Result<StructureChange> {
1374 self.delete_remotely.insert(remote_node.guid.clone());
1375 for remote_child_node in remote_node.children() {
1376 self.signal.err_if_aborted()?;
1377 if self.merged_guids.contains(&remote_child_node.guid) {
1378 trace!(
1379 self.driver,
1380 "Remote child {} can't be an orphan; already merged",
1381 remote_child_node
1382 );
1383 continue;
1384 }
1385 match self.check_for_local_structure_change_of_remote_node(
1386 merged_node,
1387 remote_node,
1388 remote_child_node,
1389 )? {
1390 StructureChange::Moved | StructureChange::Deleted => {
1391 continue;
1394 }
1395 StructureChange::Unchanged => {
1396 trace!(
1397 self.driver,
1398 "Relocating remote orphan {} to {}",
1399 remote_child_node,
1400 merged_node
1401 );
1402
1403 let mut merged_orphan_node = if let Some(local_child_node) =
1405 self.local_tree.node_for_guid(&remote_child_node.guid)
1406 {
1407 self.two_way_merge(local_child_node, remote_child_node)
1408 } else {
1409 self.merge_remote_only_node(remote_child_node)
1410 }?;
1411 merged_node.merge_state = merged_node
1412 .merge_state
1413 .with_new_local_structure()
1414 .with_new_remote_structure();
1415 merged_orphan_node.merge_state = merged_orphan_node
1416 .merge_state
1417 .with_new_local_structure()
1418 .with_new_remote_structure();
1419 merged_node.merged_children.push(merged_orphan_node);
1420 self.structure_counts.merged_nodes += 1;
1421 }
1422 }
1423 }
1424 Ok(StructureChange::Deleted)
1425 }
1426
1427 fn delete_local_node(
1432 &mut self,
1433 merged_node: &mut MergedNode<'t>,
1434 local_node: Node<'t>,
1435 ) -> Result<StructureChange> {
1436 self.delete_locally.insert(local_node.guid.clone());
1437 for local_child_node in local_node.children() {
1438 self.signal.err_if_aborted()?;
1439 if self.merged_guids.contains(&local_child_node.guid) {
1440 trace!(
1441 self.driver,
1442 "Local child {} can't be an orphan; already merged",
1443 local_child_node
1444 );
1445 continue;
1446 }
1447 match self.check_for_remote_structure_change_of_local_node(
1448 merged_node,
1449 local_node,
1450 local_child_node,
1451 )? {
1452 StructureChange::Moved | StructureChange::Deleted => {
1453 continue;
1456 }
1457 StructureChange::Unchanged => {
1458 trace!(
1459 self.driver,
1460 "Relocating local orphan {} to {}",
1461 local_child_node,
1462 merged_node
1463 );
1464
1465 let mut merged_orphan_node = if let Some(remote_child_node) =
1467 self.remote_tree.node_for_guid(&local_child_node.guid)
1468 {
1469 self.two_way_merge(local_child_node, remote_child_node)
1470 } else {
1471 self.merge_local_only_node(local_child_node)
1472 }?;
1473 merged_node.merge_state = merged_node
1474 .merge_state
1475 .with_new_local_structure()
1476 .with_new_remote_structure();
1477 merged_orphan_node.merge_state = merged_orphan_node
1478 .merge_state
1479 .with_new_local_structure()
1480 .with_new_remote_structure();
1481 merged_node.merged_children.push(merged_orphan_node);
1482 self.structure_counts.merged_nodes += 1;
1483 }
1484 }
1485 }
1486 Ok(StructureChange::Deleted)
1487 }
1488
1489 fn find_all_matching_dupes_in_folders(
1510 &self,
1511 local_parent_node: Node<'t>,
1512 remote_parent_node: Node<'t>,
1513 ) -> Result<MatchingDupes<'t>> {
1514 let mut dupe_key_to_local_nodes: HashMap<DupeKey<'_>, VecDeque<_>> = HashMap::new();
1515
1516 for (local_position, local_child_node) in local_parent_node.children().enumerate() {
1517 self.signal.err_if_aborted()?;
1518 if local_child_node.is_built_in_root() {
1519 trace!(
1520 self.driver,
1521 "Not deduping local built-in root {}",
1522 local_child_node
1523 );
1524 continue;
1525 }
1526 if self.remote_tree.mentions(&local_child_node.guid) {
1527 trace!(
1528 self.driver,
1529 "Not deduping local child {}; already deleted or exists remotely",
1530 local_child_node
1531 );
1532 continue;
1533 }
1534 match local_child_node.content() {
1535 Some(local_child_content) => {
1536 let dupe_key = match local_child_content {
1540 Content::Bookmark { .. } | Content::Folder { .. } => {
1541 DupeKey::WithoutPosition(local_child_content)
1542 }
1543 Content::Separator => {
1544 DupeKey::WithPosition(local_child_content, local_position)
1545 }
1546 };
1547 let local_nodes_for_key = dupe_key_to_local_nodes.entry(dupe_key).or_default();
1548 local_nodes_for_key.push_back(local_child_node);
1549 }
1550 None => {
1551 trace!(
1552 self.driver,
1553 "Not deduping local child {} without content info",
1554 local_child_node
1555 );
1556 }
1557 }
1558 }
1559
1560 let mut local_to_remote = HashMap::new();
1561 let mut remote_to_local = HashMap::new();
1562
1563 for (remote_position, remote_child_node) in remote_parent_node.children().enumerate() {
1564 self.signal.err_if_aborted()?;
1565 if remote_child_node.is_built_in_root() {
1566 trace!(
1567 self.driver,
1568 "Not deduping remote built-in root {}",
1569 remote_child_node
1570 );
1571 continue;
1572 }
1573 if self.local_tree.mentions(&remote_child_node.guid) {
1574 trace!(
1575 self.driver,
1576 "Not deduping remote child {}; already deleted or exists locally",
1577 remote_child_node
1578 );
1579 continue;
1580 }
1581 if remote_to_local.contains_key(&remote_child_node.guid) {
1582 trace!(
1583 self.driver,
1584 "Not deduping remote child {}; already deduped",
1585 remote_child_node
1586 );
1587 continue;
1588 }
1589 match remote_child_node.content() {
1593 Some(remote_child_content) => {
1594 let dupe_key = match remote_child_content {
1595 Content::Bookmark { .. } | Content::Folder { .. } => {
1596 DupeKey::WithoutPosition(remote_child_content)
1597 }
1598 Content::Separator => {
1599 DupeKey::WithPosition(remote_child_content, remote_position)
1600 }
1601 };
1602 if let Some(local_nodes_for_key) = dupe_key_to_local_nodes.get_mut(&dupe_key) {
1603 if let Some(local_child_node) = local_nodes_for_key.pop_front() {
1604 trace!(
1605 self.driver,
1606 "Deduping local child {} to remote child {}",
1607 local_child_node,
1608 remote_child_node
1609 );
1610 local_to_remote
1611 .insert(local_child_node.guid.clone(), remote_child_node);
1612 remote_to_local
1613 .insert(remote_child_node.guid.clone(), local_child_node);
1614 } else {
1615 trace!(
1616 self.driver,
1617 "Not deduping remote child {}; no remaining local content matches",
1618 remote_child_node
1619 );
1620 continue;
1621 }
1622 } else {
1623 trace!(
1624 self.driver,
1625 "Not deduping remote child {}; no local content matches",
1626 remote_child_node
1627 );
1628 continue;
1629 }
1630 }
1631 None => {
1632 trace!(
1633 self.driver,
1634 "Not deduping remote child {} without content info",
1635 remote_child_node
1636 );
1637 }
1638 }
1639 }
1640
1641 Ok((local_to_remote, remote_to_local))
1642 }
1643
1644 fn find_remote_node_matching_local_node(
1649 &mut self,
1650 merged_node: &MergedNode<'t>,
1651 local_parent_node: Node<'t>,
1652 remote_parent_node: Option<Node<'t>>,
1653 local_child_node: Node<'t>,
1654 ) -> Result<Option<Node<'t>>> {
1655 if let Some(remote_parent_node) = remote_parent_node {
1656 let mut matching_dupes_by_local_parent_guid = mem::replace(
1657 &mut self.matching_dupes_by_local_parent_guid,
1658 HashMap::new(),
1659 );
1660 let new_remote_node = {
1661 let (local_to_remote, _) = match matching_dupes_by_local_parent_guid
1662 .entry(local_parent_node.guid.clone())
1663 {
1664 Entry::Occupied(entry) => entry.into_mut(),
1665 Entry::Vacant(entry) => {
1666 trace!(
1667 self.driver,
1668 "First local child {} doesn't exist remotely; \
1669 finding all matching dupes in local {} and remote {}",
1670 local_child_node,
1671 local_parent_node,
1672 remote_parent_node
1673 );
1674 let matching_dupes = self.find_all_matching_dupes_in_folders(
1675 local_parent_node,
1676 remote_parent_node,
1677 )?;
1678 entry.insert(matching_dupes)
1679 }
1680 };
1681 let new_remote_node = local_to_remote.get(&local_child_node.guid);
1682 new_remote_node.map(|node| {
1683 self.structure_counts.dupes += 1;
1684 *node
1685 })
1686 };
1687 self.matching_dupes_by_local_parent_guid = matching_dupes_by_local_parent_guid;
1688 Ok(new_remote_node)
1689 } else {
1690 trace!(
1691 self.driver,
1692 "Merged node {} doesn't exist remotely; no potential dupes for local child {}",
1693 merged_node,
1694 local_child_node
1695 );
1696 Ok(None)
1697 }
1698 }
1699
1700 fn find_local_node_matching_remote_node(
1705 &mut self,
1706 merged_node: &MergedNode<'t>,
1707 local_parent_node: Option<Node<'t>>,
1708 remote_parent_node: Node<'t>,
1709 remote_child_node: Node<'t>,
1710 ) -> Result<Option<Node<'t>>> {
1711 if let Some(local_parent_node) = local_parent_node {
1712 let mut matching_dupes_by_local_parent_guid = mem::replace(
1713 &mut self.matching_dupes_by_local_parent_guid,
1714 HashMap::new(),
1715 );
1716 let new_local_node = {
1717 let (_, remote_to_local) = match matching_dupes_by_local_parent_guid
1718 .entry(local_parent_node.guid.clone())
1719 {
1720 Entry::Occupied(entry) => entry.into_mut(),
1721 Entry::Vacant(entry) => {
1722 trace!(
1723 self.driver,
1724 "First remote child {} doesn't exist locally; \
1725 finding all matching dupes in local {} and remote {}",
1726 remote_child_node,
1727 local_parent_node,
1728 remote_parent_node
1729 );
1730 let matching_dupes = self.find_all_matching_dupes_in_folders(
1731 local_parent_node,
1732 remote_parent_node,
1733 )?;
1734 entry.insert(matching_dupes)
1735 }
1736 };
1737 let new_local_node = remote_to_local.get(&remote_child_node.guid);
1738 new_local_node.map(|node| {
1739 self.structure_counts.dupes += 1;
1740 *node
1741 })
1742 };
1743 self.matching_dupes_by_local_parent_guid = matching_dupes_by_local_parent_guid;
1744 Ok(new_local_node)
1745 } else {
1746 trace!(
1747 self.driver,
1748 "Merged node {} doesn't exist locally; no potential dupes for remote child {}",
1749 merged_node,
1750 remote_child_node
1751 );
1752 Ok(None)
1753 }
1754 }
1755}
1756
1757#[derive(Debug)]
1759pub struct MergedRoot<'t> {
1760 local_tree: &'t Tree,
1761 remote_tree: &'t Tree,
1762 node: MergedNode<'t>,
1763 merged_guids: HashSet<Guid>,
1764 delete_locally: HashSet<Guid>,
1765 delete_remotely: HashSet<Guid>,
1766 structure_counts: StructureCounts,
1767}
1768
1769impl<'t> MergedRoot<'t> {
1770 #[inline]
1772 pub fn node(&self) -> &MergedNode<'_> {
1773 &self.node
1774 }
1775
1776 pub fn completion_ops_with_signal(
1780 &self,
1781 signal: &impl AbortSignal,
1782 ) -> Result<CompletionOps<'_>> {
1783 let mut ops = CompletionOps::default();
1784 accumulate(signal, &mut ops, self.node(), 1, false)?;
1785
1786 for guid in self
1789 .local_tree
1790 .deletions()
1791 .difference(&self.delete_remotely)
1792 {
1793 signal.err_if_aborted()?;
1797 ops.delete_local_tombstones.push(DeleteLocalTombstone(guid));
1798 if self.remote_tree.is_deleted(guid) {
1799 ops.set_remote_merged.push(SetRemoteMerged(guid));
1800 }
1801 }
1802 for guid in self
1803 .remote_tree
1804 .deletions()
1805 .difference(&self.delete_locally)
1806 .filter(|guid| !self.local_tree.exists(guid))
1807 {
1808 signal.err_if_aborted()?;
1817 ops.set_remote_merged.push(SetRemoteMerged(guid));
1818 if self.local_tree.is_deleted(guid) {
1819 ops.delete_local_tombstones.push(DeleteLocalTombstone(guid));
1820 }
1821 }
1822
1823 for guid in self.deletions() {
1825 signal.err_if_aborted()?;
1826 match (
1827 self.local_tree.node_for_guid(guid),
1828 self.remote_tree.node_for_guid(guid),
1829 ) {
1830 (Some(local_node), Some(remote_node)) => {
1831 ops.delete_local_items.push(DeleteLocalItem(local_node));
1834 ops.insert_local_tombstones
1835 .push(InsertLocalTombstone(remote_node));
1836 ops.upload_tombstones.push(UploadTombstone(guid));
1837 }
1838 (Some(local_node), None) => {
1839 ops.delete_local_items.push(DeleteLocalItem(local_node));
1844 if self.remote_tree.is_deleted(guid) {
1845 ops.set_remote_merged.push(SetRemoteMerged(guid));
1846 }
1847 }
1848 (None, Some(remote_node)) => {
1849 if !self.local_tree.is_deleted(guid) {
1853 ops.insert_local_tombstones
1854 .push(InsertLocalTombstone(remote_node));
1855 }
1856 ops.upload_tombstones.push(UploadTombstone(guid));
1857 }
1858 (None, None) => {
1859 if self.local_tree.is_deleted(guid) {
1862 ops.delete_local_tombstones.push(DeleteLocalTombstone(guid));
1863 }
1864 if self.remote_tree.is_deleted(guid) {
1865 ops.set_remote_merged.push(SetRemoteMerged(guid));
1866 }
1867 }
1868 }
1869 }
1870
1871 Ok(ops)
1872 }
1873
1874 #[inline]
1876 pub fn completion_ops(&self) -> CompletionOps<'_> {
1877 self.completion_ops_with_signal(&DefaultAbortSignal)
1878 .unwrap()
1879 }
1880
1881 #[inline]
1883 pub fn deletions(&self) -> impl Iterator<Item = &Guid> {
1884 self.delete_locally.union(&self.delete_remotely)
1885 }
1886
1887 #[inline]
1890 pub fn local_deletions(&self) -> impl Iterator<Item = &Guid> {
1891 self.delete_locally.difference(&self.delete_remotely)
1892 }
1893
1894 #[inline]
1897 pub fn remote_deletions(&self) -> impl Iterator<Item = &Guid> {
1898 self.delete_remotely.iter()
1899 }
1900
1901 #[inline]
1903 pub fn counts(&self) -> &StructureCounts {
1904 &self.structure_counts
1905 }
1906}
1907
1908#[derive(Clone, Debug, Default)]
1912pub struct CompletionOps<'t> {
1913 pub change_guids: Vec<ChangeGuid<'t>>,
1914 pub apply_remote_items: Vec<ApplyRemoteItem<'t>>,
1915 pub apply_new_local_structure: Vec<ApplyNewLocalStructure<'t>>,
1916 pub set_local_unmerged: Vec<SetLocalUnmerged<'t>>,
1917 pub set_local_merged: Vec<SetLocalMerged<'t>>,
1918 pub set_remote_merged: Vec<SetRemoteMerged<'t>>,
1919 pub delete_local_tombstones: Vec<DeleteLocalTombstone<'t>>,
1920 pub insert_local_tombstones: Vec<InsertLocalTombstone<'t>>,
1921 pub delete_local_items: Vec<DeleteLocalItem<'t>>,
1922 pub upload_items: Vec<UploadItem<'t>>,
1923 pub upload_tombstones: Vec<UploadTombstone<'t>>,
1924}
1925
1926impl<'t> CompletionOps<'t> {
1927 #[inline]
1929 pub fn is_empty(&self) -> bool {
1930 self.change_guids.is_empty()
1931 && self.apply_remote_items.is_empty()
1932 && self.apply_new_local_structure.is_empty()
1933 && self.set_local_unmerged.is_empty()
1934 && self.set_local_merged.is_empty()
1935 && self.set_remote_merged.is_empty()
1936 && self.delete_local_tombstones.is_empty()
1937 && self.insert_local_tombstones.is_empty()
1938 && self.delete_local_items.is_empty()
1939 && self.upload_items.is_empty()
1940 && self.upload_tombstones.is_empty()
1941 }
1942
1943 pub fn summarize(&self) -> Vec<String> {
1945 std::iter::empty()
1946 .chain(to_strings(&self.change_guids))
1947 .chain(to_strings(&self.apply_remote_items))
1948 .chain(to_strings(&self.apply_new_local_structure))
1949 .chain(to_strings(&self.set_local_unmerged))
1950 .chain(to_strings(&self.set_local_merged))
1951 .chain(to_strings(&self.set_remote_merged))
1952 .chain(to_strings(&self.delete_local_tombstones))
1953 .chain(to_strings(&self.insert_local_tombstones))
1954 .chain(to_strings(&self.delete_local_items))
1955 .chain(to_strings(&self.upload_items))
1956 .chain(to_strings(&self.upload_tombstones))
1957 .collect()
1958 }
1959}
1960
1961#[derive(Clone, Copy, Debug)]
1965pub struct ChangeGuid<'t> {
1966 pub merged_node: &'t MergedNode<'t>,
1968 pub level: usize,
1972}
1973
1974impl<'t> ChangeGuid<'t> {
1975 #[inline]
1978 pub fn local_node(&self) -> &'t Node<'t> {
1979 self.merged_node
1980 .merge_state
1981 .local_node()
1982 .expect("Can't change local GUID without local node")
1983 }
1984}
1985
1986impl<'t> fmt::Display for ChangeGuid<'t> {
1987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1988 write!(
1989 f,
1990 "Change {} to {}",
1991 self.local_node().guid,
1992 self.merged_node.guid
1993 )
1994 }
1995}
1996
1997#[derive(Clone, Copy, Debug)]
2000pub struct ApplyRemoteItem<'t> {
2001 pub merged_node: &'t MergedNode<'t>,
2002 pub level: usize,
2003}
2004
2005impl<'t> ApplyRemoteItem<'t> {
2006 #[inline]
2010 pub fn remote_node(&self) -> &'t Node<'t> {
2011 self.merged_node
2012 .merge_state
2013 .remote_node()
2014 .expect("Can't apply remote item without remote node")
2015 }
2016}
2017
2018impl<'t> fmt::Display for ApplyRemoteItem<'t> {
2019 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2020 if self.merged_node.remote_guid_changed() {
2021 write!(
2022 f,
2023 "Apply remote {} as {}",
2024 self.remote_node().guid,
2025 self.merged_node.guid
2026 )
2027 } else {
2028 write!(f, "Apply remote {}", self.merged_node.guid)
2029 }
2030 }
2031}
2032
2033#[derive(Clone, Copy, Debug)]
2035pub struct ApplyNewLocalStructure<'t> {
2036 pub merged_node: &'t MergedNode<'t>,
2037 pub merged_parent_node: &'t MergedNode<'t>,
2038 pub position: usize,
2039 pub level: usize,
2040}
2041
2042impl<'t> fmt::Display for ApplyNewLocalStructure<'t> {
2043 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2044 write!(
2045 f,
2046 "Move {} into {} at {}",
2047 self.merged_node.guid, self.merged_parent_node.guid, self.position
2048 )
2049 }
2050}
2051
2052#[derive(Clone, Copy, Debug)]
2054pub struct SetLocalUnmerged<'t> {
2055 pub merged_node: &'t MergedNode<'t>,
2056}
2057
2058impl<'t> fmt::Display for SetLocalUnmerged<'t> {
2059 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2060 write!(f, "Flag local {} as unmerged", self.merged_node.guid)
2061 }
2062}
2063
2064#[derive(Clone, Copy, Debug)]
2067pub struct SetLocalMerged<'t> {
2068 pub merged_node: &'t MergedNode<'t>,
2069}
2070
2071impl<'t> fmt::Display for SetLocalMerged<'t> {
2072 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2073 write!(f, "Flag local {} as merged", self.merged_node.guid)
2074 }
2075}
2076
2077#[derive(Clone, Copy, Debug)]
2079pub struct UploadItem<'t> {
2080 pub merged_node: &'t MergedNode<'t>,
2081}
2082
2083impl<'t> fmt::Display for UploadItem<'t> {
2084 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2085 write!(f, "Upload item {}", self.merged_node.guid)
2086 }
2087}
2088
2089#[derive(Clone, Copy, Debug)]
2091pub struct UploadTombstone<'t>(&'t Guid);
2092
2093impl<'t> UploadTombstone<'t> {
2094 #[inline]
2096 pub fn guid(self) -> &'t Guid {
2097 self.0
2098 }
2099}
2100
2101impl<'t> fmt::Display for UploadTombstone<'t> {
2102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2103 write!(f, "Upload tombstone {}", self.0)
2104 }
2105}
2106
2107#[derive(Clone, Copy, Debug)]
2109pub struct SetRemoteMerged<'t>(&'t Guid);
2110
2111impl<'t> SetRemoteMerged<'t> {
2112 #[inline]
2114 pub fn guid(self) -> &'t Guid {
2115 self.0
2116 }
2117}
2118
2119impl<'t> fmt::Display for SetRemoteMerged<'t> {
2120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2121 write!(f, "Flag remote {} as merged", self.guid())
2122 }
2123}
2124
2125#[derive(Clone, Copy, Debug)]
2127pub struct InsertLocalTombstone<'t>(Node<'t>);
2128
2129impl<'t> InsertLocalTombstone<'t> {
2130 #[inline]
2132 pub fn remote_node(&self) -> Node<'t> {
2133 self.0
2134 }
2135}
2136
2137impl<'t> fmt::Display for InsertLocalTombstone<'t> {
2138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2139 write!(f, "Insert local tombstone {}", self.0.guid)
2140 }
2141}
2142
2143#[derive(Clone, Copy, Debug)]
2145pub struct DeleteLocalTombstone<'t>(&'t Guid);
2146
2147impl<'t> DeleteLocalTombstone<'t> {
2148 #[inline]
2150 pub fn guid(self) -> &'t Guid {
2151 self.0
2152 }
2153}
2154
2155impl<'t> fmt::Display for DeleteLocalTombstone<'t> {
2156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2157 write!(f, "Delete local tombstone {}", self.0)
2158 }
2159}
2160
2161#[derive(Clone, Copy, Debug)]
2163pub struct DeleteLocalItem<'t>(Node<'t>);
2164
2165impl<'t> DeleteLocalItem<'t> {
2166 #[inline]
2168 pub fn local_node(&self) -> Node<'t> {
2169 self.0
2170 }
2171}
2172
2173impl<'t> fmt::Display for DeleteLocalItem<'t> {
2174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2175 write!(f, "Delete local item {}", self.0.guid)
2176 }
2177}
2178
2179fn accumulate<'t, A: AbortSignal>(
2182 signal: &A,
2183 ops: &mut CompletionOps<'t>,
2184 merged_node: &'t MergedNode<'t>,
2185 level: usize,
2186 is_tagging: bool,
2187) -> Result<()> {
2188 for (position, merged_child_node) in merged_node.merged_children.iter().enumerate() {
2189 signal.err_if_aborted()?;
2190 let is_tagging = if merged_child_node.guid == TAGS_GUID {
2191 true
2192 } else {
2193 is_tagging
2194 };
2195 if merged_child_node.merge_state.should_apply_item() {
2196 let apply_remote_item = ApplyRemoteItem {
2197 merged_node: merged_child_node,
2198 level,
2199 };
2200 ops.apply_remote_items.push(apply_remote_item);
2201 }
2202 if merged_child_node.local_guid_changed() {
2203 let change_guid = ChangeGuid {
2204 merged_node: merged_child_node,
2205 level,
2206 };
2207 ops.change_guids.push(change_guid);
2208 }
2209 let local_child_node = merged_node
2210 .merge_state
2211 .local_node()
2212 .and_then(|local_parent_node| local_parent_node.child(position));
2213 let merged_local_child_node = merged_child_node.merge_state.local_node();
2214 if local_child_node
2215 .and_then(|m| merged_local_child_node.map(|n| m.guid != n.guid))
2216 .unwrap_or(true)
2217 {
2218 let apply_new_local_structure = ApplyNewLocalStructure {
2223 merged_node: merged_child_node,
2224 merged_parent_node: merged_node,
2225 position,
2226 level,
2227 };
2228 ops.apply_new_local_structure
2229 .push(apply_new_local_structure);
2230 }
2231 let local_needs_merge = merged_child_node
2232 .merge_state
2233 .local_node()
2234 .map(|node| node.needs_merge)
2235 .unwrap_or(false);
2236 let should_upload = merged_child_node.merge_state.should_upload();
2237 match (local_needs_merge, should_upload) {
2238 (false, true) => {
2239 let set_local_unmerged = SetLocalUnmerged {
2241 merged_node: merged_child_node,
2242 };
2243 ops.set_local_unmerged.push(set_local_unmerged);
2244 }
2245 (true, false) => {
2246 let set_local_merged = SetLocalMerged {
2248 merged_node: merged_child_node,
2249 };
2250 ops.set_local_merged.push(set_local_merged);
2251 }
2252 _ => {}
2253 }
2254 if should_upload && !is_tagging {
2255 ops.upload_items.push(UploadItem {
2259 merged_node: merged_child_node,
2260 });
2261 }
2262 if let Some(remote_child_node) = merged_child_node.merge_state.remote_node() {
2263 if remote_child_node.needs_merge && !should_upload {
2264 let set_remote_merged = SetRemoteMerged(&remote_child_node.guid);
2269 ops.set_remote_merged.push(set_remote_merged);
2270 }
2271 }
2272 accumulate(signal, ops, merged_child_node, level + 1, is_tagging)?;
2273 }
2274 Ok(())
2275}
2276
2277pub(crate) fn to_strings<'a, T: ToString>(items: &'a [T]) -> impl Iterator<Item = String> + 'a {
2279 items.iter().map(ToString::to_string)
2280}