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