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