comparison rust/hg-core/src/dirstate_tree/on_disk.rs @ 47409:0ef8231e413f

dirstate-v2: Store a hash of ignore patterns (.hgignore) Later, this help extend `read_dir` caching to directories that contain ignored files (but no unknown files). Such cache must be invalidated when ignore patterns change since a formerly-ignored file might become unknown. This helps the default configuration of `hg status` where unknown files must be listed, but ignored files are not. Differential Revision: https://phab.mercurial-scm.org/D10836
author Simon Sapin <simon.sapin@octobus.net>
date Wed, 02 Jun 2021 11:25:18 +0200
parents bd88b6bfd8da
children 94e38822d395
comparison
equal deleted inserted replaced
47408:7954ee2d7cf7 47409:0ef8231e413f
26 /// Added at the start of `.hg/dirstate` when the "v2" format is used. 26 /// Added at the start of `.hg/dirstate` when the "v2" format is used.
27 /// This a redundant sanity check more than an actual "magic number" since 27 /// This a redundant sanity check more than an actual "magic number" since
28 /// `.hg/requires` already governs which format should be used. 28 /// `.hg/requires` already governs which format should be used.
29 pub const V2_FORMAT_MARKER: &[u8; 12] = b"dirstate-v2\n"; 29 pub const V2_FORMAT_MARKER: &[u8; 12] = b"dirstate-v2\n";
30 30
31 pub(super) const IGNORE_PATTERNS_HASH_LEN: usize = 20;
32 pub(super) type IgnorePatternsHash = [u8; IGNORE_PATTERNS_HASH_LEN];
33
31 #[derive(BytesCast)] 34 #[derive(BytesCast)]
32 #[repr(C)] 35 #[repr(C)]
33 struct Header { 36 struct Header {
34 marker: [u8; V2_FORMAT_MARKER.len()], 37 marker: [u8; V2_FORMAT_MARKER.len()],
35 38
38 parents: DirstateParents, 41 parents: DirstateParents,
39 42
40 root: ChildNodes, 43 root: ChildNodes,
41 nodes_with_entry_count: Size, 44 nodes_with_entry_count: Size,
42 nodes_with_copy_source_count: Size, 45 nodes_with_copy_source_count: Size,
46
47 /// If non-zero, a hash of ignore files that were used for some previous
48 /// run of the `status` algorithm.
49 ///
50 /// We define:
51 ///
52 /// * "Root" ignore files are `.hgignore` at the root of the repository if
53 /// it exists, and files from `ui.ignore.*` config. This set of files is
54 /// then sorted by the string representation of their path.
55 /// * The "expanded contents" of an ignore files is the byte string made
56 /// by concatenating its contents with the "expanded contents" of other
57 /// files included with `include:` or `subinclude:` files, in inclusion
58 /// order. This definition is recursive, as included files can
59 /// themselves include more files.
60 ///
61 /// This hash is defined as the SHA-1 of the concatenation (in sorted
62 /// order) of the "expanded contents" of each "root" ignore file.
63 /// (Note that computing this does not require actually concatenating byte
64 /// strings into contiguous memory, instead SHA-1 hashing can be done
65 /// incrementally.)
66 ignore_patterns_hash: IgnorePatternsHash,
43 } 67 }
44 68
45 #[derive(BytesCast)] 69 #[derive(BytesCast)]
46 #[repr(C)] 70 #[repr(C)]
47 pub(super) struct Node { 71 pub(super) struct Node {
143 /// Either nothing if `start == 0`, or a `HgPath` of `len` bytes 167 /// Either nothing if `start == 0`, or a `HgPath` of `len` bytes
144 type OptPathSlice = Slice; 168 type OptPathSlice = Slice;
145 169
146 /// Make sure that size-affecting changes are made knowingly 170 /// Make sure that size-affecting changes are made knowingly
147 fn _static_assert_size_of() { 171 fn _static_assert_size_of() {
148 let _ = std::mem::transmute::<Header, [u8; 72]>; 172 let _ = std::mem::transmute::<Header, [u8; 92]>;
149 let _ = std::mem::transmute::<Node, [u8; 57]>; 173 let _ = std::mem::transmute::<Node, [u8; 57]>;
150 } 174 }
151 175
152 /// Unexpected file format found in `.hg/dirstate` with the "v2" format. 176 /// Unexpected file format found in `.hg/dirstate` with the "v2" format.
153 /// 177 ///
195 )?), 219 )?),
196 nodes_with_entry_count: header.nodes_with_entry_count.get(), 220 nodes_with_entry_count: header.nodes_with_entry_count.get(),
197 nodes_with_copy_source_count: header 221 nodes_with_copy_source_count: header
198 .nodes_with_copy_source_count 222 .nodes_with_copy_source_count
199 .get(), 223 .get(),
224 ignore_patterns_hash: header.ignore_patterns_hash,
200 }; 225 };
201 let parents = Some(header.parents.clone()); 226 let parents = Some(header.parents.clone());
202 Ok((dirstate_map, parents)) 227 Ok((dirstate_map, parents))
203 } 228 }
204 229
471 root, 496 root,
472 nodes_with_entry_count: dirstate_map.nodes_with_entry_count.into(), 497 nodes_with_entry_count: dirstate_map.nodes_with_entry_count.into(),
473 nodes_with_copy_source_count: dirstate_map 498 nodes_with_copy_source_count: dirstate_map
474 .nodes_with_copy_source_count 499 .nodes_with_copy_source_count
475 .into(), 500 .into(),
501 ignore_patterns_hash: dirstate_map.ignore_patterns_hash,
476 }; 502 };
477 out[..header_len].copy_from_slice(header.as_bytes()); 503 out[..header_len].copy_from_slice(header.as_bytes());
478 Ok(out) 504 Ok(out)
479 } 505 }
480 506