Show More
@@ -27,6 +27,15 b' class rootcache(filecache):' | |||||
27 | def join(self, obj, fname): |
|
27 | def join(self, obj, fname): | |
28 | return obj._join(fname) |
|
28 | return obj._join(fname) | |
29 |
|
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) | |||
|
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): | |
@@ -611,7 +620,7 b' class dirstate(object):' | |||||
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 | |||
@@ -622,7 +631,40 b' class dirstate(object):' | |||||
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): |
@@ -1000,6 +1000,11 b' class localrepository(object):' | |||||
1000 | def releasefn(tr, success): |
|
1000 | def releasefn(tr, success): | |
1001 | repo = reporef() |
|
1001 | repo = reporef() | |
1002 | if success: |
|
1002 | if success: | |
|
1003 | # this should be explicitly invoked here, because | |||
|
1004 | # in-memory changes aren't written out at closing | |||
|
1005 | # transaction, if tr.addfilegenerator (via | |||
|
1006 | # dirstate.write or so) isn't invoked while | |||
|
1007 | # transaction running | |||
1003 | repo.dirstate.write() |
|
1008 | repo.dirstate.write() | |
1004 | else: |
|
1009 | else: | |
1005 | # prevent in-memory changes from being written out at |
|
1010 | # prevent in-memory changes from being written out at |
@@ -5,7 +5,7 b'' | |||||
5 | # - 'workingctx._checklookup()' (= 'repo.status()') |
|
5 | # - 'workingctx._checklookup()' (= 'repo.status()') | |
6 | # - 'committablectx.markcommitted()' |
|
6 | # - 'committablectx.markcommitted()' | |
7 |
|
7 | |||
8 | from mercurial import context, extensions, parsers, util |
|
8 | from mercurial import context, dirstate, extensions, parsers, util | |
9 |
|
9 | |||
10 | def pack_dirstate(fakenow, orig, dmap, copymap, pl, now): |
|
10 | def pack_dirstate(fakenow, orig, dmap, copymap, pl, now): | |
11 | # execute what original parsers.pack_dirstate should do actually |
|
11 | # execute what original parsers.pack_dirstate should do actually | |
@@ -34,13 +34,16 b' def fakewrite(ui, func):' | |||||
34 | fakenow = util.parsedate(fakenow, ['%Y%m%d%H%M'])[0] |
|
34 | fakenow = util.parsedate(fakenow, ['%Y%m%d%H%M'])[0] | |
35 |
|
35 | |||
36 | orig_pack_dirstate = parsers.pack_dirstate |
|
36 | orig_pack_dirstate = parsers.pack_dirstate | |
|
37 | orig_dirstate_getfsnow = dirstate._getfsnow | |||
37 | wrapper = lambda *args: pack_dirstate(fakenow, orig_pack_dirstate, *args) |
|
38 | wrapper = lambda *args: pack_dirstate(fakenow, orig_pack_dirstate, *args) | |
38 |
|
39 | |||
39 | parsers.pack_dirstate = wrapper |
|
40 | parsers.pack_dirstate = wrapper | |
|
41 | dirstate._getfsnow = lambda *args: fakenow | |||
40 | try: |
|
42 | try: | |
41 | return func() |
|
43 | return func() | |
42 | finally: |
|
44 | finally: | |
43 | parsers.pack_dirstate = orig_pack_dirstate |
|
45 | parsers.pack_dirstate = orig_pack_dirstate | |
|
46 | dirstate._getfsnow = orig_dirstate_getfsnow | |||
44 |
|
47 | |||
45 | def _checklookup(orig, workingctx, files): |
|
48 | def _checklookup(orig, workingctx, files): | |
46 | ui = workingctx.repo().ui |
|
49 | ui = workingctx.repo().ui |
General Comments 0
You need to be logged in to leave comments.
Login now