##// 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 use crate::matchers::get_ignore_function;
6 use crate::matchers::get_ignore_function;
7 use crate::matchers::Matcher;
7 use crate::matchers::Matcher;
8 use crate::utils::files::get_bytes_from_os_string;
8 use crate::utils::files::get_bytes_from_os_string;
9 use crate::utils::files::get_path_from_bytes;
9 use crate::utils::hg_path::HgPath;
10 use crate::utils::hg_path::HgPath;
10 use crate::BadMatch;
11 use crate::BadMatch;
11 use crate::DirstateStatus;
12 use crate::DirstateStatus;
@@ -83,14 +84,17 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
83 fs_path: &Path,
84 fs_path: &Path,
84 is_at_repo_root: bool,
85 is_at_repo_root: bool,
85 ) -> Result<Vec<DirEntry>, ()> {
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 let errno = error.raw_os_error().expect("expected real OS error");
92 let errno = error.raw_os_error().expect("expected real OS error");
88 self.outcome
93 self.outcome
89 .lock()
94 .lock()
90 .unwrap()
95 .unwrap()
91 .bad
96 .bad
92 .push((hg_path.to_owned().into(), BadMatch::OsError(errno)))
97 .push((hg_path.to_owned().into(), BadMatch::OsError(errno)))
93 })
94 }
98 }
95
99
96 fn traverse_fs_directory_and_dirstate(
100 fn traverse_fs_directory_and_dirstate(
@@ -101,6 +105,35 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
101 directory_fs_path: &Path,
105 directory_fs_path: &Path,
102 is_at_repo_root: bool,
106 is_at_repo_root: bool,
103 ) -> Result<(), DirstateV2ParseError> {
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 let mut fs_entries = if let Ok(entries) = self.read_dir(
137 let mut fs_entries = if let Ok(entries) = self.read_dir(
105 directory_hg_path,
138 directory_hg_path,
106 directory_fs_path,
139 directory_fs_path,
@@ -141,7 +174,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
141 match pair {
174 match pair {
142 Both(dirstate_node, fs_entry) => self
175 Both(dirstate_node, fs_entry) => self
143 .traverse_fs_and_dirstate(
176 .traverse_fs_and_dirstate(
144 fs_entry,
177 &fs_entry.full_path,
178 &fs_entry.metadata,
145 dirstate_node,
179 dirstate_node,
146 has_ignored_ancestor,
180 has_ignored_ancestor,
147 ),
181 ),
@@ -160,12 +194,13 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
160
194
161 fn traverse_fs_and_dirstate(
195 fn traverse_fs_and_dirstate(
162 &self,
196 &self,
163 fs_entry: &DirEntry,
197 fs_path: &Path,
198 fs_metadata: &std::fs::Metadata,
164 dirstate_node: NodeRef<'tree, '_>,
199 dirstate_node: NodeRef<'tree, '_>,
165 has_ignored_ancestor: bool,
200 has_ignored_ancestor: bool,
166 ) -> Result<(), DirstateV2ParseError> {
201 ) -> Result<(), DirstateV2ParseError> {
167 let hg_path = dirstate_node.full_path(self.dmap.on_disk)?;
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 let file_or_symlink = file_type.is_file() || file_type.is_symlink();
204 let file_or_symlink = file_type.is_file() || file_type.is_symlink();
170 if !file_or_symlink {
205 if !file_or_symlink {
171 // If we previously had a file here, it was removed (with
206 // If we previously had a file here, it was removed (with
@@ -186,7 +221,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
186 is_ignored,
221 is_ignored,
187 dirstate_node.children(self.dmap.on_disk)?,
222 dirstate_node.children(self.dmap.on_disk)?,
188 hg_path,
223 hg_path,
189 &fs_entry.full_path,
224 fs_path,
190 is_at_repo_root,
225 is_at_repo_root,
191 )?
226 )?
192 } else {
227 } else {
@@ -209,9 +244,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
209 .unwrap()
244 .unwrap()
210 .modified
245 .modified
211 .push(full_path),
246 .push(full_path),
212 EntryState::Normal => {
247 EntryState::Normal => self
213 self.handle_normal_file(&dirstate_node, fs_entry)?
248 .handle_normal_file(&dirstate_node, fs_metadata)?,
214 }
215 // This variant is not used in DirstateMap
249 // This variant is not used in DirstateMap
216 // nodes
250 // nodes
217 EntryState::Unknown => unreachable!(),
251 EntryState::Unknown => unreachable!(),
@@ -239,7 +273,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
239 fn handle_normal_file(
273 fn handle_normal_file(
240 &self,
274 &self,
241 dirstate_node: &NodeRef<'tree, '_>,
275 dirstate_node: &NodeRef<'tree, '_>,
242 fs_entry: &DirEntry,
276 fs_metadata: &std::fs::Metadata,
243 ) -> Result<(), DirstateV2ParseError> {
277 ) -> Result<(), DirstateV2ParseError> {
244 // Keep the low 31 bits
278 // Keep the low 31 bits
245 fn truncate_u64(value: u64) -> i32 {
279 fn truncate_u64(value: u64) -> i32 {
@@ -253,13 +287,12 b" impl<'tree, 'a> StatusCommon<'tree, 'a, "
253 .entry()?
287 .entry()?
254 .expect("handle_normal_file called with entry-less node");
288 .expect("handle_normal_file called with entry-less node");
255 let full_path = Cow::from(dirstate_node.full_path(self.dmap.on_disk)?);
289 let full_path = Cow::from(dirstate_node.full_path(self.dmap.on_disk)?);
256 let mode_changed = || {
290 let mode_changed =
257 self.options.check_exec && entry.mode_changed(&fs_entry.metadata)
291 || self.options.check_exec && entry.mode_changed(fs_metadata);
258 };
292 let size_changed = entry.size != truncate_u64(fs_metadata.len());
259 let size_changed = entry.size != truncate_u64(fs_entry.metadata.len());
260 if entry.size >= 0
293 if entry.size >= 0
261 && size_changed
294 && size_changed
262 && fs_entry.metadata.file_type().is_symlink()
295 && fs_metadata.file_type().is_symlink()
263 {
296 {
264 // issue6456: Size returned may be longer due to encryption
297 // issue6456: Size returned may be longer due to encryption
265 // on EXT-4 fscrypt. TODO maybe only do it on EXT4?
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 self.outcome.lock().unwrap().modified.push(full_path)
304 self.outcome.lock().unwrap().modified.push(full_path)
272 } else {
305 } else {
273 let mtime = mtime_seconds(&fs_entry.metadata);
306 let mtime = mtime_seconds(fs_metadata);
274 if truncate_i64(mtime) != entry.mtime
307 if truncate_i64(mtime) != entry.mtime
275 || mtime == self.options.last_normal_time
308 || mtime == self.options.last_normal_time
276 {
309 {
General Comments 0
You need to be logged in to leave comments. Login now