476 |
476 |
477 let parents = parse_dirstate_entries( |
477 let parents = parse_dirstate_entries( |
478 map.on_disk, |
478 map.on_disk, |
479 |path, entry, copy_source| { |
479 |path, entry, copy_source| { |
480 let tracked = entry.state().is_tracked(); |
480 let tracked = entry.state().is_tracked(); |
481 let node = Self::get_or_insert_node( |
481 let node = Self::get_or_insert_node_inner( |
482 map.on_disk, |
482 map.on_disk, |
483 &mut map.unreachable_bytes, |
483 &mut map.unreachable_bytes, |
484 &mut map.root, |
484 &mut map.root, |
485 path, |
485 path, |
486 WithBasename::to_cow_borrowed, |
486 WithBasename::to_cow_borrowed, |
572 return Ok(None); |
572 return Ok(None); |
573 } |
573 } |
574 } |
574 } |
575 } |
575 } |
576 |
576 |
|
577 /// Get a mutable reference to the node at `path`, creating it if it does |
|
578 /// not exist. |
|
579 /// |
|
580 /// `each_ancestor` is a callback that is called for each ancestor node |
|
581 /// when descending the tree. It is used to keep the different counters |
|
582 /// of the `DirstateMap` up-to-date. |
577 fn get_or_insert_node<'tree, 'path>( |
583 fn get_or_insert_node<'tree, 'path>( |
|
584 &'tree mut self, |
|
585 path: &'path HgPath, |
|
586 each_ancestor: impl FnMut(&mut Node), |
|
587 ) -> Result<&'tree mut Node<'on_disk>, DirstateV2ParseError> { |
|
588 Self::get_or_insert_node_inner( |
|
589 self.on_disk, |
|
590 &mut self.unreachable_bytes, |
|
591 &mut self.root, |
|
592 path, |
|
593 WithBasename::to_cow_owned, |
|
594 each_ancestor, |
|
595 ) |
|
596 } |
|
597 |
|
598 /// Lower-level version of `get_or_insert_node_inner`, which is used when |
|
599 /// parsing disk data to remove allocations for new nodes. |
|
600 fn get_or_insert_node_inner<'tree, 'path>( |
578 on_disk: &'on_disk [u8], |
601 on_disk: &'on_disk [u8], |
579 unreachable_bytes: &mut u32, |
602 unreachable_bytes: &mut u32, |
580 root: &'tree mut ChildNodes<'on_disk>, |
603 root: &'tree mut ChildNodes<'on_disk>, |
581 path: &'path HgPath, |
604 path: &'path HgPath, |
582 to_cow: impl Fn( |
605 to_cow: impl Fn( |
618 ) -> Result<(), DirstateError> { |
641 ) -> Result<(), DirstateError> { |
619 let (had_entry, was_tracked) = match old_entry_opt { |
642 let (had_entry, was_tracked) = match old_entry_opt { |
620 Some(old_entry) => (true, old_entry.tracked()), |
643 Some(old_entry) => (true, old_entry.tracked()), |
621 None => (false, false), |
644 None => (false, false), |
622 }; |
645 }; |
623 let node = Self::get_or_insert_node( |
646 let node = self.get_or_insert_node(filename, |ancestor| { |
624 self.on_disk, |
647 if !had_entry { |
625 &mut self.unreachable_bytes, |
648 ancestor.descendants_with_entry_count += 1; |
626 &mut self.root, |
649 } |
627 filename, |
650 if was_tracked { |
628 WithBasename::to_cow_owned, |
651 if !wc_tracked { |
629 |ancestor| { |
652 ancestor.tracked_descendants_count = ancestor |
630 if !had_entry { |
653 .tracked_descendants_count |
631 ancestor.descendants_with_entry_count += 1; |
654 .checked_sub(1) |
|
655 .expect("tracked count to be >= 0"); |
632 } |
656 } |
633 if was_tracked { |
657 } else { |
634 if !wc_tracked { |
658 if wc_tracked { |
635 ancestor.tracked_descendants_count = ancestor |
659 ancestor.tracked_descendants_count += 1; |
636 .tracked_descendants_count |
|
637 .checked_sub(1) |
|
638 .expect("tracked count to be >= 0"); |
|
639 } |
|
640 } else { |
|
641 if wc_tracked { |
|
642 ancestor.tracked_descendants_count += 1; |
|
643 } |
|
644 } |
660 } |
645 }, |
661 } |
646 )?; |
662 })?; |
647 |
663 |
648 let v2_data = if let Some(parent_file_data) = parent_file_data_opt { |
664 let v2_data = if let Some(parent_file_data) = parent_file_data_opt { |
649 DirstateV2Data { |
665 DirstateV2Data { |
650 wc_tracked, |
666 wc_tracked, |
651 p1_tracked, |
667 p1_tracked, |
681 let was_tracked = old_entry_opt.map_or(false, |e| e.tracked()); |
697 let was_tracked = old_entry_opt.map_or(false, |e| e.tracked()); |
682 let had_entry = old_entry_opt.is_some(); |
698 let had_entry = old_entry_opt.is_some(); |
683 let tracked_count_increment = if was_tracked { 0 } else { 1 }; |
699 let tracked_count_increment = if was_tracked { 0 } else { 1 }; |
684 let mut new = false; |
700 let mut new = false; |
685 |
701 |
686 let node = Self::get_or_insert_node( |
702 let node = self.get_or_insert_node(filename, |ancestor| { |
687 self.on_disk, |
703 if !had_entry { |
688 &mut self.unreachable_bytes, |
704 ancestor.descendants_with_entry_count += 1; |
689 &mut self.root, |
705 } |
690 filename, |
706 |
691 WithBasename::to_cow_owned, |
707 ancestor.tracked_descendants_count += tracked_count_increment; |
692 |ancestor| { |
708 })?; |
693 if !had_entry { |
709 if let Some(old_entry) = old_entry_opt { |
694 ancestor.descendants_with_entry_count += 1; |
|
695 } |
|
696 |
|
697 ancestor.tracked_descendants_count += tracked_count_increment; |
|
698 }, |
|
699 )?; |
|
700 let new_entry = if let Some(old_entry) = old_entry_opt { |
|
701 let mut e = old_entry.clone(); |
710 let mut e = old_entry.clone(); |
702 if e.tracked() { |
711 if e.tracked() { |
703 // XXX |
712 // XXX |
704 // This is probably overkill for more case, but we need this to |
713 // This is probably overkill for more case, but we need this to |
705 // fully replace the `normallookup` call with `set_tracked` |
714 // fully replace the `normallookup` call with `set_tracked` |
707 e.set_possibly_dirty(); |
716 e.set_possibly_dirty(); |
708 } else { |
717 } else { |
709 new = true; |
718 new = true; |
710 e.set_tracked(); |
719 e.set_tracked(); |
711 } |
720 } |
712 e |
721 node.data = NodeData::Entry(e) |
713 } else { |
722 } else { |
|
723 node.data = NodeData::Entry(DirstateEntry::new_tracked()); |
714 self.nodes_with_entry_count += 1; |
724 self.nodes_with_entry_count += 1; |
715 new = true; |
725 new = true; |
716 DirstateEntry::new_tracked() |
|
717 }; |
726 }; |
718 node.data = NodeData::Entry(new_entry); |
|
719 Ok(new) |
727 Ok(new) |
720 } |
728 } |
721 |
729 |
722 /// It is the responsibility of the caller to know that there was an entry |
730 /// It is the responsibility of the caller to know that there was an entry |
723 /// there before. Does not handle the removal of copy source |
731 /// there before. Does not handle the removal of copy source |
724 fn set_untracked( |
732 fn set_untracked( |
725 &mut self, |
733 &mut self, |
726 filename: &HgPath, |
734 filename: &HgPath, |
727 old_entry: DirstateEntry, |
735 old_entry: DirstateEntry, |
728 ) -> Result<(), DirstateV2ParseError> { |
736 ) -> Result<(), DirstateV2ParseError> { |
729 let node = Self::get_or_insert_node( |
737 let node = self.get_or_insert_node(filename, |ancestor| { |
730 self.on_disk, |
738 ancestor.tracked_descendants_count = ancestor |
731 &mut self.unreachable_bytes, |
739 .tracked_descendants_count |
732 &mut self.root, |
740 .checked_sub(1) |
733 filename, |
741 .expect("tracked_descendants_count should be >= 0"); |
734 WithBasename::to_cow_owned, |
742 })?; |
735 |ancestor| { |
|
736 ancestor.tracked_descendants_count = ancestor |
|
737 .tracked_descendants_count |
|
738 .checked_sub(1) |
|
739 .expect("tracked_descendants_count should be >= 0"); |
|
740 }, |
|
741 )?; |
|
742 let mut new_entry = old_entry.clone(); |
743 let mut new_entry = old_entry.clone(); |
743 new_entry.set_untracked(); |
744 new_entry.set_untracked(); |
744 node.data = NodeData::Entry(new_entry); |
745 node.data = NodeData::Entry(new_entry); |
745 Ok(()) |
746 Ok(()) |
746 } |
747 } |
751 old_entry: DirstateEntry, |
752 old_entry: DirstateEntry, |
752 mode: u32, |
753 mode: u32, |
753 size: u32, |
754 size: u32, |
754 mtime: TruncatedTimestamp, |
755 mtime: TruncatedTimestamp, |
755 ) -> Result<(), DirstateError> { |
756 ) -> Result<(), DirstateError> { |
756 let node = Self::get_or_insert_node( |
757 let node = self.get_or_insert_node(filename, |ancestor| { |
757 self.on_disk, |
758 if !old_entry.tracked() { |
758 &mut self.unreachable_bytes, |
759 ancestor.tracked_descendants_count += 1; |
759 &mut self.root, |
760 } |
760 filename, |
761 })?; |
761 WithBasename::to_cow_owned, |
|
762 |ancestor| { |
|
763 if !old_entry.tracked() { |
|
764 ancestor.tracked_descendants_count += 1; |
|
765 } |
|
766 }, |
|
767 )?; |
|
768 let mut new_entry = old_entry.clone(); |
762 let mut new_entry = old_entry.clone(); |
769 new_entry.set_clean(mode, size, mtime); |
763 new_entry.set_clean(mode, size, mtime); |
770 node.data = NodeData::Entry(new_entry); |
764 node.data = NodeData::Entry(new_entry); |
771 Ok(()) |
765 Ok(()) |
772 } |
766 } |
773 |
767 |
774 fn set_possibly_dirty( |
768 fn set_possibly_dirty( |
775 &mut self, |
769 &mut self, |
776 filename: &HgPath, |
770 filename: &HgPath, |
777 ) -> Result<(), DirstateError> { |
771 ) -> Result<(), DirstateError> { |
778 let node = Self::get_or_insert_node( |
772 let node = self.get_or_insert_node(filename, |_ancestor| {})?; |
779 self.on_disk, |
|
780 &mut self.unreachable_bytes, |
|
781 &mut self.root, |
|
782 filename, |
|
783 WithBasename::to_cow_owned, |
|
784 |_ancestor| {}, |
|
785 )?; |
|
786 let entry = node.data.as_entry_mut().expect("entry should exist"); |
773 let entry = node.data.as_entry_mut().expect("entry should exist"); |
787 entry.set_possibly_dirty(); |
774 entry.set_possibly_dirty(); |
788 node.data = NodeData::Entry(*entry); |
775 node.data = NodeData::Entry(*entry); |
789 Ok(()) |
776 Ok(()) |
790 } |
777 } |
1322 &mut self, |
1309 &mut self, |
1323 key: &HgPath, |
1310 key: &HgPath, |
1324 value: &HgPath, |
1311 value: &HgPath, |
1325 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
1312 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
1326 self.with_dmap_mut(|map| { |
1313 self.with_dmap_mut(|map| { |
1327 let node = DirstateMap::get_or_insert_node( |
1314 let node = map.get_or_insert_node(&key, |_ancestor| {})?; |
1328 map.on_disk, |
1315 let had_copy_source = node.copy_source.is_none(); |
1329 &mut map.unreachable_bytes, |
1316 let old = node |
1330 &mut map.root, |
|
1331 &key, |
|
1332 WithBasename::to_cow_owned, |
|
1333 |_ancestor| {}, |
|
1334 )?; |
|
1335 if node.copy_source.is_none() { |
|
1336 map.nodes_with_copy_source_count += 1 |
|
1337 } |
|
1338 Ok(node |
|
1339 .copy_source |
1317 .copy_source |
1340 .replace(value.to_owned().into()) |
1318 .replace(value.to_owned().into()) |
1341 .map(Cow::into_owned)) |
1319 .map(Cow::into_owned); |
|
1320 if had_copy_source { |
|
1321 map.nodes_with_copy_source_count += 1 |
|
1322 } |
|
1323 Ok(old) |
1342 }) |
1324 }) |
1343 } |
1325 } |
1344 |
1326 |
1345 pub fn len(&self) -> usize { |
1327 pub fn len(&self) -> usize { |
1346 let map = self.get_map(); |
1328 let map = self.get_map(); |
1422 files_with_p2_info.push(path.to_owned()) |
1404 files_with_p2_info.push(path.to_owned()) |
1423 } |
1405 } |
1424 } |
1406 } |
1425 self.with_dmap_mut(|map| { |
1407 self.with_dmap_mut(|map| { |
1426 for path in files_with_p2_info.iter() { |
1408 for path in files_with_p2_info.iter() { |
1427 let node = DirstateMap::get_or_insert_node( |
1409 let node = map.get_or_insert_node(path, |_| {})?; |
1428 map.on_disk, |
|
1429 &mut map.unreachable_bytes, |
|
1430 &mut map.root, |
|
1431 path, |
|
1432 WithBasename::to_cow_owned, |
|
1433 |_| {}, |
|
1434 )?; |
|
1435 let entry = |
1410 let entry = |
1436 node.data.as_entry_mut().expect("entry should exist"); |
1411 node.data.as_entry_mut().expect("entry should exist"); |
1437 entry.drop_merge_data(); |
1412 entry.drop_merge_data(); |
1438 if let Some(source) = node.copy_source.take().as_deref() { |
1413 if let Some(source) = node.copy_source.take().as_deref() { |
1439 copies.push((path.to_owned(), source.to_owned())); |
1414 copies.push((path.to_owned(), source.to_owned())); |