Compute the full `RemoteDelta` for a given view. This is the main entry point for sync operations. It: 1. Runs the dichotomy algorithm to find the divergence point 2. Downloads the remote's changelist from the divergence point 3. Compares "ours" (cached) vs "theirs" (actual) after divergence 4. Identifies changes to download, unrecords, and unknowns 5. Updates the local cache # Arguments `view
(
&mut self,
view: &str,
local_hashes: &HashSet<String>,
)
| 612 | /// * `local_hashes` - Set of change hashes present in the local repository. |
| 613 | /// Used to determine which remote changes need to be downloaded. |
| 614 | pub async fn compute_delta( |
| 615 | &mut self, |
| 616 | view: &str, |
| 617 | local_hashes: &HashSet<String>, |
| 618 | ) -> RemoteResult<RemoteDelta> { |
| 619 | // Handle from-scratch sync (no cache) |
| 620 | if self.cache.is_empty() { |
| 621 | return self.compute_delta_from_scratch(view, local_hashes).await; |
| 622 | } |
| 623 | |
| 624 | // Find divergence point |
| 625 | let divergence = self.dichotomy_changelist(view).await?; |
| 626 | self.stats.divergence_point = divergence; |
| 627 | |
| 628 | // Collect our cached entries at or after divergence |
| 629 | let ours_ge_dichotomy: Vec<(u64, Node)> = self |
| 630 | .cache |
| 631 | .entries_from(divergence) |
| 632 | .into_iter() |
| 633 | .map(|(seq, node)| (seq, node.clone())) |
| 634 | .collect(); |
| 635 | |
| 636 | let ours_ge_dichotomy_set: HashSet<Node> = ours_ge_dichotomy |
| 637 | .iter() |
| 638 | .map(|(_, node)| node.clone()) |
| 639 | .collect(); |
| 640 | |
| 641 | // Download the remote's changelist from the divergence point |
| 642 | let remote_entries = self.remote.get_changelist(view, divergence).await?; |
| 643 | self.stats.changelist_entries_fetched = remote_entries.len(); |
| 644 | |
| 645 | // Build "theirs" sets |
| 646 | let mut theirs_ge_dichotomy = Vec::new(); |
| 647 | let mut theirs_ge_dichotomy_set = HashSet::new(); |
| 648 | let mut to_download = Vec::new(); |
| 649 | |
| 650 | for entry in &remote_entries { |
| 651 | let node = entry.to_node(); |
| 652 | theirs_ge_dichotomy_set.insert(node.clone()); |
| 653 | theirs_ge_dichotomy.push((entry.sequence, node.clone())); |
| 654 | |
| 655 | // Need to download if we don't have it locally |
| 656 | if !local_hashes.contains(&entry.hash) { |
| 657 | to_download.push(node); |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | // Compute remote unrecords: entries in our cache that are no longer |
| 662 | // on the remote. These are changes that were unrecorded remotely. |
| 663 | let remote_unrecords: Vec<(u64, Node)> = ours_ge_dichotomy |
| 664 | .iter() |
| 665 | .filter(|(_, node)| !theirs_ge_dichotomy_set.contains(node)) |
| 666 | .cloned() |
| 667 | .collect(); |
| 668 | |
| 669 | if !remote_unrecords.is_empty() { |
| 670 | debug!("sync: {} remote unrecords detected", remote_unrecords.len()); |
| 671 | } |
no test coverage detected