Show More
@@ -0,0 +1,4 b'' | |||
|
1 | /// Added at the start of `.hg/dirstate` when the "v2" format is used. | |
|
2 | /// Acts like a "magic number". This is a sanity check, not strictly necessary | |
|
3 | /// since `.hg/requires` already governs which format should be used. | |
|
4 | pub const V2_FORMAT_MARKER: &[u8; 12] = b"dirstate-v2\n"; |
@@ -25,6 +25,7 b' from mercurial import (' | |||
|
25 | 25 | httpconnection, |
|
26 | 26 | match as matchmod, |
|
27 | 27 | pycompat, |
|
28 | requirements, | |
|
28 | 29 | scmutil, |
|
29 | 30 | sparse, |
|
30 | 31 | util, |
@@ -197,6 +198,7 b' def openlfdirstate(ui, repo, create=True' | |||
|
197 | 198 | vfs = repo.vfs |
|
198 | 199 | lfstoredir = longname |
|
199 | 200 | opener = vfsmod.vfs(vfs.join(lfstoredir)) |
|
201 | use_dirstate_v2 = requirements.DIRSTATE_V2_REQUIREMENT in repo.requirements | |
|
200 | 202 | lfdirstate = largefilesdirstate( |
|
201 | 203 | opener, |
|
202 | 204 | ui, |
@@ -204,6 +206,7 b' def openlfdirstate(ui, repo, create=True' | |||
|
204 | 206 | repo.dirstate._validate, |
|
205 | 207 | lambda: sparse.matcher(repo), |
|
206 | 208 | repo.nodeconstants, |
|
209 | use_dirstate_v2, | |
|
207 | 210 | ) |
|
208 | 211 | |
|
209 | 212 | # If the largefiles dirstate does not exist, populate and create |
@@ -75,7 +75,14 b' def _getfsnow(vfs):' | |||
|
75 | 75 | @interfaceutil.implementer(intdirstate.idirstate) |
|
76 | 76 | class dirstate(object): |
|
77 | 77 | def __init__( |
|
78 | self, opener, ui, root, validate, sparsematchfn, nodeconstants | |
|
78 | self, | |
|
79 | opener, | |
|
80 | ui, | |
|
81 | root, | |
|
82 | validate, | |
|
83 | sparsematchfn, | |
|
84 | nodeconstants, | |
|
85 | use_dirstate_v2, | |
|
79 | 86 | ): |
|
80 | 87 | """Create a new dirstate object. |
|
81 | 88 | |
@@ -83,6 +90,7 b' class dirstate(object):' | |||
|
83 | 90 | dirstate file; root is the root of the directory tracked by |
|
84 | 91 | the dirstate. |
|
85 | 92 | """ |
|
93 | self._use_dirstate_v2 = use_dirstate_v2 | |
|
86 | 94 | self._nodeconstants = nodeconstants |
|
87 | 95 | self._opener = opener |
|
88 | 96 | self._validate = validate |
@@ -141,7 +149,11 b' class dirstate(object):' | |||
|
141 | 149 | def _map(self): |
|
142 | 150 | """Return the dirstate contents (see documentation for dirstatemap).""" |
|
143 | 151 | self._map = self._mapcls( |
|
144 | self._ui, self._opener, self._root, self._nodeconstants | |
|
152 | self._ui, | |
|
153 | self._opener, | |
|
154 | self._root, | |
|
155 | self._nodeconstants, | |
|
156 | self._use_dirstate_v2, | |
|
145 | 157 | ) |
|
146 | 158 | return self._map |
|
147 | 159 | |
@@ -1435,13 +1447,16 b' class dirstatemap(object):' | |||
|
1435 | 1447 | denormalized form that they appear as in the dirstate. |
|
1436 | 1448 | """ |
|
1437 | 1449 | |
|
1438 | def __init__(self, ui, opener, root, nodeconstants): | |
|
1450 | def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2): | |
|
1439 | 1451 | self._ui = ui |
|
1440 | 1452 | self._opener = opener |
|
1441 | 1453 | self._root = root |
|
1442 | 1454 | self._filename = b'dirstate' |
|
1443 | 1455 | self._nodelen = 20 |
|
1444 | 1456 | self._nodeconstants = nodeconstants |
|
1457 | assert ( | |
|
1458 | not use_dirstate_v2 | |
|
1459 | ), "should have detected unsupported requirement" | |
|
1445 | 1460 | |
|
1446 | 1461 | self._parents = None |
|
1447 | 1462 | self._dirtyparents = False |
@@ -1746,13 +1761,14 b' class dirstatemap(object):' | |||
|
1746 | 1761 | if rustmod is not None: |
|
1747 | 1762 | |
|
1748 | 1763 | class dirstatemap(object): |
|
1749 | def __init__(self, ui, opener, root, nodeconstants): | |
|
1764 | def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2): | |
|
1765 | self._use_dirstate_v2 = use_dirstate_v2 | |
|
1750 | 1766 | self._nodeconstants = nodeconstants |
|
1751 | 1767 | self._ui = ui |
|
1752 | 1768 | self._opener = opener |
|
1753 | 1769 | self._root = root |
|
1754 | 1770 | self._filename = b'dirstate' |
|
1755 | self._nodelen = 20 | |
|
1771 | self._nodelen = 20 # Also update Rust code when changing this! | |
|
1756 | 1772 | self._parents = None |
|
1757 | 1773 | self._dirtyparents = False |
|
1758 | 1774 | |
@@ -1832,9 +1848,14 b' if rustmod is not None:' | |||
|
1832 | 1848 | |
|
1833 | 1849 | def parents(self): |
|
1834 | 1850 | if not self._parents: |
|
1851 | if self._use_dirstate_v2: | |
|
1852 | offset = len(rustmod.V2_FORMAT_MARKER) | |
|
1853 | else: | |
|
1854 | offset = 0 | |
|
1855 | read_len = offset + self._nodelen * 2 | |
|
1835 | 1856 | try: |
|
1836 | 1857 | fp = self._opendirstatefile() |
|
1837 |
st = fp.read( |
|
|
1858 | st = fp.read(read_len) | |
|
1838 | 1859 | fp.close() |
|
1839 | 1860 | except IOError as err: |
|
1840 | 1861 | if err.errno != errno.ENOENT: |
@@ -1843,7 +1864,8 b' if rustmod is not None:' | |||
|
1843 | 1864 | st = b'' |
|
1844 | 1865 | |
|
1845 | 1866 | l = len(st) |
|
1846 |
if l == |
|
|
1867 | if l == read_len: | |
|
1868 | st = st[offset:] | |
|
1847 | 1869 | self._parents = ( |
|
1848 | 1870 | st[: self._nodelen], |
|
1849 | 1871 | st[self._nodelen : 2 * self._nodelen], |
@@ -1887,7 +1909,7 b' if rustmod is not None:' | |||
|
1887 | 1909 | False, |
|
1888 | 1910 | ) |
|
1889 | 1911 | self._rustmap, parents = rustmod.DirstateMap.new( |
|
1890 | use_dirstate_tree, st | |
|
1912 | use_dirstate_tree, self._use_dirstate_v2, st | |
|
1891 | 1913 | ) |
|
1892 | 1914 | |
|
1893 | 1915 | if parents and not self._dirtyparents: |
@@ -1900,7 +1922,10 b' if rustmod is not None:' | |||
|
1900 | 1922 | |
|
1901 | 1923 | def write(self, st, now): |
|
1902 | 1924 | parents = self.parents() |
|
1903 | st.write(self._rustmap.write(parents[0], parents[1], now)) | |
|
1925 | packed = self._rustmap.write( | |
|
1926 | self._use_dirstate_v2, parents[0], parents[1], now | |
|
1927 | ) | |
|
1928 | st.write(packed) | |
|
1904 | 1929 | st.close() |
|
1905 | 1930 | self._dirtyparents = False |
|
1906 | 1931 |
@@ -6,7 +6,15 b' from . import util as interfaceutil' | |||
|
6 | 6 | |
|
7 | 7 | |
|
8 | 8 | class idirstate(interfaceutil.Interface): |
|
9 | def __init__(opener, ui, root, validate, sparsematchfn, nodeconstants): | |
|
9 | def __init__( | |
|
10 | opener, | |
|
11 | ui, | |
|
12 | root, | |
|
13 | validate, | |
|
14 | sparsematchfn, | |
|
15 | nodeconstants, | |
|
16 | use_dirstate_v2, | |
|
17 | ): | |
|
10 | 18 | """Create a new dirstate object. |
|
11 | 19 | |
|
12 | 20 | opener is an open()-like callable that can be used to open the |
@@ -1690,6 +1690,8 b' class localrepository(object):' | |||
|
1690 | 1690 | def _makedirstate(self): |
|
1691 | 1691 | """Extension point for wrapping the dirstate per-repo.""" |
|
1692 | 1692 | sparsematchfn = lambda: sparse.matcher(self) |
|
1693 | v2_req = requirementsmod.DIRSTATE_V2_REQUIREMENT | |
|
1694 | use_dirstate_v2 = v2_req in self.requirements | |
|
1693 | 1695 | |
|
1694 | 1696 | return dirstate.dirstate( |
|
1695 | 1697 | self.vfs, |
@@ -1698,6 +1700,7 b' class localrepository(object):' | |||
|
1698 | 1700 | self._dirstatevalidate, |
|
1699 | 1701 | sparsematchfn, |
|
1700 | 1702 | self.nodeconstants, |
|
1703 | use_dirstate_v2, | |
|
1701 | 1704 | ) |
|
1702 | 1705 | |
|
1703 | 1706 | def _dirstatevalidate(self, node): |
@@ -1,4 +1,5 b'' | |||
|
1 | 1 | pub mod dirstate_map; |
|
2 | 2 | pub mod dispatch; |
|
3 | pub mod on_disk; | |
|
3 | 4 | pub mod path_with_basename; |
|
4 | 5 | mod status; |
@@ -4,14 +4,17 b' use std::borrow::Cow;' | |||
|
4 | 4 | use std::convert::TryInto; |
|
5 | 5 | use std::path::PathBuf; |
|
6 | 6 | |
|
7 | use super::on_disk::V2_FORMAT_MARKER; | |
|
7 | 8 | use super::path_with_basename::WithBasename; |
|
8 | 9 | use crate::dirstate::parsers::clear_ambiguous_mtime; |
|
9 | 10 | use crate::dirstate::parsers::pack_entry; |
|
10 | 11 | use crate::dirstate::parsers::packed_entry_size; |
|
11 | 12 | use crate::dirstate::parsers::parse_dirstate_entries; |
|
12 | 13 | use crate::dirstate::parsers::Timestamp; |
|
14 | use crate::errors::HgError; | |
|
13 | 15 | use crate::matchers::Matcher; |
|
14 | 16 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
17 | use crate::utils::SliceExt; | |
|
15 | 18 | use crate::CopyMapIter; |
|
16 | 19 | use crate::DirstateEntry; |
|
17 | 20 | use crate::DirstateError; |
@@ -75,7 +78,24 b" type NodeDataMut<'tree, 'on_disk> = (" | |||
|
75 | 78 | ); |
|
76 | 79 | |
|
77 | 80 | impl<'on_disk> DirstateMap<'on_disk> { |
|
78 | pub fn new( | |
|
81 | #[timed] | |
|
82 | pub fn new_v2( | |
|
83 | on_disk: &'on_disk [u8], | |
|
84 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { | |
|
85 | if let Some(rest) = on_disk.drop_prefix(V2_FORMAT_MARKER) { | |
|
86 | Self::new_v1(rest) | |
|
87 | } else if on_disk.is_empty() { | |
|
88 | Self::new_v1(on_disk) | |
|
89 | } else { | |
|
90 | return Err(HgError::corrupted( | |
|
91 | "missing dirstate-v2 magic number", | |
|
92 | ) | |
|
93 | .into()); | |
|
94 | } | |
|
95 | } | |
|
96 | ||
|
97 | #[timed] | |
|
98 | pub fn new_v1( | |
|
79 | 99 | on_disk: &'on_disk [u8], |
|
80 | 100 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { |
|
81 | 101 | let mut map = Self { |
@@ -84,23 +104,16 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||
|
84 | 104 | nodes_with_entry_count: 0, |
|
85 | 105 | nodes_with_copy_source_count: 0, |
|
86 | 106 | }; |
|
87 | let parents = map.read()?; | |
|
88 |
Ok((map, |
|
|
89 | } | |
|
90 | ||
|
91 | /// Should only be called in `new` | |
|
92 | #[timed] | |
|
93 | fn read(&mut self) -> Result<Option<DirstateParents>, DirstateError> { | |
|
94 | if self.on_disk.is_empty() { | |
|
95 | return Ok(None); | |
|
107 | if map.on_disk.is_empty() { | |
|
108 | return Ok((map, None)); | |
|
96 | 109 | } |
|
97 | 110 | |
|
98 | 111 | let parents = parse_dirstate_entries( |
|
99 |
|
|
|
112 | map.on_disk, | |
|
100 | 113 | |path, entry, copy_source| { |
|
101 | 114 | let tracked = entry.state.is_tracked(); |
|
102 | 115 | let node = Self::get_or_insert_node( |
|
103 |
&mut |
|
|
116 | &mut map.root, | |
|
104 | 117 | path, |
|
105 | 118 | WithBasename::to_cow_borrowed, |
|
106 | 119 | |ancestor| { |
@@ -119,14 +132,15 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||
|
119 | 132 | ); |
|
120 | 133 | node.entry = Some(*entry); |
|
121 | 134 | node.copy_source = copy_source.map(Cow::Borrowed); |
|
122 |
|
|
|
135 | map.nodes_with_entry_count += 1; | |
|
123 | 136 | if copy_source.is_some() { |
|
124 |
|
|
|
137 | map.nodes_with_copy_source_count += 1 | |
|
125 | 138 | } |
|
126 | 139 | }, |
|
127 | 140 | )?; |
|
141 | let parents = Some(parents.clone()); | |
|
128 | 142 | |
|
129 |
Ok( |
|
|
143 | Ok((map, parents)) | |
|
130 | 144 | } |
|
131 | 145 | |
|
132 | 146 | fn get_node(&self, path: &HgPath) -> Option<&Node> { |
@@ -498,7 +512,8 b" impl<'on_disk> super::dispatch::Dirstate" | |||
|
498 | 512 | } |
|
499 | 513 | } |
|
500 | 514 | |
|
501 | fn pack( | |
|
515 | #[timed] | |
|
516 | fn pack_v1( | |
|
502 | 517 | &mut self, |
|
503 | 518 | parents: DirstateParents, |
|
504 | 519 | now: Timestamp, |
@@ -533,6 +548,18 b" impl<'on_disk> super::dispatch::Dirstate" | |||
|
533 | 548 | Ok(packed) |
|
534 | 549 | } |
|
535 | 550 | |
|
551 | #[timed] | |
|
552 | fn pack_v2( | |
|
553 | &mut self, | |
|
554 | parents: DirstateParents, | |
|
555 | now: Timestamp, | |
|
556 | ) -> Result<Vec<u8>, DirstateError> { | |
|
557 | // Inefficient but temporary | |
|
558 | let mut v2 = V2_FORMAT_MARKER.to_vec(); | |
|
559 | v2.append(&mut self.pack_v1(parents, now)?); | |
|
560 | Ok(v2) | |
|
561 | } | |
|
562 | ||
|
536 | 563 | fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { |
|
537 | 564 | // Do nothing, this `DirstateMap` does not a separate `all_dirs` that |
|
538 | 565 | // needs to be recomputed |
@@ -73,7 +73,13 b' pub trait DirstateMapMethods {' | |||
|
73 | 73 | directory: &HgPath, |
|
74 | 74 | ) -> Result<bool, DirstateMapError>; |
|
75 | 75 | |
|
76 | fn pack( | |
|
76 | fn pack_v1( | |
|
77 | &mut self, | |
|
78 | parents: DirstateParents, | |
|
79 | now: Timestamp, | |
|
80 | ) -> Result<Vec<u8>, DirstateError>; | |
|
81 | ||
|
82 | fn pack_v2( | |
|
77 | 83 | &mut self, |
|
78 | 84 | parents: DirstateParents, |
|
79 | 85 | now: Timestamp, |
@@ -211,7 +217,7 b' impl DirstateMapMethods for DirstateMap ' | |||
|
211 | 217 | self.has_dir(directory) |
|
212 | 218 | } |
|
213 | 219 | |
|
214 | fn pack( | |
|
220 | fn pack_v1( | |
|
215 | 221 | &mut self, |
|
216 | 222 | parents: DirstateParents, |
|
217 | 223 | now: Timestamp, |
@@ -219,6 +225,16 b' impl DirstateMapMethods for DirstateMap ' | |||
|
219 | 225 | self.pack(parents, now) |
|
220 | 226 | } |
|
221 | 227 | |
|
228 | fn pack_v2( | |
|
229 | &mut self, | |
|
230 | _parents: DirstateParents, | |
|
231 | _now: Timestamp, | |
|
232 | ) -> Result<Vec<u8>, DirstateError> { | |
|
233 | panic!( | |
|
234 | "should have used dirstate_tree::DirstateMap to use the v2 format" | |
|
235 | ) | |
|
236 | } | |
|
237 | ||
|
222 | 238 | fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { |
|
223 | 239 | self.set_all_dirs() |
|
224 | 240 | } |
@@ -26,6 +26,7 b' use cpython::{' | |||
|
26 | 26 | exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult, |
|
27 | 27 | PySequence, Python, |
|
28 | 28 | }; |
|
29 | use hg::dirstate_tree::on_disk::V2_FORMAT_MARKER; | |
|
29 | 30 | use hg::{utils::hg_path::HgPathBuf, DirstateEntry, EntryState, StateMap}; |
|
30 | 31 | use libc::{c_char, c_int}; |
|
31 | 32 | use std::convert::TryFrom; |
@@ -117,6 +118,7 b' pub fn init_module(py: Python, package: ' | |||
|
117 | 118 | )?; |
|
118 | 119 | m.add_class::<Dirs>(py)?; |
|
119 | 120 | m.add_class::<DirstateMap>(py)?; |
|
121 | m.add(py, "V2_FORMAT_MARKER", PyBytes::new(py, V2_FORMAT_MARKER))?; | |
|
120 | 122 | m.add( |
|
121 | 123 | py, |
|
122 | 124 | "status", |
@@ -55,13 +55,17 b' py_class!(pub class DirstateMap |py| {' | |||
|
55 | 55 | |
|
56 | 56 | /// Returns a `(dirstate_map, parents)` tuple |
|
57 | 57 | @staticmethod |
|
58 | def new(use_dirstate_tree: bool, on_disk: PyBytes) -> PyResult<PyObject> { | |
|
59 | let dirstate_error = |_: DirstateError| { | |
|
60 | PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()) | |
|
58 | def new( | |
|
59 | use_dirstate_tree: bool, | |
|
60 | use_dirstate_v2: bool, | |
|
61 | on_disk: PyBytes, | |
|
62 | ) -> PyResult<PyObject> { | |
|
63 | let dirstate_error = |e: DirstateError| { | |
|
64 | PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) | |
|
61 | 65 | }; |
|
62 | let (inner, parents) = if use_dirstate_tree { | |
|
66 | let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 { | |
|
63 | 67 | let (map, parents) = |
|
64 | OwningDirstateMap::new(py, on_disk) | |
|
68 | OwningDirstateMap::new(py, on_disk, use_dirstate_v2) | |
|
65 | 69 | .map_err(dirstate_error)?; |
|
66 | 70 | (Box::new(map) as _, parents) |
|
67 | 71 | } else { |
@@ -288,6 +292,7 b' py_class!(pub class DirstateMap |py| {' | |||
|
288 | 292 | |
|
289 | 293 | def write( |
|
290 | 294 | &self, |
|
295 | use_dirstate_v2: bool, | |
|
291 | 296 | p1: PyObject, |
|
292 | 297 | p2: PyObject, |
|
293 | 298 | now: PyObject |
@@ -298,7 +303,13 b' py_class!(pub class DirstateMap |py| {' | |||
|
298 | 303 | p2: extract_node_id(py, &p2)?, |
|
299 | 304 | }; |
|
300 | 305 | |
|
301 |
|
|
|
306 | let mut inner = self.inner(py).borrow_mut(); | |
|
307 | let result = if use_dirstate_v2 { | |
|
308 | inner.pack_v2(parents, now) | |
|
309 | } else { | |
|
310 | inner.pack_v1(parents, now) | |
|
311 | }; | |
|
312 | match result { | |
|
302 | 313 | Ok(packed) => Ok(PyBytes::new(py, &packed)), |
|
303 | 314 | Err(_) => Err(PyErr::new::<exc::OSError, _>( |
|
304 | 315 | py, |
@@ -101,12 +101,20 b' impl DirstateMapMethods for OwningDirsta' | |||
|
101 | 101 | self.get_mut().has_dir(directory) |
|
102 | 102 | } |
|
103 | 103 | |
|
104 | fn pack( | |
|
104 | fn pack_v1( | |
|
105 | 105 | &mut self, |
|
106 | 106 | parents: DirstateParents, |
|
107 | 107 | now: Timestamp, |
|
108 | 108 | ) -> Result<Vec<u8>, DirstateError> { |
|
109 | self.get_mut().pack(parents, now) | |
|
109 | self.get_mut().pack_v1(parents, now) | |
|
110 | } | |
|
111 | ||
|
112 | fn pack_v2( | |
|
113 | &mut self, | |
|
114 | parents: DirstateParents, | |
|
115 | now: Timestamp, | |
|
116 | ) -> Result<Vec<u8>, DirstateError> { | |
|
117 | self.get_mut().pack_v2(parents, now) | |
|
110 | 118 | } |
|
111 | 119 | |
|
112 | 120 | fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { |
@@ -31,9 +31,14 b' impl OwningDirstateMap {' | |||
|
31 | 31 | pub fn new( |
|
32 | 32 | py: Python, |
|
33 | 33 | on_disk: PyBytes, |
|
34 | use_dirstate_v2: bool, | |
|
34 | 35 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { |
|
35 | 36 | let bytes: &'_ [u8] = on_disk.data(py); |
|
36 |
let (map, parents) = |
|
|
37 | let (map, parents) = if use_dirstate_v2 { | |
|
38 | DirstateMap::new_v2(bytes)? | |
|
39 | } else { | |
|
40 | DirstateMap::new_v1(bytes)? | |
|
41 | }; | |
|
37 | 42 | |
|
38 | 43 | // Like in `bytes` above, this `'_` lifetime parameter borrows from |
|
39 | 44 | // the bytes buffer owned by `on_disk`. |
General Comments 0
You need to be logged in to leave comments.
Login now