Patchwork [05,of,10] changelog: handle writepending in the transaction

login
register
mail settings
Submitter Pierre-Yves David
Date Oct. 28, 2014, 3:41 p.m.
Message ID <8b1027bf74178ac96a8b.1414510879@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/6483/
State Superseded
Commit 3872d563e01a109ed11e0dd2e100e40052a642b3
Headers show

Comments

Pierre-Yves David - Oct. 28, 2014, 3:41 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1413608131 25200
#      Fri Oct 17 21:55:31 2014 -0700
# Branch stable
# Node ID 8b1027bf74178ac96a8ba09a0a68d9a6c9a4f88d
# Parent  7bc27f8375dcb9682a78d2cccf46d7644dcef497
changelog: handle writepending in the transaction

The `delayupdate` method now take a transaction object and register its
`_writepending` method for run in `transaction.writepending()`. The hook can then
use `transaction.writepending()` directly.

At some point this will allow the addition of other file creation during write
pending. But this is outside of stable scope.

Patch

diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -593,23 +593,23 @@  def addchangegroup(repo, source, srctype
         return 0
 
     changesets = files = revisions = 0
     efiles = set()
 
-    # write changelog data to temp files so concurrent readers will not see
-    # inconsistent view
-    cl = repo.changelog
-    cl.delayupdate()
-    oldheads = cl.heads()
-
     tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
     # The transaction could have been created before and already carries source
     # information. In this case we use the top level data. We overwrite the
     # argument because we need to use the top level value (if they exist) in
     # this function.
     srctype = tr.hookargs.setdefault('source', srctype)
     url = tr.hookargs.setdefault('url', url)
+
+    # write changelog data to temp files so concurrent readers will not see
+    # inconsistent view
+    cl = repo.changelog
+    cl.delayupdate(tr)
+    oldheads = cl.heads()
     try:
         repo.hook('prechangegroup', throw=True, **tr.hookargs)
 
         trp = weakref.proxy(tr)
         # pull off the changeset group
@@ -688,11 +688,11 @@  def addchangegroup(repo, source, srctype
                          " with %d changes to %d files%s\n")
                          % (changesets, revisions, files, htext))
         repo.invalidatevolatilesets()
 
         if changesets > 0:
-            p = lambda: cl.writepending() and repo.root or ""
+            p = lambda: tr.writepending() and repo.root or ""
             if 'node' not in tr.hookargs:
                 tr.hookargs['node'] = hex(cl.node(clstart))
                 hookargs = dict(tr.hookargs)
             else:
                 hookargs = dict(tr.hookargs)
diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -222,11 +222,11 @@  class changelog(revlog.revlog):
         """filtered version of revlog.flags"""
         if rev in self.filteredrevs:
             raise error.FilteredIndexError(rev)
         return super(changelog, self).flags(rev)
 
-    def delayupdate(self):
+    def delayupdate(self, tr):
         "delay visibility of index updates to other readers"
 
         if not self._delayed:
             if len(self) == 0:
                 self._divert = True
@@ -236,10 +236,11 @@  class changelog(revlog.revlog):
             else:
                 self._delaybuf = []
                 self.opener = _delayopener(self._realopener, self.indexfile,
                                            self._delaybuf)
         self._delayed = True
+        tr.addpending('cl-%i' % id(self), self._writepending)
 
     def finalize(self, tr):
         "finalize index updates"
         self._delayed = False
         self.opener = self._realopener
@@ -264,11 +265,11 @@  class changelog(revlog.revlog):
         self.index = r.index
         self.nodemap = r.nodemap
         self._nodecache = r._nodecache
         self._chunkcache = r._chunkcache
 
-    def writepending(self):
+    def _writepending(self):
         "create a file containing the unfinalized state for pretxnchangegroup"
         if self._delaybuf:
             # make a temporary copy of the index
             fp1 = self._realopener(self.indexfile)
             fp2 = self._realopener(self.indexfile + ".a", "w")
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -837,13 +837,11 @@  class pulloperation(object):
 
     def closetransaction(self):
         """close transaction if created"""
         if self._tr is not None:
             repo = self.repo
-            cl = repo.unfiltered().changelog
-            p = cl.writepending() and repo.root or ""
-            p = cl.writepending() and repo.root or ""
+            p = lambda: self._tr.writepending() and repo.root or ""
             repo.hook('b2x-pretransactionclose', throw=True, pending=p,
                       **self._tr.hookargs)
             self._tr.close()
             hookargs = dict(self._tr.hookargs)
             def runhooks():
@@ -1247,12 +1245,11 @@  def unbundle(repo, cg, heads, source, ur
                 tr = repo.transaction('unbundle')
                 tr.hookargs['source'] = source
                 tr.hookargs['url'] = url
                 tr.hookargs['bundle2-exp'] = '1'
                 r = bundle2.processbundle(repo, cg, lambda: tr).reply
-                cl = repo.unfiltered().changelog
-                p = cl.writepending() and repo.root or ""
+                p = lambda: tr.writepending() and repo.root or ""
                 repo.hook('b2x-pretransactionclose', throw=True, pending=p,
                           **tr.hookargs)
                 tr.close()
                 hookargs = dict(tr.hookargs)
                 def runhooks():
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1431,15 +1431,15 @@  class localrepository(object):
             else:
                 mn = p1.manifestnode()
                 files = []
 
             # update changelog
-            self.changelog.delayupdate()
+            self.changelog.delayupdate(tr)
             n = self.changelog.add(mn, files, ctx.description(),
                                    trp, p1.node(), p2.node(),
                                    user, ctx.date(), ctx.extra().copy())
-            p = lambda: self.changelog.writepending() and self.root or ""
+            p = lambda: tr.writepending() and self.root or ""
             xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
             self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
                       parent2=xp2, pending=p)
             self.changelog.finalize(trp)
             # set the new commit is proper phase