##// 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
@@ -61,15 +61,6 b' pub(super) struct Node {'
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 }
@@ -117,32 +108,18 b' impl DirstateMap {'
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();
@@ -150,8 +127,8 b' impl DirstateMap {'
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 {
@@ -164,6 +141,14 b' impl DirstateMap {'
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);
@@ -177,6 +162,7 b' impl DirstateMap {'
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 {
@@ -185,52 +171,37 b' impl DirstateMap {'
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,
221 }
190 |ancestor| {
222 // Borrow of `self.root` through `node` ends here
191 // We can’t use `+= increment` because the counter is unsigned,
223
192 // and we want debug builds to detect accidental underflow
193 // through zero
224 match tracked_count_increment {
194 match tracked_count_increment {
225 1 => self.for_each_ancestor_node(path, |node| {
195 1 => ancestor.tracked_descendants_count += 1,
226 node.tracked_descendants_count += 1
196 -1 => ancestor.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 _ => {}
197 _ => {}
233 }
198 }
199 },
200 );
201 if node.entry.is_none() {
202 self.nodes_with_entry_count += 1
203 }
204 node.entry = Some(new_entry)
234 }
205 }
235
206
236 fn iter_nodes<'a>(
207 fn iter_nodes<'a>(
@@ -329,17 +300,17 b' impl super::dispatch::DirstateMapMethods'
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 {
@@ -348,17 +319,25 b' impl super::dispatch::DirstateMapMethods'
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
@@ -374,13 +353,9 b' impl super::dispatch::DirstateMapMethods'
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 }
@@ -513,11 +488,30 b' impl super::dispatch::DirstateMapMethods'
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
General Comments 0
You need to be logged in to leave comments. Login now