Mercurial > hg
comparison mercurial/dirstate.py @ 48260:269ff8978086
dirstate: store mtimes with nanosecond precision in memory
Keep integer seconds since the Unix epoch,
together with integer nanoseconds in the `0 <= n < 1e9` range.
For now, nanoseconds are still always zero.
This commit is about data structure changes.
Differential Revision: https://phab.mercurial-scm.org/D11684
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 18 Oct 2021 11:23:07 +0200 |
parents | 602c8e8411f5 |
children | 8f54d9c79b12 |
comparison
equal
deleted
inserted
replaced
48259:84f6b0c41b90 | 48260:269ff8978086 |
---|---|
29 scmutil, | 29 scmutil, |
30 sparse, | 30 sparse, |
31 util, | 31 util, |
32 ) | 32 ) |
33 | 33 |
34 from .dirstateutils import ( | |
35 timestamp, | |
36 ) | |
37 | |
34 from .interfaces import ( | 38 from .interfaces import ( |
35 dirstate as intdirstate, | 39 dirstate as intdirstate, |
36 util as interfaceutil, | 40 util as interfaceutil, |
37 ) | 41 ) |
38 | 42 |
64 | 68 |
65 def _getfsnow(vfs): | 69 def _getfsnow(vfs): |
66 '''Get "now" timestamp on filesystem''' | 70 '''Get "now" timestamp on filesystem''' |
67 tmpfd, tmpname = vfs.mkstemp() | 71 tmpfd, tmpname = vfs.mkstemp() |
68 try: | 72 try: |
69 return os.fstat(tmpfd)[stat.ST_MTIME] | 73 return timestamp.mtime_of(os.fstat(tmpfd)) |
70 finally: | 74 finally: |
71 os.close(tmpfd) | 75 os.close(tmpfd) |
72 vfs.unlink(tmpname) | 76 vfs.unlink(tmpname) |
73 | 77 |
74 | 78 |
120 self._sparsematchfn = sparsematchfn | 124 self._sparsematchfn = sparsematchfn |
121 # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is | 125 # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is |
122 # UNC path pointing to root share (issue4557) | 126 # UNC path pointing to root share (issue4557) |
123 self._rootdir = pathutil.normasprefix(root) | 127 self._rootdir = pathutil.normasprefix(root) |
124 self._dirty = False | 128 self._dirty = False |
125 self._lastnormaltime = 0 | 129 self._lastnormaltime = timestamp.zero() |
126 self._ui = ui | 130 self._ui = ui |
127 self._filecache = {} | 131 self._filecache = {} |
128 self._parentwriters = 0 | 132 self._parentwriters = 0 |
129 self._filename = b'dirstate' | 133 self._filename = b'dirstate' |
130 self._pendingfilename = b'%s.pending' % self._filename | 134 self._pendingfilename = b'%s.pending' % self._filename |
438 check whether the dirstate has changed before rereading it.""" | 442 check whether the dirstate has changed before rereading it.""" |
439 | 443 |
440 for a in ("_map", "_branch", "_ignore"): | 444 for a in ("_map", "_branch", "_ignore"): |
441 if a in self.__dict__: | 445 if a in self.__dict__: |
442 delattr(self, a) | 446 delattr(self, a) |
443 self._lastnormaltime = 0 | 447 self._lastnormaltime = timestamp.zero() |
444 self._dirty = False | 448 self._dirty = False |
445 self._parentwriters = 0 | 449 self._parentwriters = 0 |
446 self._origpl = None | 450 self._origpl = None |
447 | 451 |
448 def copy(self, source, dest): | 452 def copy(self, source, dest): |
637 def _get_filedata(self, filename): | 641 def _get_filedata(self, filename): |
638 """returns""" | 642 """returns""" |
639 s = os.lstat(self._join(filename)) | 643 s = os.lstat(self._join(filename)) |
640 mode = s.st_mode | 644 mode = s.st_mode |
641 size = s.st_size | 645 size = s.st_size |
642 mtime = s[stat.ST_MTIME] | 646 mtime = timestamp.mtime_of(s) |
643 return (mode, size, mtime) | 647 return (mode, size, mtime) |
644 | 648 |
645 def _discoverpath(self, path, normed, ignoremissing, exists, storemap): | 649 def _discoverpath(self, path, normed, ignoremissing, exists, storemap): |
646 if exists is None: | 650 if exists is None: |
647 exists = os.path.lexists(os.path.join(self._root, path)) | 651 exists = os.path.lexists(os.path.join(self._root, path)) |
718 return self._normalize(path, isknown, ignoremissing) | 722 return self._normalize(path, isknown, ignoremissing) |
719 return path | 723 return path |
720 | 724 |
721 def clear(self): | 725 def clear(self): |
722 self._map.clear() | 726 self._map.clear() |
723 self._lastnormaltime = 0 | 727 self._lastnormaltime = timestamp.zero() |
724 self._dirty = True | 728 self._dirty = True |
725 | 729 |
726 def rebuild(self, parent, allfiles, changedfiles=None): | 730 def rebuild(self, parent, allfiles, changedfiles=None): |
727 if changedfiles is None: | 731 if changedfiles is None: |
728 # Rebuild entire dirstate | 732 # Rebuild entire dirstate |
821 self._origpl = None | 825 self._origpl = None |
822 | 826 |
823 if now is None: | 827 if now is None: |
824 # use the modification time of the newly created temporary file as the | 828 # use the modification time of the newly created temporary file as the |
825 # filesystem's notion of 'now' | 829 # filesystem's notion of 'now' |
826 now = util.fstat(st)[stat.ST_MTIME] & _rangemask | 830 now = timestamp.mtime_of(util.fstat(st)) |
827 | 831 |
828 # enough 'delaywrite' prevents 'pack_dirstate' from dropping | 832 # enough 'delaywrite' prevents 'pack_dirstate' from dropping |
829 # timestamp of each entries in dirstate, because of 'now > mtime' | 833 # timestamp of each entries in dirstate, because of 'now > mtime' |
830 delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite') | 834 delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite') |
831 if delaywrite > 0: | 835 if delaywrite > 0: |
838 # multiple of n seconds | 842 # multiple of n seconds |
839 clock = time.time() | 843 clock = time.time() |
840 start = int(clock) - (int(clock) % delaywrite) | 844 start = int(clock) - (int(clock) % delaywrite) |
841 end = start + delaywrite | 845 end = start + delaywrite |
842 time.sleep(end - clock) | 846 time.sleep(end - clock) |
843 now = end # trust our estimate that the end is near now | 847 # trust our estimate that the end is near now |
848 now = timestamp.timestamp((end, 0)) | |
844 break | 849 break |
845 | 850 |
846 self._map.write(tr, st, now) | 851 self._map.write(tr, st, now) |
847 self._lastnormaltime = 0 | 852 self._lastnormaltime = timestamp.zero() |
848 self._dirty = False | 853 self._dirty = False |
849 | 854 |
850 def _dirignore(self, f): | 855 def _dirignore(self, f): |
851 if self._ignore(f): | 856 if self._ignore(f): |
852 return True | 857 return True |
1375 iadd(fn) | 1380 iadd(fn) |
1376 else: | 1381 else: |
1377 uadd(fn) | 1382 uadd(fn) |
1378 continue | 1383 continue |
1379 | 1384 |
1380 # This is equivalent to 'state, mode, size, time = dmap[fn]' but not | |
1381 # written like that for performance reasons. dmap[fn] is not a | |
1382 # Python tuple in compiled builds. The CPython UNPACK_SEQUENCE | |
1383 # opcode has fast paths when the value to be unpacked is a tuple or | |
1384 # a list, but falls back to creating a full-fledged iterator in | |
1385 # general. That is much slower than simply accessing and storing the | |
1386 # tuple members one by one. | |
1387 t = dget(fn) | 1385 t = dget(fn) |
1388 mode = t.mode | 1386 mode = t.mode |
1389 size = t.size | 1387 size = t.size |
1390 time = t.mtime | |
1391 | 1388 |
1392 if not st and t.tracked: | 1389 if not st and t.tracked: |
1393 dadd(fn) | 1390 dadd(fn) |
1394 elif t.p2_info: | 1391 elif t.p2_info: |
1395 madd(fn) | 1392 madd(fn) |
1410 # issue6456: Size returned may be longer due to | 1407 # issue6456: Size returned may be longer due to |
1411 # encryption on EXT-4 fscrypt, undecided. | 1408 # encryption on EXT-4 fscrypt, undecided. |
1412 ladd(fn) | 1409 ladd(fn) |
1413 else: | 1410 else: |
1414 madd(fn) | 1411 madd(fn) |
1415 elif ( | 1412 elif not t.mtime_likely_equal_to(timestamp.mtime_of(st)): |
1416 time != st[stat.ST_MTIME] | |
1417 and time != st[stat.ST_MTIME] & _rangemask | |
1418 ): | |
1419 ladd(fn) | 1413 ladd(fn) |
1420 elif st[stat.ST_MTIME] == lastnormaltime: | 1414 elif timestamp.mtime_of(st) == lastnormaltime: |
1421 # fn may have just been marked as normal and it may have | 1415 # fn may have just been marked as normal and it may have |
1422 # changed in the same second without changing its size. | 1416 # changed in the same second without changing its size. |
1423 # This can happen if we quickly do multiple commits. | 1417 # This can happen if we quickly do multiple commits. |
1424 # Force lookup, so we don't miss such a racy file change. | 1418 # Force lookup, so we don't miss such a racy file change. |
1425 ladd(fn) | 1419 ladd(fn) |