When to use invalidate()

Greg Ward greg at gerg.ca
Tue Feb 2 17:05:50 CST 2010


On Tue, Feb 2, 2010 at 8:55 AM, Dirkjan Ochtman <dirkjan at ochtman.nl> wrote:
> On Tue, Feb 2, 2010 at 14:29, Greg Ward <greg at gerg.ca> wrote:
>>  * hgweb re-reads config when 00changelog.i has changed, not when
>> config has changed... so if you edit config on the server, nothing in
>> hgweb changes until someone pushes to the repo.  If my analysis is
>> correct, that sounds confusing as heck!
>
> Maybe hgweb should check the mtime for .hg instead?

I think checking the mtime of 00changelog.i makes sense.  If anyone is
adding (or destroying) changesets, that's the file that will show it.
It looks like the mtime of .hg changes as well, but I suspect that's a
coincidence because .hg/dirstate is rewritten too.  (I'm just doing
repeated qpop/qpush for testing this stuff, so it's hardly
definitive.)

Here's a crazy idea: if the repository (00changelog.i) changes, reread
the repository.  If the config file (.hg/hgrc) changes, reread
configuration.  No, that does not help if hgweb.conf or something in
/etc/mercurial changes.  But it's easier to explain than "Oh, you have
to push something to make it re-read configuration".

>>  * knowledge about repository structure lives in hgweb, not in
>> localrepository (so it's hard for e.g. THG to take advantage of this
>> to detect when it needs to refresh)
>
> Not sure why you think this.

Because mercurial/hgweb/common.py contains this:

"""
def get_mtime(repo_path):
    store_path = os.path.join(repo_path, ".hg")
    if not os.path.isdir(os.path.join(store_path, "data")):
        store_path = os.path.join(store_path, "store")
    cl_path = os.path.join(store_path, "00changelog.i")
    if os.path.exists(cl_path):
        return os.stat(cl_path).st_mtime
    else:
        return os.stat(store_path).st_mtime
"""

Knowing about ".hg/data", ".hg/store", "<whatever>/00changelog.i" is
what I mean by "knowledge of repository structure".  If a GUI viewer
(say, TortoiseHg) needs a quick lightweight check for "has this
repository changed?", it should not have to import hgweb to do that.
It should be able to do it with a localrepository instance.

>>  * no clear way for extensions to hook into the process and let their
>> state be torn down when the repo state is torn down
>>  * no clear way for extensions to detect/announce that they have
>> stale state that needs to be torn down
>>  * no consistent way for all long-running apps (hgweb, THG, hgview,
>> ...) to tear down repo state at the end of some processing phase (HTTP
>> request, window focus, user hits "refresh", ...)
>
> Maybe we want a hook for this?

Extensions don't need a hook.  They just need something to wrap.
Currently, a stateful extension has to wrap invalidate() to work with
TortoiseHg and hgweb.refresh() to work with hgweb.  Here's what I have
done in my bugmap extension:

    def localrepo_invalidate(orig):
        ui.debug('bugmap: invalidating\n')
        invalidate()
        orig()

    extensions.wrapfunction(repo, 'invalidate', localrepo_invalidate)

    # HAAAAACK!!!  this makes bugmap show up-to-date info in hgweb
    # running under mod_wsgi, but does nothing for 'hg serve' processes
    running_wsgi = 'APACHE_PID_FILE' in os.environ
    if running_wsgi:
        import sys
        def hgweb_refresh(orig, self):
            sys.stderr.write('bugmap under wsgi: refresh()\n')
            invalidate()
            orig(self)

        from mercurial.hgweb import hgweb_mod
        extensions.wrapfunction(hgweb_mod.hgweb, 'refresh', hgweb_refresh)

(The 'running_wsgi' check is because I do not want to import hgweb in
every single hg invocation.  But it also means that this does not help
'hg serve'.)

Greg


More information about the Mercurial-devel mailing list