Просмотр исходного кода

Improve repo sync performance by avoid git forks

By resolving the current HEAD and the manifest revision using pure
Python, we can in the common case of "no changes" avoid a lot of
git operations and directly jump out of the local sync method.

This reduces the no-op `repo sync -l` time for Android's 114 projects
from more than 6s to under 0.8s.

Signed-off-by: Shawn O. Pearce <sop@google.com>
Shawn O. Pearce 17 лет назад
Родитель
Сommit
fbcde472ca
2 измененных файлов с 60 добавлено и 15 удалено
  1. 11 0
      git_refs.py
  2. 49 15
      project.py

+ 11 - 0
git_refs.py

@@ -41,6 +41,17 @@ class GitRefs(object):
     except KeyError:
     except KeyError:
       return ''
       return ''
 
 
+  def deleted(self, name):
+    if self._phyref is not None:
+      if name in self._phyref:
+        del self._phyref[name]
+
+      if name in self._symref:
+        del self._symref[name]
+
+      if name in self._mtime:
+        del self._mtime[name]
+
   def _NeedUpdate(self):
   def _NeedUpdate(self):
     for name, mtime in self._mtime.iteritems():
     for name, mtime in self._mtime.iteritems():
       try:
       try:

+ 49 - 15
project.py

@@ -416,22 +416,31 @@ class Project(object):
 
 
 ## Publish / Upload ##
 ## Publish / Upload ##
 
 
-  def WasPublished(self, branch):
+  def WasPublished(self, branch, all=None):
     """Was the branch published (uploaded) for code review?
     """Was the branch published (uploaded) for code review?
        If so, returns the SHA-1 hash of the last published
        If so, returns the SHA-1 hash of the last published
        state for the branch.
        state for the branch.
     """
     """
-    try:
-      return self.bare_git.rev_parse(R_PUB + branch)
-    except GitError:
-      return None
+    key = R_PUB + branch
+    if all is None:
+      try:
+        return self.bare_git.rev_parse(key)
+      except GitError:
+        return None
+    else:
+      try:
+        return all[key]
+      except KeyError:
+        return None
 
 
-  def CleanPublishedCache(self):
+  def CleanPublishedCache(self, all=None):
     """Prunes any stale published refs.
     """Prunes any stale published refs.
     """
     """
+    if all is None:
+      all = self._allrefs
     heads = set()
     heads = set()
     canrm = {}
     canrm = {}
-    for name, id in self._allrefs.iteritems():
+    for name, id in all.iteritems():
       if name.startswith(R_HEADS):
       if name.startswith(R_HEADS):
         heads.add(name)
         heads.add(name)
       elif name.startswith(R_PUB):
       elif name.startswith(R_PUB):
@@ -567,17 +576,31 @@ class Project(object):
        Network access is not required.
        Network access is not required.
     """
     """
     self._InitWorkTree()
     self._InitWorkTree()
-    self.CleanPublishedCache()
+    all = self.bare_ref.all
+    self.CleanPublishedCache(all)
 
 
     rem = self.GetRemote(self.remote.name)
     rem = self.GetRemote(self.remote.name)
     rev = rem.ToLocal(self.revision)
     rev = rem.ToLocal(self.revision)
-    try:
-      self.bare_git.rev_parse('--verify', '%s^0' % rev)
-    except GitError:
-      raise ManifestInvalidRevisionError(
-        'revision %s in %s not found' % (self.revision, self.name))
+    if rev in all:
+      revid = all[rev]
+    elif IsId(rev):
+      revid = rev
+    else:
+      try:
+        revid = self.bare_git.rev_parse('--verify', '%s^0' % rev)
+      except GitError:
+        raise ManifestInvalidRevisionError(
+          'revision %s in %s not found' % (self.revision, self.name))
 
 
-    branch = self.CurrentBranch
+    head = self.work_git.GetHead()
+    if head.startswith(R_HEADS):
+      branch = head[len(R_HEADS):]
+      try:
+        head = all[head]
+      except KeyError:
+        head = None
+    else:
+      branch = None
 
 
     if branch is None or syncbuf.detach_head:
     if branch is None or syncbuf.detach_head:
       # Currently on a detached HEAD.  The user is assumed to
       # Currently on a detached HEAD.  The user is assumed to
@@ -588,6 +611,11 @@ class Project(object):
         syncbuf.fail(self, _PriorSyncFailedError())
         syncbuf.fail(self, _PriorSyncFailedError())
         return
         return
 
 
+      if head == revid:
+        # No changes; don't do anything further.
+        #
+        return
+
       lost = self._revlist(not_rev(rev), HEAD)
       lost = self._revlist(not_rev(rev), HEAD)
       if lost:
       if lost:
         syncbuf.info(self, "discarding %d commits", len(lost))
         syncbuf.info(self, "discarding %d commits", len(lost))
@@ -599,6 +627,11 @@ class Project(object):
       self._CopyFiles()
       self._CopyFiles()
       return
       return
 
 
+    if head == revid:
+      # No changes; don't do anything further.
+      #
+      return
+
     branch = self.GetBranch(branch)
     branch = self.GetBranch(branch)
     merge = branch.LocalMerge
     merge = branch.LocalMerge
 
 
@@ -618,7 +651,7 @@ class Project(object):
       return
       return
 
 
     upstream_gain = self._revlist(not_rev(HEAD), rev)
     upstream_gain = self._revlist(not_rev(HEAD), rev)
-    pub = self.WasPublished(branch.name)
+    pub = self.WasPublished(branch.name, all)
     if pub:
     if pub:
       not_merged = self._revlist(not_rev(rev), pub)
       not_merged = self._revlist(not_rev(rev), pub)
       if not_merged:
       if not_merged:
@@ -1142,6 +1175,7 @@ class Project(object):
       if not old:
       if not old:
         old = self.rev_parse(name)
         old = self.rev_parse(name)
       self.update_ref('-d', name, old)
       self.update_ref('-d', name, old)
+      self._project.bare_ref.deleted(name)
 
 
     def rev_list(self, *args):
     def rev_list(self, *args):
       cmdv = ['rev-list']
       cmdv = ['rev-list']