[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: svn commit: r23595 - in trunk: notes subversion/include subversion/libsvn_fs subversion/libsvn_fs_fs subversion/svnadmin

From: David Glasser <glasser_at_mit.edu>
Date: 2007-07-07 22:13:36 CEST

On 3/7/07, malcolm@tigris.org <malcolm@tigris.org> wrote:
> Author: malcolm
> Date: Wed Mar 7 01:12:45 2007
> New Revision: 23595
>
> Log:
> Implement 'svnadmin recover' for FSFS, recreating the db/current file
> from information in the rev/ files.

[snip; diff in fs_fs.c]

> @@ -4495,6 +4504,315 @@
> return SVN_NO_ERROR;
> }
>
> +/* Part of the recovery procedure. Return the largest revision *REV in
> + filesystem FS. Use POOL for temporary allocation. */
> +static svn_error_t *
> +recover_get_largest_revision(svn_fs_t *fs, svn_revnum_t *rev, apr_pool_t *pool)
> +{
> + /* Discovering the largest revision in the filesystem would be an
> + expensive operation if we did a readdir() or searched linearly,
> + so we'll do a form of binary search. left is a revision that we
> + know exists, right a revision that we know does not exist. */
> + apr_pool_t *iterpool;
> + svn_revnum_t left, right = 1;
> +
> + iterpool = svn_pool_create(pool);
> + /* Keep doubling right, until we find a revision that doesn't exist. */
> + while (1)
> + {
> + svn_node_kind_t kind;
> + SVN_ERR(svn_io_check_path(svn_fs_fs__path_rev(fs, right, iterpool),
> + &kind, iterpool));
> + svn_pool_clear(iterpool);
> +
> + if (kind == svn_node_none)
> + break;
> +
> + right <<= 1;
> + }
> +
> + left = right >> 1;
> +
> + /* We know that left exists and right doesn't. Do a normal bsearch to find
> + the last revision. */
> + while (left + 1 < right)
> + {
> + svn_revnum_t probe = left + ((right - left) / 2);
> + svn_node_kind_t kind;
> +
> + SVN_ERR(svn_io_check_path(svn_fs_fs__path_rev(fs, probe, iterpool),
> + &kind, iterpool));
> + svn_pool_clear(iterpool);
> +
> + if (kind == svn_node_none)
> + right = probe;
> + else
> + left = probe;
> + }
> +
> + svn_pool_destroy(iterpool);
> +
> + /* left is now the largest revision that exists. */
> + *rev = left;
> + return SVN_NO_ERROR;
> +}

Hmm. The end of commit_body looks like this:

[1] Move rev file into place.

[2] Fix svn:date and move revprops file into place.

[3] Update mergeinfo db.

[4] Update current.

If a commit process crashes after [1] but before [3], and somebody
runs FSFS recover before another commit happens, recover will turn the
incomplete revision into a real revision (without revprops or
mergeinfo). This seems bad: 'svnadmin recover' shouldn't be making
the repository *more* corrupt. I'm not sure what the best solution is
(checking for the revprops file fixes the between-[1]-and-[2] case at
least).

(Came across this because somebody was trying to make a repository
that users could commit to but not change past revisions on AFS by
only giving out "read" and "insert" permissions on the revs directory;
a crashed commit left an installed rev and revprops file without an
updated current, and future attempts to commit were unable to
overwrite the revs file. This particular issue is probably marginal
though.)

--dave

-- 
David Glasser | glasser_at_mit.edu | http://www.davidglasser.net/
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Jul 7 23:44:36 2007

This is an archived mail posted to the Subversion Dev mailing list.