hghooks: short circuit subrepos check if files missing (bug 1457342) r=glob
authorGregory Szorc <gps@mozilla.com>
Thu, 03 May 2018 04:48:52 +0000
changeset 5909 07f46c8333df
parent 5908 68dbb2ce4078
child 5910 8b6cdc921c54
push id2765
push usergszorc@mozilla.com
push dateFri, 04 May 2018 00:12:05 +0000
treeherderversion-control-tools@07f46c8333df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
hghooks: short circuit subrepos check if files missing (bug 1457342) r=glob Previously, we would read the manifest for each context and look for the presence of an .hgsub or .hgsubstate file. Reading manifests can be expensive for large manifests (such as those found in Firefox repos). I suspect that reading manifests is making large pushes to Firefox repos slower than they could be. This commit implements an optimization to make subrepo checking faster. Essentially, when the hook starts, it looks to see if there are *any* revisions for a .hgsub or .hgsubstate file. If not, then no revision contains this file and we can avoid a potentially expensive manifest resolve and lookup. Differential Revision: https://phabricator.services.mozilla.com/D1073
--- a/hghooks/mozhghooks/check/prevent_subrepos.py
+++ b/hghooks/mozhghooks/check/prevent_subrepos.py
@@ -36,16 +36,31 @@ class PreventSubReposCheck(PreTxnChangeg
         return 'prevent_subrepos'
     def relevant(self):
         return True
     def pre(self, node):
         self.done = False
+        # Subrepos are defined by .hgsub and .hgsubstate files under version
+        # control. Since resolving a manifest can be expensive and since
+        # Mercurial indexes tracked paths, we can avoid a bit of work by testing
+        # whether there is *any* versioned data for these tracked files. If not,
+        # we can short circuit the check and avoid manifest lookups.
+        seen = False
+        for p in ('.hgsub', '.hgsubstate'):
+            fl = self.repo.file(p)
+            if len(fl):
+                seen = True
+                break
+        if not seen:
+            self.done = True
     def check(self, ctx):
         # Since the check can be non-fatal and since it requires a manifest
         # (which can be expensive to obtain), no-op if there is no work to do.
         if self.done:
             return True
         if '.hgsub' not in ctx and '.hgsubstate' not in ctx:
             return True