Patchwork D11702: dirstate-v2: actually use sub-second mtime precision

login
register
mail settings
Submitter phabricator
Date Oct. 19, 2021, 10:04 p.m.
Message ID <differential-rev-PHID-DREV-n4vat5wlmpv573723iop-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/50026/
State Superseded
Headers show

Comments

phabricator - Oct. 19, 2021, 10:04 p.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Instead of zero, set the nanoseconds field to its correct value whenever
  possible and preserve it across serialization+parsing.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11702

AFFECTED FILES
  mercurial/dirstateutils/timestamp.py
  mercurial/dirstateutils/v2.py
  rust/hg-core/src/dirstate/entry.rs
  rust/hg-core/src/dirstate_tree/on_disk.rs
  rust/hg-core/src/dirstate_tree/status.rs

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/hg-core/src/dirstate_tree/status.rs b/rust/hg-core/src/dirstate_tree/status.rs
--- a/rust/hg-core/src/dirstate_tree/status.rs
+++ b/rust/hg-core/src/dirstate_tree/status.rs
@@ -531,9 +531,7 @@ 
             let mtime_looks_clean;
             if let Some(dirstate_mtime) = entry.truncated_mtime() {
                 let fs_mtime = TruncatedTimestamp::for_mtime_of(fs_metadata)
-                    .expect("OS/libc does not support mtime?")
-                    // For now don’t use sub-second precision for file mtimes
-                    .to_integer_second();
+                    .expect("OS/libc does not support mtime?");
                 mtime_looks_clean = fs_mtime.likely_equal(dirstate_mtime)
                     && !fs_mtime.likely_equal(self.options.last_normal_time)
             } else {
diff --git a/rust/hg-core/src/dirstate_tree/on_disk.rs b/rust/hg-core/src/dirstate_tree/on_disk.rs
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs
@@ -376,15 +376,7 @@ 
             // MTIME_SECOND_AMBIGUOUS requires. So we ignore the mtime
             && !self.flags().contains(Flags::MTIME_SECOND_AMBIGUOUS)
         {
-            // TODO: replace this by `self.mtime.try_into()?` to use
-            // sub-second precision from the file.
-            // We don’t do this yet because other parts of the code
-            // always set it to zero.
-            let mtime = TruncatedTimestamp::from_already_truncated(
-                self.mtime.truncated_seconds.get(),
-                0,
-            )?;
-            Some(mtime)
+            Some(self.mtime.try_into()?)
         } else {
             None
         };
diff --git a/rust/hg-core/src/dirstate/entry.rs b/rust/hg-core/src/dirstate/entry.rs
--- a/rust/hg-core/src/dirstate/entry.rs
+++ b/rust/hg-core/src/dirstate/entry.rs
@@ -91,11 +91,6 @@ 
         }
     }
 
-    pub fn to_integer_second(mut self) -> Self {
-        self.nanoseconds = 0;
-        self
-    }
-
     /// The lower 31 bits of the number of seconds since the epoch.
     pub fn truncated_seconds(&self) -> u32 {
         self.truncated_seconds
diff --git a/mercurial/dirstateutils/v2.py b/mercurial/dirstateutils/v2.py
--- a/mercurial/dirstateutils/v2.py
+++ b/mercurial/dirstateutils/v2.py
@@ -101,15 +101,12 @@ 
             flags,
             size,
             mtime_s,
-            _mtime_ns,
+            mtime_ns,
         ) = NODE.unpack(node_bytes)
 
         # Parse child nodes of this node recursively
         parse_nodes(map, copy_map, data, children_start, children_count)
 
-        # Don’t yet use sub-second precision if it exists in the file,
-        # since other parts of the code still set it to zero.
-        mtime_ns = 0
         item = parsers.DirstateItem.from_v2_data(flags, size, mtime_s, mtime_ns)
         if not item.any_tracked:
             continue
diff --git a/mercurial/dirstateutils/timestamp.py b/mercurial/dirstateutils/timestamp.py
--- a/mercurial/dirstateutils/timestamp.py
+++ b/mercurial/dirstateutils/timestamp.py
@@ -66,12 +66,22 @@ 
     Takes an `os.stat_result`-like object and returns a `timestamp` object
     for its modification time.
     """
-    # https://docs.python.org/2/library/os.html#os.stat_float_times
-    # "For compatibility with older Python versions,
-    #  accessing stat_result as a tuple always returns integers."
-    secs = stat_result[stat.ST_MTIME]
+    try:
+        # TODO: add this attribute to `osutil.stat` objects,
+        # see `mercurial/cext/osutil.c`.
+        #
+        # This attribute is also not available on Python 2.
+        nanos = stat_result.st_mtime_ns
+    except AttributeError:
+        # https://docs.python.org/2/library/os.html#os.stat_float_times
+        # "For compatibility with older Python versions,
+        #  accessing stat_result as a tuple always returns integers."
+        secs = stat_result[stat.ST_MTIME]
 
-    # For now
-    subsec_nanos = 0
+        subsec_nanos = 0
+    else:
+        billion = int(1e9)
+        secs = nanos // billion
+        subsec_nanos = nanos % billion
 
     return timestamp((secs, subsec_nanos))