diff rust/hg-core/src/dirstate/entry.rs @ 48260:269ff8978086

dirstate: store mtimes with nanosecond precision in memory Keep integer seconds since the Unix epoch, together with integer nanoseconds in the `0 <= n < 1e9` range. For now, nanoseconds are still always zero. This commit is about data structure changes. Differential Revision: https://phab.mercurial-scm.org/D11684
author Simon Sapin <simon.sapin@octobus.net>
date Mon, 18 Oct 2021 11:23:07 +0200
parents 84f6b0c41b90
children 68bb472aee9c
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate/entry.rs	Tue Oct 19 21:03:13 2021 +0200
+++ b/rust/hg-core/src/dirstate/entry.rs	Mon Oct 18 11:23:07 2021 +0200
@@ -14,14 +14,15 @@
     Merged,
 }
 
-/// The C implementation uses all signed types. This will be an issue
-/// either when 4GB+ source files are commonplace or in 2038, whichever
-/// comes first.
-#[derive(Debug, PartialEq, Copy, Clone)]
+/// `size` and `mtime.seconds` are truncated to 31 bits.
+///
+/// TODO: double-check status algorithm correctness for files
+/// larger than 2 GiB or modified after 2038.
+#[derive(Debug, Copy, Clone)]
 pub struct DirstateEntry {
     pub(crate) flags: Flags,
     mode_size: Option<(u32, u32)>,
-    mtime: Option<u32>,
+    mtime: Option<TruncatedTimestamp>,
 }
 
 bitflags! {
@@ -37,7 +38,7 @@
 }
 
 /// A Unix timestamp with nanoseconds precision
-#[derive(Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub struct TruncatedTimestamp {
     truncated_seconds: u32,
     /// Always in the `0 .. 1_000_000_000` range.
@@ -90,6 +91,11 @@
         }
     }
 
+    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
@@ -182,7 +188,7 @@
         p1_tracked: bool,
         p2_info: bool,
         mode_size: Option<(u32, u32)>,
-        mtime: Option<u32>,
+        mtime: Option<TruncatedTimestamp>,
         fallback_exec: Option<bool>,
         fallback_symlink: Option<bool>,
     ) -> Self {
@@ -191,9 +197,6 @@
             assert!(mode & !RANGE_MASK_31BIT == 0);
             assert!(size & !RANGE_MASK_31BIT == 0);
         }
-        if let Some(mtime) = mtime {
-            assert!(mtime & !RANGE_MASK_31BIT == 0);
-        }
         let mut flags = Flags::empty();
         flags.set(Flags::WDIR_TRACKED, wdir_tracked);
         flags.set(Flags::P1_TRACKED, p1_tracked);
@@ -252,6 +255,9 @@
                     let mode = u32::try_from(mode).unwrap();
                     let size = u32::try_from(size).unwrap();
                     let mtime = u32::try_from(mtime).unwrap();
+                    let mtime =
+                        TruncatedTimestamp::from_already_truncated(mtime, 0)
+                            .unwrap();
                     Self {
                         flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
                         mode_size: Some((mode, size)),
@@ -344,7 +350,7 @@
         bool,
         bool,
         Option<(u32, u32)>,
-        Option<u32>,
+        Option<TruncatedTimestamp>,
         Option<bool>,
         Option<bool>,
     ) {
@@ -429,7 +435,7 @@
         } else if !self.flags.contains(Flags::P1_TRACKED) {
             MTIME_UNSET
         } else if let Some(mtime) = self.mtime {
-            i32::try_from(mtime).unwrap()
+            i32::try_from(mtime.truncated_seconds()).unwrap()
         } else {
             MTIME_UNSET
         }
@@ -501,6 +507,10 @@
         }
     }
 
+    pub fn truncated_mtime(&self) -> Option<TruncatedTimestamp> {
+        self.mtime
+    }
+
     pub fn drop_merge_data(&mut self) {
         if self.flags.contains(Flags::P2_INFO) {
             self.flags.remove(Flags::P2_INFO);
@@ -513,9 +523,13 @@
         self.mtime = None
     }
 
-    pub fn set_clean(&mut self, mode: u32, size: u32, mtime: u32) {
+    pub fn set_clean(
+        &mut self,
+        mode: u32,
+        size: u32,
+        mtime: TruncatedTimestamp,
+    ) {
         let size = size & RANGE_MASK_31BIT;
-        let mtime = mtime & RANGE_MASK_31BIT;
         self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED);
         self.mode_size = Some((mode, size));
         self.mtime = Some(mtime);
@@ -577,8 +591,13 @@
     }
 
     /// True if the stored mtime would be ambiguous with the current time
-    pub fn need_delay(&self, now: i32) -> bool {
-        self.state() == EntryState::Normal && self.mtime() == now
+    pub fn need_delay(&self, now: TruncatedTimestamp) -> bool {
+        if let Some(mtime) = self.mtime {
+            self.state() == EntryState::Normal
+                && mtime.truncated_seconds() == now.truncated_seconds()
+        } else {
+            false
+        }
     }
 }