##// END OF EJS Templates
dirstate-tree: Skip readdir() in `hg status -mard`...
Simon Sapin -
r48129:f27f2afb default
parent child Browse files
Show More
@@ -6,6 +6,7 b' use crate::dirstate_tree::on_disk::Dirst'
6 6 use crate::matchers::get_ignore_function;
7 7 use crate::matchers::Matcher;
8 8 use crate::utils::files::get_bytes_from_os_string;
9 use crate::utils::files::get_path_from_bytes;
9 10 use crate::utils::hg_path::HgPath;
10 11 use crate::BadMatch;
11 12 use crate::DirstateStatus;
@@ -83,14 +84,17 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
83 84 fs_path: &Path,
84 85 is_at_repo_root: bool,
85 86 ) -> Result<Vec<DirEntry>, ()> {
86 DirEntry::read_dir(fs_path, is_at_repo_root).map_err(|error| {
87 DirEntry::read_dir(fs_path, is_at_repo_root)
88 .map_err(|error| self.io_error(error, hg_path))
89 }
90
91 fn io_error(&self, error: std::io::Error, hg_path: &HgPath) {
87 92 let errno = error.raw_os_error().expect("expected real OS error");
88 93 self.outcome
89 94 .lock()
90 95 .unwrap()
91 96 .bad
92 97 .push((hg_path.to_owned().into(), BadMatch::OsError(errno)))
93 })
94 98 }
95 99
96 100 fn traverse_fs_directory_and_dirstate(
@@ -101,6 +105,35 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
101 105 directory_fs_path: &Path,
102 106 is_at_repo_root: bool,
103 107 ) -> Result<(), DirstateV2ParseError> {
108 if !self.options.list_unknown && !self.options.list_ignored {
109 // We only care about files in the dirstate, so we can skip listing
110 // filesystem directories entirely.
111 return dirstate_nodes
112 .par_iter()
113 .map(|dirstate_node| {
114 let fs_path = directory_fs_path.join(get_path_from_bytes(
115 dirstate_node.base_name(self.dmap.on_disk)?.as_bytes(),
116 ));
117 match std::fs::symlink_metadata(&fs_path) {
118 Ok(fs_metadata) => self.traverse_fs_and_dirstate(
119 &fs_path,
120 &fs_metadata,
121 dirstate_node,
122 has_ignored_ancestor,
123 ),
124 Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
125 self.traverse_dirstate_only(dirstate_node)
126 }
127 Err(error) => {
128 let hg_path =
129 dirstate_node.full_path(self.dmap.on_disk)?;
130 Ok(self.io_error(error, hg_path))
131 }
132 }
133 })
134 .collect();
135 }
136
104 137 let mut fs_entries = if let Ok(entries) = self.read_dir(
105 138 directory_hg_path,
106 139 directory_fs_path,
@@ -141,7 +174,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
141 174 match pair {
142 175 Both(dirstate_node, fs_entry) => self
143 176 .traverse_fs_and_dirstate(
144 fs_entry,
177 &fs_entry.full_path,
178 &fs_entry.metadata,
145 179 dirstate_node,
146 180 has_ignored_ancestor,
147 181 ),
@@ -160,12 +194,13 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
160 194
161 195 fn traverse_fs_and_dirstate(
162 196 &self,
163 fs_entry: &DirEntry,
197 fs_path: &Path,
198 fs_metadata: &std::fs::Metadata,
164 199 dirstate_node: NodeRef<'tree, '_>,
165 200 has_ignored_ancestor: bool,
166 201 ) -> Result<(), DirstateV2ParseError> {
167 202 let hg_path = dirstate_node.full_path(self.dmap.on_disk)?;
168 let file_type = fs_entry.metadata.file_type();
203 let file_type = fs_metadata.file_type();
169 204 let file_or_symlink = file_type.is_file() || file_type.is_symlink();
170 205 if !file_or_symlink {
171 206 // If we previously had a file here, it was removed (with
@@ -186,7 +221,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
186 221 is_ignored,
187 222 dirstate_node.children(self.dmap.on_disk)?,
188 223 hg_path,
189 &fs_entry.full_path,
224 fs_path,
190 225 is_at_repo_root,
191 226 )?
192 227 } else {
@@ -209,9 +244,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
209 244 .unwrap()
210 245 .modified
211 246 .push(full_path),
212 EntryState::Normal => {
213 self.handle_normal_file(&dirstate_node, fs_entry)?
214 }
247 EntryState::Normal => self
248 .handle_normal_file(&dirstate_node, fs_metadata)?,
215 249 // This variant is not used in DirstateMap
216 250 // nodes
217 251 EntryState::Unknown => unreachable!(),
@@ -239,7 +273,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
239 273 fn handle_normal_file(
240 274 &self,
241 275 dirstate_node: &NodeRef<'tree, '_>,
242 fs_entry: &DirEntry,
276 fs_metadata: &std::fs::Metadata,
243 277 ) -> Result<(), DirstateV2ParseError> {
244 278 // Keep the low 31 bits
245 279 fn truncate_u64(value: u64) -> i32 {
@@ -253,13 +287,12 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
253 287 .entry()?
254 288 .expect("handle_normal_file called with entry-less node");
255 289 let full_path = Cow::from(dirstate_node.full_path(self.dmap.on_disk)?);
256 let mode_changed = || {
257 self.options.check_exec && entry.mode_changed(&fs_entry.metadata)
258 };
259 let size_changed = entry.size != truncate_u64(fs_entry.metadata.len());
290 let mode_changed =
291 || self.options.check_exec && entry.mode_changed(fs_metadata);
292 let size_changed = entry.size != truncate_u64(fs_metadata.len());
260 293 if entry.size >= 0
261 294 && size_changed
262 && fs_entry.metadata.file_type().is_symlink()
295 && fs_metadata.file_type().is_symlink()
263 296 {
264 297 // issue6456: Size returned may be longer due to encryption
265 298 // on EXT-4 fscrypt. TODO maybe only do it on EXT4?
@@ -270,7 +303,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
270 303 {
271 304 self.outcome.lock().unwrap().modified.push(full_path)
272 305 } else {
273 let mtime = mtime_seconds(&fs_entry.metadata);
306 let mtime = mtime_seconds(fs_metadata);
274 307 if truncate_i64(mtime) != entry.mtime
275 308 || mtime == self.options.last_normal_time
276 309 {
General Comments 0
You need to be logged in to leave comments. Login now