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

Re: [PATCH] Implement svnadmin verify --force

From: Stefan Sperling <stsp_at_elego.de>
Date: Mon, 29 Oct 2012 12:31:13 +0100

On Mon, Oct 29, 2012 at 03:26:36PM +0530, Prabhu Gnana Sundar wrote:
> Thanks much Stefan,
>
> Now, I have changed the code in libsvn_fs/fs-loader.c to handle the
> error. Passed the keep_going to the verify_fs so that it can be
> handled in both libsvn_fs_fs and libsvn_fs_base. I have attached the
> updated patch with this mail. Please share your reviews.

More review below (mostly stylistic nits).

> Index: subversion/libsvn_repos/dump.c
> ===================================================================
> --- subversion/libsvn_repos/dump.c (revision 1402414)
> +++ subversion/libsvn_repos/dump.c (working copy)
> @@ -1360,9 +1360,10 @@
> }
>
> svn_error_t *
> -svn_repos_verify_fs2(svn_repos_t *repos,
> +svn_repos_verify_fs3(svn_repos_t *repos,
> svn_revnum_t start_rev,
> svn_revnum_t end_rev,
> + svn_boolean_t keep_going,
> svn_repos_notify_func_t notify_func,
> void *notify_baton,
> svn_cancel_func_t cancel_func,
> @@ -1398,7 +1399,7 @@
>
> /* Verify global/auxiliary data and backend-specific data first. */
> SVN_ERR(svn_fs_verify(svn_fs_path(fs, pool), cancel_func, cancel_baton,
> - start_rev, end_rev, pool));
> + start_rev, end_rev, keep_going, pool));
>
> /* Create a notify object that we can reuse within the loop. */
> if (notify_func)
> @@ -1413,11 +1414,12 @@
> void *cancel_edit_baton;
> svn_fs_root_t *to_root;
> apr_hash_t *props;
> + svn_error_t *err;
>
> svn_pool_clear(iterpool);
>
> /* Get cancellable dump editor, but with our close_directory handler. */
> - SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton,
> + err = get_dump_editor(&dump_editor, &dump_edit_baton,
> fs, rev, "",
> svn_stream_empty(iterpool),
> NULL, NULL,

Please also change indentation of function parameters on additional
lines to align at the opening bracket like this:

      err = get_dump_editor(&dump_editor, &dump_edit_baton,
                            fs, rev, "",
                            svn_stream_empty(iterpool),
                            NULL, NULL,

With your patch it would look like this, which is wrong indentation
for our code base:

      err = get_dump_editor(&dump_editor, &dump_edit_baton,
                              fs, rev, "",
                              svn_stream_empty(iterpool),
                              NULL, NULL,

> @@ -1425,7 +1427,19 @@
> notify_func, notify_baton,
> start_rev,
> FALSE, TRUE, /* use_deltas, verify */
> - iterpool));
> + iterpool);
> +
> + if (err && keep_going)
> + {
> + svn_repos_notify_t *notify2 = svn_repos_notify_create(svn_repos_notify_failure, iterpool);

Why call the variable 'notify2', not just 'notify'?
Also, the above line doesn't wrap at column 78.

I'd suggest using 'notify' as variable name and indenting like this:

          svn_repos_notify_t *notify;
          
          notify = svn_repos_notify_create(svn_repos_notify_failure,
                                           iterpool);

> + notify2->err = err;
> + notify_func(notify_baton, notify2, iterpool);
> + svn_error_clear(err);
> + continue;
> + }
> + else
> + SVN_ERR(err);
> +
> SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
> dump_editor, dump_edit_baton,
> &cancel_editor,
> @@ -1433,9 +1447,21 @@
> iterpool));
>
> SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
> - SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
> + err = svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
> cancel_editor, cancel_edit_baton,

Again, please adjust indentation of function parameters.

