This flag will let us use more mtime value in the future. For now we have a
minimal handling of the flag at read time, but we will never put ourself in a
situation where we will needs to writes it.
See the flag documentation for details.
( )
| Alphare |
| hg-reviewers |
This flag will let us use more mtime value in the future. For now we have a
minimal handling of the flag at read time, but we will never put ourself in a
situation where we will needs to writes it.
See the flag documentation for details.
| Automatic diff as part of commit; lint not applicable. |
| Automatic diff as part of commit; unit tests not applicable. |
| Path | Packages | |||
|---|---|---|---|---|
| M | mercurial/cext/parsers.c (8 lines) | |||
| M | mercurial/cext/util.h (1 line) | |||
| M | mercurial/helptext/internals/dirstate-v2.txt (8 lines) | |||
| M | mercurial/pure/parsers.py (5 lines) | |||
| M | rust/hg-core/src/dirstate_tree/on_disk.rs (4 lines) |
| Status | Author | Revision | |
|---|---|---|---|
| Closed | marmoute | ||
| Closed | marmoute | ||
| Closed | marmoute | ||
| Closed | marmoute | ||
| Closed | marmoute | ||
| Closed | marmoute | ||
| Closed | SimonSapin | ||
| Closed | SimonSapin | ||
| Closed | marmoute | ||
| Closed | SimonSapin |
| &t->mtime_ns)) { | &t->mtime_ns)) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| if (t->flags & dirstate_flag_expected_state_is_modified) { | if (t->flags & dirstate_flag_expected_state_is_modified) { | ||||
| t->flags &= ~(dirstate_flag_expected_state_is_modified | | t->flags &= ~(dirstate_flag_expected_state_is_modified | | ||||
| dirstate_flag_has_meaningful_data | | dirstate_flag_has_meaningful_data | | ||||
| dirstate_flag_has_file_mtime); | dirstate_flag_has_file_mtime); | ||||
| } | } | ||||
| if (t->flags & dirstate_flag_mtime_second_ambiguous) { | |||||
| /* The current code is not able to do the more subtle comparison | |||||
| * that the MTIME_SECOND_AMBIGUOUS requires. So we ignore the | |||||
| * mtime */ | |||||
| t->flags &= ~(dirstate_flag_mtime_second_ambiguous | | |||||
| dirstate_flag_has_meaningful_data | | |||||
| dirstate_flag_has_file_mtime); | |||||
| } | |||||
| t->mode = 0; | t->mode = 0; | ||||
| if (t->flags & dirstate_flag_has_meaningful_data) { | if (t->flags & dirstate_flag_has_meaningful_data) { | ||||
| if (t->flags & dirstate_flag_mode_exec_perm) { | if (t->flags & dirstate_flag_mode_exec_perm) { | ||||
| t->mode = 0755; | t->mode = 0755; | ||||
| } else { | } else { | ||||
| t->mode = 0644; | t->mode = 0644; | ||||
| } | } | ||||
| if (t->flags & dirstate_flag_mode_is_symlink) { | if (t->flags & dirstate_flag_mode_is_symlink) { | ||||
| static const int dirstate_flag_mode_is_symlink = 1 << 7; | static const int dirstate_flag_mode_is_symlink = 1 << 7; | ||||
| static const int dirstate_flag_expected_state_is_modified = 1 << 8; | static const int dirstate_flag_expected_state_is_modified = 1 << 8; | ||||
| static const int dirstate_flag_all_unknown_recorded = 1 << 9; | static const int dirstate_flag_all_unknown_recorded = 1 << 9; | ||||
| static const int dirstate_flag_all_ignored_recorded = 1 << 10; | static const int dirstate_flag_all_ignored_recorded = 1 << 10; | ||||
| static const int dirstate_flag_fallback_exec = 1 << 11; | static const int dirstate_flag_fallback_exec = 1 << 11; | ||||
| static const int dirstate_flag_has_fallback_exec = 1 << 12; | static const int dirstate_flag_has_fallback_exec = 1 << 12; | ||||
| static const int dirstate_flag_fallback_symlink = 1 << 13; | static const int dirstate_flag_fallback_symlink = 1 << 13; | ||||
| static const int dirstate_flag_has_fallback_symlink = 1 << 14; | static const int dirstate_flag_has_fallback_symlink = 1 << 14; | ||||
| static const int dirstate_flag_mtime_second_ambiguous = 1 << 15; | |||||
| extern PyTypeObject dirstateItemType; | extern PyTypeObject dirstateItemType; | ||||
| #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType) | #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType) | ||||
| #ifndef MIN | #ifndef MIN | ||||
| #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||||
| #endif | #endif | ||||
| /* VC9 doesn't include bool and lacks stdbool.h based on my searching */ | /* VC9 doesn't include bool and lacks stdbool.h based on my searching */ | ||||
| MODE_IS_SYMLINK = 1 << 7 | MODE_IS_SYMLINK = 1 << 7 | ||||
| EXPECTED_STATE_IS_MODIFIED = 1 << 8 | EXPECTED_STATE_IS_MODIFIED = 1 << 8 | ||||
| ALL_UNKNOWN_RECORDED = 1 << 9 | ALL_UNKNOWN_RECORDED = 1 << 9 | ||||
| ALL_IGNORED_RECORDED = 1 << 10 | ALL_IGNORED_RECORDED = 1 << 10 | ||||
| HAS_FALLBACK_EXEC = 1 << 11 | HAS_FALLBACK_EXEC = 1 << 11 | ||||
| FALLBACK_EXEC = 1 << 12 | FALLBACK_EXEC = 1 << 12 | ||||
| HAS_FALLBACK_SYMLINK = 1 << 13 | HAS_FALLBACK_SYMLINK = 1 << 13 | ||||
| FALLBACK_SYMLINK = 1 << 14 | FALLBACK_SYMLINK = 1 << 14 | ||||
| MTIME_SECOND_AMBIGUOUS = 1 << 15 | |||||
| The meaning of each bit is described below. | The meaning of each bit is described below. | ||||
| Other bits are unset. | Other bits are unset. | ||||
| They may be assigned meaning if the future, | They may be assigned meaning if the future, | ||||
| with the limitation that Mercurial versions that pre-date such meaning | with the limitation that Mercurial versions that pre-date such meaning | ||||
| will always reset those bits to unset when writing nodes. | will always reset those bits to unset when writing nodes. | ||||
| (A new node is written for any mutation in its subtree, | (A new node is written for any mutation in its subtree, | ||||
| system or operating system does not support that property, (e.g. | system or operating system does not support that property, (e.g. | ||||
| Windows). | Windows). | ||||
| `FALLBACK_SYMLINK` | `FALLBACK_SYMLINK` | ||||
| Should be ignored if `HAS_FALLBACK_SYMLINK` is unset. If set the file for | Should be ignored if `HAS_FALLBACK_SYMLINK` is unset. If set the file for | ||||
| this entry should be considered a symlink if that information cannot be | this entry should be considered a symlink if that information cannot be | ||||
| extracted from the file system. If unset it should be considered a normal | extracted from the file system. If unset it should be considered a normal | ||||
| file instead. | file instead. | ||||
| `MTIME_SECOND_AMBIGUOUS` | |||||
| This flag is relevant only when `HAS_FILE_MTIME` is set. When set, the | |||||
| `mtime` stored in the entry is only valid for comparison with timestamps | |||||
| that have nanosecond information. If available timestamp does not carries | |||||
| nanosecond information, the `mtime` should be ignored and no optimisation | |||||
| can be applied. | |||||
| DIRSTATE_V2_MODE_IS_SYMLINK = 1 << 7 | DIRSTATE_V2_MODE_IS_SYMLINK = 1 << 7 | ||||
| DIRSTATE_V2_EXPECTED_STATE_IS_MODIFIED = 1 << 8 | DIRSTATE_V2_EXPECTED_STATE_IS_MODIFIED = 1 << 8 | ||||
| DIRSTATE_V2_ALL_UNKNOWN_RECORDED = 1 << 9 | DIRSTATE_V2_ALL_UNKNOWN_RECORDED = 1 << 9 | ||||
| DIRSTATE_V2_ALL_IGNORED_RECORDED = 1 << 10 | DIRSTATE_V2_ALL_IGNORED_RECORDED = 1 << 10 | ||||
| DIRSTATE_V2_HAS_FALLBACK_EXEC = 1 << 11 | DIRSTATE_V2_HAS_FALLBACK_EXEC = 1 << 11 | ||||
| DIRSTATE_V2_FALLBACK_EXEC = 1 << 12 | DIRSTATE_V2_FALLBACK_EXEC = 1 << 12 | ||||
| DIRSTATE_V2_HAS_FALLBACK_SYMLINK = 1 << 13 | DIRSTATE_V2_HAS_FALLBACK_SYMLINK = 1 << 13 | ||||
| DIRSTATE_V2_FALLBACK_SYMLINK = 1 << 14 | DIRSTATE_V2_FALLBACK_SYMLINK = 1 << 14 | ||||
| DIRSTATE_V2_MTIME_SECOND_AMBIGUOUS = 1 << 15 | |||||
| @attr.s(slots=True, init=False) | @attr.s(slots=True, init=False) | ||||
| class DirstateItem(object): | class DirstateItem(object): | ||||
| """represent a dirstate entry | """represent a dirstate entry | ||||
| It hold multiple attributes | It hold multiple attributes | ||||
| if has_meaningful_mtime: | if has_meaningful_mtime: | ||||
| self._mtime_s, self._mtime_ns = parentfiledata[2] | self._mtime_s, self._mtime_ns = parentfiledata[2] | ||||
| @classmethod | @classmethod | ||||
| def from_v2_data(cls, flags, size, mtime_s, mtime_ns): | def from_v2_data(cls, flags, size, mtime_s, mtime_ns): | ||||
| """Build a new DirstateItem object from V2 data""" | """Build a new DirstateItem object from V2 data""" | ||||
| has_mode_size = bool(flags & DIRSTATE_V2_HAS_MODE_AND_SIZE) | has_mode_size = bool(flags & DIRSTATE_V2_HAS_MODE_AND_SIZE) | ||||
| has_meaningful_mtime = bool(flags & DIRSTATE_V2_HAS_FILE_MTIME) | has_meaningful_mtime = bool(flags & DIRSTATE_V2_HAS_FILE_MTIME) | ||||
| if flags & DIRSTATE_V2_MTIME_SECOND_AMBIGUOUS: | |||||
| # The current code is not able to do the more subtle comparison that the | |||||
| # MTIME_SECOND_AMBIGUOUS requires. So we ignore the mtime | |||||
| has_meaningful_mtime = False | |||||
| mode = None | mode = None | ||||
| if flags & +DIRSTATE_V2_EXPECTED_STATE_IS_MODIFIED: | if flags & +DIRSTATE_V2_EXPECTED_STATE_IS_MODIFIED: | ||||
| # we do not have support for this flag in the code yet, | # we do not have support for this flag in the code yet, | ||||
| # force a lookup for this file. | # force a lookup for this file. | ||||
| has_mode_size = False | has_mode_size = False | ||||
| has_meaningful_mtime = False | has_meaningful_mtime = False | ||||
| const MODE_IS_SYMLINK = 1 << 7; | const MODE_IS_SYMLINK = 1 << 7; | ||||
| const EXPECTED_STATE_IS_MODIFIED = 1 << 8; | const EXPECTED_STATE_IS_MODIFIED = 1 << 8; | ||||
| const ALL_UNKNOWN_RECORDED = 1 << 9; | const ALL_UNKNOWN_RECORDED = 1 << 9; | ||||
| const ALL_IGNORED_RECORDED = 1 << 10; | const ALL_IGNORED_RECORDED = 1 << 10; | ||||
| const HAS_FALLBACK_EXEC = 1 << 11; | const HAS_FALLBACK_EXEC = 1 << 11; | ||||
| const FALLBACK_EXEC = 1 << 12; | const FALLBACK_EXEC = 1 << 12; | ||||
| const HAS_FALLBACK_SYMLINK = 1 << 13; | const HAS_FALLBACK_SYMLINK = 1 << 13; | ||||
| const FALLBACK_SYMLINK = 1 << 14; | const FALLBACK_SYMLINK = 1 << 14; | ||||
| const MTIME_SECOND_AMBIGUOUS = 1 << 15; | |||||
| } | } | ||||
| } | } | ||||
| /// Duration since the Unix epoch | /// Duration since the Unix epoch | ||||
| #[derive(BytesCast, Copy, Clone)] | #[derive(BytesCast, Copy, Clone)] | ||||
| #[repr(C)] | #[repr(C)] | ||||
| struct PackedTruncatedTimestamp { | struct PackedTruncatedTimestamp { | ||||
| truncated_seconds: U32Be, | truncated_seconds: U32Be, | ||||
| && !self.flags().contains(Flags::EXPECTED_STATE_IS_MODIFIED) | && !self.flags().contains(Flags::EXPECTED_STATE_IS_MODIFIED) | ||||
| { | { | ||||
| Some((self.synthesize_unix_mode(), self.size.into())) | Some((self.synthesize_unix_mode(), self.size.into())) | ||||
| } else { | } else { | ||||
| None | None | ||||
| }; | }; | ||||
| let mtime = if self.flags().contains(Flags::HAS_FILE_MTIME) | let mtime = if self.flags().contains(Flags::HAS_FILE_MTIME) | ||||
| && !self.flags().contains(Flags::EXPECTED_STATE_IS_MODIFIED) | && !self.flags().contains(Flags::EXPECTED_STATE_IS_MODIFIED) | ||||
| // The current code is not able to do the more subtle comparison that the | |||||
| // 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 | // TODO: replace this by `self.mtime.try_into()?` to use | ||||
| // sub-second precision from the file. | // sub-second precision from the file. | ||||
| // We don’t do this yet because other parts of the code | // We don’t do this yet because other parts of the code | ||||
| // always set it to zero. | // always set it to zero. | ||||
| let mtime = TruncatedTimestamp::from_already_truncated( | let mtime = TruncatedTimestamp::from_already_truncated( | ||||
| self.mtime.truncated_seconds.get(), | self.mtime.truncated_seconds.get(), | ||||
| 0, | 0, | ||||