[scm] Cache ResolveCommit call

The cache won't be used if ResolveCommit throws an exception or when
non-sha1 is used.

This optimization saves about 7% of overall gclient sync on
chromium/src.

R=gavinmak@google.com

Change-Id: I9c36d937dc7b8553818888e2e9c4eecd029a978c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5147496
Reviewed-by: Gavin Mak <gavinmak@google.com>
Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>
changes/96/5147496/4
Josip Sokcevic 2 years ago committed by LUCI CQ
parent e010fbf0a5
commit 31a590e0cd

@ -96,6 +96,7 @@ def only_int(val):
class GIT(object): class GIT(object):
current_version = None current_version = None
rev_parse_cache = {}
@staticmethod @staticmethod
def ApplyEnvVars(kwargs): def ApplyEnvVars(kwargs):
@ -461,20 +462,27 @@ class GIT(object):
@staticmethod @staticmethod
def ResolveCommit(cwd, rev): def ResolveCommit(cwd, rev):
cache_key = None
# We do this instead of rev-parse --verify rev^{commit}, since on # We do this instead of rev-parse --verify rev^{commit}, since on
# Windows git can be either an executable or batch script, each of which # Windows git can be either an executable or batch script, each of which
# requires escaping the caret (^) a different way. # requires escaping the caret (^) a different way.
if gclient_utils.IsFullGitSha(rev): if gclient_utils.IsFullGitSha(rev):
# Only cache full SHAs
cache_key = hash(cwd + rev)
if val := GIT.rev_parse_cache.get(cache_key):
return val
# git-rev parse --verify FULL_GIT_SHA always succeeds, even if we # git-rev parse --verify FULL_GIT_SHA always succeeds, even if we
# don't have FULL_GIT_SHA locally. Removing the last character # don't have FULL_GIT_SHA locally. Removing the last character
# forces git to check if FULL_GIT_SHA refers to an object in the # forces git to check if FULL_GIT_SHA refers to an object in the
# local database. # local database.
rev = rev[:-1] rev = rev[:-1]
try: res = GIT.Capture(['rev-parse', '--quiet', '--verify', rev], cwd=cwd)
return GIT.Capture(['rev-parse', '--quiet', '--verify', rev], if cache_key:
cwd=cwd) # We don't expect concurrent execution, so we don't lock anything.
except subprocess2.CalledProcessError: GIT.rev_parse_cache[cache_key] = res
return None
return res
@staticmethod @staticmethod
def IsValidRevision(cwd, rev, sha_only=False): def IsValidRevision(cwd, rev, sha_only=False):
@ -482,9 +490,11 @@ class GIT(object):
sha_only: Fail unless rev is a sha hash. sha_only: Fail unless rev is a sha hash.
""" """
sha = GIT.ResolveCommit(cwd, rev) try:
if sha is None: sha = GIT.ResolveCommit(cwd, rev)
return False except subprocess2.CalledProcessError:
return None
if sha_only: if sha_only:
return sha == rev.lower() return sha == rev.lower()
return True return True

@ -143,8 +143,10 @@ class RealGitTest(fake_repos.FakeReposTestBase):
self.skipTest('git fake repos not available') self.skipTest('git fake repos not available')
def testResolveCommit(self): def testResolveCommit(self):
self.assertIsNone(scm.GIT.ResolveCommit(self.cwd, 'zebra')) with self.assertRaises(Exception):
self.assertIsNone(scm.GIT.ResolveCommit(self.cwd, 'r123456')) scm.GIT.ResolveCommit(self.cwd, 'zebra')
with self.assertRaises(Exception):
scm.GIT.ResolveCommit(self.cwd, 'r123456')
first_rev = self.githash('repo_1', 1) first_rev = self.githash('repo_1', 1)
self.assertEqual(first_rev, scm.GIT.ResolveCommit(self.cwd, first_rev)) self.assertEqual(first_rev, scm.GIT.ResolveCommit(self.cwd, first_rev))
self.assertEqual(self.githash('repo_1', 2), self.assertEqual(self.githash('repo_1', 2),

Loading…
Cancel
Save