> - NULL, NULL, iterpool));
> + NULL, NULL, iterpool);
> +
> + if (err && keep_going)
> + {
> + svn_repos_notify_t *notify2 = svn_repos_notify_create(svn_repos_notify_failure, iterpool);

Same as above suggestion for 'notify' + indentation.

> + notify2->err = err;
> + notify_func(notify_baton, notify2, iterpool);
> + svn_error_clear(err);
> + continue;
> + }
> + else
> + SVN_ERR(err);
> +
> /* While our editor close_edit implementation is a no-op, we still
> do this for completeness. */
> SVN_ERR(cancel_editor->close_edit(cancel_edit_baton, iterpool));
> Index: subversion/libsvn_repos/deprecated.c
> ===================================================================
> --- subversion/libsvn_repos/deprecated.c (revision 1402414)
> +++ subversion/libsvn_repos/deprecated.c (working copy)
> @@ -728,6 +728,27 @@
> }
>
> svn_error_t *
> +svn_repos_verify_fs2(svn_repos_t *repos,
> + svn_revnum_t start_rev,
> + svn_revnum_t end_rev,
> + svn_repos_notify_func_t notify_func,
> + void *notify_baton,
> + svn_cancel_func_t cancel_func,
> + void *cancel_baton,
> + apr_pool_t *pool)
> +{
> + return svn_error_trace(svn_repos_verify_fs3(repos,
> + start_rev,
> + end_rev,
> + FALSE,
> + notify_func,
> + notify_baton,
> + cancel_func,
> + cancel_baton,
> + pool));
> +}
> +
> +svn_error_t *
> svn_repos_verify_fs(svn_repos_t *repos,
> svn_stream_t *feedback_stream,
> svn_revnum_t start_rev,
> Index: subversion/libsvn_fs_fs/fs_fs.c
> ===================================================================
> --- subversion/libsvn_fs_fs/fs_fs.c (revision 1402414)
> +++ subversion/libsvn_fs_fs/fs_fs.c (working copy)
> @@ -10117,6 +10117,7 @@
> void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *pool)
> {
> fs_fs_data_t *ffd = fs->fsap_data;
> @@ -10151,6 +10152,7 @@
> commit-time checks in validate_root_noderev(). */
> {
> svn_revnum_t i;
> + svn_error_t *err;

We usually add a blank line between variable declarations and code.
So you should add a blank here.

> for (i = start; i <= end; i++)
> {
> svn_fs_root_t *root;
> @@ -10162,7 +10164,15 @@
> When this code is called in the library, we want to ensure we
> use the on-disk data --- rather than some data that was read
> in the possibly-distance past and cached since. */
> - SVN_ERR(svn_fs_fs__revision_root(&root, fs, i, iterpool));
> + err = svn_fs_fs__revision_root(&root, fs, i, iterpool);
> + if (err && keep_going)
> + {
> + svn_error_clear(err);

No notification about this error?

Instead of pushing the repos-layer notifier down into the FS-layer,
I'd suggest catching this error thrown from svn_fs_fs__verify() in the
repos-layer caller and notifying there if --keep-going was used.

And then this function won't even need a keep_going parameter and all
the FS-layer bits can be left unchanged, making your patch a bit smaller.

> + return SVN_NO_ERROR;
> + }
> + else
> + SVN_ERR(err);
> +
> SVN_ERR(svn_fs_fs__verify_root(root, iterpool));
> }
> }
> Index: subversion/libsvn_fs_fs/fs_fs.h
> ===================================================================
> --- subversion/libsvn_fs_fs/fs_fs.h (revision 1402414)
> +++ subversion/libsvn_fs_fs/fs_fs.h (working copy)
> @@ -38,12 +38,14 @@
> svn_error_t *svn_fs_fs__upgrade(svn_fs_t *fs,
> apr_pool_t *pool);
>
> -/* Verify the fsfs filesystem FS. Use POOL for temporary allocations. */
> +/* Verify the fsfs filesystem FS. Use POOL for temporary allocations.
> + * If KEEP_GOING is TRUE, do not stop upon failure. */
> svn_error_t *svn_fs_fs__verify(svn_fs_t *fs,
> svn_cancel_func_t cancel_func,
> void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *pool);
>
> /* Copy the fsfs filesystem SRC_FS at SRC_PATH into a new copy DST_FS at
> Index: subversion/libsvn_fs_fs/fs.c
> ===================================================================
> --- subversion/libsvn_fs_fs/fs.c (revision 1402414)
> +++ subversion/libsvn_fs_fs/fs.c (working copy)
> @@ -287,6 +287,7 @@
> void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *pool,
> apr_pool_t *common_pool)
> {
> @@ -295,7 +296,8 @@
> SVN_ERR(svn_fs_fs__open(fs, path, pool));
> SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
> SVN_ERR(fs_serialized_init(fs, common_pool, pool));
> - return svn_fs_fs__verify(fs, cancel_func, cancel_baton, start, end, pool);
> + return svn_fs_fs__verify(fs, cancel_func, cancel_baton, start, end,
> + keep_going, pool);
> }
>
> static svn_error_t *
> Index: subversion/libsvn_fs/fs-loader.c
> ===================================================================
> --- subversion/libsvn_fs/fs-loader.c (revision 1402414)
> +++ subversion/libsvn_fs/fs-loader.c (working copy)
> @@ -487,6 +487,7 @@
> void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *pool)
> {
> fs_library_vtable_t *vtable;
> @@ -497,7 +498,7 @@
>
> SVN_MUTEX__WITH_LOCK(common_pool_lock,
> vtable->verify_fs(fs, path, cancel_func, cancel_baton,
> - start, end, pool, common_pool));
> + start, end, keep_going, pool, common_pool));
> return SVN_NO_ERROR;
> }
>
> Index: subversion/libsvn_fs/fs-loader.h
> ===================================================================
> --- subversion/libsvn_fs/fs-loader.h (revision 1402414)
> +++ subversion/libsvn_fs/fs-loader.h (working copy)
> @@ -92,6 +92,7 @@
> svn_cancel_func_t cancel_func, void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *pool,
> apr_pool_t *common_pool);
> svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
> Index: subversion/svnadmin/main.c
> ===================================================================
> --- subversion/svnadmin/main.c (revision 1402414)
> +++ subversion/svnadmin/main.c (working copy)
> @@ -176,6 +176,7 @@
> {
> svnadmin__version = SVN_OPT_FIRST_LONGOPT_ID,
> svnadmin__incremental,
> + svnadmin__keep_going,
> svnadmin__deltas,
> svnadmin__ignore_uuid,
> svnadmin__force_uuid,
> @@ -288,6 +289,9 @@
> N_("use format compatible with Subversion versions\n"
> " earlier than 1.8")},
>
> + {"keep-going", svnadmin__keep_going, 0,
> + N_("continue verifying even if there is a corruption")},
> +
> {"memory-cache-size", 'M', 1,
> N_("size of the extra in-memory cache in MB used to\n"
> " minimize redundant operations. Default: 16.\n"
> @@ -475,7 +479,7 @@
> {"verify", subcommand_verify, {0}, N_
> ("usage: svnadmin verify REPOS_PATH\n\n"
> "Verifies the data stored in the repository.\n"),
> - {'r', 'q', 'M'} },
> + {'r', 'q', svnadmin__keep_going, 'M'} },
>
> { NULL, NULL, {0}, NULL, {0} }
> };
> @@ -505,6 +509,7 @@
> svn_boolean_t clean_logs; /* --clean-logs */
> svn_boolean_t bypass_hooks; /* --bypass-hooks */
> svn_boolean_t wait; /* --wait */
> + svn_boolean_t keep_going; /* --keep-going */
> svn_boolean_t bypass_prop_validation; /* --bypass-prop-validation */
> enum svn_repos_load_uuid uuid_action; /* --ignore-uuid,
> --force-uuid */
> @@ -738,6 +743,10 @@
> notify->warning_str));
> return;
>
> + case svn_repos_notify_failure:
> + svn_handle_error2(notify->err, stderr, FALSE /* non-fatal */, "svnadmin: ");

