Author: stsp
Date: Wed Nov 27 17:08:01 2013
New Revision: 1546114
URL: http://svn.apache.org/r1546114
Log:
Merge the verify-keep-going branch to trunk.
'svnadmin verify --keep-going' now shows a summary of errors at the end.
Modified:
subversion/trunk/ (props changed)
subversion/trunk/subversion/libsvn_fs_x/ (props changed)
subversion/trunk/subversion/svnadmin/svnadmin.c
subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
subversion/trunk/subversion/tests/libsvn_fs_x/ (props changed)
Propchange: subversion/trunk/
------------------------------------------------------------------------------
Merged /subversion/branches/verify-keep-going:r1492640-1546110
Propchange: subversion/trunk/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
Merged
/subversion/branches/verify-keep-going/subversion/libsvn_fs_x:r1546002-1546110
Modified: subversion/trunk/subversion/svnadmin/svnadmin.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnadmin/svnadmin.c?rev=1546114&r1=1546113&r2=1546114&view=diff
==============================================================================
--- subversion/trunk/subversion/svnadmin/svnadmin.c (original)
+++ subversion/trunk/subversion/svnadmin/svnadmin.c Wed Nov 27 17:08:01 2013
@@ -805,6 +805,34 @@ subcommand_deltify(apr_getopt_t *os, voi
return SVN_NO_ERROR;
}
+/* Structure for errors encountered during 'svnadmin verify --keep-going'. */
+struct verification_error
+{
+ svn_revnum_t rev;
+ svn_error_t *err;
+};
+
+/* Pool cleanup function to clear an svn_error_t *. */
+static apr_status_t
+err_cleanup(void *data)
+{
+ svn_error_t *err = data;
+
+ svn_error_clear(err);
+
+ return APR_SUCCESS;
+}
+
+struct repos_notify_handler_baton {
+ /* Stream to write progress and other non-error output to. */
+ svn_stream_t *feedback_stream;
+
+ /* List of errors encountered during 'svnadmin verify --keep-going'. */
+ apr_array_header_t *error_summary;
+
+ /* Pool for data collected during notifications. */
+ apr_pool_t *result_pool;
+};
/* Implementation of svn_repos_notify_func_t to wrap the output to a
response stream for svn_repos_dump_fs2() and svn_repos_verify_fs() */
@@ -813,7 +841,8 @@ repos_notify_handler(void *baton,
const svn_repos_notify_t *notify,
apr_pool_t *scratch_pool)
{
- svn_stream_t *feedback_stream = baton;
+ struct repos_notify_handler_baton *b = baton;
+ svn_stream_t *feedback_stream = b->feedback_stream;
switch (notify->action)
{
@@ -829,8 +858,22 @@ repos_notify_handler(void *baton,
_("* Error verifying revision %ld.\n"),
notify->revision));
if (notify->err)
- svn_handle_error2(notify->err, stderr, FALSE /* non-fatal */,
- "svnadmin: ");
+ {
+ svn_handle_error2(notify->err, stderr, FALSE /* non-fatal */,
+ "svnadmin: ");
+ if (b->error_summary && notify->revision != SVN_INVALID_REVNUM)
+ {
+ struct verification_error *verr;
+
+ verr = apr_palloc(b->result_pool, sizeof(*verr));
+ verr->rev = notify->revision;
+ verr->err = svn_error_dup(notify->err);
+ apr_pool_cleanup_register(b->result_pool, verr->err, err_cleanup,
+ apr_pool_cleanup_null);
+ APR_ARRAY_PUSH(b->error_summary,
+ struct verification_error *) = verr;
+ }
+ }
return;
case svn_repos_notify_dump_rev_end:
@@ -1065,7 +1108,7 @@ subcommand_dump(apr_getopt_t *os, void *
svn_stream_t *stdout_stream;
svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
svn_revnum_t youngest;
- svn_stream_t *progress_stream = NULL;
+ struct repos_notify_handler_baton notify_baton = { 0 };
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
@@ -1099,12 +1142,12 @@ subcommand_dump(apr_getopt_t *os, void *
/* Progress feedback goes to STDERR, unless they asked to suppress it. */
if (! opt_state->quiet)
- progress_stream = recode_stream_create(stderr, pool);
+ notify_baton.feedback_stream = recode_stream_create(stderr, pool);
SVN_ERR(svn_repos_dump_fs3(repos, stdout_stream, lower, upper,
opt_state->incremental, opt_state->use_deltas,
!opt_state->quiet ? repos_notify_handler : NULL,
- progress_stream, check_cancel, NULL, pool));
+ ¬ify_baton, check_cancel, NULL, pool));
return SVN_NO_ERROR;
}
@@ -1251,7 +1294,8 @@ subcommand_load(apr_getopt_t *os, void *
struct svnadmin_opt_state *opt_state = baton;
svn_repos_t *repos;
svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
- svn_stream_t *stdin_stream, *stdout_stream = NULL;
+ svn_stream_t *stdin_stream;
+ struct repos_notify_handler_baton notify_baton = { 0 };
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
@@ -1285,7 +1329,7 @@ subcommand_load(apr_getopt_t *os, void *
/* Progress feedback goes to STDOUT, unless they asked to suppress it. */
if (! opt_state->quiet)
- stdout_stream = recode_stream_create(stdout, pool);
+ notify_baton.feedback_stream = recode_stream_create(stdout, pool);
err = svn_repos_load_fs4(repos, stdin_stream, lower, upper,
opt_state->uuid_action, opt_state->parent_dir,
@@ -1293,7 +1337,7 @@ subcommand_load(apr_getopt_t *os, void *
opt_state->use_post_commit_hook,
!opt_state->bypass_prop_validation,
opt_state->quiet ? NULL : repos_notify_handler,
- stdout_stream, check_cancel, NULL, pool);
+ ¬ify_baton, check_cancel, NULL, pool);
if (err && err->apr_err == SVN_ERR_BAD_PROPERTY_VALUE)
return svn_error_quick_wrap(err,
_("Invalid property value found in "
@@ -1340,12 +1384,12 @@ subcommand_recover(apr_getopt_t *os, voi
svn_repos_t *repos;
svn_error_t *err;
struct svnadmin_opt_state *opt_state = baton;
- svn_stream_t *stdout_stream;
+ struct repos_notify_handler_baton notify_baton = { 0 };
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
- SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+ SVN_ERR(svn_stream_for_stdout(¬ify_baton.feedback_stream, pool));
/* Restore default signal handlers until after we have acquired the
* exclusive lock so that the user interrupt before we actually
@@ -1353,7 +1397,7 @@ subcommand_recover(apr_getopt_t *os, voi
setup_cancellation_signals(SIG_DFL);
err = svn_repos_recover4(opt_state->repository_path, TRUE,
- repos_notify_handler, stdout_stream,
+ repos_notify_handler, ¬ify_baton,
check_cancel, NULL, pool);
if (err)
{
@@ -1371,7 +1415,7 @@ subcommand_recover(apr_getopt_t *os, voi
" another process has it open?\n")));
SVN_ERR(svn_cmdline_fflush(stdout));
SVN_ERR(svn_repos_recover4(opt_state->repository_path, FALSE,
- repos_notify_handler, stdout_stream,
+ repos_notify_handler, ¬ify_baton,
check_cancel, NULL, pool));
}
@@ -1626,7 +1670,7 @@ subcommand_pack(apr_getopt_t *os, void *
{
struct svnadmin_opt_state *opt_state = baton;
svn_repos_t *repos;
- svn_stream_t *progress_stream = NULL;
+ struct repos_notify_handler_baton notify_baton = { 0 };
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
@@ -1635,11 +1679,11 @@ subcommand_pack(apr_getopt_t *os, void *
/* Progress feedback goes to STDOUT, unless they asked to suppress it. */
if (! opt_state->quiet)
- progress_stream = recode_stream_create(stdout, pool);
+ notify_baton.feedback_stream = recode_stream_create(stdout, pool);
return svn_error_trace(
svn_repos_fs_pack2(repos, !opt_state->quiet ? repos_notify_handler : NULL,
- progress_stream, check_cancel, NULL, pool));
+ ¬ify_baton, check_cancel, NULL, pool));
}
@@ -1651,7 +1695,8 @@ subcommand_verify(apr_getopt_t *os, void
svn_repos_t *repos;
svn_fs_t *fs;
svn_revnum_t youngest, lower, upper;
- svn_stream_t *progress_stream = NULL;
+ struct repos_notify_handler_baton notify_baton = { 0 };
+ svn_error_t *verify_err;
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
@@ -1696,15 +1741,63 @@ subcommand_verify(apr_getopt_t *os, void
}
if (! opt_state->quiet)
- progress_stream = recode_stream_create(stdout, pool);
+ notify_baton.feedback_stream = recode_stream_create(stdout, pool);
- return svn_error_trace(svn_repos_verify_fs3(repos, lower, upper,
- opt_state->keep_going,
- opt_state->check_ucs_norm,
- !opt_state->quiet
- ? repos_notify_handler : NULL,
- progress_stream, check_cancel,
- NULL, pool));
+ if (opt_state->keep_going)
+ notify_baton.error_summary =
+ apr_array_make(pool, 0, sizeof(struct verification_error *));
+
+ notify_baton.result_pool = pool;
+
+ verify_err = svn_repos_verify_fs3(repos, lower, upper,
+ opt_state->keep_going,
+ opt_state->check_ucs_norm,
+ !opt_state->quiet
+ ? repos_notify_handler : NULL,
+ ¬ify_baton, check_cancel,
+ NULL, pool);
+
+ /* Show the --keep-going error summary. */
+ if (opt_state->keep_going && notify_baton.error_summary->nelts > 0)
+ {
+ apr_pool_t *iterpool;
+ int i;
+
+ svn_error_clear(
+ svn_stream_printf(notify_baton.feedback_stream, pool,
+ _("\n-----Summary of corrupt revisions-----\n")));
+
+ iterpool = svn_pool_create(pool);
+ for (i = 0; i < notify_baton.error_summary->nelts; i++)
+ {
+ struct verification_error *verr;
+ svn_error_t *err;
+ const char *rev_str;
+
+ svn_pool_clear(iterpool);
+
+ verr = APR_ARRAY_IDX(notify_baton.error_summary, i,
+ struct verification_error *);
+ rev_str = apr_psprintf(iterpool, "r%ld", verr->rev);
+ for (err = svn_error_purge_tracing(verr->err);
+ err != SVN_NO_ERROR; err = err->child)
+ {
+ char buf[512];
+ const char *message;
+
+ message = svn_err_best_message(err, buf, sizeof(buf));
+ svn_error_clear(svn_stream_printf(notify_baton.feedback_stream,
+ iterpool,
+ "%6s: E%06d: %s\n",
+ rev_str, err->apr_err,
+ message));
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+ }
+
+ return svn_error_trace(verify_err);
}
/* This implements `svn_opt_subcommand_t'. */
@@ -2091,18 +2184,18 @@ subcommand_upgrade(apr_getopt_t *os, voi
{
svn_error_t *err;
struct svnadmin_opt_state *opt_state = baton;
- svn_stream_t *stdout_stream;
+ struct repos_notify_handler_baton notify_baton = { 0 };
/* Expect no more arguments. */
SVN_ERR(parse_args(NULL, os, 0, 0, pool));
- SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+ SVN_ERR(svn_stream_for_stdout(¬ify_baton.feedback_stream, pool));
/* Restore default signal handlers. */
setup_cancellation_signals(SIG_DFL);
err = svn_repos_upgrade2(opt_state->repository_path, TRUE,
- repos_notify_handler, stdout_stream, pool);
+ repos_notify_handler, ¬ify_baton, pool);
if (err)
{
if (APR_STATUS_IS_EAGAIN(err->apr_err))
@@ -2120,7 +2213,7 @@ subcommand_upgrade(apr_getopt_t *os, voi
" another process has it open?\n")));
SVN_ERR(svn_cmdline_fflush(stdout));
SVN_ERR(svn_repos_upgrade2(opt_state->repository_path, FALSE,
- repos_notify_handler, stdout_stream,
+ repos_notify_handler, ¬ify_baton,
pool));
}
else if (err->apr_err == SVN_ERR_FS_UNSUPPORTED_UPGRADE)
Modified: subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py?rev=1546114&r1=1546113&r2=1546114&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py Wed Nov 27
17:08:01 2013
@@ -1894,7 +1894,12 @@ def verify_keep_going(sbox):
".*Verified revision 0.",
".*Verified revision 1.",
".*Error verifying revision 2.",
- ".*Error verifying revision 3."])
+ ".*Error verifying revision 3.",
+ ".*",
+ ".*Summary.*",
+ ".*r2: E160004:.*",
+ ".*r3: E160004:.*",
+ ".*r3: E160004:.*"])
exp_err = svntest.verify.RegexListOutput(["svnadmin: E160004:.*",
"svnadmin: E165011:.*"], False)
@@ -2006,10 +2011,28 @@ def verify_invalid_path_changes(sbox):
".*Error verifying revision 16.",
".*Verified revision 17.",
".*Error verifying revision 18.",
- ".*Verified revision 19."])
+ ".*Verified revision 19.",
+ ".*",
+ ".*Summary.*",
+ ".*r2: E160020:.*",
+ ".*r2: E160020:.*",
+ ".*r4: E160013:.*",
+ ".*r6: E160013:.*",
+ ".*r6: E160013:.*",
+ ".*r10: E160013:.*",
+ ".*r10: E160013:.*",
+ ".*r12: E145001:.*",
+ ".*r12: E145001:.*",
+ ".*r14: E160013:.*",
+ ".*r14: E160013:.*",
+ ".*r16: E145001:.*",
+ ".*r16: E145001:.*",
+ ".*r18: E160013:.*",
+ ".*r18: E160013:.*"])
exp_err = svntest.verify.RegexListOutput(["svnadmin: E160020:.*",
- "svnadmin: E165011:.*"], False)
+ "svnadmin: E145001:.*",
+ "svnadmin: E160013:.*"], False)
if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin
verify'.",
@@ -2024,6 +2047,9 @@ def verify_invalid_path_changes(sbox):
".*Verified revision 1.",
".*Error verifying revision 2."])
+ exp_err = svntest.verify.RegexListOutput(["svnadmin: E160020:.*",
+ "svnadmin: E165011:.*"], False)
+
if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin
verify'.",
output, errput, exp_out, exp_err):
raise svntest.Failure
Propchange: subversion/trunk/subversion/tests/libsvn_fs_x/
------------------------------------------------------------------------------
Merged
/subversion/branches/verify-keep-going/subversion/tests/libsvn_fs_x:r1546002-1546110