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
--- 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