comparison mercurial/hg.py @ 26219:ae33fff17c1e

hg: establish a cache for localrepository instances hgweb contained code for determining whether a cached localrepository instance was up to date. This code was way too low-level to be in hgweb. This functionality has been moved to a new "cachedlocalrepo" class in hg.py. The code has been changed slightly to facilitate use inside a class. hgweb has been refactored to use the new API. As part of this refactor, hgweb.repo no longer exists! We're very close to using a distinct repo instance per thread. The new cache records state when it is created. This intelligence prevents an extra localrepository from being created on the first hgweb request. This is why some redundant output from test-extension.t has gone away.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 22 Aug 2015 18:54:34 -0700
parents 30be3aeb5344
children 2b1434e5eaa0
comparison
equal deleted inserted replaced
26218:7d45ec47c0af 26219:ae33fff17c1e
821 dst.setconfig('web', 'cacerts', v, 'copied') 821 dst.setconfig('web', 'cacerts', v, 'copied')
822 elif v: 822 elif v:
823 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied') 823 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
824 824
825 return dst 825 return dst
826
827 # Files of interest
828 # Used to check if the repository has changed looking at mtime and size of
829 # theses files.
830 foi = [('spath', '00changelog.i'),
831 ('spath', 'phaseroots'), # ! phase can change content at the same size
832 ('spath', 'obsstore'),
833 ('path', 'bookmarks'), # ! bookmark can change content at the same size
834 ]
835
836 class cachedlocalrepo(object):
837 """Holds a localrepository that can be cached and reused."""
838
839 def __init__(self, repo):
840 """Create a new cached repo from an existing repo.
841
842 We assume the passed in repo was recently created. If the
843 repo has changed between when it was created and when it was
844 turned into a cache, it may not refresh properly.
845 """
846 assert isinstance(repo, localrepo.localrepository)
847 self._repo = repo
848 self._state, self.mtime = self._repostate()
849
850 def fetch(self):
851 """Refresh (if necessary) and return a repository.
852
853 If the cached instance is out of date, it will be recreated
854 automatically and returned.
855
856 Returns a tuple of the repo and a boolean indicating whether a new
857 repo instance was created.
858 """
859 # We compare the mtimes and sizes of some well-known files to
860 # determine if the repo changed. This is not precise, as mtimes
861 # are susceptible to clock skew and imprecise filesystems and
862 # file content can change while maintaining the same size.
863
864 state, mtime = self._repostate()
865 if state == self._state:
866 return self._repo, False
867
868 self._repo = repository(self._repo.baseui, self._repo.url())
869 self._state = state
870 self.mtime = mtime
871
872 return self._repo, True
873
874 def _repostate(self):
875 state = []
876 maxmtime = -1
877 for attr, fname in foi:
878 prefix = getattr(self._repo, attr)
879 p = os.path.join(prefix, fname)
880 try:
881 st = os.stat(p)
882 except OSError:
883 st = os.stat(prefix)
884 state.append((st.st_mtime, st.st_size))
885 maxmtime = max(maxmtime, st.st_mtime)
886
887 return tuple(state), maxmtime
888
889 def copy(self):
890 """Obtain a copy of this class instance."""
891 c = cachedlocalrepo(self._repo)
892 c._state = self._state
893 c.mtime = self.mtime
894 return c