Patchwork D6208: [RFC] branchmap: lazily validate nodes from the branchmap

login
register
mail settings
Submitter phabricator
Date April 5, 2019, 1:31 p.m.
Message ID <differential-rev-PHID-DREV-uc5atywxwak7sru4jud6-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/39505/
State Superseded
Headers show

Comments

phabricator - April 5, 2019, 1:31 p.m.
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  On my personal hg-repository with 365 entries in .hg/cache/branch2, following
  are the numbers for perfbranchmapload.
  
  Before this patch:
  
  ! wall 0.000866 comb 0.000000 user 0.000000 sys 0.000000 (best of 2680)
  ! wall 0.001525 comb 0.000000 user 0.000000 sys 0.000000 (max of 2680)
  ! wall 0.001107 comb 0.001097 user 0.001086 sys 0.000011 (avg of 2680)
  ! wall 0.001104 comb 0.000000 user 0.000000 sys 0.000000 (median of 2680)
  
  With this patch:
  
  ! wall 0.000530 comb 0.000000 user 0.000000 sys 0.000000 (best of 4240)
  ! wall 0.001078 comb 0.000000 user 0.000000 sys 0.000000 (max of 4240)
  ! wall 0.000696 comb 0.000693 user 0.000677 sys 0.000017 (avg of 4240)
  ! wall 0.000690 comb 0.000000 user 0.000000 sys 0.000000 (median of 4240)
  
  On our internal repository with ~20k entries in branchcache, I see improvement
  from 0.125 sec to 0.066 sec which is 47% speed up.
  
  The above are the numbers of perfbranchmapload which shows how much time we
  saved by not validating the nodes. But we need to validate some nodes. Following
  are timings of some mercurial operations which have speed up because of this
  lazy validation of nodes:
  
  No-op `hg update` on our internal repository (Avg on 4 runs):
  
  Before: 0.540 secs
  After: 0.430 secs
  
  Setting a branch name which already exists without --force (Avg of 4 runs):
  
  Before: 0.510 secs
  After: 0.250 secs
  
  I ran the ASV performance suite and was unable to see any improvements except
  there was improvement of perfdirstatewrite() on netbeans which I think was not
  related.
  
  I looked into the commit code, the command which I am trying to speedup, it
  looks like it uses revbranchcache to update the branchcache.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6208

AFFECTED FILES
  mercurial/branchmap.py

CHANGE DETAILS




To: pulkit, #hg-reviewers
Cc: mercurial-devel
Yuya Nishihara - April 13, 2019, 1:07 a.m.
The idea sounds good to me. Is this still an RFC (i.e. draft) patch?
phabricator - April 13, 2019, 1:12 a.m.
yuja added a comment.


  The idea sounds good to me. Is this still an RFC (i.e. draft) patch?

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6208

To: pulkit, #hg-reviewers
Cc: yuja, mercurial-devel
phabricator - April 15, 2019, 4:29 p.m.
pulkit added a comment.


  In https://phab.mercurial-scm.org/D6208#90673, @yuja wrote:
  
  > The idea sounds good to me. Is this still an RFC (i.e. draft) patch?
  
  
  It's good to be reviewed.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6208

To: pulkit, #hg-reviewers
Cc: yuja, mercurial-devel
Yuya Nishihara - April 15, 2019, 11:06 p.m.
>      def copy(self):
>          """return an deep copy of the branchcache object"""
> +        self._verifyall()
>          return type(self)(
>              self._entries, self.tipnode, self.tiprev, self.filteredhash,
>              self._closednodes)

Maybe the copy would be marked as not verified?
phabricator - April 15, 2019, 11:16 p.m.
yuja added a comment.


  >   def copy(self):
  >       """return an deep copy of the branchcache object"""
  > 
  > +        self._verifyall()
  > 
  >   return type(self)(
  >       self._entries, self.tipnode, self.tiprev, self.filteredhash,
  >       self._closednodes)
  
  Maybe the copy would be marked as not verified?

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D6208

To: pulkit, #hg-reviewers
Cc: yuja, mercurial-devel

Patch

diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -210,16 +210,20 @@ 
         self._entries[key] = value
 
     def __getitem__(self, key):
+        self._verifybranch(key)
         return self._entries[key]
 
     def __contains__(self, key):
+        self._verifybranch(key)
         return key in self._entries
 
     def iteritems(self):
+        self._verifyall()
         return self._entries.iteritems()
 
     def hasbranch(self, label):
         """ checks whether a branch of this name exists or not """
+        self._verifybranch(label)
         return label in self._entries
 
     @classmethod
@@ -262,7 +266,6 @@ 
     def load(self, repo, lineiter):
         """ fully loads the branchcache by reading from the file using the line
         iterator passed"""
-        cl = repo.changelog
         for line in lineiter:
             line = line.rstrip('\n')
             if not line:
@@ -272,14 +275,9 @@ 
                 raise ValueError(r'invalid branch state')
             label = encoding.tolocal(label.strip())
             node = bin(node)
-            if not cl.hasnode(node):
-                raise ValueError(
-                    r'node %s does not exist' % pycompat.sysstr(hex(node)))
             self._entries.setdefault(label, []).append(node)
-            self._verifiedbranches.add(label)
             if state == 'c':
                 self._closednodes.add(node)
-        self._closedverified = True
 
     @staticmethod
     def _filename(repo):
@@ -306,6 +304,7 @@ 
         otherwise return last closed head and true.'''
         tip = heads[-1]
         closed = True
+        self._verifyclosed()
         for h in reversed(heads):
             if h not in self._closednodes:
                 tip = h
@@ -320,9 +319,11 @@ 
         return self._branchtip(self[branch])[0]
 
     def iteropen(self, nodes):
+        self._verifyclosed()
         return (n for n in nodes if n not in self._closednodes)
 
     def branchheads(self, branch, closed=False):
+        self._verifybranch(branch)
         heads = self._entries[branch]
         if not closed:
             heads = list(self.iteropen(heads))
@@ -334,10 +335,12 @@ 
 
     def iterheads(self):
         """ returns all the heads """
+        self._verifyall()
         return self._entries.itervalues()
 
     def copy(self):
         """return an deep copy of the branchcache object"""
+        self._verifyall()
         return type(self)(
             self._entries, self.tipnode, self.tiprev, self.filteredhash,
             self._closednodes)