Mercurial > hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
48259:84f6b0c41b90 | 48260:269ff8978086 |
---|---|
12 Added, | 12 Added, |
13 Removed, | 13 Removed, |
14 Merged, | 14 Merged, |
15 } | 15 } |
16 | 16 |
17 /// The C implementation uses all signed types. This will be an issue | 17 /// `size` and `mtime.seconds` are truncated to 31 bits. |
18 /// either when 4GB+ source files are commonplace or in 2038, whichever | 18 /// |
19 /// comes first. | 19 /// TODO: double-check status algorithm correctness for files |
20 #[derive(Debug, PartialEq, Copy, Clone)] | 20 /// larger than 2 GiB or modified after 2038. |
21 #[derive(Debug, Copy, Clone)] | |
21 pub struct DirstateEntry { | 22 pub struct DirstateEntry { |
22 pub(crate) flags: Flags, | 23 pub(crate) flags: Flags, |
23 mode_size: Option<(u32, u32)>, | 24 mode_size: Option<(u32, u32)>, |
24 mtime: Option<u32>, | 25 mtime: Option<TruncatedTimestamp>, |
25 } | 26 } |
26 | 27 |
27 bitflags! { | 28 bitflags! { |
28 pub(crate) struct Flags: u8 { | 29 pub(crate) struct Flags: u8 { |
29 const WDIR_TRACKED = 1 << 0; | 30 const WDIR_TRACKED = 1 << 0; |
35 const FALLBACK_SYMLINK = 1 << 6; | 36 const FALLBACK_SYMLINK = 1 << 6; |
36 } | 37 } |
37 } | 38 } |
38 | 39 |
39 /// A Unix timestamp with nanoseconds precision | 40 /// A Unix timestamp with nanoseconds precision |
40 #[derive(Copy, Clone)] | 41 #[derive(Debug, Copy, Clone)] |
41 pub struct TruncatedTimestamp { | 42 pub struct TruncatedTimestamp { |
42 truncated_seconds: u32, | 43 truncated_seconds: u32, |
43 /// Always in the `0 .. 1_000_000_000` range. | 44 /// Always in the `0 .. 1_000_000_000` range. |
44 nanoseconds: u32, | 45 nanoseconds: u32, |
45 } | 46 } |
86 } | 87 } |
87 #[cfg(not(unix))] | 88 #[cfg(not(unix))] |
88 { | 89 { |
89 metadata.modified().map(Self::from) | 90 metadata.modified().map(Self::from) |
90 } | 91 } |
92 } | |
93 | |
94 pub fn to_integer_second(mut self) -> Self { | |
95 self.nanoseconds = 0; | |
96 self | |
91 } | 97 } |
92 | 98 |
93 /// The lower 31 bits of the number of seconds since the epoch. | 99 /// The lower 31 bits of the number of seconds since the epoch. |
94 pub fn truncated_seconds(&self) -> u32 { | 100 pub fn truncated_seconds(&self) -> u32 { |
95 self.truncated_seconds | 101 self.truncated_seconds |
180 pub fn from_v2_data( | 186 pub fn from_v2_data( |
181 wdir_tracked: bool, | 187 wdir_tracked: bool, |
182 p1_tracked: bool, | 188 p1_tracked: bool, |
183 p2_info: bool, | 189 p2_info: bool, |
184 mode_size: Option<(u32, u32)>, | 190 mode_size: Option<(u32, u32)>, |
185 mtime: Option<u32>, | 191 mtime: Option<TruncatedTimestamp>, |
186 fallback_exec: Option<bool>, | 192 fallback_exec: Option<bool>, |
187 fallback_symlink: Option<bool>, | 193 fallback_symlink: Option<bool>, |
188 ) -> Self { | 194 ) -> Self { |
189 if let Some((mode, size)) = mode_size { | 195 if let Some((mode, size)) = mode_size { |
190 // TODO: return an error for out of range values? | 196 // TODO: return an error for out of range values? |
191 assert!(mode & !RANGE_MASK_31BIT == 0); | 197 assert!(mode & !RANGE_MASK_31BIT == 0); |
192 assert!(size & !RANGE_MASK_31BIT == 0); | 198 assert!(size & !RANGE_MASK_31BIT == 0); |
193 } | |
194 if let Some(mtime) = mtime { | |
195 assert!(mtime & !RANGE_MASK_31BIT == 0); | |
196 } | 199 } |
197 let mut flags = Flags::empty(); | 200 let mut flags = Flags::empty(); |
198 flags.set(Flags::WDIR_TRACKED, wdir_tracked); | 201 flags.set(Flags::WDIR_TRACKED, wdir_tracked); |
199 flags.set(Flags::P1_TRACKED, p1_tracked); | 202 flags.set(Flags::P1_TRACKED, p1_tracked); |
200 flags.set(Flags::P2_INFO, p2_info); | 203 flags.set(Flags::P2_INFO, p2_info); |
250 } else { | 253 } else { |
251 // TODO: return an error for negative values? | 254 // TODO: return an error for negative values? |
252 let mode = u32::try_from(mode).unwrap(); | 255 let mode = u32::try_from(mode).unwrap(); |
253 let size = u32::try_from(size).unwrap(); | 256 let size = u32::try_from(size).unwrap(); |
254 let mtime = u32::try_from(mtime).unwrap(); | 257 let mtime = u32::try_from(mtime).unwrap(); |
258 let mtime = | |
259 TruncatedTimestamp::from_already_truncated(mtime, 0) | |
260 .unwrap(); | |
255 Self { | 261 Self { |
256 flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED, | 262 flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED, |
257 mode_size: Some((mode, size)), | 263 mode_size: Some((mode, size)), |
258 mtime: Some(mtime), | 264 mtime: Some(mtime), |
259 } | 265 } |
342 ) -> ( | 348 ) -> ( |
343 bool, | 349 bool, |
344 bool, | 350 bool, |
345 bool, | 351 bool, |
346 Option<(u32, u32)>, | 352 Option<(u32, u32)>, |
347 Option<u32>, | 353 Option<TruncatedTimestamp>, |
348 Option<bool>, | 354 Option<bool>, |
349 Option<bool>, | 355 Option<bool>, |
350 ) { | 356 ) { |
351 if !self.any_tracked() { | 357 if !self.any_tracked() { |
352 // TODO: return an Option instead? | 358 // TODO: return an Option instead? |
427 } else if self.flags.contains(Flags::P2_INFO) { | 433 } else if self.flags.contains(Flags::P2_INFO) { |
428 MTIME_UNSET | 434 MTIME_UNSET |
429 } else if !self.flags.contains(Flags::P1_TRACKED) { | 435 } else if !self.flags.contains(Flags::P1_TRACKED) { |
430 MTIME_UNSET | 436 MTIME_UNSET |
431 } else if let Some(mtime) = self.mtime { | 437 } else if let Some(mtime) = self.mtime { |
432 i32::try_from(mtime).unwrap() | 438 i32::try_from(mtime.truncated_seconds()).unwrap() |
433 } else { | 439 } else { |
434 MTIME_UNSET | 440 MTIME_UNSET |
435 } | 441 } |
436 } | 442 } |
437 | 443 |
499 } | 505 } |
500 } | 506 } |
501 } | 507 } |
502 } | 508 } |
503 | 509 |
510 pub fn truncated_mtime(&self) -> Option<TruncatedTimestamp> { | |
511 self.mtime | |
512 } | |
513 | |
504 pub fn drop_merge_data(&mut self) { | 514 pub fn drop_merge_data(&mut self) { |
505 if self.flags.contains(Flags::P2_INFO) { | 515 if self.flags.contains(Flags::P2_INFO) { |
506 self.flags.remove(Flags::P2_INFO); | 516 self.flags.remove(Flags::P2_INFO); |
507 self.mode_size = None; | 517 self.mode_size = None; |
508 self.mtime = None; | 518 self.mtime = None; |
511 | 521 |
512 pub fn set_possibly_dirty(&mut self) { | 522 pub fn set_possibly_dirty(&mut self) { |
513 self.mtime = None | 523 self.mtime = None |
514 } | 524 } |
515 | 525 |
516 pub fn set_clean(&mut self, mode: u32, size: u32, mtime: u32) { | 526 pub fn set_clean( |
527 &mut self, | |
528 mode: u32, | |
529 size: u32, | |
530 mtime: TruncatedTimestamp, | |
531 ) { | |
517 let size = size & RANGE_MASK_31BIT; | 532 let size = size & RANGE_MASK_31BIT; |
518 let mtime = mtime & RANGE_MASK_31BIT; | |
519 self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED); | 533 self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED); |
520 self.mode_size = Some((mode, size)); | 534 self.mode_size = Some((mode, size)); |
521 self.mtime = Some(mtime); | 535 self.mtime = Some(mtime); |
522 } | 536 } |
523 | 537 |
575 pub fn debug_tuple(&self) -> (u8, i32, i32, i32) { | 589 pub fn debug_tuple(&self) -> (u8, i32, i32, i32) { |
576 (self.state().into(), self.mode(), self.size(), self.mtime()) | 590 (self.state().into(), self.mode(), self.size(), self.mtime()) |
577 } | 591 } |
578 | 592 |
579 /// True if the stored mtime would be ambiguous with the current time | 593 /// True if the stored mtime would be ambiguous with the current time |
580 pub fn need_delay(&self, now: i32) -> bool { | 594 pub fn need_delay(&self, now: TruncatedTimestamp) -> bool { |
581 self.state() == EntryState::Normal && self.mtime() == now | 595 if let Some(mtime) = self.mtime { |
596 self.state() == EntryState::Normal | |
597 && mtime.truncated_seconds() == now.truncated_seconds() | |
598 } else { | |
599 false | |
600 } | |
582 } | 601 } |
583 } | 602 } |
584 | 603 |
585 impl EntryState { | 604 impl EntryState { |
586 pub fn is_tracked(self) -> bool { | 605 pub fn is_tracked(self) -> bool { |