[PATCH 1 of 3 V4] journal: add dirstate tracking

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Thu Jul 14 13:26:50 EDT 2016


At Mon, 11 Jul 2016 14:06:58 +0100,
Martijn Pieters wrote:
> 
> # HG changeset patch
> # User Martijn Pieters <mjpieters at fb.com>
> # Date 1468240764 -3600
> #      Mon Jul 11 13:39:24 2016 +0100
> # Node ID ccd47220f3d910ac2c682ec1c53e3a660b7b3e8f
> # Parent  b4d117cee636be8a566f56e84d4b351a736a1299
> journal: add dirstate tracking
> 
> Note that now the default action for `hg journal` is to list the working copy
> history, not all bookmarks. In its place is the `--all` switch which lists all
> name changes recorded, including the name for which the change was recorded on
> each line.
> 
> Locking is switched to using a dedicated lock to avoid issues with the dirstate
> being written during wlock unlocking (you can't re-lock during that process).
> 
> diff --git a/hgext/journal.py b/hgext/journal.py
> --- a/hgext/journal.py
> +++ b/hgext/journal.py

(snip)

> @@ -58,6 +67,42 @@
>      journalstorage.recordcommand(*fullargs)
>      return orig(lui, repo, cmd, fullargs, *args)
>  
> +# hooks to record dirstate changes
> +def wrapdirstate(orig, repo):
> +    """Make journal storage available to the dirstate object"""
> +    dirstate = orig(repo)
> +    if util.safehasattr(repo, 'journal'):
> +        dirstate.journalstorage = repo.journal
> +    return dirstate
> +
> +def recorddirstateparents(orig, dirstate, dirstatefp):
> +    """Records all dirstate parent changes in the journal."""
> +    if util.safehasattr(dirstate, 'journalstorage'):
> +        old = [node.nullid, node.nullid]
> +        nodesize = len(node.nullid)
> +        try:
> +            # The only source for the old state is in the dirstate file still
> +            # on disk; the in-memory dirstate object only contains the new
> +            # state. dirstate._opendirstatefile() switches beteen .hg/dirstate
> +            # and .hg/dirstate.pending depending on the transaction state.
> +            with dirstate._opendirstatefile() as fp:
> +                state = fp.read(2 * nodesize)

(sorry for late response)

If you expect dirstate._opendirstatefile() to read from ".hg/dirstate"
or ".hg/dirstate.pending" according to transaction state of the
CURRENT process, it doesn't work as expected, because:

  - dirstate._opendirstatefile() reads from ".hg/dirstate.pending",
    only if HG_PENDING env is defined

  - HG_PENDING env is defined only in the process spawned from the
    process starting transaction

    (use PARENT as "the process starting transaction", and CHILD as
    "the process spawned from" PARENT)

  - therefore:

    - in PARENT process, _opendirstatefile() never reads from
      ".hg/dirstate.pending"

      because HG_PENDING env isn't defined in PARENT

    - in CHILD process, _opendirstatefile() reads from
      ".hg/dirstate.pending" according to HG_PENDING env

      But reading from ".hg/dirstate.pending" in CHILD process is
      meaningless (at least for journal extension), because:

      - existence of ".hg/dirstate.pending" means that wlock is
        already acquired by PARENT process

      - CHILD process can't acquire wlock in such case

      - then, CHILD process shouldn't write dirstate changes out

To read from ".hg/dirstate" or ".hg/dirstate.pending" according to
transaction state of the CURRENT process correctly, you should
implement it locally in journal extension.

If it isn't matter that journal extension records changing parents
while automated commit from "base" to "final" in transaction like
below, reading always from ".hg/dirstate" is enough.

    base -> intermediate1
    base -> intermediate2
    base -> intermediate3
    base -> final

According to your last reply in thread for V2 series, the latter
solution seems enough for usecase of journal extension (or sorry if I
misunderstood).

https://www.mercurial-scm.org/pipermail/mercurial-devel/2016-July/085964.html


> +            if len(state) == 2 * nodesize:
> +                old = [state[:nodesize], state[nodesize:]]
> +        except IOError:
> +            pass
> +
> +        new = dirstate.parents()
> +        if old != new:
> +            # only record two hashes if there was a merge
> +            oldhashes = old[:1] if old[1] == node.nullid else old
> +            newhashes = new[:1] if new[1] == node.nullid else new
> +            dirstate.journalstorage.record(
> +                wdirparenttype, '.', oldhashes, newhashes)
> +
> +    return orig(dirstate, dirstatefp)
> +
> +# hooks to record bookmark changes (both local and remote)
>  def recordbookmarks(orig, store, fp):
>      """Records all bookmark changes in the journal."""
>      repo = store._repo

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy at lares.dti.ne.jp


More information about the Mercurial-devel mailing list