721 }) |
721 }) |
722 } |
722 } |
723 |
723 |
724 impl OwningDirstateMap { |
724 impl OwningDirstateMap { |
725 pub fn clear(&mut self) { |
725 pub fn clear(&mut self) { |
726 let map = self.get_map_mut(); |
726 self.with_dmap_mut(|map| { |
727 map.root = Default::default(); |
727 map.root = Default::default(); |
728 map.nodes_with_entry_count = 0; |
728 map.nodes_with_entry_count = 0; |
729 map.nodes_with_copy_source_count = 0; |
729 map.nodes_with_copy_source_count = 0; |
|
730 }); |
730 } |
731 } |
731 |
732 |
732 pub fn set_entry( |
733 pub fn set_entry( |
733 &mut self, |
734 &mut self, |
734 filename: &HgPath, |
735 filename: &HgPath, |
735 entry: DirstateEntry, |
736 entry: DirstateEntry, |
736 ) -> Result<(), DirstateV2ParseError> { |
737 ) -> Result<(), DirstateV2ParseError> { |
737 let map = self.get_map_mut(); |
738 self.with_dmap_mut(|map| { |
738 map.get_or_insert(&filename)?.data = NodeData::Entry(entry); |
739 map.get_or_insert(&filename)?.data = NodeData::Entry(entry); |
739 Ok(()) |
740 Ok(()) |
|
741 }) |
740 } |
742 } |
741 |
743 |
742 pub fn add_file( |
744 pub fn add_file( |
743 &mut self, |
745 &mut self, |
744 filename: &HgPath, |
746 filename: &HgPath, |
745 entry: DirstateEntry, |
747 entry: DirstateEntry, |
746 ) -> Result<(), DirstateError> { |
748 ) -> Result<(), DirstateError> { |
747 let old_state = self.get(filename)?.map(|e| e.state()); |
749 let old_state = self.get(filename)?.map(|e| e.state()); |
748 let map = self.get_map_mut(); |
750 self.with_dmap_mut(|map| { |
749 Ok(map.add_or_remove_file(filename, old_state, entry)?) |
751 Ok(map.add_or_remove_file(filename, old_state, entry)?) |
|
752 }) |
750 } |
753 } |
751 |
754 |
752 pub fn remove_file( |
755 pub fn remove_file( |
753 &mut self, |
756 &mut self, |
754 filename: &HgPath, |
757 filename: &HgPath, |
775 } |
778 } |
776 } |
779 } |
777 if size == 0 { |
780 if size == 0 { |
778 self.copy_map_remove(filename)?; |
781 self.copy_map_remove(filename)?; |
779 } |
782 } |
780 let map = self.get_map_mut(); |
783 self.with_dmap_mut(|map| { |
781 let entry = DirstateEntry::new_removed(size); |
784 let entry = DirstateEntry::new_removed(size); |
782 Ok(map.add_or_remove_file(filename, old_state, entry)?) |
785 Ok(map.add_or_remove_file(filename, old_state, entry)?) |
|
786 }) |
783 } |
787 } |
784 |
788 |
785 pub fn drop_entry_and_copy_source( |
789 pub fn drop_entry_and_copy_source( |
786 &mut self, |
790 &mut self, |
787 filename: &HgPath, |
791 filename: &HgPath, |
788 ) -> Result<(), DirstateError> { |
792 ) -> Result<(), DirstateError> { |
789 let was_tracked = self |
793 let was_tracked = self |
790 .get(filename)? |
794 .get(filename)? |
791 .map_or(false, |e| e.state().is_tracked()); |
795 .map_or(false, |e| e.state().is_tracked()); |
792 let map = self.get_map_mut(); |
|
793 struct Dropped { |
796 struct Dropped { |
794 was_tracked: bool, |
797 was_tracked: bool, |
795 had_entry: bool, |
798 had_entry: bool, |
796 had_copy_source: bool, |
799 had_copy_source: bool, |
797 } |
800 } |
824 &mut node.children, |
827 &mut node.children, |
825 rest, |
828 rest, |
826 )? { |
829 )? { |
827 dropped = d; |
830 dropped = d; |
828 if dropped.had_entry { |
831 if dropped.had_entry { |
829 node.descendants_with_entry_count -= 1; |
832 node.descendants_with_entry_count = node |
|
833 .descendants_with_entry_count |
|
834 .checked_sub(1) |
|
835 .expect( |
|
836 "descendants_with_entry_count should be >= 0", |
|
837 ); |
830 } |
838 } |
831 if dropped.was_tracked { |
839 if dropped.was_tracked { |
832 node.tracked_descendants_count -= 1; |
840 node.tracked_descendants_count = node |
|
841 .tracked_descendants_count |
|
842 .checked_sub(1) |
|
843 .expect( |
|
844 "tracked_descendants_count should be >= 0", |
|
845 ); |
833 } |
846 } |
834 |
847 |
835 // Directory caches must be invalidated when removing a |
848 // Directory caches must be invalidated when removing a |
836 // child node |
849 // child node |
837 if removed { |
850 if removed { |
841 } |
854 } |
842 } else { |
855 } else { |
843 return Ok(None); |
856 return Ok(None); |
844 } |
857 } |
845 } else { |
858 } else { |
846 let had_entry = node.data.has_entry(); |
859 let entry = node.data.as_entry(); |
|
860 let was_tracked = entry.map_or(false, |entry| entry.tracked()); |
|
861 let had_entry = entry.is_some(); |
847 if had_entry { |
862 if had_entry { |
848 node.data = NodeData::None |
863 node.data = NodeData::None |
849 } |
864 } |
|
865 let mut had_copy_source = false; |
850 if let Some(source) = &node.copy_source { |
866 if let Some(source) = &node.copy_source { |
851 DirstateMap::count_dropped_path(unreachable_bytes, source); |
867 DirstateMap::count_dropped_path(unreachable_bytes, source); |
|
868 had_copy_source = true; |
852 node.copy_source = None |
869 node.copy_source = None |
853 } |
870 } |
854 dropped = Dropped { |
871 dropped = Dropped { |
855 was_tracked: node |
872 was_tracked, |
856 .data |
|
857 .as_entry() |
|
858 .map_or(false, |entry| entry.state().is_tracked()), |
|
859 had_entry, |
873 had_entry, |
860 had_copy_source: node.copy_source.take().is_some(), |
874 had_copy_source, |
861 }; |
875 }; |
862 } |
876 } |
863 // After recursion, for both leaf (rest_of_path is None) nodes and |
877 // After recursion, for both leaf (rest_of_path is None) nodes and |
864 // parent nodes, remove a node if it just became empty. |
878 // parent nodes, remove a node if it just became empty. |
865 let remove = !node.data.has_entry() |
879 let remove = !node.data.has_entry() |
874 ) |
888 ) |
875 } |
889 } |
876 Ok(Some((dropped, remove))) |
890 Ok(Some((dropped, remove))) |
877 } |
891 } |
878 |
892 |
879 if let Some((dropped, _removed)) = recur( |
893 self.with_dmap_mut(|map| { |
880 map.on_disk, |
894 if let Some((dropped, _removed)) = recur( |
881 &mut map.unreachable_bytes, |
895 map.on_disk, |
882 &mut map.root, |
896 &mut map.unreachable_bytes, |
883 filename, |
897 &mut map.root, |
884 )? { |
898 filename, |
885 if dropped.had_entry { |
899 )? { |
886 map.nodes_with_entry_count -= 1 |
900 if dropped.had_entry { |
887 } |
901 map.nodes_with_entry_count = map |
888 if dropped.had_copy_source { |
902 .nodes_with_entry_count |
889 map.nodes_with_copy_source_count -= 1 |
903 .checked_sub(1) |
890 } |
904 .expect("nodes_with_entry_count should be >= 0"); |
891 } else { |
905 } |
892 debug_assert!(!was_tracked); |
906 if dropped.had_copy_source { |
893 } |
907 map.nodes_with_copy_source_count = map |
894 Ok(()) |
908 .nodes_with_copy_source_count |
|
909 .checked_sub(1) |
|
910 .expect("nodes_with_copy_source_count should be >= 0"); |
|
911 } |
|
912 } else { |
|
913 debug_assert!(!was_tracked); |
|
914 } |
|
915 Ok(()) |
|
916 }) |
895 } |
917 } |
896 |
918 |
897 pub fn has_tracked_dir( |
919 pub fn has_tracked_dir( |
898 &mut self, |
920 &mut self, |
899 directory: &HgPath, |
921 directory: &HgPath, |
900 ) -> Result<bool, DirstateError> { |
922 ) -> Result<bool, DirstateError> { |
901 let map = self.get_map_mut(); |
923 self.with_dmap_mut(|map| { |
902 if let Some(node) = map.get_node(directory)? { |
924 if let Some(node) = map.get_node(directory)? { |
903 // A node without a `DirstateEntry` was created to hold child |
925 // A node without a `DirstateEntry` was created to hold child |
904 // nodes, and is therefore a directory. |
926 // nodes, and is therefore a directory. |
905 let state = node.state()?; |
927 let state = node.state()?; |
906 Ok(state.is_none() && node.tracked_descendants_count() > 0) |
928 Ok(state.is_none() && node.tracked_descendants_count() > 0) |
907 } else { |
929 } else { |
908 Ok(false) |
930 Ok(false) |
909 } |
931 } |
|
932 }) |
910 } |
933 } |
911 |
934 |
912 pub fn has_dir( |
935 pub fn has_dir( |
913 &mut self, |
936 &mut self, |
914 directory: &HgPath, |
937 directory: &HgPath, |
915 ) -> Result<bool, DirstateError> { |
938 ) -> Result<bool, DirstateError> { |
916 let map = self.get_map_mut(); |
939 self.with_dmap_mut(|map| { |
917 if let Some(node) = map.get_node(directory)? { |
940 if let Some(node) = map.get_node(directory)? { |
918 // A node without a `DirstateEntry` was created to hold child |
941 // A node without a `DirstateEntry` was created to hold child |
919 // nodes, and is therefore a directory. |
942 // nodes, and is therefore a directory. |
920 let state = node.state()?; |
943 let state = node.state()?; |
921 Ok(state.is_none() && node.descendants_with_entry_count() > 0) |
944 Ok(state.is_none() && node.descendants_with_entry_count() > 0) |
922 } else { |
945 } else { |
923 Ok(false) |
946 Ok(false) |
924 } |
947 } |
|
948 }) |
925 } |
949 } |
926 |
950 |
927 #[timed] |
951 #[timed] |
928 pub fn pack_v1( |
952 pub fn pack_v1( |
929 &self, |
953 &self, |
971 ) -> Result<(Vec<u8>, on_disk::TreeMetadata, bool), DirstateError> { |
995 ) -> Result<(Vec<u8>, on_disk::TreeMetadata, bool), DirstateError> { |
972 let map = self.get_map(); |
996 let map = self.get_map(); |
973 on_disk::write(map, can_append) |
997 on_disk::write(map, can_append) |
974 } |
998 } |
975 |
999 |
976 pub fn status<'a>( |
1000 /// `callback` allows the caller to process and do something with the |
977 &'a mut self, |
1001 /// results of the status. This is needed to do so efficiently (i.e. |
978 matcher: &'a (dyn Matcher + Sync), |
1002 /// without cloning the `DirstateStatus` object with its paths) because |
|
1003 /// we need to borrow from `Self`. |
|
1004 pub fn with_status<R>( |
|
1005 &mut self, |
|
1006 matcher: &(dyn Matcher + Sync), |
979 root_dir: PathBuf, |
1007 root_dir: PathBuf, |
980 ignore_files: Vec<PathBuf>, |
1008 ignore_files: Vec<PathBuf>, |
981 options: StatusOptions, |
1009 options: StatusOptions, |
982 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError> |
1010 callback: impl for<'r> FnOnce( |
983 { |
1011 Result<(DirstateStatus<'r>, Vec<PatternFileWarning>), StatusError>, |
984 let map = self.get_map_mut(); |
1012 ) -> R, |
985 super::status::status(map, matcher, root_dir, ignore_files, options) |
1013 ) -> R { |
|
1014 self.with_dmap_mut(|map| { |
|
1015 callback(super::status::status( |
|
1016 map, |
|
1017 matcher, |
|
1018 root_dir, |
|
1019 ignore_files, |
|
1020 options, |
|
1021 )) |
|
1022 }) |
986 } |
1023 } |
987 |
1024 |
988 pub fn copy_map_len(&self) -> usize { |
1025 pub fn copy_map_len(&self) -> usize { |
989 let map = self.get_map(); |
1026 let map = self.get_map(); |
990 map.nodes_with_copy_source_count as usize |
1027 map.nodes_with_copy_source_count as usize |
1028 |
1065 |
1029 pub fn copy_map_remove( |
1066 pub fn copy_map_remove( |
1030 &mut self, |
1067 &mut self, |
1031 key: &HgPath, |
1068 key: &HgPath, |
1032 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
1069 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
1033 let map = self.get_map_mut(); |
1070 self.with_dmap_mut(|map| { |
1034 let count = &mut map.nodes_with_copy_source_count; |
1071 let count = &mut map.nodes_with_copy_source_count; |
1035 let unreachable_bytes = &mut map.unreachable_bytes; |
1072 let unreachable_bytes = &mut map.unreachable_bytes; |
1036 Ok(DirstateMap::get_node_mut( |
1073 Ok(DirstateMap::get_node_mut( |
1037 map.on_disk, |
1074 map.on_disk, |
1038 unreachable_bytes, |
1075 unreachable_bytes, |
1039 &mut map.root, |
1076 &mut map.root, |
1040 key, |
1077 key, |
1041 )? |
1078 )? |
1042 .and_then(|node| { |
1079 .and_then(|node| { |
1043 if let Some(source) = &node.copy_source { |
1080 if let Some(source) = &node.copy_source { |
1044 *count -= 1; |
1081 *count -= 1; |
1045 DirstateMap::count_dropped_path(unreachable_bytes, source); |
1082 DirstateMap::count_dropped_path(unreachable_bytes, source); |
1046 } |
1083 } |
1047 node.copy_source.take().map(Cow::into_owned) |
1084 node.copy_source.take().map(Cow::into_owned) |
1048 })) |
1085 })) |
|
1086 }) |
1049 } |
1087 } |
1050 |
1088 |
1051 pub fn copy_map_insert( |
1089 pub fn copy_map_insert( |
1052 &mut self, |
1090 &mut self, |
1053 key: HgPathBuf, |
1091 key: HgPathBuf, |
1054 value: HgPathBuf, |
1092 value: HgPathBuf, |
1055 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
1093 ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
1056 let map = self.get_map_mut(); |
1094 self.with_dmap_mut(|map| { |
1057 let node = DirstateMap::get_or_insert_node( |
1095 let node = DirstateMap::get_or_insert_node( |
1058 map.on_disk, |
1096 map.on_disk, |
1059 &mut map.unreachable_bytes, |
1097 &mut map.unreachable_bytes, |
1060 &mut map.root, |
1098 &mut map.root, |
1061 &key, |
1099 &key, |
1062 WithBasename::to_cow_owned, |
1100 WithBasename::to_cow_owned, |
1063 |_ancestor| {}, |
1101 |_ancestor| {}, |
1064 )?; |
1102 )?; |
1065 if node.copy_source.is_none() { |
1103 if node.copy_source.is_none() { |
1066 map.nodes_with_copy_source_count += 1 |
1104 map.nodes_with_copy_source_count += 1 |
1067 } |
1105 } |
1068 Ok(node.copy_source.replace(value.into()).map(Cow::into_owned)) |
1106 Ok(node.copy_source.replace(value.into()).map(Cow::into_owned)) |
|
1107 }) |
1069 } |
1108 } |
1070 |
1109 |
1071 pub fn len(&self) -> usize { |
1110 pub fn len(&self) -> usize { |
1072 let map = self.get_map(); |
1111 let map = self.get_map(); |
1073 map.nodes_with_entry_count as usize |
1112 map.nodes_with_entry_count as usize |