##// 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 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 64 pub(super) fn state(&self) -> Option<EntryState> {
74 65 self.entry.as_ref().map(|entry| entry.state)
75 66 }
@@ -117,32 +108,18 b' impl DirstateMap {'
117 108 root: &'tree mut ChildNodes,
118 109 path: &HgPath,
119 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
124 /// that node itself), starting from nearest the root.
114 /// Same as `get_node_mut`, and calls `each_ancestor` for each ancestor of
115 /// the node.
125 116 ///
126 /// Panics (possibly after some calls to `each`) if there is no node at
127 /// `path`.
128 fn for_each_ancestor_node<'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>(
117 /// Note that `each_ancestor` may be called (with what would be ancestors)
118 /// even if it turns out there is no node at `path`.
119 fn get_node_mut_tracing_ancestors<'tree>(
143 120 root: &'tree mut ChildNodes,
144 121 path: &HgPath,
145 mut each: impl FnMut(&mut Node),
122 mut each_ancestor: impl FnMut(&mut Node),
146 123 ) -> Option<&'tree mut Node> {
147 124 let mut children = root;
148 125 let mut components = path.components();
@@ -150,8 +127,8 b' impl DirstateMap {'
150 127 components.next().expect("expected at least one components");
151 128 loop {
152 129 let child = children.get_mut(component)?;
153 each(child);
154 130 if let Some(next_component) = components.next() {
131 each_ancestor(child);
155 132 component = next_component;
156 133 children = &mut child.children;
157 134 } else {
@@ -164,6 +141,14 b' impl DirstateMap {'
164 141 root: &'tree mut ChildNodes,
165 142 path: &HgPath,
166 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 152 let mut child_nodes = root;
168 153 let mut inclusive_ancestor_paths =
169 154 WithBasename::inclusive_ancestors_of(path);
@@ -177,6 +162,7 b' impl DirstateMap {'
177 162 let child_node =
178 163 child_nodes.entry(ancestor_path.to_owned()).or_default();
179 164 if let Some(next) = inclusive_ancestor_paths.next() {
165 each_ancestor(child_node);
180 166 ancestor_path = next;
181 167 child_nodes = &mut child_node.children;
182 168 } else {
@@ -185,52 +171,37 b' impl DirstateMap {'
185 171 }
186 172 }
187 173
188 /// The meaning of `new_copy_source` is:
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(
174 fn add_or_remove_file(
194 175 &mut self,
195 176 path: &HgPath,
177 old_state: EntryState,
196 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 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 182 (false, true) => 1,
214 183 (true, false) => -1,
215 184 _ => 0,
216 185 };
217 186
218 node.entry = Some(new_entry);
219 if let Some(source) = new_copy_source {
220 node.copy_source = source
221 }
222 // Borrow of `self.root` through `node` ends here
223
187 let node = Self::get_or_insert_node_tracing_ancestors(
188 &mut self.root,
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
224 194 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 }),
195 1 => ancestor.tracked_descendants_count += 1,
196 -1 => ancestor.tracked_descendants_count -= 1,
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 207 fn iter_nodes<'a>(
@@ -329,17 +300,17 b' impl super::dispatch::DirstateMapMethods'
329 300 fn add_file(
330 301 &mut self,
331 302 filename: &HgPath,
332 _old_state: EntryState,
303 old_state: EntryState,
333 304 entry: DirstateEntry,
334 305 ) -> Result<(), DirstateMapError> {
335 self.add_file_node(filename, entry, None);
306 self.add_or_remove_file(filename, old_state, entry);
336 307 Ok(())
337 308 }
338 309
339 310 fn remove_file(
340 311 &mut self,
341 312 filename: &HgPath,
342 _old_state: EntryState,
313 old_state: EntryState,
343 314 size: i32,
344 315 ) -> Result<(), DirstateMapError> {
345 316 let entry = DirstateEntry {
@@ -348,17 +319,25 b' impl super::dispatch::DirstateMapMethods'
348 319 size,
349 320 mtime: 0,
350 321 };
351 self.add_file_node(filename, entry, None);
322 self.add_or_remove_file(filename, old_state, entry);
352 323 Ok(())
353 324 }
354 325
355 326 fn drop_file(
356 327 &mut self,
357 328 filename: &HgPath,
358 _old_state: EntryState,
329 old_state: EntryState,
359 330 ) -> Result<bool, DirstateMapError> {
360 if let Some(node) = Self::get_node_mut(&mut self.root, filename) {
361 let was_tracked = node.is_tracked_file();
331 let was_tracked = old_state.is_tracked();
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 341 let had_entry = node.entry.is_some();
363 342 let had_copy_source = node.copy_source.is_some();
364 343
@@ -374,13 +353,9 b' impl super::dispatch::DirstateMapMethods'
374 353 if had_copy_source {
375 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 356 Ok(had_entry)
383 357 } else {
358 assert!(!was_tracked);
384 359 Ok(false)
385 360 }
386 361 }
@@ -513,11 +488,30 b' impl super::dispatch::DirstateMapMethods'
513 488 let parents = parse_dirstate_entries(
514 489 file_contents,
515 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 494 path,
518 *entry,
519 Some(copy_source.map(HgPath::to_owned)),
520 )
495 |ancestor| {
496 if tracked {
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