comparison mercurial/vfs.py @ 51649:ba205f944cb4 stable

mmap: add a `is_mmap_safe` method to vfs This will be useful to safeguard mmap usage to void SIGBUS when repositories lives on a NFS drive.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 03 Jul 2024 12:22:48 +0200
parents b5500857e173
children be6d8ea6d3d2
comparison
equal deleted inserted replaced
51647:5b803e5c1325 51649:ba205f944cb4
186 def lexists(self, path: Optional[bytes] = None) -> bool: 186 def lexists(self, path: Optional[bytes] = None) -> bool:
187 return os.path.lexists(self.join(path)) 187 return os.path.lexists(self.join(path))
188 188
189 def lstat(self, path: Optional[bytes] = None): 189 def lstat(self, path: Optional[bytes] = None):
190 return os.lstat(self.join(path)) 190 return os.lstat(self.join(path))
191
192 def is_mmap_safe(self, path: Optional[bytes] = None) -> bool:
193 """return True if it is safe to read a file content as mmap
194
195 This focus on the file system aspect of such safety, the application
196 logic around that file is not taken into account, so caller need to
197 make sure the file won't be truncated in a way that will create SIGBUS
198 on access.
199
200
201 The initial motivation for this logic is that if mmap is used on NFS
202 and somebody deletes the mapped file (e.g. by renaming on top of it),
203 then you get SIGBUS, which can be pretty disruptive: we get core dump
204 reports, and the process terminates without writing to the blackbox.
205
206 Instead in this situation we prefer to read the file normally.
207 The risk of ESTALE in the middle of the read remains, but it's
208 smaller because we read sooner and the error should be reported
209 just as any other error.
210
211 Note that python standard library does not offer the necessary function
212 to detect the file stem bits. So this detection rely on compiled bits
213 and is not available in pure python.
214 """
215 # XXX Since we already assume a vfs to address a consistent file system
216 # in other location, we could determine the fstype once for the root
217 # and cache that value.
218 fstype = util.getfstype(self.join(path))
219 return fstype is not None and fstype != b'nfs'
191 220
192 def listdir(self, path: Optional[bytes] = None): 221 def listdir(self, path: Optional[bytes] = None):
193 return os.listdir(self.join(path)) 222 return os.listdir(self.join(path))
194 223
195 def makedir(self, path: Optional[bytes] = None, notindexed=True): 224 def makedir(self, path: Optional[bytes] = None, notindexed=True):