On 12/20/2012 11:25 PM, Julian Foad wrote:
Hi Prabhu.

I have now looked in detail at your patch and tried using it.  I think I have 
found an inconsistency and a serious problem.

The output for a failed revision depends on whether --keep-going was passed.  With 
--keep-going you print a "* Error verifying revision 2." line; without it you 
don't.

Consistency of the output is important, but even more important is simplicity 
of the code.  I would expect the code to look something like (pseudo-code):

   for R in range:
     err = verify_rev(R)
     if (err)
       show the error and a 'Failed' notification
       had_error = TRUE
       if not keep_going:
         break

   if had_error:
     return a 'Failed to verify the repo' error

but
  you seem to have several different code paths.  Why do you have two
different places that generate the "Repository '%s' failed to verify"
message; can you do it in just one place?

Yeah Julian, now the code generates the "Repository '%s' failed to verify" message only in one place, thanks for the idea.


Another justification for always printing the "* Error verifying revision 2." 
line is that with the old output:

[[[
$ svnadmin verify repo
...
* Verified revision 15921.
* Verified revision 15922.
* Verified revision 15923.
svnadmin: E160004: Invalid change kind in rev file
]]]

it
  can be a little confusing at first glance to realize that the error
relates to a revision number that was not mentioned -- revision 15924 in this 
example.  I have often in the past wished that we would print a
notification line like "* Error verifying revision 15924." here.

Also, in email [1] I suggested
  that the final summary error should be printed even when keep-going is
false.  Did you consider that suggestion?  What do you think?

Yeah I have taken that into consideration and implemented it as well.

<snip>

$ svnadmin verify repo2
* Verified revision 0.
* Verified revision 1.
* Error verifying revision 2.
svnadmin: E160004: Invalid change kind in rev file
svnadmin: E165005: Repository 'repo2' failed to verify

$ echo $?
1

</snip>



A more serious problem: it doesn't always report the error at the end.

[[[
$ bin/svnadmin verify --keep-going repo2
* Verified revision 0.
* Verified revision 1.
* Error verifying revision 2.
subversion/libsvn_repos/replay.c:859: (apr_err=160004)
subversion/libsvn_fs_fs/fs_fs.c:6335: (apr_err=160004)
subversion/libsvn_fs_fs/fs_fs.c:6311: (apr_err=160004)
subversion/libsvn_fs_fs/fs_fs.c:6242: (apr_err=160004)
subversion/libsvn_fs_fs/fs_fs.c:6065: (apr_err=160004)
svnadmin: E160004: Invalid change kind in rev file
* Verified revision 3.
]]]

The exit code is 0 here.  Clearly a bug.  The repository I used for this test 
is attached as 'jaf-corrupt-repo-2.tgz'.
Ahh, I missed out a code when moving my code from main.c to svnadmin.c (sorry about that). This works fine now.


<snip>

$ svnadmin verify repo2 --keep-going
* Verified revision 0.
* Verified revision 1.
* Error verifying revision 2.
svnadmin: E160004: Invalid change kind in rev file
* Verified revision 3.
svnadmin: E165005: Repository 'repo2' failed to verify

$ echo $?
1

</snip>



I am now sure that you need more tests.  You added a test, but can you tell us 
what it tests in  functional terms?  It looks like it tests verifying a repo 
where there is an error in r6, and the youngest rev is r6.  That doesn't cover 
the main purpose of the 'keep going' feature, which is to keep going, does it?

Can you think of other things that should be tested?  Please write a short list 
 of tests that we should ideally have -- even if we might not write them all.  
It might start with something like:

   Scenario 1:
     Repo: youngest=r3, an error in r3.
     Command: svnadmin verify --keep-going repo
   Expected results:
     stdout: Nothing
     stderr: Success messages for r0, r1, r2.
             A 'revision failed' message for r3.
             At least one error message relating to r3.
     exit code: non-zero.
Scenario 2:
  Repo: youngest=r3, an error in r2
  Command: svnadmin verify repo
