##// END OF EJS Templates
dirstate-tree: Fold "tracked descendants" counter update in main walk...
Simon Sapin -
r47890:7109a388 default
parent child Browse files
Show More
@@ -1,653 +1,647 b''
1 use bytes_cast::BytesCast;
1 use bytes_cast::BytesCast;
2 use micro_timer::timed;
2 use micro_timer::timed;
3 use std::convert::TryInto;
3 use std::convert::TryInto;
4 use std::path::PathBuf;
4 use std::path::PathBuf;
5
5
6 use super::path_with_basename::WithBasename;
6 use super::path_with_basename::WithBasename;
7 use crate::dirstate::parsers::clear_ambiguous_mtime;
7 use crate::dirstate::parsers::clear_ambiguous_mtime;
8 use crate::dirstate::parsers::pack_entry;
8 use crate::dirstate::parsers::pack_entry;
9 use crate::dirstate::parsers::packed_entry_size;
9 use crate::dirstate::parsers::packed_entry_size;
10 use crate::dirstate::parsers::parse_dirstate_entries;
10 use crate::dirstate::parsers::parse_dirstate_entries;
11 use crate::dirstate::parsers::parse_dirstate_parents;
11 use crate::dirstate::parsers::parse_dirstate_parents;
12 use crate::dirstate::parsers::Timestamp;
12 use crate::dirstate::parsers::Timestamp;
13 use crate::matchers::Matcher;
13 use crate::matchers::Matcher;
14 use crate::revlog::node::NULL_NODE;
14 use crate::revlog::node::NULL_NODE;
15 use crate::utils::hg_path::{HgPath, HgPathBuf};
15 use crate::utils::hg_path::{HgPath, HgPathBuf};
16 use crate::CopyMapIter;
16 use crate::CopyMapIter;
17 use crate::DirstateEntry;
17 use crate::DirstateEntry;
18 use crate::DirstateError;
18 use crate::DirstateError;
19 use crate::DirstateMapError;
19 use crate::DirstateMapError;
20 use crate::DirstateParents;
20 use crate::DirstateParents;
21 use crate::DirstateStatus;
21 use crate::DirstateStatus;
22 use crate::EntryState;
22 use crate::EntryState;
23 use crate::FastHashMap;
23 use crate::FastHashMap;
24 use crate::PatternFileWarning;
24 use crate::PatternFileWarning;
25 use crate::StateMapIter;
25 use crate::StateMapIter;
26 use crate::StatusError;
26 use crate::StatusError;
27 use crate::StatusOptions;
27 use crate::StatusOptions;
28
28
29 pub struct DirstateMap {
29 pub struct DirstateMap {
30 parents: Option<DirstateParents>,
30 parents: Option<DirstateParents>,
31 dirty_parents: bool,
31 dirty_parents: bool,
32 pub(super) root: ChildNodes,
32 pub(super) root: ChildNodes,
33
33
34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
35 nodes_with_entry_count: usize,
35 nodes_with_entry_count: usize,
36
36
37 /// Number of nodes anywhere in the tree that have
37 /// Number of nodes anywhere in the tree that have
38 /// `.copy_source.is_some()`.
38 /// `.copy_source.is_some()`.
39 nodes_with_copy_source_count: usize,
39 nodes_with_copy_source_count: usize,
40 }
40 }
41
41
42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
43 /// map key would also work: all paths in a given map have the same parent
43 /// map key would also work: all paths in a given map have the same parent
44 /// path, so comparing full paths gives the same result as comparing base
44 /// path, so comparing full paths gives the same result as comparing base
45 /// names. However `BTreeMap` would waste time always re-comparing the same
45 /// names. However `BTreeMap` would waste time always re-comparing the same
46 /// string prefix.
46 /// string prefix.
47 pub(super) type ChildNodes = FastHashMap<WithBasename<HgPathBuf>, Node>;
47 pub(super) type ChildNodes = FastHashMap<WithBasename<HgPathBuf>, Node>;
48
48
49 /// Represents a file or a directory
49 /// Represents a file or a directory
50 #[derive(Default)]
50 #[derive(Default)]
51 pub(super) struct Node {
51 pub(super) struct Node {
52 /// `None` for directories
52 /// `None` for directories
53 pub(super) entry: Option<DirstateEntry>,
53 pub(super) entry: Option<DirstateEntry>,
54
54
55 pub(super) copy_source: Option<HgPathBuf>,
55 pub(super) copy_source: Option<HgPathBuf>,
56
56
57 pub(super) children: ChildNodes,
57 pub(super) children: ChildNodes,
58
58
59 /// How many (non-inclusive) descendants of this node are tracked files
59 /// How many (non-inclusive) descendants of this node are tracked files
60 tracked_descendants_count: usize,
60 tracked_descendants_count: usize,
61 }
61 }
62
62
63 impl Node {
63 impl Node {
64 /// Whether this node has a `DirstateEntry` with `.state.is_tracked()`
65 fn is_tracked_file(&self) -> bool {
66 if let Some(entry) = &self.entry {
67 entry.state.is_tracked()
68 } else {
69 false
70 }
71 }
72
73 pub(super) fn state(&self) -> Option<EntryState> {
64 pub(super) fn state(&self) -> Option<EntryState> {
74 self.entry.as_ref().map(|entry| entry.state)
65 self.entry.as_ref().map(|entry| entry.state)
75 }
66 }
76 }
67 }
77
68
78 /// `(full_path, entry, copy_source)`
69 /// `(full_path, entry, copy_source)`
79 type NodeDataMut<'a> = (
70 type NodeDataMut<'a> = (
80 &'a WithBasename<HgPathBuf>,
71 &'a WithBasename<HgPathBuf>,
81 &'a mut Option<DirstateEntry>,
72 &'a mut Option<DirstateEntry>,
82 &'a mut Option<HgPathBuf>,
73 &'a mut Option<HgPathBuf>,
83 );
74 );
84
75
85 impl DirstateMap {
76 impl DirstateMap {
86 pub fn new() -> Self {
77 pub fn new() -> Self {
87 Self {
78 Self {
88 parents: None,
79 parents: None,
89 dirty_parents: false,
80 dirty_parents: false,
90 root: ChildNodes::default(),
81 root: ChildNodes::default(),
91 nodes_with_entry_count: 0,
82 nodes_with_entry_count: 0,
92 nodes_with_copy_source_count: 0,
83 nodes_with_copy_source_count: 0,
93 }
84 }
94 }
85 }
95
86
96 fn get_node(&self, path: &HgPath) -> Option<&Node> {
87 fn get_node(&self, path: &HgPath) -> Option<&Node> {
97 let mut children = &self.root;
88 let mut children = &self.root;
98 let mut components = path.components();
89 let mut components = path.components();
99 let mut component =
90 let mut component =
100 components.next().expect("expected at least one components");
91 components.next().expect("expected at least one components");
101 loop {
92 loop {
102 let child = children.get(component)?;
93 let child = children.get(component)?;
103 if let Some(next_component) = components.next() {
94 if let Some(next_component) = components.next() {
104 component = next_component;
95 component = next_component;
105 children = &child.children;
96 children = &child.children;
106 } else {
97 } else {
107 return Some(child);
98 return Some(child);
108 }
99 }
109 }
100 }
110 }
101 }
111
102
112 /// Returns a mutable reference to the node at `path` if it exists
103 /// Returns a mutable reference to the node at `path` if it exists
113 ///
104 ///
114 /// This takes `root` instead of `&mut self` so that callers can mutate
105 /// This takes `root` instead of `&mut self` so that callers can mutate
115 /// other fields while the returned borrow is still valid
106 /// other fields while the returned borrow is still valid
116 fn get_node_mut<'tree>(
107 fn get_node_mut<'tree>(
117 root: &'tree mut ChildNodes,
108 root: &'tree mut ChildNodes,
118 path: &HgPath,
109 path: &HgPath,
119 ) -> Option<&'tree mut Node> {
110 ) -> Option<&'tree mut Node> {
120 Self::each_and_get(root, path, |_| {})
111 Self::get_node_mut_tracing_ancestors(root, path, |_| {})
121 }
112 }
122
113
123 /// Call `each` for each ancestor node of the one at `path` (not including
114 /// Same as `get_node_mut`, and calls `each_ancestor` for each ancestor of
124 /// that node itself), starting from nearest the root.
115 /// the node.
125 ///
116 ///
126 /// Panics (possibly after some calls to `each`) if there is no node at
117 /// Note that `each_ancestor` may be called (with what would be ancestors)
127 /// `path`.
118 /// even if it turns out there is no node at `path`.
128 fn for_each_ancestor_node<'tree>(
119 fn get_node_mut_tracing_ancestors<'tree>(
129 &mut self,
130 path: &HgPath,
131 each: impl FnMut(&mut Node),
132 ) {
133 let parent = path.parent();
134 if !parent.is_empty() {
135 Self::each_and_get(&mut self.root, parent, each)
136 .expect("missing dirstate node");
137 }
138 }
139
140 /// Common implementation detail of `get_node_mut` and
141 /// `for_each_ancestor_node`
142 fn each_and_get<'tree>(
143 root: &'tree mut ChildNodes,
120 root: &'tree mut ChildNodes,
144 path: &HgPath,
121 path: &HgPath,
145 mut each: impl FnMut(&mut Node),
122 mut each_ancestor: impl FnMut(&mut Node),
146 ) -> Option<&'tree mut Node> {
123 ) -> Option<&'tree mut Node> {
147 let mut children = root;
124 let mut children = root;
148 let mut components = path.components();
125 let mut components = path.components();
149 let mut component =
126 let mut component =
150 components.next().expect("expected at least one components");
127 components.next().expect("expected at least one components");
151 loop {
128 loop {
152 let child = children.get_mut(component)?;
129 let child = children.get_mut(component)?;
153 each(child);
154 if let Some(next_component) = components.next() {
130 if let Some(next_component) = components.next() {
131 each_ancestor(child);
155 component = next_component;
132 component = next_component;
156 children = &mut child.children;
133 children = &mut child.children;
157 } else {
134 } else {
158 return Some(child);
135 return Some(child);
159 }
136 }
160 }
137 }
161 }
138 }
162
139
163 fn get_or_insert_node<'tree>(
140 fn get_or_insert_node<'tree>(
164 root: &'tree mut ChildNodes,
141 root: &'tree mut ChildNodes,
165 path: &HgPath,
142 path: &HgPath,
166 ) -> &'tree mut Node {
143 ) -> &'tree mut Node {
144 Self::get_or_insert_node_tracing_ancestors(root, path, |_| {})
145 }
146
147 fn get_or_insert_node_tracing_ancestors<'tree>(
148 root: &'tree mut ChildNodes,
149 path: &HgPath,
150 mut each_ancestor: impl FnMut(&mut Node),
151 ) -> &'tree mut Node {
167 let mut child_nodes = root;
152 let mut child_nodes = root;
168 let mut inclusive_ancestor_paths =
153 let mut inclusive_ancestor_paths =
169 WithBasename::inclusive_ancestors_of(path);
154 WithBasename::inclusive_ancestors_of(path);
170 let mut ancestor_path = inclusive_ancestor_paths
155 let mut ancestor_path = inclusive_ancestor_paths
171 .next()
156 .next()
172 .expect("expected at least one inclusive ancestor");
157 .expect("expected at least one inclusive ancestor");
173 loop {
158 loop {
174 // TODO: can we avoid allocating an owned key in cases where the
159 // TODO: can we avoid allocating an owned key in cases where the
175 // map already contains that key, without introducing double
160 // map already contains that key, without introducing double
176 // lookup?
161 // lookup?
177 let child_node =
162 let child_node =
178 child_nodes.entry(ancestor_path.to_owned()).or_default();
163 child_nodes.entry(ancestor_path.to_owned()).or_default();
179 if let Some(next) = inclusive_ancestor_paths.next() {
164 if let Some(next) = inclusive_ancestor_paths.next() {
165 each_ancestor(child_node);
180 ancestor_path = next;
166 ancestor_path = next;
181 child_nodes = &mut child_node.children;
167 child_nodes = &mut child_node.children;
182 } else {
168 } else {
183 return child_node;
169 return child_node;
184 }
170 }
185 }
171 }
186 }
172 }
187
173
188 /// The meaning of `new_copy_source` is:
174 fn add_or_remove_file(
189 ///
190 /// * `Some(Some(x))`: set `Node::copy_source` to `Some(x)`
191 /// * `Some(None)`: set `Node::copy_source` to `None`
192 /// * `None`: leave `Node::copy_source` unchanged
193 fn add_file_node(
194 &mut self,
175 &mut self,
195 path: &HgPath,
176 path: &HgPath,
177 old_state: EntryState,
196 new_entry: DirstateEntry,
178 new_entry: DirstateEntry,
197 new_copy_source: Option<Option<HgPathBuf>>,
198 ) {
179 ) {
199 let node = Self::get_or_insert_node(&mut self.root, path);
200 if node.entry.is_none() {
201 self.nodes_with_entry_count += 1
202 }
203 if let Some(source) = &new_copy_source {
204 if node.copy_source.is_none() && source.is_some() {
205 self.nodes_with_copy_source_count += 1
206 }
207 if node.copy_source.is_some() && source.is_none() {
208 self.nodes_with_copy_source_count -= 1
209 }
210 }
211 let tracked_count_increment =
180 let tracked_count_increment =
212 match (node.is_tracked_file(), new_entry.state.is_tracked()) {
181 match (old_state.is_tracked(), new_entry.state.is_tracked()) {
213 (false, true) => 1,
182 (false, true) => 1,
214 (true, false) => -1,
183 (true, false) => -1,
215 _ => 0,
184 _ => 0,
216 };
185 };
217
186
218 node.entry = Some(new_entry);
187 let node = Self::get_or_insert_node_tracing_ancestors(
219 if let Some(source) = new_copy_source {
188 &mut self.root,
220 node.copy_source = source
189 path,
190 |ancestor| {
191 // We can’t use `+= increment` because the counter is unsigned,
192 // and we want debug builds to detect accidental underflow
193 // through zero
194 match tracked_count_increment {
195 1 => ancestor.tracked_descendants_count += 1,
196 -1 => ancestor.tracked_descendants_count -= 1,
197 _ => {}
198 }
199 },
200 );
201 if node.entry.is_none() {
202 self.nodes_with_entry_count += 1
221 }
203 }
222 // Borrow of `self.root` through `node` ends here
204 node.entry = Some(new_entry)
223
224 match tracked_count_increment {
225 1 => self.for_each_ancestor_node(path, |node| {
226 node.tracked_descendants_count += 1
227 }),
228 // We can’t use `+= -1` because the counter is unsigned
229 -1 => self.for_each_ancestor_node(path, |node| {
230 node.tracked_descendants_count -= 1
231 }),
232 _ => {}
233 }
234 }
205 }
235
206
236 fn iter_nodes<'a>(
207 fn iter_nodes<'a>(
237 &'a self,
208 &'a self,
238 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
209 ) -> impl Iterator<Item = (&'a WithBasename<HgPathBuf>, &'a Node)> + 'a
239 {
210 {
240 // Depth first tree traversal.
211 // Depth first tree traversal.
241 //
212 //
242 // If we could afford internal iteration and recursion,
213 // If we could afford internal iteration and recursion,
243 // this would look like:
214 // this would look like:
244 //
215 //
245 // ```
216 // ```
246 // fn traverse_children(
217 // fn traverse_children(
247 // children: &ChildNodes,
218 // children: &ChildNodes,
248 // each: &mut impl FnMut(&Node),
219 // each: &mut impl FnMut(&Node),
249 // ) {
220 // ) {
250 // for child in children.values() {
221 // for child in children.values() {
251 // traverse_children(&child.children, each);
222 // traverse_children(&child.children, each);
252 // each(child);
223 // each(child);
253 // }
224 // }
254 // }
225 // }
255 // ```
226 // ```
256 //
227 //
257 // However we want an external iterator and therefore can’t use the
228 // However we want an external iterator and therefore can’t use the
258 // call stack. Use an explicit stack instead:
229 // call stack. Use an explicit stack instead:
259 let mut stack = Vec::new();
230 let mut stack = Vec::new();
260 let mut iter = self.root.iter();
231 let mut iter = self.root.iter();
261 std::iter::from_fn(move || {
232 std::iter::from_fn(move || {
262 while let Some((key, child_node)) = iter.next() {
233 while let Some((key, child_node)) = iter.next() {
263 // Pseudo-recursion
234 // Pseudo-recursion
264 let new_iter = child_node.children.iter();
235 let new_iter = child_node.children.iter();
265 let old_iter = std::mem::replace(&mut iter, new_iter);
236 let old_iter = std::mem::replace(&mut iter, new_iter);
266 stack.push((key, child_node, old_iter));
237 stack.push((key, child_node, old_iter));
267 }
238 }
268 // Found the end of a `children.iter()` iterator.
239 // Found the end of a `children.iter()` iterator.
269 if let Some((key, child_node, next_iter)) = stack.pop() {
240 if let Some((key, child_node, next_iter)) = stack.pop() {
270 // "Return" from pseudo-recursion by restoring state from the
241 // "Return" from pseudo-recursion by restoring state from the
271 // explicit stack
242 // explicit stack
272 iter = next_iter;
243 iter = next_iter;
273
244
274 Some((key, child_node))
245 Some((key, child_node))
275 } else {
246 } else {
276 // Reached the bottom of the stack, we’re done
247 // Reached the bottom of the stack, we’re done
277 None
248 None
278 }
249 }
279 })
250 })
280 }
251 }
281
252
282 /// Mutable iterator for the `(entry, copy source)` of each node.
253 /// Mutable iterator for the `(entry, copy source)` of each node.
283 ///
254 ///
284 /// It would not be safe to yield mutable references to nodes themeselves
255 /// It would not be safe to yield mutable references to nodes themeselves
285 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
256 /// with `-> impl Iterator<Item = &mut Node>` since child nodes are
286 /// reachable from their ancestor nodes, potentially creating multiple
257 /// reachable from their ancestor nodes, potentially creating multiple
287 /// `&mut` references to a given node.
258 /// `&mut` references to a given node.
288 fn iter_node_data_mut<'a>(
259 fn iter_node_data_mut<'a>(
289 &'a mut self,
260 &'a mut self,
290 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
261 ) -> impl Iterator<Item = NodeDataMut<'a>> + 'a {
291 // Explict stack for pseudo-recursion, see `iter_nodes` above.
262 // Explict stack for pseudo-recursion, see `iter_nodes` above.
292 let mut stack = Vec::new();
263 let mut stack = Vec::new();
293 let mut iter = self.root.iter_mut();
264 let mut iter = self.root.iter_mut();
294 std::iter::from_fn(move || {
265 std::iter::from_fn(move || {
295 while let Some((key, child_node)) = iter.next() {
266 while let Some((key, child_node)) = iter.next() {
296 // Pseudo-recursion
267 // Pseudo-recursion
297 let data =
268 let data =
298 (key, &mut child_node.entry, &mut child_node.copy_source);
269 (key, &mut child_node.entry, &mut child_node.copy_source);
299 let new_iter = child_node.children.iter_mut();
270 let new_iter = child_node.children.iter_mut();
300 let old_iter = std::mem::replace(&mut iter, new_iter);
271 let old_iter = std::mem::replace(&mut iter, new_iter);
301 stack.push((data, old_iter));
272 stack.push((data, old_iter));
302 }
273 }
303 // Found the end of a `children.values_mut()` iterator.
274 // Found the end of a `children.values_mut()` iterator.
304 if let Some((data, next_iter)) = stack.pop() {
275 if let Some((data, next_iter)) = stack.pop() {
305 // "Return" from pseudo-recursion by restoring state from the
276 // "Return" from pseudo-recursion by restoring state from the
306 // explicit stack
277 // explicit stack
307 iter = next_iter;
278 iter = next_iter;
308
279
309 Some(data)
280 Some(data)
310 } else {
281 } else {
311 // Reached the bottom of the stack, we’re done
282 // Reached the bottom of the stack, we’re done
312 None
283 None
313 }
284 }
314 })
285 })
315 }
286 }
316 }
287 }
317
288
318 impl super::dispatch::DirstateMapMethods for DirstateMap {
289 impl super::dispatch::DirstateMapMethods for DirstateMap {
319 fn clear(&mut self) {
290 fn clear(&mut self) {
320 self.set_parents(&DirstateParents {
291 self.set_parents(&DirstateParents {
321 p1: NULL_NODE,
292 p1: NULL_NODE,
322 p2: NULL_NODE,
293 p2: NULL_NODE,
323 });
294 });
324 self.root.clear();
295 self.root.clear();
325 self.nodes_with_entry_count = 0;
296 self.nodes_with_entry_count = 0;
326 self.nodes_with_copy_source_count = 0;
297 self.nodes_with_copy_source_count = 0;
327 }
298 }
328
299
329 fn add_file(
300 fn add_file(
330 &mut self,
301 &mut self,
331 filename: &HgPath,
302 filename: &HgPath,
332 _old_state: EntryState,
303 old_state: EntryState,
333 entry: DirstateEntry,
304 entry: DirstateEntry,
334 ) -> Result<(), DirstateMapError> {
305 ) -> Result<(), DirstateMapError> {
335 self.add_file_node(filename, entry, None);
306 self.add_or_remove_file(filename, old_state, entry);
336 Ok(())
307 Ok(())
337 }
308 }
338
309
339 fn remove_file(
310 fn remove_file(
340 &mut self,
311 &mut self,
341 filename: &HgPath,
312 filename: &HgPath,
342 _old_state: EntryState,
313 old_state: EntryState,
343 size: i32,
314 size: i32,
344 ) -> Result<(), DirstateMapError> {
315 ) -> Result<(), DirstateMapError> {
345 let entry = DirstateEntry {
316 let entry = DirstateEntry {
346 state: EntryState::Removed,
317 state: EntryState::Removed,
347 mode: 0,
318 mode: 0,
348 size,
319 size,
349 mtime: 0,
320 mtime: 0,
350 };
321 };
351 self.add_file_node(filename, entry, None);
322 self.add_or_remove_file(filename, old_state, entry);
352 Ok(())
323 Ok(())
353 }
324 }
354
325
355 fn drop_file(
326 fn drop_file(
356 &mut self,
327 &mut self,
357 filename: &HgPath,
328 filename: &HgPath,
358 _old_state: EntryState,
329 old_state: EntryState,
359 ) -> Result<bool, DirstateMapError> {
330 ) -> Result<bool, DirstateMapError> {
360 if let Some(node) = Self::get_node_mut(&mut self.root, filename) {
331 let was_tracked = old_state.is_tracked();
361 let was_tracked = node.is_tracked_file();
332 if let Some(node) = Self::get_node_mut_tracing_ancestors(
333 &mut self.root,
334 filename,
335 |ancestor| {
336 if was_tracked {
337 ancestor.tracked_descendants_count -= 1
338 }
339 },
340 ) {
362 let had_entry = node.entry.is_some();
341 let had_entry = node.entry.is_some();
363 let had_copy_source = node.copy_source.is_some();
342 let had_copy_source = node.copy_source.is_some();
364
343
365 // TODO: this leaves in the tree a "non-file" node. Should we
344 // TODO: this leaves in the tree a "non-file" node. Should we
366 // remove the node instead, together with ancestor nodes for
345 // remove the node instead, together with ancestor nodes for
367 // directories that become empty?
346 // directories that become empty?
368 node.entry = None;
347 node.entry = None;
369 node.copy_source = None;
348 node.copy_source = None;
370
349
371 if had_entry {
350 if had_entry {
372 self.nodes_with_entry_count -= 1
351 self.nodes_with_entry_count -= 1
373 }
352 }
374 if had_copy_source {
353 if had_copy_source {
375 self.nodes_with_copy_source_count -= 1
354 self.nodes_with_copy_source_count -= 1
376 }
355 }
377 if was_tracked {
378 self.for_each_ancestor_node(filename, |node| {
379 node.tracked_descendants_count -= 1
380 })
381 }
382 Ok(had_entry)
356 Ok(had_entry)
383 } else {
357 } else {
358 assert!(!was_tracked);
384 Ok(false)
359 Ok(false)
385 }
360 }
386 }
361 }
387
362
388 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
363 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
389 for filename in filenames {
364 for filename in filenames {
390 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
365 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
391 if let Some(entry) = node.entry.as_mut() {
366 if let Some(entry) = node.entry.as_mut() {
392 clear_ambiguous_mtime(entry, now);
367 clear_ambiguous_mtime(entry, now);
393 }
368 }
394 }
369 }
395 }
370 }
396 }
371 }
397
372
398 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
373 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
399 self.get_node(key)
374 self.get_node(key)
400 .and_then(|node| node.entry.as_ref())
375 .and_then(|node| node.entry.as_ref())
401 .map_or(false, DirstateEntry::is_non_normal)
376 .map_or(false, DirstateEntry::is_non_normal)
402 }
377 }
403
378
404 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
379 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
405 // Do nothing, this `DirstateMap` does not have a separate "non normal
380 // Do nothing, this `DirstateMap` does not have a separate "non normal
406 // entries" set that need to be kept up to date
381 // entries" set that need to be kept up to date
407 }
382 }
408
383
409 fn non_normal_or_other_parent_paths(
384 fn non_normal_or_other_parent_paths(
410 &mut self,
385 &mut self,
411 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
386 ) -> Box<dyn Iterator<Item = &HgPathBuf> + '_> {
412 Box::new(self.iter_nodes().filter_map(|(path, node)| {
387 Box::new(self.iter_nodes().filter_map(|(path, node)| {
413 node.entry
388 node.entry
414 .as_ref()
389 .as_ref()
415 .filter(|entry| {
390 .filter(|entry| {
416 entry.is_non_normal() || entry.is_from_other_parent()
391 entry.is_non_normal() || entry.is_from_other_parent()
417 })
392 })
418 .map(|_| path.full_path())
393 .map(|_| path.full_path())
419 }))
394 }))
420 }
395 }
421
396
422 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
397 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
423 // Do nothing, this `DirstateMap` does not have a separate "non normal
398 // Do nothing, this `DirstateMap` does not have a separate "non normal
424 // entries" and "from other parent" sets that need to be recomputed
399 // entries" and "from other parent" sets that need to be recomputed
425 }
400 }
426
401
427 fn iter_non_normal_paths(
402 fn iter_non_normal_paths(
428 &mut self,
403 &mut self,
429 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
404 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
430 self.iter_non_normal_paths_panic()
405 self.iter_non_normal_paths_panic()
431 }
406 }
432
407
433 fn iter_non_normal_paths_panic(
408 fn iter_non_normal_paths_panic(
434 &self,
409 &self,
435 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
410 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
436 Box::new(self.iter_nodes().filter_map(|(path, node)| {
411 Box::new(self.iter_nodes().filter_map(|(path, node)| {
437 node.entry
412 node.entry
438 .as_ref()
413 .as_ref()
439 .filter(|entry| entry.is_non_normal())
414 .filter(|entry| entry.is_non_normal())
440 .map(|_| path.full_path())
415 .map(|_| path.full_path())
441 }))
416 }))
442 }
417 }
443
418
444 fn iter_other_parent_paths(
419 fn iter_other_parent_paths(
445 &mut self,
420 &mut self,
446 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
421 ) -> Box<dyn Iterator<Item = &HgPathBuf> + Send + '_> {
447 Box::new(self.iter_nodes().filter_map(|(path, node)| {
422 Box::new(self.iter_nodes().filter_map(|(path, node)| {
448 node.entry
423 node.entry
449 .as_ref()
424 .as_ref()
450 .filter(|entry| entry.is_from_other_parent())
425 .filter(|entry| entry.is_from_other_parent())
451 .map(|_| path.full_path())
426 .map(|_| path.full_path())
452 }))
427 }))
453 }
428 }
454
429
455 fn has_tracked_dir(
430 fn has_tracked_dir(
456 &mut self,
431 &mut self,
457 directory: &HgPath,
432 directory: &HgPath,
458 ) -> Result<bool, DirstateMapError> {
433 ) -> Result<bool, DirstateMapError> {
459 if let Some(node) = self.get_node(directory) {
434 if let Some(node) = self.get_node(directory) {
460 // A node without a `DirstateEntry` was created to hold child
435 // A node without a `DirstateEntry` was created to hold child
461 // nodes, and is therefore a directory.
436 // nodes, and is therefore a directory.
462 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
437 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
463 } else {
438 } else {
464 Ok(false)
439 Ok(false)
465 }
440 }
466 }
441 }
467
442
468 fn has_dir(
443 fn has_dir(
469 &mut self,
444 &mut self,
470 directory: &HgPath,
445 directory: &HgPath,
471 ) -> Result<bool, DirstateMapError> {
446 ) -> Result<bool, DirstateMapError> {
472 if let Some(node) = self.get_node(directory) {
447 if let Some(node) = self.get_node(directory) {
473 // A node without a `DirstateEntry` was created to hold child
448 // A node without a `DirstateEntry` was created to hold child
474 // nodes, and is therefore a directory.
449 // nodes, and is therefore a directory.
475 Ok(node.entry.is_none())
450 Ok(node.entry.is_none())
476 } else {
451 } else {
477 Ok(false)
452 Ok(false)
478 }
453 }
479 }
454 }
480
455
481 fn parents(
456 fn parents(
482 &mut self,
457 &mut self,
483 file_contents: &[u8],
458 file_contents: &[u8],
484 ) -> Result<&DirstateParents, DirstateError> {
459 ) -> Result<&DirstateParents, DirstateError> {
485 if self.parents.is_none() {
460 if self.parents.is_none() {
486 let parents = if !file_contents.is_empty() {
461 let parents = if !file_contents.is_empty() {
487 parse_dirstate_parents(file_contents)?.clone()
462 parse_dirstate_parents(file_contents)?.clone()
488 } else {
463 } else {
489 DirstateParents {
464 DirstateParents {
490 p1: NULL_NODE,
465 p1: NULL_NODE,
491 p2: NULL_NODE,
466 p2: NULL_NODE,
492 }
467 }
493 };
468 };
494 self.parents = Some(parents);
469 self.parents = Some(parents);
495 }
470 }
496 Ok(self.parents.as_ref().unwrap())
471 Ok(self.parents.as_ref().unwrap())
497 }
472 }
498
473
499 fn set_parents(&mut self, parents: &DirstateParents) {
474 fn set_parents(&mut self, parents: &DirstateParents) {
500 self.parents = Some(parents.clone());
475 self.parents = Some(parents.clone());
501 self.dirty_parents = true;
476 self.dirty_parents = true;
502 }
477 }
503
478
504 #[timed]
479 #[timed]
505 fn read<'a>(
480 fn read<'a>(
506 &mut self,
481 &mut self,
507 file_contents: &'a [u8],
482 file_contents: &'a [u8],
508 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
483 ) -> Result<Option<&'a DirstateParents>, DirstateError> {
509 if file_contents.is_empty() {
484 if file_contents.is_empty() {
510 return Ok(None);
485 return Ok(None);
511 }
486 }
512
487
513 let parents = parse_dirstate_entries(
488 let parents = parse_dirstate_entries(
514 file_contents,
489 file_contents,
515 |path, entry, copy_source| {
490 |path, entry, copy_source| {
516 self.add_file_node(
491 let tracked = entry.state.is_tracked();
492 let node = Self::get_or_insert_node_tracing_ancestors(
493 &mut self.root,
517 path,
494 path,
518 *entry,
495 |ancestor| {
519 Some(copy_source.map(HgPath::to_owned)),
496 if tracked {
520 )
497 ancestor.tracked_descendants_count += 1
498 }
499 },
500 );
501 assert!(
502 node.entry.is_none(),
503 "duplicate dirstate entry in read"
504 );
505 assert!(
506 node.copy_source.is_none(),
507 "duplicate dirstate entry in read"
508 );
509 node.entry = Some(*entry);
510 node.copy_source = copy_source.map(HgPath::to_owned);
511 self.nodes_with_entry_count += 1;
512 if copy_source.is_some() {
513 self.nodes_with_copy_source_count += 1
514 }
521 },
515 },
522 )?;
516 )?;
523
517
524 if !self.dirty_parents {
518 if !self.dirty_parents {
525 self.set_parents(parents);
519 self.set_parents(parents);
526 }
520 }
527
521
528 Ok(Some(parents))
522 Ok(Some(parents))
529 }
523 }
530
524
531 fn pack(
525 fn pack(
532 &mut self,
526 &mut self,
533 parents: DirstateParents,
527 parents: DirstateParents,
534 now: Timestamp,
528 now: Timestamp,
535 ) -> Result<Vec<u8>, DirstateError> {
529 ) -> Result<Vec<u8>, DirstateError> {
536 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
530 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
537 // reallocations
531 // reallocations
538 let mut size = parents.as_bytes().len();
532 let mut size = parents.as_bytes().len();
539 for (path, node) in self.iter_nodes() {
533 for (path, node) in self.iter_nodes() {
540 if node.entry.is_some() {
534 if node.entry.is_some() {
541 size += packed_entry_size(
535 size += packed_entry_size(
542 path.full_path(),
536 path.full_path(),
543 node.copy_source.as_ref(),
537 node.copy_source.as_ref(),
544 )
538 )
545 }
539 }
546 }
540 }
547
541
548 let mut packed = Vec::with_capacity(size);
542 let mut packed = Vec::with_capacity(size);
549 packed.extend(parents.as_bytes());
543 packed.extend(parents.as_bytes());
550
544
551 let now: i32 = now.0.try_into().expect("time overflow");
545 let now: i32 = now.0.try_into().expect("time overflow");
552 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
546 for (path, opt_entry, copy_source) in self.iter_node_data_mut() {
553 if let Some(entry) = opt_entry {
547 if let Some(entry) = opt_entry {
554 clear_ambiguous_mtime(entry, now);
548 clear_ambiguous_mtime(entry, now);
555 pack_entry(
549 pack_entry(
556 path.full_path(),
550 path.full_path(),
557 entry,
551 entry,
558 copy_source.as_ref(),
552 copy_source.as_ref(),
559 &mut packed,
553 &mut packed,
560 );
554 );
561 }
555 }
562 }
556 }
563 self.dirty_parents = false;
557 self.dirty_parents = false;
564 Ok(packed)
558 Ok(packed)
565 }
559 }
566
560
567 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
561 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
568 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
562 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
569 // needs to be recomputed
563 // needs to be recomputed
570 Ok(())
564 Ok(())
571 }
565 }
572
566
573 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
567 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
574 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
568 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
575 // to be recomputed
569 // to be recomputed
576 Ok(())
570 Ok(())
577 }
571 }
578
572
579 fn status<'a>(
573 fn status<'a>(
580 &'a mut self,
574 &'a mut self,
581 matcher: &'a (dyn Matcher + Sync),
575 matcher: &'a (dyn Matcher + Sync),
582 root_dir: PathBuf,
576 root_dir: PathBuf,
583 ignore_files: Vec<PathBuf>,
577 ignore_files: Vec<PathBuf>,
584 options: StatusOptions,
578 options: StatusOptions,
585 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
579 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
586 {
580 {
587 super::status::status(self, matcher, root_dir, ignore_files, options)
581 super::status::status(self, matcher, root_dir, ignore_files, options)
588 }
582 }
589
583
590 fn copy_map_len(&self) -> usize {
584 fn copy_map_len(&self) -> usize {
591 self.nodes_with_copy_source_count
585 self.nodes_with_copy_source_count
592 }
586 }
593
587
594 fn copy_map_iter(&self) -> CopyMapIter<'_> {
588 fn copy_map_iter(&self) -> CopyMapIter<'_> {
595 Box::new(self.iter_nodes().filter_map(|(path, node)| {
589 Box::new(self.iter_nodes().filter_map(|(path, node)| {
596 node.copy_source
590 node.copy_source
597 .as_ref()
591 .as_ref()
598 .map(|copy_source| (path.full_path(), copy_source))
592 .map(|copy_source| (path.full_path(), copy_source))
599 }))
593 }))
600 }
594 }
601
595
602 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
596 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
603 if let Some(node) = self.get_node(key) {
597 if let Some(node) = self.get_node(key) {
604 node.copy_source.is_some()
598 node.copy_source.is_some()
605 } else {
599 } else {
606 false
600 false
607 }
601 }
608 }
602 }
609
603
610 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
604 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf> {
611 self.get_node(key)?.copy_source.as_ref()
605 self.get_node(key)?.copy_source.as_ref()
612 }
606 }
613
607
614 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
608 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
615 let count = &mut self.nodes_with_copy_source_count;
609 let count = &mut self.nodes_with_copy_source_count;
616 Self::get_node_mut(&mut self.root, key).and_then(|node| {
610 Self::get_node_mut(&mut self.root, key).and_then(|node| {
617 if node.copy_source.is_some() {
611 if node.copy_source.is_some() {
618 *count -= 1
612 *count -= 1
619 }
613 }
620 node.copy_source.take()
614 node.copy_source.take()
621 })
615 })
622 }
616 }
623
617
624 fn copy_map_insert(
618 fn copy_map_insert(
625 &mut self,
619 &mut self,
626 key: HgPathBuf,
620 key: HgPathBuf,
627 value: HgPathBuf,
621 value: HgPathBuf,
628 ) -> Option<HgPathBuf> {
622 ) -> Option<HgPathBuf> {
629 let node = Self::get_or_insert_node(&mut self.root, &key);
623 let node = Self::get_or_insert_node(&mut self.root, &key);
630 if node.copy_source.is_none() {
624 if node.copy_source.is_none() {
631 self.nodes_with_copy_source_count += 1
625 self.nodes_with_copy_source_count += 1
632 }
626 }
633 node.copy_source.replace(value)
627 node.copy_source.replace(value)
634 }
628 }
635
629
636 fn len(&self) -> usize {
630 fn len(&self) -> usize {
637 self.nodes_with_entry_count
631 self.nodes_with_entry_count
638 }
632 }
639
633
640 fn contains_key(&self, key: &HgPath) -> bool {
634 fn contains_key(&self, key: &HgPath) -> bool {
641 self.get(key).is_some()
635 self.get(key).is_some()
642 }
636 }
643
637
644 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
638 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
645 self.get_node(key)?.entry.as_ref()
639 self.get_node(key)?.entry.as_ref()
646 }
640 }
647
641
648 fn iter(&self) -> StateMapIter<'_> {
642 fn iter(&self) -> StateMapIter<'_> {
649 Box::new(self.iter_nodes().filter_map(|(path, node)| {
643 Box::new(self.iter_nodes().filter_map(|(path, node)| {
650 node.entry.as_ref().map(|entry| (path.full_path(), entry))
644 node.entry.as_ref().map(|entry| (path.full_path(), entry))
651 }))
645 }))
652 }
646 }
653 }
647 }
General Comments 0
You need to be logged in to leave comments. Login now