[PATCH] repoview: introduce a `experimental.extra-filter-revs` config

Gregory Szorc gregory.szorc at gmail.com
Wed Apr 17 08:08:26 EDT 2019



> On Apr 17, 2019, at 13:34, Pierre-Yves David <pierre-yves.david at ens-lyon.org> wrote:
> 
> 
> 
>> On 4/17/19 1:22 PM, Gregory Szorc wrote:
>> On Tue, Apr 16, 2019 at 4:54 PM Pierre-Yves David <pierre-yves.david at ens-lyon.org <mailto:pierre-yves.david at ens-lyon.org>> wrote:
>>    # HG changeset patch
>>    # User Pierre-Yves David <pierre-yves.david at octobus.net
>>    <mailto:pierre-yves.david at octobus.net>>
>>    # Date 1554565579 -7200
>>    #      Sat Apr 06 17:46:19 2019 +0200
>>    # Node ID 86eac5d2d7a1386dca5970126506d07201058200
>>    # Parent  eebf78724d94649de84f921ff5bd39cbc0f48cb6
>>    # EXP-Topic repoview
>>    # Available At https://bitbucket.org/octobus/mercurial-devel/
>>    #              hg pull
>>    https://bitbucket.org/octobus/mercurial-devel/ -r 86eac5d2d7a1
>>    repoview: introduce a `experimental.extra-filter-revs` config
>>    The option define revisions to additionally filter out of all
>>    repository "view".
>>    The end goal is to provide and easy to way to serve multiple subset
>>    of the same
>>    repository using multiple "shares".
>>    The simplest use case of this feature is to have one view serving
>>    the public
>>    changesets and one view also serving the draft. This is currently
>>    achievable
>>    using the new `server.view` option introduced recently by Joerg
>>    Sonnenberger.
>>    However, more advanced use cases need more advanced definitions. For
>>    example
>>    some needs a view dedicated to some release branches, or view that hides
>>    security fixes to be released. Joerg Sonnenberger and I discussed
>>    this topic at
>>    the recent mini-sprint and the both of us have seen real life use
>>    cases for
>>    this. (This series got written during the same mini-sprint).
>>    The feature is fully functional, and use similar cache-fallback
>>    mechanism to
>>    ensure decent performance. However,there remaining room to ensure
>>    each share
>>    caches and hooks collaborate with each others. This will come at a
>>    later time
>>    once users start to actually test this feature on real usecase.
>>    diff --git a/mercurial/configitems.py b/mercurial/configitems.py
>>    --- a/mercurial/configitems.py
>>    +++ b/mercurial/configitems.py
>>    @@ -529,6 +529,13 @@ coreconfigitem('experimental', 'evolutio
>>      coreconfigitem('experimental', 'evolution.track-operation',
>>          default=True,
>>      )
>>    +# repo-level config to exclude a revset visibility
>>    +#
>>    +# The target use case is to use `share` to expose different subset
>>    of the same
>>    +# repository, especially server side. See also `server.view`.
>>    +coreconfigitem('experimental', 'extra-filter-revs',
>>    +    default=None,
>>    +)
>>      coreconfigitem('experimental', 'maxdeltachainspan',
>>          default=-1,
>>      )
>>    diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
>>    --- a/mercurial/localrepo.py
>>    +++ b/mercurial/localrepo.py
>>    @@ -1050,6 +1050,8 @@ class localrepository(object):
>>              # Signature to cached matcher instance.
>>              self._sparsematchercache = {}
>>    +        self._extrafilterid = repoview.extrafilter(ui)
>>    +
>>          def _getvfsward(self, origfunc):
>>              """build a ward for self.vfs"""
>>              rref = weakref.ref(self)
>>    @@ -1197,6 +1199,9 @@ class localrepository(object):
>>              In other word, there is always only one level of
>>    `repoview` "filtering".
>>              """
>>    +        if self._extrafilterid is not None:
>>    +            name = name + '%'  + self._extrafilterid
>>    +
>>              cls = repoview.newtype(self.unfiltered().__class__)
>>              return cls(self, name, visibilityexceptions)
>>    diff --git a/mercurial/repoview.py b/mercurial/repoview.py
>>    --- a/mercurial/repoview.py
>>    +++ b/mercurial/repoview.py
>>    @@ -17,6 +17,10 @@ from . import (
>>          phases,
>>          pycompat,
>>          tags as tagsmod,
>>    +    util,
>>    +)
>>    +from .utils import (
>>    +    repoviewutil,
>>      )
>>      def hideablerevs(repo):
>>    @@ -154,6 +158,35 @@ filtertable = {'visible': computehidden,
>>                     'immutable':  computemutable,
>>                     'base':  computeimpactable}
>>    +_basefiltername = list(filtertable)
>>    +
>>    +def extrafilter(ui):
>>    +    """initialize extra filter and return its id
>>    +
>>    +    If extra filtering is configured, we make sure the associated
>>    filtered view
>>    +    are declared and return the associated id.
>>    +    """
>>    +    frevs = ui.config('experimental', 'extra-filter-revs')
>>    +    if frevs is None:
>>    +        return None
>>    +
>>    +    fid = util.DIGESTS['sha512'](frevs).hexdigest()
>> Why are we computing a hash here? Why not store the raw query? Is it because the filter names can be persisted to disk in the cache and must therefore be valid filenames?
> 
> Since query can be arbitrarily long, complex with any char. It seems simple to keep the ID simple. Especially because we persist it on disk
> 
>> Is % an allowed character on all filesystems? Maybe '-' would be safer?
> 
> % is a valid filename character on all system but RT-11. I think we are safe. I would rather keep the "-" char for something more meaningful (like what we are doing for ".hidden").
> 
> In the final design of this feature, we might end up with each query having an explicitly declared name.

Fair enough.

Could you please send a v2 using sha-256 (sha-512 is overkill) and with the necessary pycompat bits to make the hexdigest() bytes so things work on Python 3?

> 
>>    +
>>    +    combine = lambda fname: fname + '%' + fid
>>    +
>>    +    subsettable = repoviewutil.subsettable
>>    +
>>    +    if combine('base') not in filtertable:
>>    +        for name in _basefiltername:
>>    +            def extrafilteredrevs(repo, *args, **kwargs):
>>    +                baserevs = filtertable[name](repo, *args, **kwargs)
>>    +                extrarevs = frozenset(repo.revs(frevs))
>>    +                return baserevs | extrarevs
>>    +            filtertable[combine(name)] = extrafilteredrevs
>>    +            if name in subsettable:
>>    +                subsettable[combine(name)] = combine(subsettable[name])
>>    +    return fid
>>    +
>>      def filterrevs(repo, filtername, visibilityexceptions=None):
>>          """returns set of filtered revision for this filter name
>>    diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py
>>    --- a/mercurial/statichttprepo.py
>>    +++ b/mercurial/statichttprepo.py
>>    @@ -155,6 +155,7 @@ class statichttprepository(localrepo.loc
>>              self.names = namespaces.namespaces()
>>              self.filtername = None
>>    +        self._extrafilterid = None
>>              try:
>>                  requirements =
>>    set(self.vfs.read(b'requires').splitlines())
>>    diff --git a/tests/test-server-view.t b/tests/test-server-view.t
>>    --- a/tests/test-server-view.t
>>    +++ b/tests/test-server-view.t
>>    @@ -34,5 +34,21 @@
>>        date:        Thu Jan 01 00:00:00 1970 +0000
>>        summary:     r0
>>    +
>>    +Check same result using `experimental.extra-filter-revs`
>>    +
>>    +  $ hg -R test --config experimental.extra-filter-revs='not
>>    public()' serve -p $HGPORT1 -d --pid-file=hg2.pid -E errors.log
>>    +  $ cat hg2.pid >> $DAEMON_PIDS
>>    +  $ hg -R test2 incoming http://foo:xyzzy@localhost:$HGPORT1/
>>    +  comparing with http://foo:***@localhost:$HGPORT1/
>>    +  changeset:   0:1ea73414a91b
>>    +  tag:         tip
>>    +  user:        debugbuilddag
>>    +  date:        Thu Jan 01 00:00:00 1970 +0000
>>    +  summary:     r0
>>    +

Could we also please get a test that the on-disk cache file(s) are crested as expected?

Regarding those on-disk cache files, are there any cache invalidation issues since revsets are dynamic? (I think we’re OK but I want to make sure we have thought things through.)

>>    +
>>    +cleanup
>>    +
>>        $ cat errors.log
>>        $ killdaemons.py
>>    _______________________________________________
>>    Mercurial-devel mailing list
>>    Mercurial-devel at mercurial-scm.org
>>    <mailto:Mercurial-devel at mercurial-scm.org>
>>    https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
> 
> -- 
> Pierre-Yves David


More information about the Mercurial-devel mailing list