Expected results:
  stdout: nothing
  stderr: Success for r1
              Revision failed message for r2
              Error message relating to r2
              Repository %s failed to verify message
  exit code: non-zero


Scenario 3:
  Repo: youngest=r3, an error in r2
  Command: svnadmin verify repo --keep-going
Expected results:
  stdout: nothing
  stderr: Success for r1
              Revision failed message for r2
              Error message relating to r2
              Success for r3
              Repository %s failed to verify message
  exit code: non-zero

Scenario 4:
  Repo: youngest=r3, an error in r3
  Command: svnadmin verify repo -r1:2
Expected results:
  stdout: nothing
  stderr: Success for r1, r2
  exit code: zero


Scenario 5:
  Repo: youngest=r3, an error in r3
  Command: svnadmin verify repo -r1:2 --keep-going
Expected results:
  stdout: nothing
  stderr: Success for r1, r2
  exit code: zero

   Scenario 2:
     Repo: youngest=r5, error in r3 only (not affecting r4 or r5)
     Command: svnadmin verify --keep-going repo
   Expected results:
     ...


In svn_repos.h: svn_repos_verify_fs3():

  /**
   * Verify the contents of the file system in @a repos.
   *
   * If @a feedback_stream is not @c NULL, write feedback to it (lines of
   * the form "* Verified revision %ld\n").

This mentions what feedback the function gives.  You are adding new feedback, 
so please update the doc string.  It must be out of date already because the 
function doesn't have a 'feedback_stream' parameter, so please fix that at the 
same time.
Updated the doc string...


   * If @a start_rev is #SVN_INVALID_REVNUM, then start verifying at
   * revision 0.  If @a end_rev is #SVN_INVALID_REVNUM, then verify
   * through the @c HEAD revision.
   *
   * For every verified revision call @a notify_func with @a rev set to
   * the verified revision and @a warning_text @c NULL. For warnings call @a
   * notify_func with @a warning_text set.

Is that paragraph still correct or does it need updating?

Updated the paragraph...


+ * If @a keep_going is @c TRUE, the verify process notifies the error message
+ * and continues. If @a notify_func is @c NULL, the verification failure is
+ * not notified.

Please document what this function returns (as I asked in [2]).
Yeah sure, documented the changes


+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_repos_verify_fs3(svn_repos_t *repos, ...);


In subversion/libsvn_repos/dump.c: svn_repos_verify_fs3():

You are doing error detection and handling in two places in this function out of 
more than two possible places where an error could be thrown.  As I wrote in [3], 
"Instead of checking for errors in several places within the main loop,
put the verification code in a wrapper function and check for errors
exactly once where you call that function.  That way you won't miss
any.  In your last patch, there is at least one call that could return a
  verification error that isn't checked -- the call to
svn_fs_revision_root()."


Yeah I get that, sounds a good idea :)
Now used a new wrapper function verification_checks() to perform all the error checks, thus catching any possible error in one shot.

In svnadmin.c:
+    case svn_repos_notify_failure:
+      if (notify->revision != SVN_INVALID_REVNUM)
+        svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
+                            ("* Error verifying revision %ld.\n"),
+                            notify->revision));

The message needs _() not just () around it for localization.

oops, I get it... Updated the code...


Attaching the updated patch and the log message with this mail. Please share your views..


Thanks and regards
Prabhu


(The feature has been rightly name "keep-going", so does it :) )
Implement svnadmin verify --keep-going, which would continue the verification
even if there is some corruption, after printing the errors to stderr.

* subversion/svnadmin/svnadmin.c
  (svnadmin__cmdline_options_t): Add keep-going option.
  (svnadmin_opt_state): Add keep-going option.
  (subcommand_verify): Switch to the new svn_repos_verify_fs3 function instead
   of svn_repos_verify_fs2, and pass the keep-going option.
  (repos_notify_handler): Handle svn_repos_notify_failure notification by
   printing warnings to stderr with the respective revision number.

* 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.
  (svn_repos_notify_t): Add "err", the error chain which indicates what went
   wrong during verification.

* subversion/libsvn_repos/dump.c
  (svn_repos_verify_fs3): Handle "keep-going". If "keep-going" is TRUE, the
   error message is notified and verification process continues.
  When a repository fails to verify, return an SVN_ERR_REPOS_CORRUPTED error
  message and return a non-zero exit code.
  (notify_verification_error): New function to notify the verification
  failure error message.
  (verification_checks): New wrapper function to perform all the error checks for
  a particular revision in one go.

* subversion/libsvn_repos/deprecated.c
  (svn_repos_verify_fs2): Deprecate. Call svn_repos_verify_fs3 with
   keep_going as FALSE by default to keep the old default implementation.

* subversion/tests/cmdline/svnadmin_tests.py
  (verify_keep_going): New test case to test svnadmin verify and the new
  switch --keep-going.

Patch by: Prabhu Gnana Sundar <prabhugs{_AT_}collab.net>
Index: subversion/svnadmin/svnadmin.c
===================================================================
--- subversion/svnadmin/svnadmin.c	(revision 1427745)
+++ subversion/svnadmin/svnadmin.c	(working copy)
@@ -175,6 +175,7 @@ enum svnadmin__cmdline_options_t
   {
     svnadmin__version = SVN_OPT_FIRST_LONGOPT_ID,
     svnadmin__incremental,
+    svnadmin__keep_going,
     svnadmin__deltas,
     svnadmin__ignore_uuid,
     svnadmin__force_uuid,
@@ -280,6 +281,9 @@ static const apr_getopt_option_t options_table[] =
     {"pre-1.6-compatible",     svnadmin__pre_1_6_compatible, 0,
      N_("deprecated; see --compatible-version")},
 
+    {"keep-going",    svnadmin__keep_going, 0,
+     N_("continue verifying after detecting 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"
@@ -471,7 +475,7 @@ static const svn_opt_subcommand_desc2_t cmd_table[
   {"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} }
 };
@@ -501,6 +505,7 @@ struct svnadmin_opt_state
   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 */
