# HG changeset patch # User Joerg Sonnenberger # Date 2021-07-20 13:07:10 # Node ID 5b65721a75ebdf796002673b7adb2c6e2ef7ee6f # Parent b999edb15f8c3c481da2e57999f8f53b90995f4f revlog: recommit 49fd21f32695 with a fix for issue6528 `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, 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. Differential Revision: https://phab.mercurial-scm.org/D11203 diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -992,6 +992,16 @@ class basefilectx: 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 diff --git a/mercurial/filelog.py b/mercurial/filelog.py --- a/mercurial/filelog.py +++ b/mercurial/filelog.py @@ -32,6 +32,7 @@ class filelog: target=(revlog_constants.KIND_FILELOG, path), radix=b'/'.join((b'data', path)), 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. @@ -207,6 +208,7 @@ class filelog: 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/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -298,6 +298,7 @@ class revlog: persistentnodemap=False, concurrencychecker=None, trypending=False, + canonical_parent_order=True, ): """ create a revlog object @@ -373,6 +374,13 @@ class revlog: 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 abuses 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 _init_opts(self): """process options (from above/config) to setup associated default revlog mode @@ -898,7 +906,10 @@ class revlog: 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 @@ -919,7 +930,11 @@ class revlog: def parents(self, node): 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] == self.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/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 @@ has been emitted, just in a different or $ 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