Another overlong line. I'd suggest:

      svn_handle_error2(notify->err, stderr, FALSE /* non-fatal */,
                        "svnadmin: ");

> + return;
> +
> case svn_repos_notify_dump_rev_end:
> svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
> _("* Dumped revision %ld.\n"),
> @@ -1527,7 +1536,8 @@
> if (! opt_state->quiet)
> progress_stream = recode_stream_create(stderr, pool);
>
> - return svn_repos_verify_fs2(repos, lower, upper,
> + return svn_repos_verify_fs3(repos, lower, upper,
> + opt_state->keep_going,
> !opt_state->quiet
> ? repos_notify_handler : NULL,
> progress_stream, check_cancel, NULL, pool);
> @@ -1992,6 +2002,9 @@
> case svnadmin__pre_1_8_compatible:
> opt_state.pre_1_8_compatible = TRUE;
> break;
> + case svnadmin__keep_going:
> + opt_state.keep_going = TRUE;
> + break;
> case svnadmin__fs_type:
> SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.fs_type, opt_arg, pool));
> break;
> Index: subversion/libsvn_fs_base/fs.c
> ===================================================================
> --- subversion/libsvn_fs_base/fs.c (revision 1402414)
> +++ subversion/libsvn_fs_base/fs.c (working copy)
> @@ -896,6 +896,7 @@
> void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *pool,
> apr_pool_t *common_pool)
> {
> Index: subversion/include/svn_fs.h
> ===================================================================
> --- subversion/include/svn_fs.h (revision 1402414)
> +++ subversion/include/svn_fs.h (working copy)
> @@ -280,6 +280,7 @@
> void *cancel_baton,
> svn_revnum_t start,
> svn_revnum_t end,
> + svn_boolean_t keep_going,
> apr_pool_t *scratch_pool);
>
> /**
> Index: subversion/include/svn_repos.h
> ===================================================================
> --- subversion/include/svn_repos.h (revision 1402414)
> +++ subversion/include/svn_repos.h (working copy)
> @@ -193,6 +193,9 @@
> /** A warning message is waiting. */
> svn_repos_notify_warning = 0,
>
> + /** A revision is found with corruption/errors. */
> + svn_repos_notify_failure,
> +