@@ -744,6 +749,16 @@ repos_notify_handler(void *baton,
                                         notify->warning_str));
       return;
 
+    case svn_repos_notify_failure:
+      if (notify->revision != SVN_INVALID_REVNUM)
+        svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
+                                          _("* Error verifying revision %ld.\n"),
+                                          notify->revision));
+      if (notify->err)
+        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"),
@@ -1533,10 +1548,12 @@ subcommand_verify(apr_getopt_t *os, void *baton, a
   if (! opt_state->quiet)
     progress_stream = recode_stream_create(stderr, pool);
 
-  return svn_repos_verify_fs2(repos, lower, upper,
-                              !opt_state->quiet
-                                ? repos_notify_handler : NULL,
-                              progress_stream, check_cancel, NULL, pool);
+  return svn_error_trace(svn_repos_verify_fs3(repos, lower, upper,
+                                              opt_state->keep_going,
+                                              !opt_state->quiet
+                                              ? repos_notify_handler : NULL,
+                                              progress_stream, check_cancel,
+                                              NULL, pool));
 }
 
 /* This implements `svn_opt_subcommand_t'. */
@@ -2032,6 +2049,9 @@ sub_main(int argc, const char *argv[], apr_pool_t
           opt_state.compatible_version = compatible_version;
         }
         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/tests/cmdline/svnadmin_tests.py
===================================================================
--- subversion/tests/cmdline/svnadmin_tests.py	(revision 1427745)
+++ subversion/tests/cmdline/svnadmin_tests.py	(working copy)
@@ -1835,6 +1835,107 @@ def recover_old(sbox):
   svntest.main.run_svnadmin("recover", sbox.repo_dir)
 
 
