[PATCH RFC] repair: add mechanism to convert/upgrade a repo in place

Yuya Nishihara yuya at tcha.org
Fri Feb 19 23:43:34 EST 2016


On Mon, 15 Feb 2016 15:47:45 -0800, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1455580051 28800
> #      Mon Feb 15 15:47:31 2016 -0800
> # Node ID d65feeab5bc118778d9523e7df44fe38804046ce
> # Parent  a3fcea8d55f7c2b3e9d83c00cbe303890a906775
> repair: add mechanism to convert/upgrade a repo in place
> 
> Pierre-Yves wants a debug command to "upgrade" repositories to
> generaldelta. Taking a step backward, upgrading a repository to
> generaldelta is a subset of the general task of adding a new
> requirement to an existing repository.
> 
> This patch begins the implementation of a generic, in-place
> repository "upgrade" mechanism that can be performed on a live
> repo with minimal downtime (as opposed to `hg clone` which
> doesn't take out a lock on the source repo and therefore is
> susceptible from repositories gaining new data while operating
> on them).

[snip]

> + at command('debugupgraderepo')
> +def debugupgraderepo(ui, repo):
> +    """upgrade a repository to use different features
> +
> +    During the upgrade, errors may be encountered when reading from the
> +    repository. This command should therefore not be executed on live
> +    repositories.
> +    """
> +    repair.upgraderepo(repo)

You said "hg clone" is susceptible because it doesn't take a lock, but
"debugupgraderepo" is also unusable for live repositories. What's the benefit
of this command?

Even if "debugupgraderepo" takes a lock, another client may see old "requires"
and will go wrong after a lock released.

> +def _upgradestore(repo, requirements):
> +    try:
> +        # It is easier to create a new repo than to instantiate all the
> +        # components separately.
> +        tmprepo = localrepo.localrepository(repo.baseui,
> +                                            path=repo.join('tmprepo'),
> +                                            create=True)
> +
> +        with tmprepo.transaction('upgrade') as tr:
> +            # Start by cloning revlogs individually.
> +            total = 0
> +            for t in repo.store.walk():
> +                if t[0].endswith('.i'):
> +                    total += 1
> +
> +            i = 0
> +            for unencoded, encoded, size in repo.store.walk():
> +                if unencoded.endswith('.d'):
> +                    continue
> +
> +                i += 1
> +                repo.ui.progress('upgrade', i, total=total)
> +
> +                oldrl = revlog.revlog(repo.svfs, unencoded)
> +                newrl = revlog.revlog(tmprepo.svfs, unencoded)
> +
> +                # generaldelta is never enabled on changelog because it isn't
> +                # useful.
> +                if unencoded == '00changelog.i':
> +                    newrl.version &= ~revlog.REVLOGGENERALDELTA
> +                    newrl._generaldelta = False
> +
> +                oldrl.clone(newrl, tr)

Missed a patch for revlog.clone() ?


More information about the Mercurial-devel mailing list