comparison mercurial/context.py @ 32814:2083d1643d69

workingctx: add a way for extensions to run code at status fixup time Some extensions like fsmonitor need to run code after dirstate.status is called, but while the wlock is held. The extensions could grab the wlock again, but that has its own peculiar race issues. For example, fsmonitor would not like its state to be written out if the dirstate has changed underneath (see issue5581 for what can go wrong in that sort of case). To protect against these sorts of issues, allow extensions to declare that they would like to run some code to run at fixup time. fsmonitor will switch to using this in the next patch in the series.
author Siddharth Agarwal <sid0@fb.com>
date Mon, 12 Jun 2017 13:56:50 -0700
parents 6d73b7ff8f92
children 582080a4a812
comparison
equal deleted inserted replaced
32813:6d73b7ff8f92 32814:2083d1643d69
1740 1740
1741 return modified, deleted, fixup 1741 return modified, deleted, fixup
1742 1742
1743 def _poststatusfixup(self, status, fixup): 1743 def _poststatusfixup(self, status, fixup):
1744 """update dirstate for files that are actually clean""" 1744 """update dirstate for files that are actually clean"""
1745 if fixup: 1745 poststatus = self._repo.postdsstatus()
1746 if fixup or poststatus:
1746 try: 1747 try:
1747 oldid = self._repo.dirstate.identity() 1748 oldid = self._repo.dirstate.identity()
1748 1749
1749 # updating the dirstate is optional 1750 # updating the dirstate is optional
1750 # so we don't wait on the lock 1751 # so we don't wait on the lock
1751 # wlock can invalidate the dirstate, so cache normal _after_ 1752 # wlock can invalidate the dirstate, so cache normal _after_
1752 # taking the lock 1753 # taking the lock
1753 with self._repo.wlock(False): 1754 with self._repo.wlock(False):
1754 if self._repo.dirstate.identity() == oldid: 1755 if self._repo.dirstate.identity() == oldid:
1755 normal = self._repo.dirstate.normal 1756 if fixup:
1756 for f in fixup: 1757 normal = self._repo.dirstate.normal
1757 normal(f) 1758 for f in fixup:
1758 # write changes out explicitly, because nesting 1759 normal(f)
1759 # wlock at runtime may prevent 'wlock.release()' 1760 # write changes out explicitly, because nesting
1760 # after this block from doing so for subsequent 1761 # wlock at runtime may prevent 'wlock.release()'
1761 # changing files 1762 # after this block from doing so for subsequent
1762 tr = self._repo.currenttransaction() 1763 # changing files
1763 self._repo.dirstate.write(tr) 1764 tr = self._repo.currenttransaction()
1765 self._repo.dirstate.write(tr)
1766
1767 if poststatus:
1768 for ps in poststatus:
1769 ps(self, status)
1764 else: 1770 else:
1765 # in this case, writing changes out breaks 1771 # in this case, writing changes out breaks
1766 # consistency, because .hg/dirstate was 1772 # consistency, because .hg/dirstate was
1767 # already changed simultaneously after last 1773 # already changed simultaneously after last
1768 # caching (see also issue5584 for detail) 1774 # caching (see also issue5584 for detail)
1769 self._repo.ui.debug('skip updating dirstate: ' 1775 self._repo.ui.debug('skip updating dirstate: '
1770 'identity mismatch\n') 1776 'identity mismatch\n')
1771 except error.LockError: 1777 except error.LockError:
1772 pass 1778 pass
1779 finally:
1780 # Even if the wlock couldn't be grabbed, clear out the list.
1781 self._repo.clearpostdsstatus()
1773 1782
1774 def _dirstatestatus(self, match=None, ignored=False, clean=False, 1783 def _dirstatestatus(self, match=None, ignored=False, clean=False,
1775 unknown=False): 1784 unknown=False):
1776 '''Gets the status from the dirstate -- internal use only.''' 1785 '''Gets the status from the dirstate -- internal use only.'''
1777 listignored, listclean, listunknown = ignored, clean, unknown 1786 listignored, listclean, listunknown = ignored, clean, unknown