24 |
24 |
25 class rootcache(filecache): |
25 class rootcache(filecache): |
26 """filecache for files in the repository root""" |
26 """filecache for files in the repository root""" |
27 def join(self, obj, fname): |
27 def join(self, obj, fname): |
28 return obj._join(fname) |
28 return obj._join(fname) |
|
29 |
|
30 def _getfsnow(vfs): |
|
31 '''Get "now" timestamp on filesystem''' |
|
32 tmpfd, tmpname = vfs.mkstemp() |
|
33 try: |
|
34 return util.statmtimesec(os.fstat(tmpfd)) |
|
35 finally: |
|
36 os.close(tmpfd) |
|
37 vfs.unlink(tmpname) |
29 |
38 |
30 class dirstate(object): |
39 class dirstate(object): |
31 |
40 |
32 def __init__(self, opener, ui, root, validate): |
41 def __init__(self, opener, ui, root, validate): |
33 '''Create a new dirstate object. |
42 '''Create a new dirstate object. |
609 else: |
618 else: |
610 self._map[f] = dirstatetuple('n', 0o666, -1, 0) |
619 self._map[f] = dirstatetuple('n', 0o666, -1, 0) |
611 self._pl = (parent, nullid) |
620 self._pl = (parent, nullid) |
612 self._dirty = True |
621 self._dirty = True |
613 |
622 |
614 def write(self): |
623 def write(self, repo=None): |
615 if not self._dirty: |
624 if not self._dirty: |
616 return |
625 return |
617 |
626 |
618 # enough 'delaywrite' prevents 'pack_dirstate' from dropping |
627 # enough 'delaywrite' prevents 'pack_dirstate' from dropping |
619 # timestamp of each entries in dirstate, because of 'now > mtime' |
628 # timestamp of each entries in dirstate, because of 'now > mtime' |
620 delaywrite = self._ui.configint('debug', 'dirstate.delaywrite', 0) |
629 delaywrite = self._ui.configint('debug', 'dirstate.delaywrite', 0) |
621 if delaywrite > 0: |
630 if delaywrite > 0: |
622 import time # to avoid useless import |
631 import time # to avoid useless import |
623 time.sleep(delaywrite) |
632 time.sleep(delaywrite) |
624 |
633 |
625 st = self._opener(self._filename, "w", atomictemp=True) |
634 filename = self._filename |
|
635 if not repo: |
|
636 tr = None |
|
637 if self._opener.lexists(self._pendingfilename): |
|
638 # if pending file already exists, in-memory changes |
|
639 # should be written into it, because it has priority |
|
640 # to '.hg/dirstate' at reading under HG_PENDING mode |
|
641 filename = self._pendingfilename |
|
642 else: |
|
643 tr = repo.currenttransaction() |
|
644 |
|
645 if tr: |
|
646 # 'dirstate.write()' is not only for writing in-memory |
|
647 # changes out, but also for dropping ambiguous timestamp. |
|
648 # delayed writing re-raise "ambiguous timestamp issue". |
|
649 # See also the wiki page below for detail: |
|
650 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan |
|
651 |
|
652 # emulate dropping timestamp in 'parsers.pack_dirstate' |
|
653 now = _getfsnow(repo.vfs) |
|
654 dmap = self._map |
|
655 for f, e in dmap.iteritems(): |
|
656 if e[0] == 'n' and e[3] == now: |
|
657 dmap[f] = dirstatetuple(e[0], e[1], e[2], -1) |
|
658 |
|
659 # emulate that all 'dirstate.normal' results are written out |
|
660 self._lastnormaltime = 0 |
|
661 |
|
662 # delay writing in-memory changes out |
|
663 tr.addfilegenerator('dirstate', (self._filename,), |
|
664 self._writedirstate, location='plain') |
|
665 return |
|
666 |
|
667 st = self._opener(filename, "w", atomictemp=True) |
626 self._writedirstate(st) |
668 self._writedirstate(st) |
627 |
669 |
628 def _writedirstate(self, st): |
670 def _writedirstate(self, st): |
629 # use the modification time of the newly created temporary file as the |
671 # use the modification time of the newly created temporary file as the |
630 # filesystem's notion of 'now' |
672 # filesystem's notion of 'now' |