Patchwork D11203: revlog: recommit 49fd21f32695 with a fix for issue6528

login
register
mail settings
Submitter phabricator
Date July 20, 2021, 1:58 p.m.
Message ID <differential-rev-PHID-DREV-exrobmzyv74zej3w7u2j-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49517/
State New
Headers show

Comments

phabricator - July 20, 2021, 1:58 p.m.
joerg.sonnenberger created this revision.
Herald added a reviewer: durin42.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  `filelog.size` currently special cases two forms of metadata encoding:
  
  - copy data via the parent order as flag bit
  - censor data by peaking into the raw delta
  
  All other forms of metadata encoding including the empty metadata block
  are mishandled. In `basefilectx.cmp` the empty metadata block is
  explicitly checked to compensate for this.
  
  Restore 49fd21f32695 <https://phab.mercurial-scm.org/rHG49fd21f32695d885d730b56d91707c9059c6bd54>, but disable it for filelog, so that the original
  flag bit use contines to work. Document all this mess for now in
  preparation of a proper rework.

REPOSITORY
  rHG Mercurial

BRANCH
  stable

REVISION DETAIL
  https://phab.mercurial-scm.org/D11203

AFFECTED FILES
  mercurial/context.py
  mercurial/filelog.py
  mercurial/revlog.py
  tests/test-narrow-shallow-merges.t

CHANGE DETAILS




To: joerg.sonnenberger, durin42, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/tests/test-narrow-shallow-merges.t b/tests/test-narrow-shallow-merges.t
--- a/tests/test-narrow-shallow-merges.t
+++ b/tests/test-narrow-shallow-merges.t
@@ -179,7 +179,7 @@ 
   
 
   $ hg log -T '{if(ellipsis,"...")}{node|short} {p1node|short} {p2node|short} {desc}\n' | sort
-  ...2a20009de83e 000000000000 3ac1f5779de3 outside 10
+  ...2a20009de83e 3ac1f5779de3 000000000000 outside 10
   ...3ac1f5779de3 bb96a08b062a 465567bdfb2d merge a/b/c/d 9
   ...8d874d57adea 7ef88b4dd4fa 000000000000 outside 12
   ...b844052e7b3b 000000000000 000000000000 outside 2c
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -434,6 +434,7 @@ 
         upperboundcomp=None,
         persistentnodemap=False,
         concurrencychecker=None,
+        canonical_parent_order=True,
     ):
         """
         create a revlog object
@@ -491,6 +492,13 @@ 
 
         self._concurrencychecker = concurrencychecker
 
+        # parent order is supposed to be semantically irrelevant, so we
+        # normally resort parents to ensure that the first parent is non-null,
+        # if there is a non-null parent at all.
+        # filelog obuses the parent order as flag to mark some instances of
+        # meta-encoded files, so allow it to disable this behavior.
+        self.canonical_parent_order = canonical_parent_order
+
     def _loadindex(self):
         mmapindexthreshold = None
         opts = self.opener.options
@@ -885,7 +893,10 @@ 
                 raise error.WdirUnsupported
             raise
 
-        return entry[5], entry[6]
+        if self.canonical_parent_order and entry[5] == nullrev:
+            return entry[6], entry[5]
+        else:
+            return entry[5], entry[6]
 
     # fast parentrevs(rev) where rev isn't filtered
     _uncheckedparentrevs = parentrevs
@@ -907,6 +918,11 @@ 
         i = self.index
         d = i[self.rev(node)]
         return i[d[5]][7], i[d[6]][7]  # map revisions to nodes inline
+        # inline node() to avoid function call overhead
+        if self.canonical_parent_order and d[5] == nullid:
+            return i[d[6]][7], i[d[5]][7]
+        else:
+            return i[d[5]][7], i[d[6]][7]
 
     def chainlen(self, rev):
         return self._chaininfo(rev)[0]
diff --git a/mercurial/filelog.py b/mercurial/filelog.py
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -27,7 +27,10 @@ 
 class filelog(object):
     def __init__(self, opener, path):
         self._revlog = revlog.revlog(
-            opener, b'/'.join((b'data', path + b'.i')), censorable=True
+            opener,
+            b'/'.join((b'data', path + b'.i')),
+            censorable=True,
+            canonical_parent_order=False,  # see comment in revlog.py
         )
         # Full name of the user visible file, relative to the repository root.
         # Used by LFS.
@@ -197,6 +200,7 @@ 
             return 0
 
         # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
+        # XXX See also basefilectx.cmp.
         return self._revlog.size(rev)
 
     def cmp(self, node, text):
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -988,6 +988,16 @@ 
             if self._repo._encodefilterpats:
                 # can't rely on size() because wdir content may be decoded
                 return self._filelog.cmp(self._filenode, fctx.data())
+            # filelog.size() has two special cases:
+            # - censored metadata
+            # - copy/rename tracking
+            # The first is detected by peaking into the delta,
+            # the second is detected by abusing parent order
+            # in the revlog index as flag bit. This leaves files using
+            # the dummy encoding and non-standard meta attributes.
+            # The following check is a special case for the empty
+            # metadata block used if the raw file content starts with '\1\n'.
+            # Cases of arbitrary metadata flags are currently mishandled.
             if self.size() - 4 == fctx.size():
                 # size() can match:
                 # if file data starts with '\1\n', empty metadata block is