+def verify_keep_going(sbox):
+  "svnadmin verify --keep-going test"
+  test_create(sbox)
+  dumpfile_skeleton = open(os.path.join(os.path.dirname(sys.argv[0]),
+                                                        'svnadmin_tests_data',
+                                                        'skeleton_repos.dump')).read()
+  load_dumpstream(sbox, dumpfile_skeleton, '--ignore-uuid')
+
+  r6 = fsfs_file(sbox.repo_dir, 'revs', '6')
+  fp = open(r6, 'wb')
+  fp.write("""id: 3-6.0.r6/0
+type: file
+count: 0
+text: 2 0 60 48 02d086e41b03058c5f1af6282c1f483f cc67e4dd7cd8ca83095c8b95f65b6698b39cb263 5-5/_5
+props: 2 73 34 0 25e6c2f7558b7484000d4d090dea5b92
+cpath: /Projects/docs/README
+copyroot: 0 /
+
+PLAIN
+K 6
+README
+V 15
+file 3-6.0.r6/0
+END
+ENDREP
+id: 1-6.0.r6/275
+type: dir
+count: 0
+text: 6 226 36 0 2c3f6410944c6ff8667fa1b3e78f45a2
+cpath: /Projects/docs
+copyroot: 0 /
+
+PLAIN
+K 9
+Project-X
+V 14
+dir 1-3.0.r3/0
+K 9
+Project-Y
+V 14
+dir 1-4.0.r4/0
+K 9
+Project-Z
+V 14
+dir 1-5.0.r5/0
+K 4
+docs
+V 16
+dir 1-6.0.r6/275
+END
+ENDREP
+id: 0-1.0.r6/548
+type: dir
+pred: 0-1.0.r5/195
+count: 4
+text: 6 398 137 0 c758f548da93cc57d68af0610766b549
+cpath: /Projects
+copyroot: 0 /
+
+PLAIN
+K 8
+Projects
+V 16
+dir 0-1.0.r6/548
+K 6
+README
+V 17
+file 0-2.0.r2/120
+END
+ENDREP
+id: 0.0.r6/772
+type: dir
+pred: 0.0.r5/418
+count: 6
+text: 6 686 73 0 353c6bbf43b0f2ae474d85e206337bbd
+cpath: /
+copyroot: 0 /
+
+_1.0.t5-5 add-dir false false /Projects/docs
+
+_3.0.t5-5 add-file true true /Projects/docs/README
+
+
+""")
+  fp.close()
+  exit_code, output, errput = svntest.main.run_svnadmin("verify",
+                                                        sbox.repo_dir)
+  exit_code, output, errput2 = svntest.main.run_svnadmin("verify",
+                                                         "--keep-going",
+                                                         sbox.repo_dir)
+
+  if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.",
+                                 [], errput, None, ".*svnadmin: E165005: .*"):
+    raise svntest.Failure
+
+  # The last line of the rev 6 file is made blank to corrupt it.
+  # And hence the error "Could not convert '' into a number
+  if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.",
+                                 [], errput2, None, ".*svnadmin: E165005: .*"):
+      raise svntest.Failure
+
 ########################################################################
 # Run the tests
 
@@ -1871,6 +1972,7 @@ test_list = [ None,
               locking,
               mergeinfo_race,
               recover_old,
+              verify_keep_going,
              ]
 
 if __name__ == '__main__':
Index: subversion/libsvn_repos/deprecated.c
===================================================================
--- subversion/libsvn_repos/deprecated.c	(revision 1427745)
+++ subversion/libsvn_repos/deprecated.c	(working copy)
@@ -728,6 +728,27 @@ svn_repos_dump_fs2(svn_repos_t *repos,
 }
 
 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_repos/dump.c
===================================================================
--- subversion/libsvn_repos/dump.c	(revision 1427745)
+++ subversion/libsvn_repos/dump.c	(working copy)
@@ -1359,10 +1359,75 @@ verify_close_directory(void *dir_baton,
   return close_directory(dir_baton, pool);
 }
 
+static void
+notify_verification_error(svn_revnum_t rev,
+                          svn_error_t *err,
+                          svn_repos_notify_func_t notify_func,
+                          void *notify_baton,
+                          apr_pool_t *pool)
+{
+  if (notify_func)
+    {
+      svn_repos_notify_t *notify_failure;
+      notify_failure = svn_repos_notify_create(svn_repos_notify_failure, pool);
+      notify_failure->err = err;
+      notify_failure->revision = rev;
+      notify_func(notify_baton, notify_failure, pool);
+    }
+}
+
 svn_error_t *
