Mercurial > public > mercurial-scm > hg
comparison mercurial/utils/storageutil.py @ 40008:842ffcf1d42f
storageutil: extract most of emitrevisions() to standalone function
As part of implementing a storage backend, I found myself copying
most of revlog.emitrevisions(). This code is highly nuanced and it
bothered me greatly to be copying such low-level code.
This commit extracts the bulk of revlog.emitrevisions() into a
new standalone function. In order to make the function generally
usable, all "self" function calls that aren't exposed on the
ifilestorage interface are passed in via callable arguments.
No meaningful behavior should have changed as part of the port.
Upcoming commits will tweak behavior to make the code more
generically usable.
Differential Revision: https://phab.mercurial-scm.org/D4803
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 28 Sep 2018 16:16:22 -0700 |
parents | 1470183068b8 |
children | 631c6f5058b9 |
comparison
equal
deleted
inserted
replaced
40007:1470183068b8 | 40008:842ffcf1d42f |
---|---|
260 heads[p] = plinkrev | 260 heads[p] = plinkrev |
261 if plinkrev >= minlinkrev: | 261 if plinkrev >= minlinkrev: |
262 futurelargelinkrevs.add(plinkrev) | 262 futurelargelinkrevs.add(plinkrev) |
263 | 263 |
264 return strippoint, brokenrevs | 264 return strippoint, brokenrevs |
265 | |
266 def emitrevisions(store, revs, resultcls, deltaparentfn, candeltafn, | |
267 rawsizefn, revdifffn, flagsfn, sendfulltext=False, | |
268 revisiondata=False, assumehaveparentrevisions=False, | |
269 deltaprevious=False): | |
270 """Generic implementation of ifiledata.emitrevisions(). | |
271 | |
272 Emitting revision data is subtly complex. This function attempts to | |
273 encapsulate all the logic for doing so in a backend-agnostic way. | |
274 | |
275 ``store`` | |
276 Object conforming to ``ifilestorage`` interface. | |
277 | |
278 ``revs`` | |
279 List of integer revision numbers whose data to emit. | |
280 | |
281 ``resultcls`` | |
282 A type implementing the ``irevisiondelta`` interface that will be | |
283 constructed and returned. | |
284 | |
285 ``deltaparentfn`` | |
286 Callable receiving a revision number and returning the revision number | |
287 of a revision that the internal delta is stored against. This delta | |
288 will be preferred over computing a new arbitrary delta. | |
289 | |
290 ``candeltafn`` | |
291 Callable receiving a pair of revision numbers that returns a bool | |
292 indicating whether a delta between them can be produced. | |
293 | |
294 ``rawsizefn`` | |
295 Callable receiving a revision number and returning the length of the | |
296 ``store.revision(rev, raw=True)``. | |
297 | |
298 ``revdifffn`` | |
299 Callable receiving a pair of revision numbers that returns a delta | |
300 between them. | |
301 | |
302 ``flagsfn`` | |
303 Callable receiving a revision number and returns the integer flags | |
304 value for it. | |
305 | |
306 ``sendfulltext`` | |
307 Whether to send fulltext revisions instead of deltas, if allowed. | |
308 | |
309 ``revisiondata`` | |
310 ``assumehaveparentrevisions`` | |
311 ``deltaprevious`` | |
312 See ``ifiledata.emitrevisions()`` interface documentation. | |
313 """ | |
314 | |
315 fnode = store.node | |
316 | |
317 prevrev = None | |
318 | |
319 if deltaprevious or assumehaveparentrevisions: | |
320 prevrev = store.parentrevs(revs[0])[0] | |
321 | |
322 # Set of revs available to delta against. | |
323 available = set() | |
324 | |
325 for rev in revs: | |
326 if rev == nullrev: | |
327 continue | |
328 | |
329 node = fnode(rev) | |
330 deltaparentrev = deltaparentfn(rev) | |
331 p1rev, p2rev = store.parentrevs(rev) | |
332 | |
333 # Forced delta against previous mode. | |
334 if deltaprevious: | |
335 baserev = prevrev | |
336 | |
337 # We're instructed to send fulltext. Honor that. | |
338 elif sendfulltext: | |
339 baserev = nullrev | |
340 | |
341 # There is a delta in storage. We try to use that because it | |
342 # amounts to effectively copying data from storage and is | |
343 # therefore the fastest. | |
344 elif deltaparentrev != nullrev: | |
345 # Base revision was already emitted in this group. We can | |
346 # always safely use the delta. | |
347 if deltaparentrev in available: | |
348 baserev = deltaparentrev | |
349 | |
350 # Base revision is a parent that hasn't been emitted already. | |
351 # Use it if we can assume the receiver has the parent revision. | |
352 elif (assumehaveparentrevisions | |
353 and deltaparentrev in (p1rev, p2rev)): | |
354 baserev = deltaparentrev | |
355 | |
356 # No guarantee the receiver has the delta parent. Send delta | |
357 # against last revision (if possible), which in the common case | |
358 # should be similar enough to this revision that the delta is | |
359 # reasonable. | |
360 elif prevrev is not None: | |
361 baserev = prevrev | |
362 else: | |
363 baserev = nullrev | |
364 | |
365 # Storage has a fulltext revision. | |
366 | |
367 # Let's use the previous revision, which is as good a guess as any. | |
368 # There is definitely room to improve this logic. | |
369 elif prevrev is not None: | |
370 baserev = prevrev | |
371 else: | |
372 baserev = nullrev | |
373 | |
374 # But we can't actually use our chosen delta base for whatever | |
375 # reason. Reset to fulltext. | |
376 if baserev != nullrev and not candeltafn(baserev, rev): | |
377 baserev = nullrev | |
378 | |
379 revision = None | |
380 delta = None | |
381 baserevisionsize = None | |
382 | |
383 if revisiondata: | |
384 if store.iscensored(baserev) or store.iscensored(rev): | |
385 try: | |
386 revision = store.revision(node, raw=True) | |
387 except error.CensoredNodeError as e: | |
388 revision = e.tombstone | |
389 | |
390 if baserev != nullrev: | |
391 baserevisionsize = rawsizefn(baserev) | |
392 | |
393 elif baserev == nullrev and not deltaprevious: | |
394 revision = store.revision(node, raw=True) | |
395 available.add(rev) | |
396 else: | |
397 delta = revdifffn(baserev, rev) | |
398 available.add(rev) | |
399 | |
400 yield resultcls( | |
401 node=node, | |
402 p1node=fnode(p1rev), | |
403 p2node=fnode(p2rev), | |
404 basenode=fnode(baserev), | |
405 flags=flagsfn(rev), | |
406 baserevisionsize=baserevisionsize, | |
407 revision=revision, | |
408 delta=delta) | |
409 | |
410 prevrev = rev |