This enum has already been released in 1.7!
We must add new values at the end to preserve binary compatibility.
So please put svn_repos_notify_failure after svn_repos_notify_load_skipped_rev.

And please add "@since New in 1.8" to the docstring, like this:

  /** A revision is found with corruption/errors. @since New in 1.8. */

> /** A revision has finished being dumped. */
> svn_repos_notify_dump_rev_end,
>
> @@ -318,9 +321,13 @@
> /** For #svn_repos_notify_load_node_start, the path of the node. */
> const char *path;
>
> + /** The error chain. */

Please expand this comment to explain the intended use of this field.

I'd suggest:

  /** For #svn_repos_notify_failure, this error chain indicates what
   * went wrong during verification. */

> + svn_error_t *err;
> +
> /* NOTE: Add new fields at the end to preserve binary compatibility.
> Also, if you add fields here, you have to update
> svn_repos_notify_create(). */
> +

Why add a blank line here?

> } svn_repos_notify_t;
>
> /** Callback for providing notification from the repository.
> @@ -2517,8 +2524,29 @@
> * cancel_baton as argument to see if the caller wishes to cancel the
> * verification.
> *
> + * If @a keep_going is @c TRUE, the verify process prints the error message
> + * to the stderr and continues.
> + *
> + * @since New in 1.8.
> + */
> +svn_error_t *
> +svn_repos_verify_fs3(svn_repos_t *repos,
> + svn_revnum_t start_rev,
> + svn_revnum_t end_rev,
> + svn_boolean_t keep_going,
> + svn_repos_notify_func_t notify_func,
> + void *notify_baton,
> + svn_cancel_func_t cancel,
> + void *cancel_baton,
> + apr_pool_t *scratch_pool);
> +
> +/**
> + * Similar to svn_repos_verify_fs3(), but without force.

It's now called 'keep_going', not 'force'.

I'd suggest to say:

 * Like svn_repos_verify_fs3(), but with @a keep_going set to @c FALSE.

> + *
> * @since New in 1.7.
> + * @deprecated Provided for backward compatibility with the 1.7 API.
> */
> +SVN_DEPRECATED
> svn_error_t *
> svn_repos_verify_fs2(svn_repos_t *repos,
> svn_revnum_t start_rev,

> Implement svnadmin verify --keep-going, which would continue the verification
> even if there is some corruption, after printing the errors to stderr.
>
> * subversion/svnadmin/main.c
> (svnadmin__cmdline_options_t):

Missing change description? Or has svnadmin__cmdline_options_t not changed?

> (svnadmin_opt_state) : add keep-going option.

The indentation style of the log message differs from the style
we usually use. I'd suggest formatting log entries like this:

* subversion/svnadmin/main.c
  (svnadmin_opt_state): add keep-going option.
  (subcommand_verify): uses the new svn_repos_verify_fs3 function.
  (repos_notify_handler): svn_repos_notify_failure handles failure and
   prints warning to stderr.

I'd also suggest using proper capitalisation.

* subversion/svnadmin/main.c
  (svnadmin_opt_state): Add keep-going option.

What follows are stylistic suggestions. Log messages all differ based on
personal style and preferences. There are no strict guidelines and what
follows is just my personal opinion.

> (subcommand_verify) : uses the new svn_repos_verify_fs3 function.

The above doesn't describe the change itself but the result of the change.

Also, third-person simple present verbs like "X uses Y" makes it sounds as
if you're stating a fact, something that is always true and independent of
your change, rather than describing a change you are making.

Compare to this:

  (subcommand_verify): Switch to the new svn_repos_verify_fs3 function
   instead of svn_repos_verify_fs2, and pass the keep-going option.

I've added a minor detail by mentioning the keep-going option.
When describing changes I often try to describe each chunk of the diff
in a way that allows the reader of the log message to imagine what the
chunk might look like. This might seem overly detailed and it's not a
strict requirement of the project. But I found that this helps me with
writing log messages that I can make sense of myself when I read them
again half a year later :)

