Mercurial > hg
changeset 29200:ca4065028e00
util: add filestat class to detect ambiguity of file stat
Current posix.cachestat implementation might overlook change of a
file, if changing keeps ctime, mtime and size of file. Comparison of
inode number also overlooks changing in such situation, because inode
number is rapidly reused.
Contents of a file cached before changing isn't invalidated as
expected, if change of a file is overlooked for this "ambiguity" of
file stat.
This patch adds filestat class to detect ambiguity of file stat.
This patch is a part of preparation for "Exact Cache Validation Plan":
https://www.mercurial-scm.org/wiki/ExactCacheValidationPlan
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Thu, 19 May 2016 00:20:37 +0900 |
parents | daff05dcd184 |
children | a109bf7e0dc2 |
files | mercurial/util.py |
diffstat | 1 files changed, 63 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/util.py Thu May 05 23:17:19 2016 +0000 +++ b/mercurial/util.py Thu May 19 00:20:37 2016 +0900 @@ -1381,6 +1381,69 @@ raise return temp +class filestat(object): + """help to exactly detect change of a file + + 'stat' attribute is result of 'os.stat()' if specified 'path' + exists. Otherwise, it is None. This can avoid preparative + 'exists()' examination on client side of this class. + """ + def __init__(self, path): + try: + self.stat = os.stat(path) + except OSError as err: + if err.errno != errno.ENOENT: + raise + self.stat = None + + __hash__ = object.__hash__ + + def __eq__(self, old): + try: + # if ambiguity between stat of new and old file is + # avoided, comparision of size, ctime and mtime is enough + # to exactly detect change of a file regardless of platform + return (self.stat.st_size == old.stat.st_size and + self.stat.st_ctime == old.stat.st_ctime and + self.stat.st_mtime == old.stat.st_mtime) + except AttributeError: + return False + + def isambig(self, old): + """Examine whether new (= self) stat is ambiguous against old one + + "S[N]" below means stat of a file at N-th change: + + - S[n-1].ctime < S[n].ctime: can detect change of a file + - S[n-1].ctime == S[n].ctime + - S[n-1].ctime < S[n].mtime: means natural advancing (*1) + - S[n-1].ctime == S[n].mtime: is ambiguous (*2) + - S[n-1].ctime > S[n].mtime: never occurs naturally (don't care) + - S[n-1].ctime > S[n].ctime: never occurs naturally (don't care) + + Case (*2) above means that a file was changed twice or more at + same time in sec (= S[n-1].ctime), and comparison of timestamp + is ambiguous. + + Base idea to avoid such ambiguity is "advance mtime 1 sec, if + timestamp is ambiguous". + + But advancing mtime only in case (*2) doesn't work as + expected, because naturally advanced S[n].mtime in case (*1) + might be equal to manually advanced S[n-1 or earlier].mtime. + + Therefore, all "S[n-1].ctime == S[n].ctime" cases should be + treated as ambiguous regardless of mtime, to avoid overlooking + by confliction between such mtime. + + Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime != + S[n].mtime", even if size of a file isn't changed. + """ + try: + return (self.stat.st_ctime == old.stat.st_ctime) + except AttributeError: + return False + class atomictempfile(object): '''writable file object that atomically updates a file