##// END OF EJS Templates
dirstate: Document Timestamp.second_ambiguous...
Simon Sapin -
r49271:c8ca2196 default
parent child Browse files
Show More
@@ -1,124 +1,128 b''
1 1 # Copyright Mercurial Contributors
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6 from __future__ import absolute_import
7 7
8 8 import functools
9 9 import os
10 10 import stat
11 11
12 12 from .. import error
13 13
14 14
15 15 rangemask = 0x7FFFFFFF
16 16
17 17
18 18 @functools.total_ordering
19 19 class timestamp(tuple):
20 20 """
21 21 A Unix timestamp with optional nanoseconds precision,
22 22 modulo 2**31 seconds.
23 23
24 A 2-tuple containing:
24 A 3-tuple containing:
25 25
26 26 `truncated_seconds`: seconds since the Unix epoch,
27 27 truncated to its lower 31 bits
28 28
29 29 `subsecond_nanoseconds`: number of nanoseconds since `truncated_seconds`.
30 30 When this is zero, the sub-second precision is considered unknown.
31
32 `second_ambiguous`: whether this timestamp is still "reliable"
33 (see `reliable_mtime_of`) if we drop its sub-second component.
31 34 """
32 35
33 36 def __new__(cls, value):
34 37 truncated_seconds, subsec_nanos, second_ambiguous = value
35 38 value = (truncated_seconds & rangemask, subsec_nanos, second_ambiguous)
36 39 return super(timestamp, cls).__new__(cls, value)
37 40
38 41 def __eq__(self, other):
39 42 raise error.ProgrammingError(
40 43 'timestamp should never be compared directly'
41 44 )
42 45
43 46 def __gt__(self, other):
44 47 raise error.ProgrammingError(
45 48 'timestamp should never be compared directly'
46 49 )
47 50
48 51
49 52 def get_fs_now(vfs):
50 53 """return a timestamp for "now" in the current vfs
51 54
52 55 This will raise an exception if no temporary files could be created.
53 56 """
54 57 tmpfd, tmpname = vfs.mkstemp()
55 58 try:
56 59 return mtime_of(os.fstat(tmpfd))
57 60 finally:
58 61 os.close(tmpfd)
59 62 vfs.unlink(tmpname)
60 63
61 64
62 65 def zero():
63 66 """
64 67 Returns the `timestamp` at the Unix epoch.
65 68 """
66 69 return tuple.__new__(timestamp, (0, 0))
67 70
68 71
69 72 def mtime_of(stat_result):
70 73 """
71 74 Takes an `os.stat_result`-like object and returns a `timestamp` object
72 75 for its modification time.
73 76 """
74 77 try:
75 78 # TODO: add this attribute to `osutil.stat` objects,
76 79 # see `mercurial/cext/osutil.c`.
77 80 #
78 81 # This attribute is also not available on Python 2.
79 82 nanos = stat_result.st_mtime_ns
80 83 except AttributeError:
81 84 # https://docs.python.org/2/library/os.html#os.stat_float_times
82 85 # "For compatibility with older Python versions,
83 86 # accessing stat_result as a tuple always returns integers."
84 87 secs = stat_result[stat.ST_MTIME]
85 88
86 89 subsec_nanos = 0
87 90 else:
88 91 billion = int(1e9)
89 92 secs = nanos // billion
90 93 subsec_nanos = nanos % billion
91 94
92 95 return timestamp((secs, subsec_nanos, False))
93 96
94 97
95 98 def reliable_mtime_of(stat_result, present_mtime):
96 """same as `mtime_of`, but return None if the date might be ambiguous
99 """Same as `mtime_of`, but return `None` or a `Timestamp` with
100 `second_ambiguous` set if the date might be ambiguous.
97 101
98 102 A modification time is reliable if it is older than "present_time" (or
99 103 sufficiently in the future).
100 104
101 105 Otherwise a concurrent modification might happens with the same mtime.
102 106 """
103 107 file_mtime = mtime_of(stat_result)
104 108 file_second = file_mtime[0]
105 109 file_ns = file_mtime[1]
106 110 boundary_second = present_mtime[0]
107 111 boundary_ns = present_mtime[1]
108 112 # If the mtime of the ambiguous file is younger (or equal) to the starting
109 113 # point of the `status` walk, we cannot garantee that another, racy, write
110 114 # will not happen right after with the same mtime and we cannot cache the
111 115 # information.
112 116 #
113 117 # However if the mtime is far away in the future, this is likely some
114 118 # mismatch between the current clock and previous file system operation. So
115 119 # mtime more than one days in the future are considered fine.
116 120 if boundary_second == file_second:
117 121 if file_ns and boundary_ns:
118 122 if file_ns < boundary_ns:
119 123 return timestamp((file_second, file_ns, True))
120 124 return None
121 125 elif boundary_second < file_second < (3600 * 24 + boundary_second):
122 126 return None
123 127 else:
124 128 return file_mtime
General Comments 0
You need to be logged in to leave comments. Login now