Mercurial > hg-stable
comparison mercurial/repoview.py @ 22150:45b5cd948a4d
repoview: add caching bits
Add a caching infrastructure to cache hidden changesets. The cache tries to read
the cache lazily and falls back to recomputing if no wlock can be obtain.
To validate the cache we store a sha of the obstore content and repo heads in
the beginning of the cache which we check every request.
author | David Soria Parra <davidsp@fb.com> |
---|---|
date | Tue, 12 Aug 2014 16:48:54 -0700 |
parents | 16ef2c485f03 |
children | c0c369aec643 |
comparison
equal
deleted
inserted
replaced
22149:16ef2c485f03 | 22150:45b5cd948a4d |
---|---|
5 # | 5 # |
6 # This software may be used and distributed according to the terms of the | 6 # This software may be used and distributed according to the terms of the |
7 # GNU General Public License version 2 or any later version. | 7 # GNU General Public License version 2 or any later version. |
8 | 8 |
9 import copy | 9 import copy |
10 import error | |
11 import hashlib | |
10 import phases | 12 import phases |
11 import util | 13 import util |
12 import obsolete | 14 import obsolete |
15 import struct | |
13 import tags as tagsmod | 16 import tags as tagsmod |
14 | 17 from mercurial.i18n import _ |
15 | 18 |
16 def hideablerevs(repo): | 19 def hideablerevs(repo): |
17 """Revisions candidates to be hidden | 20 """Revisions candidates to be hidden |
18 | 21 |
19 This is a standalone function to help extensions to wrap it.""" | 22 This is a standalone function to help extensions to wrap it.""" |
53 tagsmod.readlocaltags(repo.ui, repo, tags, {}) | 56 tagsmod.readlocaltags(repo.ui, repo, tags, {}) |
54 if tags: | 57 if tags: |
55 rev, nodemap = cl.rev, cl.nodemap | 58 rev, nodemap = cl.rev, cl.nodemap |
56 blockers.update(rev(t[0]) for t in tags.values() if t[0] in nodemap) | 59 blockers.update(rev(t[0]) for t in tags.values() if t[0] in nodemap) |
57 return blockers | 60 return blockers |
61 | |
62 cacheversion = 1 | |
63 cachefile = 'cache/hidden' | |
64 | |
65 def cachehash(repo, hideable): | |
66 """return sha1 hash of repository data to identify a valid cache. | |
67 | |
68 We calculate a sha1 of repo heads and the content of the obsstore and write | |
69 it to the cache. Upon reading we can easily validate by checking the hash | |
70 against the stored one and discard the cache in case the hashes don't match. | |
71 """ | |
72 h = hashlib.sha1() | |
73 h.update(''.join(repo.heads())) | |
74 h.update(str(hash(frozenset(hideable)))) | |
75 return h.digest() | |
76 | |
77 def trywritehiddencache(repo, hideable, hidden): | |
78 """write cache of hidden changesets to disk | |
79 | |
80 Will not write the cache if a wlock cannot be obtained lazily. | |
81 The cache consists of a head of 22byte: | |
82 2 byte version number of the cache | |
83 20 byte sha1 to validate the cache | |
84 n*4 byte hidden revs | |
85 """ | |
86 wlock = fh = None | |
87 try: | |
88 wlock = repo.wlock(wait=False) | |
89 # write cache to file | |
90 newhash = cachehash(repo, hideable) | |
91 sortedset = sorted(hidden) | |
92 data = struct.pack('>%iI' % len(sortedset), *sortedset) | |
93 fh = repo.vfs.open(cachefile, 'w+b', atomictemp=True) | |
94 fh.write(struct.pack(">H", cacheversion)) | |
95 fh.write(newhash) | |
96 fh.write(data) | |
97 except (IOError, OSError): | |
98 ui.debug('error writing hidden changesets cache') | |
99 except error.LockHeld: | |
100 ui.debug('cannot obtain lock to write hidden changesets cache') | |
101 finally: | |
102 if fh: | |
103 fh.close() | |
104 if wlock: | |
105 wlock.release() | |
106 | |
107 def tryreadcache(repo, hideable): | |
108 """read a cache if the cache exists and is valid, otherwise returns None.""" | |
109 hidden = fh = None | |
110 try: | |
111 if repo.vfs.exists(cachefile): | |
112 fh = repo.vfs.open(cachefile, 'rb') | |
113 version, = struct.unpack(">H", fh.read(2)) | |
114 oldhash = fh.read(20) | |
115 newhash = cachehash(repo, hideable) | |
116 if (cacheversion, oldhash) == (version, newhash): | |
117 # cache is valid, so we can start reading the hidden revs | |
118 data = fh.read() | |
119 count = len(data) / 4 | |
120 hidden = frozenset(struct.unpack('>%iI' % count, data)) | |
121 return hidden | |
122 finally: | |
123 if fh: | |
124 fh.close() | |
58 | 125 |
59 def computehidden(repo): | 126 def computehidden(repo): |
60 """compute the set of hidden revision to filter | 127 """compute the set of hidden revision to filter |
61 | 128 |
62 During most operation hidden should be filtered.""" | 129 During most operation hidden should be filtered.""" |