##// END OF EJS Templates
scmutil: add file object wrapper class to check ambiguity at closing...
FUJIWARA Katsunori -
r29995:57830bd0 default
parent child Browse files
Show More
@@ -1431,3 +1431,34 b' class backgroundfilecloser(object):'
1431 return
1431 return
1432
1432
1433 self._queue.put(fh, block=True, timeout=None)
1433 self._queue.put(fh, block=True, timeout=None)
1434
1435 class checkambigatclosing(closewrapbase):
1436 """Proxy for a file object, to avoid ambiguity of file stat
1437
1438 See also util.filestat for detail about "ambiguity of file stat".
1439
1440 This proxy is useful only if the target file is guarded by any
1441 lock (e.g. repo.lock or repo.wlock)
1442
1443 Do not instantiate outside of the vfs layer.
1444 """
1445 def __init__(self, fh):
1446 super(checkambigatclosing, self).__init__(fh)
1447 object.__setattr__(self, '_oldstat', util.filestat(fh.name))
1448
1449 def _checkambig(self):
1450 oldstat = self._oldstat
1451 if oldstat.stat:
1452 newstat = util.filestat(self._origfh.name)
1453 if newstat.isambig(oldstat):
1454 # stat of changed file is ambiguous to original one
1455 advanced = (oldstat.stat.st_mtime + 1) & 0x7fffffff
1456 os.utime(self._origfh.name, (advanced, advanced))
1457
1458 def __exit__(self, exc_type, exc_value, exc_tb):
1459 self._origfh.__exit__(exc_type, exc_value, exc_tb)
1460 self._checkambig()
1461
1462 def close(self):
1463 self._origfh.close()
1464 self._checkambig()
@@ -179,6 +179,56 b' def setbeforeget(repo):'
179 print("* file y created")
179 print("* file y created")
180 print(repo.cached)
180 print(repo.cached)
181
181
182 def antiambiguity():
183 filename = 'ambigcheck'
184
185 # try some times, because reproduction of ambiguity depends on
186 # "filesystem time"
187 for i in xrange(5):
188 fp = open(filename, 'w')
189 fp.write('FOO')
190 fp.close()
191
192 oldstat = os.stat(filename)
193 if oldstat.st_ctime != oldstat.st_mtime:
194 # subsequent changing never causes ambiguity
195 continue
196
197 repetition = 3
198
199 # repeat changing via checkambigatclosing, to examine whether
200 # st_mtime is advanced multiple times as expecetd
201 for i in xrange(repetition):
202 # explicit closing
203 fp = scmutil.checkambigatclosing(open(filename, 'a'))
204 fp.write('FOO')
205 fp.close()
206
207 # implicit closing by "with" statement
208 with scmutil.checkambigatclosing(open(filename, 'a')) as fp:
209 fp.write('BAR')
210
211 newstat = os.stat(filename)
212 if oldstat.st_ctime != newstat.st_ctime:
213 # timestamp ambiguity was naturally avoided while repetition
214 continue
215
216 # st_mtime should be advanced "repetition * 2" times, because
217 # all changes occured at same time (in sec)
218 expected = (oldstat.st_mtime + repetition * 2) & 0x7fffffff
219 if newstat.st_mtime != expected:
220 print("'newstat.st_mtime %s is not %s (as %s + %s * 2)" %
221 (newstat.st_mtime, expected, oldstat.st_mtime, repetition))
222
223 # no more examination is needed regardless of result
224 break
225 else:
226 # This platform seems too slow to examine anti-ambiguity
227 # of file timestamp (or test happened to be executed at
228 # bad timing). Exit silently in this case, because running
229 # on other faster platforms can detect problems
230 pass
231
182 print('basic:')
232 print('basic:')
183 print()
233 print()
184 basic(fakerepo())
234 basic(fakerepo())
@@ -191,3 +241,7 b' print()'
191 print('setbeforeget:')
241 print('setbeforeget:')
192 print()
242 print()
193 setbeforeget(fakerepo())
243 setbeforeget(fakerepo())
244 print()
245 print('antiambiguity:')
246 print()
247 antiambiguity()
@@ -58,3 +58,6 b' string 2 set externally'
58 * file y created
58 * file y created
59 creating
59 creating
60 string from function
60 string from function
61
62 antiambiguity:
63
General Comments 0
You need to be logged in to leave comments. Login now