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)