Forgot the commit message in this one, is there a way I can update this single patch with the commit message?
Commit message: revlog: processflags() Add the ability for revlog objects to process revision flags and apply registered transforms on read/write operations. This patch introduces the 'revlog.processflags()' method that looks at revision flags and applies transforms registered on them. Due to the need to handle non-commutative operations, flag transforms are applied in stable order but the order in which the transforms are applied is reversed between read and write operations. The 'flagtransform' namedtuple is also introduced, and is to be used by extensions to define the behavior of transforms via its 'apply' and 'applyraw' fields. The 'processflags()' method uses the 'raw' argument of 'revision()' and '_addrevision()' to determine which field to use when applying transforms. The 'raw' argument usually indicates that the contents are not to be modified by the transform, and might not be validable for hash integrity. This is expected for specific workflows such as changegroup generation and debug commands that are interested in the actual contents of revlogs rather than the transformed contnts after application of a transform. On Sat, 24 Dec 2016 at 11:36 Remi Chaintron <r...@fb.com> wrote: > # HG changeset patch > # User Remi Chaintron <r...@fb.com> > # Date 1482596881 18000 > # Sat Dec 24 11:28:01 2016 -0500 > # Node ID c94d2907a470ca03b4a4a8da514b66d2f8952bce > # Parent b1d220e584e6fc861a40a5aeefa0c3b19ae09126 > revlog: processflags() > > diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py > --- a/mercurial/bundlerepo.py > +++ b/mercurial/bundlerepo.py > @@ -148,7 +148,9 @@ > delta = self._chunk(chain.pop()) > text = mdiff.patches(text, [delta]) > > - self.checkhash(text, node, rev=rev) > + text, validatehash = self.processflags(text, self.flags(rev), > raw=raw) > + if validatehash is True: > + self.checkhash(text, node, rev=rev) > self._cache = (node, rev, text) > return text > > diff --git a/mercurial/revlog.py b/mercurial/revlog.py > --- a/mercurial/revlog.py > +++ b/mercurial/revlog.py > @@ -56,6 +56,10 @@ > REVIDX_ISCENSORED = (1 << 15) # revision has censor metadata, must be > verified > REVIDX_DEFAULT_FLAGS = 0 > REVIDX_KNOWN_FLAGS = REVIDX_ISCENSORED > +# stable order in which flags need to be processed and their transforms > applied > +REVIDX_FLAGS_ORDER = [ > + REVIDX_ISCENSORED, > +] > > # max size of revlog with inline data > _maxinline = 131072 > @@ -65,6 +69,33 @@ > LookupError = error.LookupError > CensoredNodeError = error.CensoredNodeError > > +# 'flagtransform' namedtuple type for extensions to use to register > transforms > +# on revlog flags. > +# - The apply transform will be used as a default behavior. > +# - The applyraw transform will be used for changegroup generation and > debug > +# methods. > +flagtransform = collections.namedtuple('flagtransform', ['apply', > 'applyraw']) > +# Store flag transforms (cf. 'addflagtransform()' to register) > +_flagtransforms = { } > + > +def addflagtransform(flag, transform): > + """Register transforms on revision data flags. > + > + Invariant: > + - Flags need to be defined in REVIDX_KNOWN_FLAGS and > REVIDX_FLAGS_ORDER. > + - Only one transform can be registered on a specific flag. > + - the transform must be of type 'flagtransform' > + """ > + if not flag & REVIDX_KNOWN_FLAGS: > + raise error.Abort(_("cannot register transform on unknown flag.")) > + if not flag in REVIDX_FLAGS_ORDER: > + raise error.Abort(_("flag need to be defined in > REVIDX_FLAGS_ORDER.")) > + if _flagtransforms.get(flag, None) is not None: > + raise error.Abort(_("cannot register multiple transforms on > flag.")) > + if not isinstance(transform, flagtransform): > + raise error.Abort(_("invalid transform type.")) > + _flagtransforms[flag] = transform > + > def getoffset(q): > return int(q >> 16) > > @@ -1248,7 +1279,11 @@ > bins = bins[1:] > > text = mdiff.patches(text, bins) > - self.checkhash(text, node, rev=rev) > + > + text, validatehash = self.processflags(text, self.flags(rev), > raw=raw) > + if validatehash: > + self.checkhash(text, node, rev=rev) > + > self._cache = (node, rev, text) > return text > > @@ -1260,6 +1295,56 @@ > """ > return hash(text, p1, p2) > > + def processflags(self, text, flags, raw=False, reverse=False): > + """Process revision flags and apply registered transforms. > + > + ``text`` - the revision data to process > + ``flags`` - the revision flags > + ``raw`` - an optional argument describing if the raw transform > should be > + applied. > + ``reverse`` - an optional argument describing whether the flags > should > + be processed in order or reverse order. > + > + This method processes the flags in the order (or reverse order if > + ``reverse`` is False) defined by REVIDX_FLAGS_ORDER, applying the > + transforms registered for present flags. The order of flags > defined in > + REVIDX_FLAGS_ORDER needs to be stable for non-commutative > + operations. > + > + If a ``flagtransform`` namedtuple has been registered on a flag, > the > + ``raw`` argument is used to determine which transform apply. If > ``raw`` > + is True, the ``applyraw`` field is used, ``apply`` if not > (default). > + If the ``raw`` argument is set, it indicates we are currently > processing > + flags in the context of changegroup generation or debug commands. > + > + Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is > the > + processed text and ``validatehash`` is a bool indicating whether > the > + returned text should be checked for hash integrity. > + """ > + # Check all flags are known. > + if flags & ~REVIDX_KNOWN_FLAGS: > + raise RevlogError(_('incompatible revision flag %x') % > + (flags & ~REVIDX_KNOWN_FLAGS)) > + validatehash = True > + # Depending on the operation (read or write), the order might be > + # reversed due to non-commutative transforms. > + orderedflags = REVIDX_FLAGS_ORDER > + if reverse: > + orderedflags = reversed(orderedflags) > + > + for flag in orderedflags: > + # If a transform has been registered for a known flag, apply > and > + # update result tuple. > + if flag & flags: > + transform = _flagtransforms.get(flag, None) > + if transform is not None: > + apply, applyraw = transform > + f = apply > + if raw: > + f = applyraw > + text, validatehash = f(self, text) > + return text, validatehash > + > def checkhash(self, text, node, p1=None, p2=None, rev=None): > """Check node hash integrity. > > @@ -1447,7 +1532,11 @@ > btext[0] = mdiff.patch(basetext, delta) > > try: > - self.checkhash(btext[0], node, p1=p1, p2=p2) > + btext[0], validatehash = self.processflags(btext[0], > flags, > + raw=raw, > + reverse=True) > + if validatehash is True: > + self.checkhash(btext[0], node, p1=p1, p2=p2) > if flags & REVIDX_ISCENSORED: > raise RevlogError(_('node %s is not censored') % node) > except CensoredNodeError: > _______________________________________________ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel > -- Rémi
_______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel