comparison mercurial/merge.py @ 52059: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 f5742367a279
children 8b7123c8947b
comparison
equal deleted inserted replaced
52058:f5742367a279 52059:b332ae615714
2212 When we reach the current code, the "on disk" part of the update operation 2212 When we reach the current code, the "on disk" part of the update operation
2213 is finished. We still assume that no other process raced that "on disk" 2213 is finished. We still assume that no other process raced that "on disk"
2214 part, but we want to at least prevent later file changes to alter the 2214 part, but we want to at least prevent later file changes to alter the
2215 contents of the file right after the update operation so quickly that the 2215 contents of the file right after the update operation so quickly that the
2216 same mtime is recorded for the operation. 2216 same mtime is recorded for the operation.
2217 To prevent such ambiguities from happenning, we will only keep the 2217
2218 "file data" for files with mtimes that are strictly in the past, 2218 To prevent such ambiguities from happenning, we will do (up to) two things:
2219 i.e. whose mtime is strictly lower than the current time. 2219 - wait until the filesystem clock has ticked
2220 - only keep the "file data" for files with mtimes that are strictly in
2221 the past, i.e. whose mtime is strictly lower than the current time.
2222
2223 We only wait for the system clock to tick if using dirstate-v2, since v1
2224 only has second-level granularity and waiting for a whole second is
2225 too much of a penalty in the general case.
2226
2227 Although we're assuming that people running dirstate-v2 on Linux
2228 don't have a second-granularity FS (with the exclusion of NFS), users
2229 can be surprising, and at some point in the future, dirstate-v2 will become
2230 the default. To that end, we limit the wait time to 100ms and fall back
2231 to the filtering method in case of a timeout.
2232
2233 +------------+------+--------------+
2234 | version | wait | filter level |
2235 +------------+------+--------------+
2236 | V1 | No | Second |
2237 | V2 | Yes | Nanosecond |
2238 | V2-slow-fs | No | Second |
2239 +------------+------+--------------+
2220 2240
2221 This protects us from race conditions from operations that could run right 2241 This protects us from race conditions from operations that could run right
2222 after this one, especially other Mercurial operations that could be waiting 2242 after this one, especially other Mercurial operations that could be waiting
2223 for the wlock to touch files contents and the dirstate. 2243 for the wlock to touch files contents and the dirstate.
2224 2244
2225 In an ideal world, we could only get reliable information in `getfiledata` 2245 In an ideal world, we could only get reliable information in `getfiledata`
2226 (from `getbatch`), however the current approach has been a successful 2246 (from `getbatch`), however this filtering approach has been a successful
2227 compromise for many years. 2247 compromise for many years. A patch series of the linux kernel might change
2248 this in 6.12³.
2228 2249
2229 At the time this comment is written, not using any "cache" file data at all 2250 At the time this comment is written, not using any "cache" file data at all
2230 here would not be viable, as it would result is a very large amount of work 2251 here would not be viable, as it would result is a very large amount of work
2231 (equivalent to the previous `hg update` during the next status after an 2252 (equivalent to the previous `hg update` during the next status after an
2232 update). 2253 update).
2237 2258
2238 [2] using nano-second precision can greatly help here because it makes the 2259 [2] using nano-second precision can greatly help here because it makes the
2239 "different write with same mtime" issue virtually vanish. However, 2260 "different write with same mtime" issue virtually vanish. However,
2240 dirstate v1 cannot store such precision and a bunch of python-runtime, 2261 dirstate v1 cannot store such precision and a bunch of python-runtime,
2241 operating-system and filesystem parts do not provide us with such 2262 operating-system and filesystem parts do not provide us with such
2242 precision, so we have to operate as if it wasn't available.""" 2263 precision, so we have to operate as if it wasn't available.
2264
2265 [3] https://lore.kernel.org/all/20241002-mgtime-v10-8-d1c4717f5284@kernel.org
2266 """
2243 ambiguous_mtime: FileData = {} 2267 ambiguous_mtime: FileData = {}
2244 now = timestamp.get_fs_now(repo.vfs) 2268 dirstate_v2 = repo.dirstate._use_dirstate_v2
2269 fs_now_result = None
2270 fast_enough_fs = True
2271 if dirstate_v2:
2272 fstype = util.getfstype(repo.vfs.base)
2273 # Exclude NFS right off the bat
2274 fast_enough_fs = fstype != b'nfs'
2275 if fstype is not None and fast_enough_fs:
2276 fs_now_result = timestamp.wait_until_fs_tick(repo.vfs)
2277
2278 if fs_now_result is None:
2279 try:
2280 now = timestamp.get_fs_now(repo.vfs)
2281 fs_now_result = (now, False)
2282 except OSError:
2283 pass
2284
2245 if fs_now_result is None: 2285 if fs_now_result is None:
2246 # we can't write to the FS, so we won't actually update 2286 # we can't write to the FS, so we won't actually update
2247 # the dirstate content anyway, no need to put cache 2287 # the dirstate content anyway, no need to put cache
2248 # information. 2288 # information.
2249 return None 2289 return None
2250 else: 2290 else:
2251 now_sec = now[0]
2252 now, timed_out = fs_now_result 2291 now, timed_out = fs_now_result
2253 if timed_out: 2292 if timed_out:
2254 fast_enough_fs = False 2293 fast_enough_fs = False
2255 for f, m in file_data.items(): 2294 for f, m in file_data.items():
2256 if m is not None and m[2][0] >= now_sec: 2295 if m is not None:
2257 ambiguous_mtime[f] = (m[0], m[1], None) 2296 reliable = timestamp.make_mtime_reliable(m[2], now)
2297 if reliable is None or (
2298 reliable[2] and (not dirstate_v2 or not fast_enough_fs)
2299 ):
2300 # Either it's not reliable, or it's second ambiguous
2301 # and we're in dirstate-v1 or in a slow fs, so discard
2302 # the mtime.
2303 ambiguous_mtime[f] = (m[0], m[1], None)
2304 elif reliable[2]:
2305 # We need to remember that this time is "second ambiguous"
2306 # otherwise the next status might miss a subsecond change
2307 # if its "stat" doesn't provide nanoseconds.
2308 #
2309 # TODO make osutil.c understand nanoseconds when possible
2310 # (see timestamp.py for the same note)
2311 ambiguous_mtime[f] = (m[0], m[1], reliable)
2258 for f, m in ambiguous_mtime.items(): 2312 for f, m in ambiguous_mtime.items():
2259 file_data[f] = m 2313 file_data[f] = m
2260 return file_data 2314 return file_data
2261 2315
2262 2316