annotate mercurial/dirstateutils/timestamp.py @ 52055:b332ae615714

merge: improve working-copy mtime race handling Explanations inline. This also makes use of `make_mtime_reliable`, which unifies our mtime raciness logic from the status. On top of this, this fixes the handling of the pure dirstate status to better catch racy status, as we've been doing in Rust for a long time now.
author Rapha?l Gom?s <rgomes@octobus.net>
date Wed, 16 Oct 2024 19:14:30 +0200
parents 572d80e51094
children 5cc8deb96b48
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
1 # Copyright Mercurial Contributors
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
2 #
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
3 # This software may be used and distributed according to the terms of the
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
4 # GNU General Public License version 2 or any later version.
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
5
51859
f4733654f144 typing: add `from __future__ import annotations` to most files
Matt Harbison <matt_harbison@yahoo.com>
parents: 48875
diff changeset
6 from __future__ import annotations
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
7
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
8 import functools
48379
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
9 import os
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10 import stat
52052
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
11 import time
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
12 from typing import Optional, Tuple
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
13
48397
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
14 from .. import error
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
15
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17 rangemask = 0x7FFFFFFF
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
20 @functools.total_ordering
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 class timestamp(tuple):
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
22 """
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
23 A Unix timestamp with optional nanoseconds precision,
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
24 modulo 2**31 seconds.
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
25
48442
c8ca21962ff4 dirstate: Document Timestamp.second_ambiguous
Simon Sapin <simon.sapin@octobus.net>
parents: 48422
diff changeset
26 A 3-tuple containing:
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
27
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
28 `truncated_seconds`: seconds since the Unix epoch,
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
29 truncated to its lower 31 bits
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
30
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
31 `subsecond_nanoseconds`: number of nanoseconds since `truncated_seconds`.
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
32 When this is zero, the sub-second precision is considered unknown.
48442
c8ca21962ff4 dirstate: Document Timestamp.second_ambiguous
Simon Sapin <simon.sapin@octobus.net>
parents: 48422
diff changeset
33
c8ca21962ff4 dirstate: Document Timestamp.second_ambiguous
Simon Sapin <simon.sapin@octobus.net>
parents: 48422
diff changeset
34 `second_ambiguous`: whether this timestamp is still "reliable"
c8ca21962ff4 dirstate: Document Timestamp.second_ambiguous
Simon Sapin <simon.sapin@octobus.net>
parents: 48422
diff changeset
35 (see `reliable_mtime_of`) if we drop its sub-second component.
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
36 """
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
37
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
38 def __new__(cls, value):
48398
111098af6356 dirstate-item: add a "second_ambiguous` flag in the mtime tuple
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48397
diff changeset
39 truncated_seconds, subsec_nanos, second_ambiguous = value
111098af6356 dirstate-item: add a "second_ambiguous` flag in the mtime tuple
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48397
diff changeset
40 value = (truncated_seconds & rangemask, subsec_nanos, second_ambiguous)
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 return super(timestamp, cls).__new__(cls, value)
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
42
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
43 def __eq__(self, other):
48397
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
44 raise error.ProgrammingError(
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
45 'timestamp should never be compared directly'
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
46 )
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
47
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
48 def __gt__(self, other):
48397
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
49 raise error.ProgrammingError(
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
50 'timestamp should never be compared directly'
8d585aa9becf dirstate: drop comparison primitive on the timestamp class
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48395
diff changeset
51 )
48262
68bb472aee9c dirstate: ignore sub-second component when either is zero in mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
52
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
53
52052
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
54 def get_fs_now(vfs) -> Optional[timestamp]:
48379
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
55 """return a timestamp for "now" in the current vfs
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
56
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
57 This will raise an exception if no temporary files could be created.
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
58 """
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
59 tmpfd, tmpname = vfs.mkstemp()
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
60 try:
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
61 return mtime_of(os.fstat(tmpfd))
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
62 finally:
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
63 os.close(tmpfd)
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
64 vfs.unlink(tmpname)
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
65
08b060abd658 dirstate: move "get fs now" in the timestamp utility module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
66
52052
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
67 def zero() -> timestamp:
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
68 """
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
69 Returns the `timestamp` at the Unix epoch.
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
70 """
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
71 return tuple.__new__(timestamp, (0, 0))
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
72
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
73
52052
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
74 def mtime_of(stat_result: os.stat_result) -> timestamp:
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
75 """
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
76 Takes an `os.stat_result`-like object and returns a `timestamp` object
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
77 for its modification time.
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
78 """
48263
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
79 try:
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
80 # TODO: add this attribute to `osutil.stat` objects,
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
81 # see `mercurial/cext/osutil.c`.
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
82 #
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
83 # This attribute is also not available on Python 2.
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
84 nanos = stat_result.st_mtime_ns
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
85 except AttributeError:
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
86 # https://docs.python.org/2/library/os.html#os.stat_float_times
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
87 # "For compatibility with older Python versions,
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
88 # accessing stat_result as a tuple always returns integers."
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
89 secs = stat_result[stat.ST_MTIME]
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
90
48263
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
91 subsec_nanos = 0
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
92 else:
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
93 billion = int(1e9)
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
94 secs = nanos // billion
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48262
diff changeset
95 subsec_nanos = nanos % billion
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
96
48398
111098af6356 dirstate-item: add a "second_ambiguous` flag in the mtime tuple
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48397
diff changeset
97 return timestamp((secs, subsec_nanos, False))
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
98
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
99
52052
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
100 def reliable_mtime_of(
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
101 stat_result: os.stat_result, present_mtime: timestamp
7ea1cb46b590 timestamp: add type information to the module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51859
diff changeset
102 ) -> Optional[timestamp]:
52053
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
103 """Wrapper for `make_mtime_reliable` for stat objects"""
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
104 file_mtime = mtime_of(stat_result)
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
105 return make_mtime_reliable(file_mtime, present_mtime)
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
106
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
107
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
108 def make_mtime_reliable(
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
109 file_timestamp: timestamp, present_mtime: timestamp
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
110 ) -> Optional[timestamp]:
48442
c8ca21962ff4 dirstate: Document Timestamp.second_ambiguous
Simon Sapin <simon.sapin@octobus.net>
parents: 48422
diff changeset
111 """Same as `mtime_of`, but return `None` or a `Timestamp` with
c8ca21962ff4 dirstate: Document Timestamp.second_ambiguous
Simon Sapin <simon.sapin@octobus.net>
parents: 48422
diff changeset
112 `second_ambiguous` set if the date might be ambiguous.
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
113
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
114 A modification time is reliable if it is older than "present_time" (or
48422
000130cfafb6 rhg: Update the dirstate on disk after status
Simon Sapin <simon.sapin@octobus.net>
parents: 48403
diff changeset
115 sufficiently in the future).
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
116
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
117 Otherwise a concurrent modification might happens with the same mtime.
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
118 """
52053
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
119 file_second = file_timestamp[0]
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
120 file_ns = file_timestamp[1]
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
121 boundary_second = present_mtime[0]
48403
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
122 boundary_ns = present_mtime[1]
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
123 # If the mtime of the ambiguous file is younger (or equal) to the starting
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
124 # point of the `status` walk, we cannot garantee that another, racy, write
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
125 # will not happen right after with the same mtime and we cannot cache the
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
126 # information.
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
127 #
48403
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
128 # However if the mtime is far away in the future, this is likely some
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
129 # mismatch between the current clock and previous file system operation. So
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
130 # mtime more than one days in the future are considered fine.
48403
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
131 if boundary_second == file_second:
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
132 if file_ns and boundary_ns:
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
133 if file_ns < boundary_ns:
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
134 return timestamp((file_second, file_ns, True))
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
135 return None
ca42667c8d26 status: keep second-ambiguous mtimes during fixup
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48398
diff changeset
136 elif boundary_second < file_second < (3600 * 24 + boundary_second):
48395
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
137 return None
9ae0353c9f5d status: move the boundary comparison logic within the timestamp module
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48379
diff changeset
138 else:
52053
572d80e51094 timestamp: make the reliable comparison more usable from outside
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52052
diff changeset
139 return file_timestamp
52055
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
140
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
141
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
142 FS_TICK_WAIT_TIMEOUT = 0.1 # 100 milliseconds
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
143
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
144
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
145 def wait_until_fs_tick(vfs) -> Optional[Tuple[timestamp, bool]]:
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
146 """Wait until the next update from the filesystem time by writing in a loop
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
147 a new temporary file inside the working directory and checking if its time
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
148 differs from the first one observed.
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
149
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
150 Returns `None` if we are unable to get the filesystem time,
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
151 `(timestamp, True)` if we've timed out waiting for the filesystem clock
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
152 to tick, and `(timestamp, False)` if we've waited successfully.
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
153
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
154 On Linux, your average tick is going to be a "jiffy", or 1/HZ.
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
155 HZ is your kernel's tick rate (if it has one configured) and the value
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
156 is the one returned by `grep 'CONFIG_HZ=' /boot/config-$(uname -r)`,
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
157 again assuming a normal setup.
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
158
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
159 In my case (Alphare) at the time of writing, I get `CONFIG_HZ=250`,
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
160 which equates to 4ms.
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
161 This might change with a series that could make it to Linux 6.12:
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
162 https://lore.kernel.org/all/20241002-mgtime-v10-8-d1c4717f5284@kernel.org
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
163 """
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
164 start = time.monotonic()
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
165
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
166 try:
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
167 old_fs_time = get_fs_now(vfs)
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
168 new_fs_time = get_fs_now(vfs)
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
169
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
170 while (
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
171 new_fs_time[0] == old_fs_time[0]
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
172 and new_fs_time[1] == old_fs_time[1]
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
173 ):
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
174 if time.monotonic() - start > FS_TICK_WAIT_TIMEOUT:
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
175 return (old_fs_time, True)
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
176 new_fs_time = get_fs_now(vfs)
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
177 except OSError:
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
178 return None
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
179 else:
b332ae615714 merge: improve working-copy mtime race handling
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52053
diff changeset
180 return (new_fs_time, False)