Mercurial > hg-stable
changeset 47357:3b9914b28133
dirstate-v2: Add --dirs to debugdirstate command
`hg debugdirstate --dirs` also shows information stored in the dirstate
(for `read_dir` caching) about directories.
Differential Revision: https://phab.mercurial-scm.org/D10828
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 31 May 2021 19:54:41 +0200 |
parents | 04d1f17f49e7 |
children | 9d58e54b5966 |
files | mercurial/debugcommands.py mercurial/dirstate.py rust/hg-core/src/dirstate/parsers.rs rust/hg-core/src/dirstate_tree/dirstate_map.rs rust/hg-core/src/dirstate_tree/dispatch.rs rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-cpython/src/dirstate/dirstate_map.rs rust/hg-cpython/src/dirstate/dispatch.rs rust/hg-cpython/src/parsers.rs tests/test-completion.t tests/test-status.t |
diffstat | 11 files changed, 145 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/debugcommands.py Mon May 31 18:35:44 2021 +0200 +++ b/mercurial/debugcommands.py Mon May 31 19:54:41 2021 +0200 @@ -941,6 +941,7 @@ ), (b'', b'dates', True, _(b'display the saved mtime')), (b'', b'datesort', None, _(b'sort by saved mtime')), + (b'', b'dirs', False, _(b'display directories')), ], _(b'[OPTION]...'), ) @@ -956,7 +957,11 @@ keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename else: keyfunc = None # sort by filename - for file_, ent in sorted(pycompat.iteritems(repo.dirstate), key=keyfunc): + entries = list(pycompat.iteritems(repo.dirstate)) + if opts['dirs']: + entries.extend(repo.dirstate.directories()) + entries.sort(key=keyfunc) + for file_, ent in entries: if ent[3] == -1: timestr = b'unset ' elif nodates:
--- a/mercurial/dirstate.py Mon May 31 18:35:44 2021 +0200 +++ b/mercurial/dirstate.py Mon May 31 19:54:41 2021 +0200 @@ -315,6 +315,9 @@ iteritems = items + def directories(self): + return self._map.directories() + def parents(self): return [self._validate(p) for p in self._pl] @@ -1479,6 +1482,10 @@ self._map return self.copymap + def directories(self): + # Rust / dirstate-v2 only + return [] + def clear(self): self._map.clear() self.copymap.clear() @@ -1806,6 +1813,9 @@ def copymap(self): return self._rustmap.copymap() + def directories(self): + return self._rustmap.directories() + def preload(self): self._rustmap
--- a/rust/hg-core/src/dirstate/parsers.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-core/src/dirstate/parsers.rs Mon May 31 19:54:41 2021 +0200 @@ -129,7 +129,7 @@ } /// Seconds since the Unix epoch -pub struct Timestamp(pub u64); +pub struct Timestamp(pub i64); impl DirstateEntry { pub fn mtime_is_ambiguous(&self, now: i32) -> bool {
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Mon May 31 19:54:41 2021 +0200 @@ -319,7 +319,7 @@ pub(super) fn cached_directory_mtime( &self, - ) -> Option<&on_disk::Timestamp> { + ) -> Option<&'tree on_disk::Timestamp> { match self { NodeRef::InMemory(_path, node) => match &node.data { NodeData::CachedDirectory { mtime } => Some(mtime), @@ -1068,4 +1068,28 @@ }) })) } + + fn iter_directories( + &self, + ) -> Box< + dyn Iterator< + Item = Result< + (&HgPath, Option<Timestamp>), + DirstateV2ParseError, + >, + > + Send + + '_, + > { + Box::new(filter_map_results(self.iter_nodes(), move |node| { + Ok(if node.state()?.is_none() { + Some(( + node.full_path(self.on_disk)?, + node.cached_directory_mtime() + .map(|mtime| Timestamp(mtime.seconds())), + )) + } else { + None + }) + })) + } }
--- a/rust/hg-core/src/dirstate_tree/dispatch.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-core/src/dirstate_tree/dispatch.rs Mon May 31 19:54:41 2021 +0200 @@ -143,6 +143,18 @@ ) -> Result<Option<DirstateEntry>, DirstateV2ParseError>; fn iter(&self) -> StateMapIter<'_>; + + fn iter_directories( + &self, + ) -> Box< + dyn Iterator< + Item = Result< + (&HgPath, Option<Timestamp>), + DirstateV2ParseError, + >, + > + Send + + '_, + >; } impl DirstateMapMethods for DirstateMap { @@ -350,4 +362,18 @@ fn iter(&self) -> StateMapIter<'_> { Box::new((&**self).iter().map(|(key, value)| Ok((&**key, *value)))) } + + fn iter_directories( + &self, + ) -> Box< + dyn Iterator< + Item = Result< + (&HgPath, Option<Timestamp>), + DirstateV2ParseError, + >, + > + Send + + '_, + > { + Box::new(std::iter::empty()) + } }
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs Mon May 31 19:54:41 2021 +0200 @@ -352,6 +352,12 @@ } } +impl Timestamp { + pub fn seconds(&self) -> i64 { + self.seconds.get() + } +} + impl From<SystemTime> for Timestamp { fn from(system_time: SystemTime) -> Self { let (secs, nanos) = match system_time.duration_since(UNIX_EPOCH) {
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Mon May 31 19:54:41 2021 +0200 @@ -535,6 +535,18 @@ ) } + def directories(&self) -> PyResult<PyList> { + let dirs = PyList::new(py, &[]); + for item in self.inner(py).borrow().iter_directories() { + let (path, mtime) = item.map_err(|e| v2_error(py, e))?; + let path = PyBytes::new(py, path.as_bytes()); + let mtime = mtime.map(|t| t.0).unwrap_or(-1); + let tuple = (path, (b'd', 0, 0, mtime)); + dirs.append(py, tuple.to_py_object(py).into_object()) + } + Ok(dirs) + } + }); impl DirstateMap {
--- a/rust/hg-cpython/src/dirstate/dispatch.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-cpython/src/dirstate/dispatch.rs Mon May 31 19:54:41 2021 +0200 @@ -206,4 +206,18 @@ fn iter(&self) -> StateMapIter<'_> { self.get().iter() } + + fn iter_directories( + &self, + ) -> Box< + dyn Iterator< + Item = Result< + (&HgPath, Option<Timestamp>), + DirstateV2ParseError, + >, + > + Send + + '_, + > { + self.get().iter_directories() + } }
--- a/rust/hg-cpython/src/parsers.rs Mon May 31 18:35:44 2021 +0200 +++ b/rust/hg-cpython/src/parsers.rs Mon May 31 19:54:41 2021 +0200 @@ -98,7 +98,7 @@ p1: p1.try_into().unwrap(), p2: p2.try_into().unwrap(), }, - Timestamp(now.as_object().extract::<u64>(py)?), + Timestamp(now.as_object().extract::<i64>(py)?), ) { Ok(packed) => { for (filename, entry) in dirstate_map.iter() {
--- a/tests/test-completion.t Mon May 31 18:35:44 2021 +0200 +++ b/tests/test-completion.t Mon May 31 19:54:41 2021 +0200 @@ -282,7 +282,7 @@ debugdata: changelog, manifest, dir debugdate: extended debugdeltachain: changelog, manifest, dir, template - debugdirstate: nodates, dates, datesort + debugdirstate: nodates, dates, datesort, dirs debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template debugdownload: output debugextensions: template
--- a/tests/test-status.t Mon May 31 18:35:44 2021 +0200 +++ b/tests/test-status.t Mon May 31 19:54:41 2021 +0200 @@ -915,3 +915,46 @@ I A.hs I B.hs I ignored-folder/ctest.hs + +#if dirstate-v2 + +Check read_dir caching + + $ cd .. + $ hg init repo8 + $ cd repo8 + $ mkdir subdir + $ touch subdir/a subdir/b + $ hg ci -Aqm '#0' + +The cached mtime is initially unset + + $ hg debugdirstate --dirs --no-dates | grep '^d' + d 0 0 unset subdir + +It is still not set when there are unknown files + + $ touch subdir/unknown + $ hg status + ? subdir/unknown + $ hg debugdirstate --dirs --no-dates | grep '^d' + d 0 0 unset subdir + +Now the directory is eligible for caching, so its mtime is save in the dirstate + + $ rm subdir/unknown + $ hg status + $ hg debugdirstate --dirs --no-dates | grep '^d' + d 0 0 set subdir + +This time the command should be ever so slightly faster since it does not need `read_dir("subdir")` + + $ hg status + +Creating a new file changes the directory’s mtime, invalidating the cache + + $ touch subdir/unknown + $ hg status + ? subdir/unknown + +#endif