debugdeltachain: detect a special case where parents are "skipped"
See inline comment for details, this is a case where the delta is neither
against p1 or p2, Yet it is still a simple delta part of a simple chain.
We now display them as `skip1/skip2` instead of `other`.
--- a/mercurial/debugcommands.py Wed May 18 17:29:03 2022 +0100
+++ b/mercurial/debugcommands.py Thu May 19 00:51:36 2022 +0100
@@ -768,6 +768,10 @@
- snap: an intermediate snapshot
- p1: a delta against the first parent
- p2: a delta against the second parent
+ - skip1: a delta against the same base as p1
+ (when p1 has empty delta
+ - skip2: a delta against the same base as p2
+ (when p2 has empty delta
- prev: a delta against the previous revision
- other: a delta against an arbitrary revision
:``compsize``: compressed size of revision
@@ -803,6 +807,9 @@
generaldelta = r._generaldelta
withsparseread = getattr(r, '_withsparseread', False)
+ # security to avoid crash on corrupted revlogs
+ total_revs = len(index)
+
def revinfo(rev):
e = index[rev]
compsize = e[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH]
@@ -813,6 +820,39 @@
p1 = e[revlog_constants.ENTRY_PARENT_1]
p2 = e[revlog_constants.ENTRY_PARENT_2]
+ # If the parents of a revision has an empty delta, we never try to delta
+ # against that parent, but directly against the delta base of that
+ # parent (recursively). It avoids adding a useless entry in the chain.
+ #
+ # However we need to detect that as a special case for delta-type, that
+ # is not simply "other".
+ p1_base = p1
+ if p1 != nullrev and p1 < total_revs:
+ e1 = index[p1]
+ while e1[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH] == 0:
+ new_base = e1[revlog_constants.ENTRY_DELTA_BASE]
+ if (
+ new_base == p1_base
+ or new_base == nullrev
+ or new_base >= total_revs
+ ):
+ break
+ p1_base = new_base
+ e1 = index[p1_base]
+ p2_base = p2
+ if p2 != nullrev and p2 < total_revs:
+ e2 = index[p2]
+ while e2[revlog_constants.ENTRY_DATA_COMPRESSED_LENGTH] == 0:
+ new_base = e2[revlog_constants.ENTRY_DELTA_BASE]
+ if (
+ new_base == p2_base
+ or new_base == nullrev
+ or new_base >= total_revs
+ ):
+ break
+ p2_base = new_base
+ e2 = index[p2_base]
+
if generaldelta:
if base == p1:
deltatype = b'p1'
@@ -820,6 +860,10 @@
deltatype = b'p2'
elif base == rev:
deltatype = b'base'
+ elif base == p1_base:
+ deltatype = b'skip1'
+ elif base == p2_base:
+ deltatype = b'skip2'
elif r.issnapshot(rev):
deltatype = b'snap'
elif base == rev - 1: