Mercurial > public > mercurial-scm > evolve
comparison hgext3rd/pullbundle.py @ 4130:a1f6b8211016
pullbundle: add caching logic
We now only generate a bundle once (and store it to disk). If we need it again,
we use it directly from disk.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Sun, 23 Sep 2018 00:08:02 +0200 |
parents | bc4e62a1cb82 |
children | afc933d32085 |
comparison
equal
deleted
inserted
replaced
4129:bc4e62a1cb82 | 4130:a1f6b8211016 |
---|---|
121 skipped = headdepth - nbrevs | 121 skipped = headdepth - nbrevs |
122 rangeid = (headrev, skipped) | 122 rangeid = (headrev, skipped) |
123 | 123 |
124 subranges = canonicalsubranges(repo, stablerange, rangeid) | 124 subranges = canonicalsubranges(repo, stablerange, rangeid) |
125 idx = 0 | 125 idx = 0 |
126 slices =[] | 126 slices = [] |
127 nodes.reverse() | 127 nodes.reverse() |
128 for rangeid in subranges: | 128 for rangeid in subranges: |
129 size = rangelength(rangeid) | 129 size = rangelength(rangeid) |
130 slices.append((rangeid, nodes[idx:idx + size])) | 130 slices.append((rangeid, nodes[idx:idx + size])) |
131 idx += size | 131 idx += size |
156 if cut + cursor < rangedepth: | 156 if cut + cursor < rangedepth: |
157 precut = cut | 157 precut = cut |
158 cut += cursor | 158 cut += cursor |
159 if cursor == 1: | 159 if cursor == 1: |
160 break | 160 break |
161 cursor //=2 | 161 cursor //= 2 |
162 | 162 |
163 # 2. optimise, bottom part | 163 # 2. optimise, bottom part |
164 if skip != cut: | 164 if skip != cut: |
165 tailranges = [] | 165 tailranges = [] |
166 tailsize = cut - skip | 166 tailsize = cut - skip |
214 | 214 |
215 def _changegroupinfo(repo, nodes, source): | 215 def _changegroupinfo(repo, nodes, source): |
216 if repo.ui.verbose or source == 'bundle': | 216 if repo.ui.verbose or source == 'bundle': |
217 repo.ui.status(_("%d changesets found\n") % len(nodes)) | 217 repo.ui.status(_("%d changesets found\n") % len(nodes)) |
218 | 218 |
219 def makeonecgpart(newpart, repo, rangeid, outgoing, version, source, | 219 def _makenewstream(newpart, repo, outgoing, version, source, |
220 bundlecaps, filematcher, cgversions): | 220 bundlecaps, filematcher, cgversions): |
221 # same as upstream code | |
222 | |
223 old = changegroup._changegroupinfo | 221 old = changegroup._changegroupinfo |
224 try: | 222 try: |
225 changegroup._changegroupinfo = _changegroupinfo | 223 changegroup._changegroupinfo = _changegroupinfo |
226 cgstream = changegroup.makestream(repo, outgoing, version, source, | 224 cgstream = changegroup.makestream(repo, outgoing, version, source, |
227 bundlecaps=bundlecaps, | 225 bundlecaps=bundlecaps, |
228 filematcher=filematcher) | 226 filematcher=filematcher) |
229 finally: | 227 finally: |
230 changegroup._changegroupinfo = old | 228 changegroup._changegroupinfo = old |
231 | 229 |
230 nbchanges = len(outgoing.missing) | |
231 pversion = None | |
232 if cgversions: | |
233 pversion = version | |
234 return (cgstream, nbchanges, pversion) | |
235 | |
236 def _makepartfromstream(newpart, repo, cgstream, nbchanges, version): | |
237 # same as upstream code | |
238 | |
232 part = newpart('changegroup', data=cgstream) | 239 part = newpart('changegroup', data=cgstream) |
233 if cgversions: | 240 if version: |
234 part.addparam('version', version) | 241 part.addparam('version', version) |
235 | 242 |
236 part.addparam('nbchanges', '%d' % len(outgoing.missing), | 243 part.addparam('nbchanges', '%d' % nbchanges, |
237 mandatory=False) | 244 mandatory=False) |
238 | 245 |
239 if 'treemanifest' in repo.requirements: | 246 if 'treemanifest' in repo.requirements: |
240 part.addparam('treemanifest', '1') | 247 part.addparam('treemanifest', '1') |
248 | |
249 # cache management | |
250 | |
251 def cachedir(repo): | |
252 return repo.cachevfs.join('pullbundles') | |
253 | |
254 def getcache(repo, bundlename): | |
255 cdir = cachedir(repo) | |
256 bundlepath = os.path.join(cdir, bundlename) | |
257 try: | |
258 fd = open(bundlepath, 'rb') | |
259 return util.filechunkiter(fd) | |
260 except IOError as exc: | |
261 if exc.errno != errno.ENOENT: | |
262 raise | |
263 return None | |
264 | |
265 def cachewriter(repo, bundlename, stream): | |
266 cdir = cachedir(repo) | |
267 bundlepath = os.path.join(cdir, bundlename) | |
268 try: | |
269 os.makedirs(cdir) | |
270 except OSError as exc: | |
271 if exc.errno == errno.EEXIST: | |
272 pass | |
273 with util.atomictempfile(bundlepath) as cachefile: | |
274 for chunk in stream: | |
275 cachefile.write(chunk) | |
276 yield chunk | |
277 | |
278 BUNDLEMASK = "%s-%s-%010iskip-%010isize.hg" | |
279 | |
280 def makeonecgpart(newpart, repo, rangeid, outgoing, version, source, | |
281 bundlecaps, filematcher, cgversions): | |
282 bundlename = cachedata = None | |
283 if rangeid is not None: | |
284 nbchanges = repo.stablerange.rangelength(repo, rangeid) | |
285 headnode = nodemod.hex(repo.changelog.node(rangeid[0])) | |
286 # XXX do we need to use cgversion in there? | |
287 bundlename = BUNDLEMASK % (version, headnode, rangeid[1], nbchanges) | |
288 cachedata = getcache(repo, bundlename) | |
289 if cachedata is None: | |
290 partdata = _makenewstream(newpart, repo, outgoing, version, source, | |
291 bundlecaps, filematcher, cgversions) | |
292 if bundlename is not None: | |
293 cgstream = cachewriter(repo, bundlename, partdata[0]) | |
294 partdata = (cgstream,) + partdata[1:] | |
295 else: | |
296 if repo.ui.verbose or source == 'bundle': | |
297 repo.ui.status(_("%d changesets found in caches\n") % nbchanges) | |
298 pversion = None | |
299 if cgversions: | |
300 pversion = version | |
301 partdata = (cachedata, nbchanges, pversion) | |
302 return _makepartfromstream(newpart, repo, *partdata) |