Mercurial > public > mercurial-scm > hg
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 |