Mercurial > hg
comparison rust/hg-core/src/dirstate_tree/dirstate_map.rs @ 49005:12adf8c695ed
merge: stable into default
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Tue, 05 Apr 2022 11:09:03 +0200 |
parents | 11c0411bf4e2 ce919b1a1063 |
children | a85c123c625a |
comparison
equal
deleted
inserted
replaced
48997:20c6c9e43397 | 49005:12adf8c695ed |
---|---|
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 |
1111 + Send | 1150 + Send |
1112 + '_, | 1151 + '_, |
1113 >, | 1152 >, |
1114 DirstateError, | 1153 DirstateError, |
1115 > { | 1154 > { |
1116 let map = self.get_map_mut(); | 1155 let map = self.get_map(); |
1117 let on_disk = map.on_disk; | 1156 let on_disk = map.on_disk; |
1118 Ok(Box::new(filter_map_results( | 1157 Ok(Box::new(filter_map_results( |
1119 map.iter_nodes(), | 1158 map.iter_nodes(), |
1120 move |node| { | 1159 move |node| { |
1121 Ok(if node.tracked_descendants_count() > 0 { | 1160 Ok(if node.tracked_descendants_count() > 0 { |