-svn_repos_verify_fs2(svn_repos_t *repos,
+verification_checks(svn_fs_t *fs,
+                    svn_revnum_t rev,
+                    svn_repos_notify_func_t notify_func,
+                    void *notify_baton,
+                    svn_revnum_t start_rev,
+                    svn_cancel_func_t cancel_func,
+                    void *cancel_baton,
+                    apr_pool_t *iterpool)
+{
+  const svn_delta_editor_t *dump_editor;
+  void *dump_edit_baton;
+
+  svn_fs_root_t *to_root;
+  apr_hash_t *props;
+  const svn_delta_editor_t *cancel_editor;
+  void *cancel_edit_baton;
+
+  /* Get cancellable dump editor, but with our close_directory handler. */
+  SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton,
+                          fs, rev, "",
+                          svn_stream_empty(iterpool),
+                          NULL, NULL,
+                          verify_close_directory,
+                          notify_func, notify_baton,
+                          start_rev,
+                          FALSE, TRUE, /* use_deltas, verify */
+                          iterpool));
+  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
+                                            dump_editor, dump_edit_baton,
+                                            &cancel_editor,
+                                            &cancel_edit_baton,
+                                            iterpool));
+
+  SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
+  SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
+                            cancel_editor, cancel_edit_baton,
+                            NULL, NULL, iterpool));
+
+  /* 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));
+
+  SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, iterpool));
+
+}
+
+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_func,
@@ -1374,6 +1439,8 @@ svn_error_t *
   svn_revnum_t rev;
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_repos_notify_t *notify;
+  svn_error_t *err;
+  svn_boolean_t found_corruption = FALSE;
 
   /* Determine the current youngest revision of the filesystem. */
   SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1397,8 +1464,27 @@ svn_error_t *
                              end_rev, youngest);
 
   /* 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));
+  err = svn_fs_verify(svn_fs_path(fs, pool), cancel_func, cancel_baton,
+                      start_rev, end_rev, pool);
+  if (err && !keep_going)
+    {
+      rev = SVN_INVALID_REVNUM;
+      found_corruption = TRUE;
+      notify_verification_error(rev, err, notify_func, notify_baton,
+                                  iterpool);
+      svn_error_clear(err);
+      return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+                               _("Repository '%s' failed to verify"),
+                               svn_dirent_local_style(svn_repos_path(repos,
+                                                                     pool),
+                                                      pool));
+    }
+  else
+    {
+      if (err)
+        found_corruption = TRUE;
+      svn_error_clear(err);
+    }
 
   /* Create a notify object that we can reuse within the loop. */
   if (notify_func)
@@ -1407,41 +1493,32 @@ svn_error_t *
 
   for (rev = start_rev; rev <= end_rev; rev++)
     {
-      const svn_delta_editor_t *dump_editor;
-      void *dump_edit_baton;
-      const svn_delta_editor_t *cancel_editor;
-      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,
-                              fs, rev, "",
-                              svn_stream_empty(iterpool),
-                              NULL, NULL,
-                              verify_close_directory,
-                              notify_func, notify_baton,
-                              start_rev,
-                              FALSE, TRUE, /* use_deltas, verify */
-                              iterpool));
-      SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
-                                                dump_editor, dump_edit_baton,
-                                                &cancel_editor,
-                                                &cancel_edit_baton,
-                                                iterpool));
+      /* Wrapper function to catch the possible errors. */
+      err = verification_checks(fs, rev, notify_func, notify_baton, start_rev,
+                                cancel_func, cancel_baton, iterpool);
 