> (repos_notify_handler) : svn_repos_notify_failure handles failure and
> prints warning to stderr.

When expressing code changes in English, I prefer to phrase data structures
(in this case, svn_repos_notify_failure) as grammatical objects and executing
code acting on the data (in this case, repos_notify_handler) as the
grammatical subject acting on the object.

Your wording suggests that svn_repos_notify_failure (the data), and not
repos_notify_handler (the executing code), prints the warning to stderr.

Compare to phrasing it like this:

  (repos_notify_handler): Handle svn_repos_notify_failure notification
   by printing warnings to stderr.

That's all for now. I haven't tried to compile and run the patch yet.

You might also want to add a regression test for your change, by the way,
to make sure the --keep-going option doesn't break when we make further
changes in the future. But that can be done as a separate patch.

Thanks!

>
> * subversion/include/svn_repos.h
> (svn_repos_notify_action_t): add svn_repos_notify_failure to notify failure.
> (svn_repos_verify_fs3) : newly added to handle "keep-going" option.
>
> * subversion/include/svn_fs.h
> (svn_fs_verify) : handles keep-going. If keep-going is TRUE, svn_fs_verify
> would return no error.
>
> * subversion/libsvn_fs_fs/fs_fs.h
> (svn_fs_fs__verify) : added the keep_going parameter.
>
> * subversion/libsvn_fs_fs/fs_fs.c
> (svn_fs_fs__verify) : handles keep_going. If keep_going is TRUE, SVN_NO_ERROR
> is returned upon failure too.
>
> * subversion/libsvn_fs/fs-loader.h
> (fs_library_vtable_t) : added keep_going parameter.
>
> * subversion/libsvn_fs/fs-loader.c
> (svn_fs_verify) : handles keep_going, which is also passed on to vtable->verify_fs.
>
> * subversion/libsvn_fs_base/fs.c
> (base_verify) : handles keep_going parameter.
>
> * subversion/libsvn_fs_fs/fs.c
> (fs_verify) : send keep_going to svn_fs_fs__verify function.
>
> * subversion/libsvn_repos/dump.c
> (svn_repos_verify_fs3): now handles "keep-going".
> If "keep-going" is TRUE, then the error message is
> written to the stderr and verify process continues.
>
> * subversion/libsvn_repos/deprecated.c
> (svn_repos_verify_fs2) : deprecated.
> Now calls svn_repos_verify_fs3 with keep-going as FALSE.
>
>
> Patch by: Prabhu Gnana Sundar <prabhugs{_AT_}collab.net>
Received on 2012-10-29 12:32:02 CET

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