-      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
-      SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
-                                cancel_editor, cancel_edit_baton,
-                                NULL, NULL, iterpool));
-      /* 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));
+      if (err && keep_going)
+        {
+          found_corruption = TRUE;
+          notify_verification_error(rev, err, notify_func, notify_baton,
+                                    iterpool);
+          svn_error_clear(err);
+          continue;
+        }
+      else
+        if (err)
+          {
+            found_corruption = TRUE;
+            notify_verification_error(rev, err, notify_func, notify_baton,
+                                      iterpool);
+            svn_error_clear(err);
+            break;
+          }
 
-      SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, iterpool));
-
       if (notify_func)
         {
           notify->revision = rev;
@@ -1459,5 +1536,11 @@ svn_error_t *
   /* Per-backend verification. */
   svn_pool_destroy(iterpool);
 
+  if (found_corruption)
+    return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+                             _("Repository '%s' failed to verify"),
+                             svn_dirent_local_style(svn_repos_path(repos,
+                                                                   pool),
+                                                    pool));
   return SVN_NO_ERROR;
 }
Index: subversion/include/svn_error_codes.h
===================================================================
--- subversion/include/svn_error_codes.h	(revision 1427745)
+++ subversion/include/svn_error_codes.h	(working copy)
@@ -814,6 +814,10 @@ SVN_ERROR_START
              SVN_ERR_REPOS_CATEGORY_START + 4,
              "Bogus revision report")
 
+  SVN_ERRDEF(SVN_ERR_REPOS_CORRUPTED,
+             SVN_ERR_REPOS_CATEGORY_START + 5,
+             "Repository has corruptions")
+
   /* This is analogous to SVN_ERR_FS_UNSUPPORTED_FORMAT.  To avoid
    * confusion with "versions" (i.e., releases) of Subversion, we
    * started using the word "format" instead of "version".  However,
Index: subversion/include/svn_repos.h
===================================================================
--- subversion/include/svn_repos.h	(revision 1427745)
+++ subversion/include/svn_repos.h	(working copy)
@@ -245,8 +245,11 @@ typedef enum svn_repos_notify_action_t
   svn_repos_notify_upgrade_start,
 
   /** A revision was skipped during loading. @since New in 1.8. */
-  svn_repos_notify_load_skipped_rev
+  svn_repos_notify_load_skipped_rev,
 
+  /** A revision is found with corruption/errors. @since New in 1.8. */
+  svn_repos_notify_failure
+
 } svn_repos_notify_action_t;
 
 /** The type of error occurring.
@@ -318,6 +321,11 @@ typedef struct svn_repos_notify_t
   /** For #svn_repos_notify_load_node_start, the path of the node. */
   const char *path;
 
+  /** For #svn_repos_notify_failure, this error chain indicates what
+      went wrong during verification.
+      @since New in 1.8. */
+  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(). */
@@ -2503,8 +2511,9 @@ svn_repos_node_from_baton(void *edit_baton);
 /**
  * Verify the contents of the file system in @a repos.
  *
- * If @a feedback_stream is not @c NULL, write feedback to it (lines of
- * the form "* Verified revision %ld\n").
+ * If @a notify_func is not @c NULL, write feedback to it (lines of
+ * the form "* Verified revision %ld\n". If an error/corruption is found,
+ * the feedback is of the form "* Error verifying revision %ld\n").
  *
  * If @a start_rev is #SVN_INVALID_REVNUM, then start verifying at
  * revision 0.  If @a end_rev is #SVN_INVALID_REVNUM, then verify
@@ -2513,13 +2522,38 @@ svn_repos_node_from_baton(void *edit_baton);
  * For every verified revision call @a notify_func with @a rev set to
  * the verified revision and @a warning_text @c NULL. For warnings call @a
  * notify_func with @a warning_text set.
+ * 
+ * For every revision verification failure call notify_verification_error
+ * with @a rev set to the corrupt revision.
  *
  * If @a cancel_func is not @c NULL, call it periodically with @a
  * cancel_baton as argument to see if the caller wishes to cancel the
  * verification.
  *
+ * If @a keep_going is @c TRUE, the verify process notifies the error message
+ * and continues. If @a notify_func is @c NULL, the verification failure is
+ * not notified. Upon successful completion of verification, return SVN_NO_ERROR
+ * else return the corresponding failure.
+ *
+ * @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);
+
+/**
+ * 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,

Reply via email to